{
  "schemaVersion": 1,
  "id": "aurora-tunnel",
  "version": "1.0.0",
  "status": "published",
  "kind": "background",
  "title": "Aurora Tunnel",
  "summary": "Flying down a corridor of shimmering aurora curtains that stream past towards you. Loops perfectly.",
  "description": "A tunnel lined with aurora: ribbons of green, teal, violet and magenta light hang from the walls of a cylindrical corridor, ripple and fold as they stream past, thin bright ridges where a curtain folds edge-on, with a soft glow and stars at the far end. Choose the colours (borealis, ember, glacier or toxic), the speed of the flight, the brightness, the stars and the seed.",
  "role": "Background (WebGL shader, full frame): a hypnotic, flowing backdrop for music, tech and title content.",
  "collections": [
    "backgrounds",
    "hypnotic-loops"
  ],
  "tags": [
    "aurora",
    "tunnel",
    "corridor",
    "northern lights",
    "flight",
    "light curtains",
    "hypnotic",
    "loop",
    "background"
  ],
  "synonyms": [
    "aurora corridor",
    "light tunnel",
    "northern lights tunnel",
    "time tunnel",
    "glowing tunnel",
    "wormhole"
  ],
  "useCases": [
    "A music-visualiser or club backdrop",
    "A tech or sci-fi title scene",
    "A meditative flowing loop"
  ],
  "featured": null,
  "publishedAt": "2026-10-06",
  "implementation": {
    "target": "three",
    "runtime": "browser",
    "language": "javascript",
    "module": "esm",
    "entry": "src/aurora-tunnel.js",
    "exports": [
      {
        "name": "createAuroraTunnel",
        "signature": "createAuroraTunnel({ palette?, speed?, brightness?, stars?, seed? }) => { scene, camera, setSize(width, height), update(time, loopSeconds), dispose() }",
        "description": "The corridor as one full-screen shader; render its scene with its camera, 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."
      },
      {
        "name": "PALETTES",
        "signature": "PALETTES: { borealis, ember, glacier, toxic }",
        "description": "Curtain colour ramps (sRGB hex)."
      }
    ],
    "reusable": [
      "src/aurora-tunnel.js"
    ],
    "demo": "demo.js",
    "harness": "index.html"
  },
  "dependencies": [
    {
      "id": "three",
      "version": "0.185.1",
      "reason": "Renderer, geometry and shader materials."
    },
    {
      "id": "apw-runtime",
      "version": "1.0.0",
      "scope": "demo",
      "reason": "Demo harness."
    }
  ],
  "params": [
    {
      "key": "palette",
      "label": "Colours",
      "type": "select",
      "default": "borealis",
      "options": [
        {
          "value": "borealis",
          "label": "Borealis"
        },
        {
          "value": "ember",
          "label": "Ember"
        },
        {
          "value": "glacier",
          "label": "Glacier"
        },
        {
          "value": "toxic",
          "label": "Toxic"
        }
      ]
    },
    {
      "key": "speed",
      "label": "Speed",
      "help": "Whole periods of the pattern that stream past in one loop.",
      "type": "integer",
      "min": 1,
      "max": 2,
      "step": 1,
      "default": 1
    },
    {
      "key": "brightness",
      "label": "Brightness",
      "type": "number",
      "min": 0.5,
      "max": 1.6,
      "step": 0.05,
      "default": 1
    },
    {
      "key": "stars",
      "label": "Stars",
      "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": 4
    }
  ],
  "presets": [
    {
      "id": "default",
      "label": "Borealis corridor",
      "params": {}
    },
    {
      "id": "ember",
      "label": "Ember",
      "params": {
        "palette": "ember",
        "seed": 9
      }
    },
    {
      "id": "glacier",
      "label": "Glacier, fast",
      "params": {
        "palette": "glacier",
        "speed": 2,
        "seed": 3
      }
    },
    {
      "id": "toxic",
      "label": "Toxic green",
      "params": {
        "palette": "toxic",
        "brightness": 1.2,
        "seed": 14
      }
    }
  ],
  "output": {
    "width": 1080,
    "height": 1080,
    "fps": 30,
    "durationSeconds": 12,
    "posterSeconds": 3,
    "alpha": false,
    "motion": "procedural",
    "loop": {
      "seamless": true,
      "cycleSeconds": 12,
      "method": "The pattern scrolls a whole number of its periods per loop and is built from the angle's cosine and sine at whole multiples, so it wraps round the tunnel and returns after the loop exactly."
    },
    "seed": {
      "param": "seed",
      "behavior": "Seed shapes the noise of the curtains' folds: same seed, same corridor."
    }
  },
  "composition": {
    "inputs": "Time within the loop; the palette, speed, brightness, stars and seed.",
    "outputs": "A full frame, drawn by one shader on a full-screen quad.",
    "coordinates": "The tunnel's axis points into the screen at the centre; distance down it is 0.45 / radius.",
    "lighting": "Self-lit: the curtains' colours add up; the bloom gives the glow.",
    "timing": "update(time, loopSeconds) sets the loop phase; frames render in any order.",
    "compatibleWith": [
      "kinetic-title",
      "number-reveal"
    ],
    "notes": [
      "Two layers of curtains (3 and 5 round the tunnel); each is a ridge of a folded noise sampled on the circle (cos and sin of the angle at whole multiples) and a distance that scrolls by whole periods of the baked noise texture."
    ]
  },
  "reuse": [
    "Visualiser backdrop: Borealis corridor.",
    "Warm intro: Ember.",
    "Tech opener: Glacier, fast."
  ],
  "integration": {
    "newProject": "Create a WebGLRenderer, createAuroraTunnel() and createBloomPass(renderer, { width, height }); call tunnel.setSize(width, height), then each frame tunnel.update(time, loopSeconds) and bloom.render(tunnel.scene, tunnel.camera).",
    "existingProject": "Copy src/aurora-tunnel.js; render tunnel.scene with tunnel.camera into a render target (or through the bloom pass) as a backdrop."
  },
  "performance": {
    "notes": "One full-screen pass with about twenty texture lookups per pixel and a small bloom. A few milliseconds a frame at 1080p on an integrated Intel GPU.",
    "limits": "Software WebGL renders in about a second a frame."
  },
  "limitations": [
    "The tunnel is a coordinate trick, not 3D geometry: there are no real curtains to fly between.",
    "The flight is straight and constant: no turns or banking."
  ],
  "license": {
    "spdx": "MIT",
    "notice": "Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License. See LICENSE in this folder.",
    "thirdParty": []
  },
  "provenance": "Adapted from the owner's threejs-sketches/light-atmosphere/aurora-tunnel (MIT) and rebuilt for AI Pixel Wizard in October 2026 as an original shader: ridged noise curtains on a circle-sampled baked texture, whole-period scrolling for an exact loop and a bloom.",
  "changelog": [
    {
      "version": "1.0.0",
      "date": "2026-10-05",
      "notes": "Initial release."
    }
  ]
}
