{
  "schemaVersion": 1,
  "id": "digital-rain",
  "version": "1.0.0",
  "status": "published",
  "kind": "background",
  "title": "Digital Rain",
  "summary": "Columns of glowing code falling around the camera in layers of depth, with a message you can write in the rain. Loops perfectly.",
  "description": "Streams of invented glyphs falling in the dark, each with a white-hot head and a trail fading to black, seen from the middle of four concentric cylinders of them: the near glyphs are big and soft, the far ones small and fine, and the camera's slow sway slides the layers past each other. Cells flicker through an alphabet of 128 glyphs, quicker at the head of a column. Write a message of up to 24 letters and it appears in the finest layer as a dot-matrix of glowing glyphs that stays lit while the rain falls through it. Choose the colours (terminal green, cyan, amber or magenta), the message, how much rain, how fast it falls, how long the trails are, how big the glyphs, how many depth layers, how far the camera sways and how much the glyphs glow.",
  "role": "Background (WebGL shader, full frame): a code-rain backdrop for tech, hacker, AI and title content, with an optional message.",
  "collections": [
    "backgrounds",
    "hypnotic-loops"
  ],
  "tags": [
    "digital rain",
    "code rain",
    "matrix",
    "glyphs",
    "hacker",
    "cyber",
    "terminal",
    "falling code",
    "text reveal",
    "loop",
    "background"
  ],
  "synonyms": [
    "matrix rain",
    "falling code",
    "binary rain",
    "code waterfall",
    "cyberpunk background",
    "hacker background",
    "data rain",
    "green code"
  ],
  "useCases": [
    "A tech, AI or cybersecurity intro or title backdrop",
    "A message or countdown revealed in code",
    "A game or app loading screen"
  ],
  "featured": null,
  "publishedAt": "2026-10-06",
  "implementation": {
    "target": "three",
    "runtime": "browser",
    "language": "javascript",
    "module": "esm",
    "entry": "src/digital-rain.js",
    "exports": [
      {
        "name": "createDigitalRain",
        "signature": "createDigitalRain({ palette?, density?, fall?, trail?, size?, layers?, sway?, glow?, message?, seed? }) => { scene, camera, material, setSize(width, height), update(time, loopSeconds), dispose() }",
        "description": "The whole rain as one full-screen shader: render its scene with its camera after setSize and update, ideally through createBloomPass."
      },
      {
        "name": "createBloomPass",
        "signature": "createBloomPass(renderer, { width, height, glow?, exposure?, grain? }) => { render(scene, camera, output?), dispose() }",
        "description": "A small bloom with filmic tone mapping: draws a scene to the canvas with its glow."
      },
      {
        "name": "PALETTES",
        "signature": "PALETTES: { green, cyan, amber, magenta }",
        "description": "The colour of the head of a column, of its body, and of the tail it fades to."
      },
      {
        "name": "MAX_MESSAGE",
        "signature": "MAX_MESSAGE: 24",
        "description": "The most letters a message can have."
      }
    ],
    "reusable": [
      "src/digital-rain.js"
    ],
    "demo": "demo.js",
    "harness": "index.html"
  },
  "dependencies": [
    {
      "id": "three",
      "version": "0.185.1",
      "reason": "Renderer and the full-screen shader."
    },
    {
      "id": "apw-runtime",
      "version": "1.0.0",
      "scope": "demo",
      "reason": "Demo harness."
    }
  ],
  "params": [
    {
      "key": "palette",
      "label": "Colours",
      "type": "select",
      "default": "green",
      "options": [
        {
          "value": "green",
          "label": "Terminal green"
        },
        {
          "value": "cyan",
          "label": "Cyan"
        },
        {
          "value": "amber",
          "label": "Amber"
        },
        {
          "value": "magenta",
          "label": "Magenta"
        }
      ]
    },
    {
      "key": "message",
      "label": "Message",
      "help": "Up to 24 letters, written in the finest layer of the rain.",
      "type": "text",
      "default": "Hello, world",
      "maxLength": 24,
      "sensitive": true
    },
    {
      "key": "density",
      "label": "Rain",
      "type": "number",
      "min": 0.3,
      "max": 1,
      "step": 0.05,
      "default": 0.8
    },
    {
      "key": "fall",
      "label": "Fall speed",
      "type": "integer",
      "min": 1,
      "max": 3,
      "step": 1,
      "default": 1
    },
    {
      "key": "trail",
      "label": "Trail length",
      "type": "number",
      "min": 0.5,
      "max": 1.6,
      "step": 0.05,
      "default": 1
    },
    {
      "key": "size",
      "label": "Glyph size",
      "type": "number",
      "min": 0.6,
      "max": 1.6,
      "step": 0.05,
      "default": 1
    },
    {
      "key": "layers",
      "label": "Depth layers",
      "type": "integer",
      "min": 2,
      "max": 4,
      "step": 1,
      "default": 4
    },
    {
      "key": "sway",
      "label": "Camera sway",
      "type": "number",
      "min": 0,
      "max": 1.5,
      "step": 0.05,
      "default": 1
    },
    {
      "key": "glow",
      "label": "Glow",
      "type": "number",
      "min": 0,
      "max": 1.5,
      "step": 0.05,
      "default": 1
    },
    {
      "key": "seed",
      "label": "Seed",
      "type": "integer",
      "min": 1,
      "max": 999,
      "step": 1,
      "default": 7
    }
  ],
  "presets": [
    {
      "id": "default",
      "label": "Terminal green, with a message",
      "params": {}
    },
    {
      "id": "blue",
      "label": "Blue rain, no message",
      "params": {
        "palette": "cyan",
        "message": "",
        "density": 0.9,
        "fall": 2,
        "trail": 1.2,
        "seed": 21
      }
    },
    {
      "id": "amber",
      "label": "Amber terminal",
      "params": {
        "palette": "amber",
        "message": "System ready",
        "layers": 3,
        "size": 1.3,
        "sway": 0.6,
        "seed": 4
      }
    },
    {
      "id": "storm",
      "label": "Magenta downpour",
      "params": {
        "palette": "magenta",
        "message": "",
        "density": 1,
        "fall": 2,
        "trail": 0.8,
        "size": 0.8,
        "glow": 1.3,
        "seed": 33
      }
    }
  ],
  "output": {
    "width": 1080,
    "height": 1080,
    "fps": 30,
    "durationSeconds": 12,
    "posterSeconds": 2,
    "alpha": false,
    "motion": "procedural",
    "loop": {
      "seamless": true,
      "cycleSeconds": 12,
      "method": "Each column's head falls a whole number of its own length per loop, so the rain wraps exactly; every cell changes glyph a whole number of times a loop (the glyph is picked from the cell and the count of changes modulo that whole number); the camera's sway is a sine of the loop, so the last frame meets the first."
    },
    "seed": {
      "param": "seed",
      "behavior": "Seed invents the 128 glyphs and picks which columns rain, their speed and trail: same seed, same rain."
    }
  },
  "composition": {
    "inputs": "Time within the loop; the colours, message, amount of rain, speed, trails, glyph size, layers, sway and glow.",
    "outputs": "A full frame, drawn by one shader on a full-screen quad; the glyphs come from an atlas baked in JavaScript.",
    "coordinates": "The camera sits on the axis of four concentric cylinders (radii 1.2 to 4.6) of columns; the rays are intersected with them, so the glyphs curve gently towards the edges of the frame.",
    "lighting": "Self-lit: every glyph glows; the bloom adds the halation.",
    "timing": "update(time, loopSeconds) sets the loop phase; frames render in any order.",
    "compatibleWith": [
      "kinetic-title",
      "number-reveal"
    ],
    "notes": [
      "No fonts and no image files: the alphabet is 128 invented glyphs (strokes between lattice points) baked into a signed-distance atlas, sharp or soft at any size.",
      "The message uses a 5 × 7 dot font, one cell of the finest layer to a dot."
    ]
  },
  "reuse": [
    "AI or tech title: Terminal green with the title as the message.",
    "Countdown or reveal: Amber terminal with a short message.",
    "Background for code and security explainers: Blue rain, no message."
  ],
  "integration": {
    "newProject": "Create a WebGLRenderer, createDigitalRain({ message }) and createBloomPass(renderer, { width, height }); call rain.setSize(width, height), then each frame rain.update(time, loopSeconds) and bloom.render(rain.scene, rain.camera).",
    "existingProject": "Copy src/digital-rain.js; render rain.scene with rain.camera into a render target (or through the bloom pass) as the backdrop of your scene."
  },
  "performance": {
    "notes": "One full-screen pass: up to four layers, each a ray-cylinder intersection, a few hashes and one texture lookup, plus a small bloom. About 14 ms a frame at 1080p on an integrated Intel GPU.",
    "limits": "Messages are capped at 24 letters; characters outside letters, digits and . , ! ? - : ' are drawn as spaces."
  },
  "limitations": [
    "The glyphs are invented shapes, not real writing systems.",
    "The message sits in the finest layer, so it is small on screen unless it is short."
  ],
  "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/abstract-artistic/matrix-rain (MIT) and rebuilt for AI Pixel Wizard in October 2026 as an original shader: concentric cylinders of columns seen from their axis, signed-distance glyphs invented in code, a dot-matrix message, an exact loop and the frame/time contract.",
  "changelog": [
    {
      "version": "1.0.0",
      "date": "2026-10-05",
      "notes": "Initial release."
    }
  ]
}
