# 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`)