{
  "schemaVersion": 1,
  "id": "kinetic-title",
  "version": "1.0.0",
  "status": "published",
  "kind": "text",
  "title": "Kinetic Title Reveal",
  "summary": "Bold letters spring up into place one by one, an underline draws itself and a subtitle fades in.",
  "description": "A clean, punchy title animation: each letter rises out of an invisible slot with a little springy overshoot, an accent line sweeps underneath, and an optional subtitle fades up. Type your own words, pick colours and how bouncy it feels. The text size adjusts itself to fit the frame.",
  "role": "Foreground text layer (Canvas 2D).",
  "collections": [
    "kinetic-text",
    "product-reveals"
  ],
  "tags": [
    "title",
    "text",
    "typography",
    "kinetic type",
    "reveal",
    "headline",
    "letters",
    "intro",
    "launch",
    "2d",
    "canvas"
  ],
  "synonyms": [
    "animated title",
    "text animation",
    "animated text",
    "title card",
    "product launch title",
    "text reveal",
    "headline animation",
    "intro text",
    "lower third"
  ],
  "useCases": [
    "Product launch title",
    "Intro or end card",
    "Quote or announcement"
  ],
  "featured": 7,
  "publishedAt": "2026-10-02",
  "implementation": {
    "target": "canvas2d",
    "runtime": "browser",
    "language": "javascript",
    "module": "esm",
    "entry": "src/kinetic-title.js",
    "exports": [
      {
        "name": "createKineticTitle",
        "signature": "createKineticTitle({ text?, subtitle?, fontFamily?, weight?, color?, accent?, delay?, stagger?, letterDuration?, overshoot?, style?, exitAt?, maxWidth?, y? }) => { draw(ctx, info, width, height), revealDuration }",
        "description": "Canvas 2D text layer driven by info.time (seconds)."
      }
    ],
    "reusable": [
      "src/kinetic-title.js"
    ],
    "demo": "demo.js",
    "harness": "index.html"
  },
  "dependencies": [
    {
      "id": "apw-runtime",
      "version": "1.0.0",
      "scope": "demo",
      "reason": "Demo harness. src/kinetic-title.js has no dependencies."
    }
  ],
  "params": [
    {
      "key": "text",
      "label": "Title",
      "type": "text",
      "default": "MAKE IT MOVE",
      "maxLength": 40,
      "sensitive": true
    },
    {
      "key": "subtitle",
      "label": "Subtitle",
      "type": "text",
      "default": "Made with JavaScript",
      "maxLength": 60,
      "sensitive": true
    },
    {
      "key": "style",
      "label": "Entrance",
      "type": "select",
      "default": "rise",
      "options": [
        {
          "value": "rise",
          "label": "Rise up"
        },
        {
          "value": "drop",
          "label": "Drop down"
        },
        {
          "value": "scale",
          "label": "Pop (scale)"
        }
      ]
    },
    {
      "key": "stagger",
      "label": "Letter delay",
      "help": "Seconds between letters.",
      "type": "number",
      "min": 0.01,
      "max": 0.2,
      "step": 0.005,
      "default": 0.055
    },
    {
      "key": "bounce",
      "label": "Bounce",
      "type": "number",
      "min": 0,
      "max": 3,
      "step": 0.1,
      "default": 1.6
    },
    {
      "key": "exit",
      "label": "Fade out at the end",
      "type": "boolean",
      "default": false
    },
    {
      "key": "color",
      "label": "Text colour",
      "type": "color",
      "default": "#ffffff"
    },
    {
      "key": "accent",
      "label": "Underline colour",
      "type": "color",
      "default": "#7c6cff"
    },
    {
      "key": "background",
      "label": "Background",
      "type": "color",
      "default": "#0c0b12"
    }
  ],
  "presets": [
    {
      "id": "default",
      "label": "Rise",
      "params": {}
    },
    {
      "id": "pop",
      "label": "Pop",
      "params": {
        "style": "scale",
        "bounce": 2.4,
        "accent": "#ff6fb5"
      }
    },
    {
      "id": "calm",
      "label": "Calm drop",
      "params": {
        "style": "drop",
        "bounce": 0.4,
        "stagger": 0.09,
        "exit": true
      }
    }
  ],
  "output": {
    "width": 1080,
    "height": 1080,
    "fps": 30,
    "durationSeconds": 4,
    "posterSeconds": 2.5,
    "alpha": false,
    "motion": "procedural",
    "loop": {
      "seamless": false,
      "method": "A reveal that ends on the finished title (or fades out with the exit option)."
    },
    "seed": null
  },
  "composition": {
    "inputs": "Canvas 2D context, info.time (seconds), width, height.",
    "outputs": "Draws text on top of the canvas. Does not clear it.",
    "coordinates": "Centred horizontally; y option is a fraction of height.",
    "lighting": "None.",
    "timing": "Pure function of time. revealDuration tells you when it has finished.",
    "compatibleWith": [
      "particle-tunnel",
      "gradient-background",
      "torus-wave",
      "spring-motion"
    ],
    "notes": [
      "Title text is treated as private: it is not stored in shared packs unless you choose to include it.",
      "System fonts differ between computers; pass fontFamily and load the font first for identical renders."
    ]
  },
  "reuse": [
    "Put it over Hypnotic Particle Tunnel for an intro (see Hypnotic Tunnel Title).",
    "Use it as an end card after any 3D scene by drawing it onto a 2D overlay canvas.",
    "Set y to 0.82 and a smaller maxWidth for a lower-third caption."
  ],
  "integration": {
    "newProject": "Create the title once, then each frame draw your background and call title.draw(ctx, { time: frame / fps }, width, height).",
    "existingProject": "Copy src/kinetic-title.js. Call draw on your existing 2D canvas (or an overlay canvas above a WebGL scene) after the rest of the frame."
  },
  "performance": {
    "notes": "One measureText per letter per frame; negligible.",
    "limits": "Best under ~30 characters per line (no automatic line wrapping)."
  },
  "limitations": [
    "Single line, left-to-right scripts. No automatic wrapping or right-to-left shaping."
  ],
  "license": {
    "spdx": "MIT",
    "notice": "Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License (see LICENSE in this folder).",
    "thirdParty": []
  },
  "provenance": "Original code written for AI Pixel Wizard in October 2026. Uses the viewer's system font; no font files are bundled.",
  "changelog": [
    {
      "version": "1.0.0",
      "date": "2026-10-02",
      "notes": "Initial release."
    }
  ]
}
