# Template JSON Schema This document describes the template structure for creating custom t-shirt design templates. > **Note (2026-07-06):** this doc predates the goods-editor extraction and the > v4 multi-view template schema. The authoritative element schema lives in > `goods-editor-module/CLAUDE.md` ("Element schema") and the accepted payload > shape in `template-manager/src/server/lib/validation.js`. The property > tables below are still accurate for the fields they list. ## Template Structure ```json { "id": "string (unique identifier)", "name": "string (display name)", "category": "string (Sports|Music|Quotes|Animals|Abstract|Vintage|Nature|Tech)", "description": "string (short description)", "elements": [ { "type": "text" | "image", "text": "string (for text elements only)", "x": "number (x position in canvas units)", "y": "number (y position in canvas units)", "fontSize": "number (for text elements)", "fontFamily": "string (Google Font name)", "fill": "string (hex color)", "rotation": "number (degrees, -180 to 180)", "width": "number (for image elements)", "height": "number (for image elements)", "src": "string (image URL or path)" } ] } ``` ## Element Properties ### Text Element | Property | Type | Required | Description | |------------|--------|----------|---------------------------------------| | `type` | string | Yes | Must be `"text"` | | `text` | string | Yes | The text content to display | | `x` | number | Yes | X position on canvas (0-300) | | `y` | number | Yes | Y position on canvas (0-300) | | `fontSize` | number | Yes | Font size in pixels (12-120) | | `fontFamily`| string| No | Google Font name (default: "DM Sans") | | `fill` | string | No | Hex color (default: "#0f172a") | | `rotation` | number | No | Rotation in degrees (default: 0) | | `arc` | number | No | Curve amount (default: 0 = flat). `> 0` arcs up (rainbow), `< 0` arcs down (smile). See "Curved text" below. | | `align` | string | No | `left` \| `center` \| `right` (default: `center`; multi-line) | | `lineHeight` | number | No | Line-box ratio of fontSize (default: 1.2) | | `letterSpacing` | number | No | Absolute tracking in canvas units (default: 0; suspended while curved) | #### Curved text (`arc`) - The editor's Curve slider writes values in **−100..100**; hand-authored templates should stay in that range. - The stored value up to **±200** is honored by the renderer and the print exporter (`ARC_MODEL_MAX` in the goods-editor module, 2026-07-06): the editor itself *derives* values above 100 when preserving an authored curve on long customer text whose font size auto-shrank. Don't hand-author above ±100 — the headroom exists for derived values. - What is visually preserved across customer edits is the curve's **density** (`arc · fontSize / width`), not the raw number: the editor rescales `arc` as text, font, or size changes so the perceived sweep the template author designed stays constant. Expect saved customer designs to carry arc values that differ from the authored one. - `letterSpacing` has no effect while `|arc| > 0.5` (suspension rule); the stored value survives and reapplies when the text goes flat. ### Image Element | Property | Type | Required | Description | |------------|--------|----------|---------------------------------------| | `type` | string | Yes | Must be `"image"` | | `src` | string | Yes | Image URL or server path | | `x` | number | Yes | X position on canvas (0-300) | | `y` | number | Yes | Y position on canvas (0-300) | | `width` | number | Yes | Width in canvas units (min: 20) | | `height` | number | Yes | Height in canvas units (min: 20) | | `rotation` | number | No | Rotation in degrees (default: 0) | ## Advanced Template Features ### Template with Background and Overlay For templates that include background images and overlay elements: ```json { "id": "team-sport", "name": "Team Sport", "category": "Sports", "description": "Classic team jersey with number and text", "background": { "type": "color" | "image", "color": "string (hex, if type is color)", "src": "string (URL/path, if type is image)" }, "overlay": [ { "type": "text" | "image", "nonPrintable": false, "...": "same properties as regular elements" } ], "elements": [...] } ``` ### Slot-Based Templates For templates with image slots (auto-crop regions): ```json { "id": "classic-tee-front", "name": "Classic Tee - Front", "slots": [ { "id": "chest-logo", "bounds": { "x": 100, "y": 80, "width": 100, "height": 100 }, "aspectRatio": 1.0, "label": "Chest Logo" }, { "id": "sleeve-left", "bounds": { "x": 20, "y": 100, "width": 60, "height": 60 }, "aspectRatio": 1.0, "label": "Left Sleeve" } ], "elements": [] } ``` ### Slot Crop Region When an image is assigned to a slot, the crop property is applied: ```json { "type": "image", "src": "/uploads/image.png", "x": 100, "y": 80, "width": 100, "height": 100, "crop": { "sx": 0, "sy": 0, "sWidth": 500, "sHeight": 500 } } ``` | Property | Type | Description | |-----------|--------|--------------------------------------| | `sx` | number | Source x coordinate for crop | | `sy` | number | Source y coordinate for crop | | `sWidth` | number | Source width for crop | | `sHeight` | number | Source height for crop | ## Non-Printable Elements Elements can be marked as non-printable to exclude them from export: ```json { "type": "text", "text": "Guide Text", "nonPrintable": true, "x": 150, "y": 150, "fontSize": 12, "fill": "#cccccc" } ``` ## Example Templates ### Minimal Quote Template ```json { "id": "minimal-quote", "name": "Minimal Quote", "category": "Quotes", "description": "Simple centered quote design", "elements": [ { "type": "text", "text": "\"Be the change\"", "x": 150, "y": 130, "fontSize": 24, "fontFamily": "Georgia", "fill": "#1e293b", "rotation": 0 }, { "type": "text", "text": "you wish to see", "x": 150, "y": 160, "fontSize": 18, "fontFamily": "Arial", "fill": "#64748b", "rotation": 0 } ] } ``` ### Team Sport Template ```json { "id": "team-sport", "name": "Team Sport", "category": "Sports", "description": "Classic team jersey with number and text", "elements": [ { "type": "text", "text": "TEAM NAME", "x": 75, "y": 80, "fontSize": 28, "fontFamily": "Impact", "fill": "#ffffff", "rotation": 0 }, { "type": "text", "text": "23", "x": 150, "y": 150, "fontSize": 72, "fontFamily": "Impact", "fill": "#ffffff", "rotation": 0 } ] } ``` ## Canvas Coordinate System - Canvas size: 300x300 units (preview) - Export size: 4500x4500 pixels (300 DPI, 15"x15") - Scale factor: 15x (export / preview) - Origin (0,0): Top-left corner - X increases: Left to right - Y increases: Top to bottom ## Best Practices 1. **Keep text readable**: Use font sizes between 18-72px for main text 2. **Respect print area**: Keep elements within 0-300 canvas bounds 3. **Use contrasting colors**: Ensure text is visible on shirt colors 4. **Test at export size**: Verify designs look good at 4500x4500px 5. **Limit elements**: 5-10 elements maximum for performance