153 lines
5.8 KiB
Markdown
153 lines
5.8 KiB
Markdown
# CLAUDE.md
|
||
|
||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
||
## Project Overview
|
||
|
||
Labelmaker is a Phoenix LiveView web application that generates text-based images via URL. Users can visit `labelmaker.xyz/Your Text` to instantly get an image with their text, with various customization options (font, color, outline, size). The app is designed for creating decals in Tabletop Simulator.
|
||
|
||
## Technology Stack
|
||
|
||
- **Elixir + Phoenix Framework** (Phoenix 1.7+ with LiveView)
|
||
- **ImageMagick** (`magick` command) for image generation
|
||
- **Tailwind CSS** for styling
|
||
- **esbuild** for JavaScript bundling
|
||
|
||
## Common Commands
|
||
|
||
### Development
|
||
```sh
|
||
# Install dependencies and set up assets
|
||
mix setup
|
||
|
||
# Start Phoenix server (runs on http://localhost:4000)
|
||
mix phx.server
|
||
|
||
# Start server with interactive Elixir shell
|
||
iex -S mix phx.server
|
||
```
|
||
|
||
### Testing
|
||
```sh
|
||
# Run all tests
|
||
mix test
|
||
|
||
# Run a specific test file
|
||
mix test test/labelmaker_web/controllers/label_controller_test.exs
|
||
|
||
# Run a specific test
|
||
mix test test/labelmaker_web/controllers/label_controller_test.exs:42
|
||
```
|
||
|
||
### Assets
|
||
```sh
|
||
# Install asset build tools (Tailwind, esbuild)
|
||
mix assets.setup
|
||
|
||
# Build assets for development
|
||
mix assets.build
|
||
|
||
# Build assets for production (minified + digest)
|
||
mix assets.deploy
|
||
```
|
||
|
||
### Docker
|
||
```sh
|
||
docker build -t labelmaker .
|
||
docker run -p 4000:4000 labelmaker
|
||
```
|
||
|
||
## Architecture
|
||
|
||
### Request Flow
|
||
|
||
1. **Homepage (`/`)**: `LabelmakerWeb.Home` LiveView provides an interactive form where users can preview text with different styling options
|
||
2. **Image Generation (`/:label`)**: `LabelmakerWeb.LabelController.show/2` handles dynamic image generation
|
||
|
||
### Core Components
|
||
|
||
**`LabelmakerWeb.LabelController`** (lib/labelmaker_web/controllers/label_controller.ex)
|
||
- Main entry point for image generation requests
|
||
- Takes URL path (label text) and query parameters (color, font, outline, size, width, height, align)
|
||
- Generates SHA256 hash from parameters to create unique filename for caching
|
||
- Checks if cached image exists; if not, builds ImageMagick command and generates image
|
||
- Stores generated images in `priv/static/labels/`
|
||
- Returns image as PNG response
|
||
|
||
**`LabelmakerWeb.Tools`** (lib/labelmaker_web/tools.ex)
|
||
- Contains parameter processing and validation logic
|
||
- `process_parameters/1`: Validates and normalizes user input against permitted values
|
||
- Handles two sizing modes:
|
||
- **Font mode** (default): Uses `label:` with `-pointsize` for natural text sizing
|
||
- **Width x Height mode**: Uses `caption:` with `-size WxH` for fixed dimensions
|
||
- `generate_link/1`: Creates URLs based on current parameters and sizing mode
|
||
- `process_label/1`: Handles `\n` to actual newline conversion for multi-line labels
|
||
- Input validation: filters colors, fonts, sizes, outlines against permitted lists
|
||
|
||
**`LabelmakerWeb.Constants`** (lib/labelmaker_web/constants.ex)
|
||
- Single source of truth for all permitted values and defaults
|
||
- Defines available colors, fonts, sizes, alignments
|
||
- Font map supports shortcuts (e.g., "h" → "Helvetica", "cs" → "Comic-Sans-MS")
|
||
- Max dimensions: 1024x1024 pixels
|
||
- Max label length: 1024 characters
|
||
- Available fonts: Comic Sans, Courier, Georgia, Helvetica, Impact, Verdana
|
||
|
||
**`LabelmakerWeb.Home`** (lib/labelmaker_web/live/home.ex)
|
||
- LiveView for homepage with interactive preview
|
||
- Handles real-time updates via `handle_event/3`:
|
||
- `update_label`: Updates label text and styling parameters
|
||
- `update_preview`: Changes preview background (gradient/solid)
|
||
- `update_sizing`: Toggles between font size mode and width×height mode
|
||
- `update_alignment`: Changes text alignment (left/center/right)
|
||
- Redirects to `/:label` route when user submits the form
|
||
|
||
**`LabelmakerWeb.RadioComponent`** (lib/labelmaker_web/live/components/radio_component.ex)
|
||
- Reusable Phoenix Component for radio button groups
|
||
- Used in the homepage form for alignment selection
|
||
|
||
### ImageMagick Command Construction
|
||
|
||
The controller builds ImageMagick commands programmatically:
|
||
|
||
1. **Basic settings**: background, fill color, font
|
||
2. **Outline settings**: stroke color and width (if not "none")
|
||
3. **Size settings**: Either pointsize + `label:` OR width×height + `caption:`
|
||
4. **Final settings**: Adds metadata comment and output filepath
|
||
|
||
Example generated command:
|
||
```sh
|
||
magick -background none -fill black -font Helvetica -stroke white -strokewidth 1 -pointsize 72 label:Hello World output.png
|
||
```
|
||
|
||
### Sizing Modes
|
||
|
||
The app supports two distinct sizing modes (controlled by `sizing` parameter):
|
||
|
||
- **Font mode** (`sizing=font`): ImageMagick calculates image size based on font size; natural text rendering
|
||
- **Width × Height mode** (`sizing=wxh`): Fixed canvas dimensions with text wrapped/aligned within bounds
|
||
|
||
### Parameter Processing
|
||
|
||
All parameters flow through `Tools.process_parameters/1`:
|
||
1. Merge with defaults from `Constants.defaults()`
|
||
2. Process label (convert `\n` escapes)
|
||
3. Validate each parameter against permitted lists
|
||
4. Filter out invalid values
|
||
5. Calculate derived values (preview_height, rows, link)
|
||
6. Return merged map with all parameters
|
||
|
||
### Caching Strategy
|
||
|
||
Images are cached using SHA256 hash of the processed options map:
|
||
- Hash includes: label, color, font, outline, size, width, height, align
|
||
- Cached files stored in `priv/static/labels/`
|
||
- Before generating, checks if file exists
|
||
- No expiration mechanism (cache persists until manually cleared)
|
||
|
||
## Important Notes
|
||
|
||
- **ImageMagick dependency**: The `magick` command must be available in PATH
|
||
- **Alignment/Gravity mapping**: User-facing "left/center/right" maps to ImageMagick "west/center/east" gravity values (see `Tools.process_gravity/1`)
|
||
- **URL escaping**: Special characters in labels must be URL-encoded; `\n` is processed as literal newline
|
||
- **Main branch**: This repo uses `trunk` as the main branch (not `main` or `master`)
|