{
  "schemaVersion": 1,
  "id": "neon-sign",
  "version": "1.0.0",
  "status": "published",
  "kind": "text",
  "title": "Neon Sign",
  "summary": "Your words as a glowing neon sign on a brick wall at night, flickering on like the real thing.",
  "description": "Type one or two lines and they are bent in glass tube like a real neon sign: hot, slightly overexposed tubes, a soft glow in the air and coloured light spilling onto the bricks around them. It switches on with a stutter, letter by letter, or writes itself on, or buzzes on a seamless loop. Choose the two tube colours, a border, the wall (red brick, painted brick, concrete, or black for blending), how much it flickers, and one dying letter if you like.",
  "role": "Title or sign (Three.js, full frame): neon lettering with its own wall and light.",
  "collections": [
    "kinetic-text"
  ],
  "tags": [
    "neon",
    "neon sign",
    "neon text",
    "glow",
    "sign",
    "night",
    "brick wall",
    "flicker",
    "retro",
    "bar",
    "title"
  ],
  "synonyms": [
    "neon light text",
    "glowing sign",
    "neon lettering",
    "open sign",
    "bar sign",
    "light-up sign",
    "neon title",
    "flickering neon",
    "neon tube text"
  ],
  "useCases": [
    "An opener or end card with your channel or brand name in neon",
    "\"Open\", \"Live\" or \"Sale\" signs for shop, bar and event videos",
    "A moody night-time title for music, gaming and nightlife reels"
  ],
  "featured": null,
  "publishedAt": "2026-10-05",
  "implementation": {
    "target": "three",
    "runtime": "browser",
    "language": "javascript",
    "module": "esm",
    "entry": "src/neon-sign.js",
    "exports": [
      {
        "name": "createNeonSign",
        "signature": "createNeonSign({ renderer, width, height, lines?, frame?, frameColor?, wall?, animation?, flicker?, faulty?, tube?, glow?, size?, duration?, seed? }) => { render(time, renderTarget?), units, tubeWidth, capHeight, onAt, brightness(index, time), dispose() }",
        "description": "The whole frame: wall, glass tubes and light. render(time) draws it to the canvas, or to a WebGLRenderTarget to use as a texture."
      },
      {
        "name": "neonGlyphs",
        "signature": "neonGlyphs(text) => { width, letters: [{ char, x, width, strokes: [{ closed, points }] }] }",
        "description": "The single-stroke alphabet on its own: one line of text as tube centre-lines in cap heights, to draw another way (for example as THREE.TubeGeometry)."
      },
      {
        "name": "WALLS",
        "signature": "WALLS: { brick, painted, concrete, black }",
        "description": "The built-in walls and their room light."
      }
    ],
    "reusable": [
      "src/neon-sign.js"
    ],
    "demo": "demo.js",
    "harness": "index.html"
  },
  "dependencies": [
    {
      "id": "three",
      "version": "0.185.1",
      "reason": "Renderer, render targets and shaders for the glow."
    },
    {
      "id": "apw-runtime",
      "version": "1.0.0",
      "scope": "demo",
      "reason": "Demo harness."
    }
  ],
  "params": [
    {
      "key": "line1",
      "label": "Line 1",
      "help": "Letters, numbers, punctuation and ♥ ★ ⚡ → (type <3 for a heart).",
      "type": "text",
      "default": "OPEN",
      "maxLength": 24,
      "sensitive": true
    },
    {
      "key": "line2",
      "label": "Line 2",
      "help": "Smaller, under line 1. Leave empty for one line.",
      "type": "text",
      "default": "ALL NIGHT",
      "maxLength": 32,
      "sensitive": true
    },
    {
      "key": "color1",
      "label": "Line 1 colour",
      "type": "color",
      "default": "#ff2a6d"
    },
    {
      "key": "color2",
      "label": "Line 2 and border colour",
      "type": "color",
      "default": "#2bb3ff"
    },
    {
      "key": "frame",
      "label": "Border",
      "type": "select",
      "default": "box",
      "options": [
        {
          "value": "none",
          "label": "None"
        },
        {
          "value": "box",
          "label": "Rounded box"
        },
        {
          "value": "oval",
          "label": "Oval"
        }
      ]
    },
    {
      "key": "wall",
      "label": "Wall",
      "type": "select",
      "default": "brick",
      "options": [
        {
          "value": "brick",
          "label": "Red brick"
        },
        {
          "value": "painted",
          "label": "Painted brick"
        },
        {
          "value": "concrete",
          "label": "Concrete"
        },
        {
          "value": "black",
          "label": "Black (for Screen blending)"
        }
      ]
    },
    {
      "key": "animation",
      "label": "Animation",
      "type": "select",
      "default": "ignite",
      "options": [
        {
          "value": "ignite",
          "label": "Switch on"
        },
        {
          "value": "write",
          "label": "Write on"
        },
        {
          "value": "buzz",
          "label": "Buzzing loop"
        },
        {
          "value": "steady",
          "label": "Steady"
        }
      ]
    },
    {
      "key": "flicker",
      "label": "Flicker",
      "type": "number",
      "min": 0,
      "max": 1,
      "step": 0.05,
      "default": 0.4
    },
    {
      "key": "faulty",
      "label": "Dying letter",
      "help": "Number of a letter, counting from the first, that flickers like a failing tube. 0 for none.",
      "type": "integer",
      "min": 0,
      "max": 40,
      "step": 1,
      "default": 0
    },
    {
      "key": "tube",
      "label": "Tube thickness",
      "type": "number",
      "min": 0.6,
      "max": 1.6,
      "step": 0.05,
      "default": 1
    },
    {
      "key": "glow",
      "label": "Glow",
      "type": "number",
      "min": 0.3,
      "max": 2,
      "step": 0.05,
      "default": 1
    },
    {
      "key": "size",
      "label": "Size",
      "help": "How much of the frame the sign fills.",
      "type": "number",
      "min": 0.4,
      "max": 1,
      "step": 0.05,
      "default": 1
    },
    {
      "key": "seed",
      "label": "Variation",
      "help": "Changes the flicker timing and the bricks.",
      "type": "integer",
      "min": 1,
      "max": 9999,
      "step": 1,
      "default": 1
    }
  ],
  "presets": [
    {
      "id": "default",
      "label": "Open all night",
      "params": {}
    },
    {
      "id": "good-vibes",
      "label": "Good vibes, written on",
      "params": {
        "line1": "GOOD VIBES",
        "line2": "ONLY ♥",
        "color1": "#ff4fd8",
        "color2": "#ffd166",
        "frame": "none",
        "wall": "painted",
        "animation": "write"
      }
    },
    {
      "id": "game-on",
      "label": "Game on, buzzing loop",
      "params": {
        "line1": "GAME ON",
        "line2": "PRESS START",
        "color1": "#b14cff",
        "color2": "#39ff88",
        "frame": "oval",
        "wall": "concrete",
        "animation": "buzz",
        "flicker": 0.6
      }
    },
    {
      "id": "motel",
      "label": "Motel with a dying letter",
      "params": {
        "line1": "MOTEL",
        "line2": "VACANCY",
        "color1": "#ff5a36",
        "color2": "#3dffb0",
        "frame": "none",
        "animation": "buzz",
        "flicker": 0.7,
        "faulty": 4,
        "seed": 3
      }
    }
  ],
  "output": {
    "width": 1080,
    "height": 1080,
    "fps": 30,
    "durationSeconds": 6,
    "posterSeconds": 4,
    "alpha": false,
    "motion": "procedural",
    "loop": {
      "seamless": false,
      "method": "Switches on and then holds, buzzing. Choose the Buzzing loop animation for a seamless loop: every flicker sits inside the loop and the hum completes whole cycles."
    },
    "seed": {
      "param": "seed",
      "behavior": "Seed picks the flicker timing and the bricks: same seed, same sign."
    }
  },
  "composition": {
    "inputs": "A WebGLRenderer, the frame size, your lines and colours. Time in seconds for each frame.",
    "outputs": "The whole frame (wall, tubes and glow) drawn to the canvas or to a WebGLRenderTarget.",
    "coordinates": "The sign is centred and sized to fit the frame; any aspect ratio works.",
    "lighting": "Self-lit: the tubes light the wall themselves; scene lights do not affect it.",
    "timing": "render(time) is a pure function of time; frames render in any order. onAt tells you when the sign is fully lit.",
    "compatibleWith": [
      "kinetic-title",
      "particle-tunnel",
      "dither-animation"
    ],
    "notes": [
      "Text is treated as private: it is not stored in shared packs unless you choose to include it.",
      "The alphabet is built in (no fonts to load), so renders are identical on every computer. Letters it does not have are skipped.",
      "Use the black wall and Screen (or Add) blending to put the sign over your own footage."
    ]
  },
  "reuse": [
    "Bar or shop opener: your venue's name on brick with Switch on, then cut to footage.",
    "Over your own footage: black wall, render to a video, and blend it with Screen in your editor.",
    "Neon in a 3D room: render to a WebGLRenderTarget and use its texture on a plane, or build TubeGeometry from neonGlyphs()."
  ],
  "integration": {
    "newProject": "Create a WebGLRenderer, then createNeonSign({ renderer, width, height, lines }) once and call sign.render(frame / fps) every frame.",
    "existingProject": "Copy src/neon-sign.js. Render it to a WebGLRenderTarget and use the texture in your scene, or render it to its own canvas and layer that over yours."
  },
  "performance": {
    "notes": "The lit tubes are redrawn only when their brightness changes; the glow is a few blur passes at quarter to sixteenth resolution. Smooth at 1080p on laptop GPUs.",
    "limits": "Best under about 20 characters per line (no line wrapping): longer lines get smaller. Software WebGL (no GPU) renders slowly."
  },
  "limitations": [
    "Capital letters only (lower case is shown in capitals), in one built-in tube style: A–Z with accents, 0–9, common punctuation and ♥ ★ ⚡ → ←.",
    "Seen straight on: the tubes and wall are drawn, not modelled in 3D."
  ],
  "license": {
    "spdx": "MIT",
    "notice": "Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License. See LICENSE in this folder.",
    "thirdParty": [
      {
        "name": "three.js",
        "version": "0.185.1",
        "license": "MIT",
        "url": "https://github.com/mrdoob/three.js"
      }
    ]
  },
  "provenance": "Adapted from the owner's threejs-sketches/light-atmosphere/webgpu-neon-tubes (MIT), rebuilt for AI Pixel Wizard in October 2026: a single-stroke neon alphabet for your own words, HDR glow with light spilling onto a lit brick wall, deterministic switch-on and flicker, and the frame/time contract.",
  "changelog": [
    {
      "version": "1.0.0",
      "date": "2026-10-05",
      "notes": "Initial release."
    }
  ]
}
