Files
apparel-designer/docs/template-schema.md
khalid@traclabs.com aba2dbedfb v0.6: template-manager owns the product catalog
The host no longer carries a runtime product catalog. products.js
shrinks to a legacy single-product stub; the canonical catalog lives in
template-manager's productsStore, seeded ONCE on first boot from the
new seedProducts.js (after that the store under templates/ is
authoritative and the seed is ignored — intentional, so restarts never
rewrite an admin-managed catalog). phoneModels.js and
templateCategories.js are the supporting constant sets, and
docs/template-schema.md documents the v4 schema.

templates/ is the admin-managed store itself (_products_index.json +
products/<id>/product.json, JSON only) — committed so the configured
catalog (sizes, pricing, options built up in the admin UI) survives a
fresh checkout rather than regressing to the seed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-01 23:28:48 -05:00

7.8 KiB
Raw Blame History

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

{
  "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:

{
  "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):

{
  "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:

{
  "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:

{
  "type": "text",
  "text": "Guide Text",
  "nonPrintable": true,
  "x": 150,
  "y": 150,
  "fontSize": 12,
  "fill": "#cccccc"
}

Example Templates

Minimal Quote Template

{
  "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

{
  "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