{"id":"particle-tunnel","version":"1.0.0","title":"Hypnotic Particle Tunnel","summary":"Fly forever through a twisting tunnel of colourful light streaks. A perfect loop.","kind":"effect","target":"canvas2d","collections":["hypnotic-loops","particles","backgrounds"],"tags":["tunnel","particles","hyperspace","warp","wormhole","loop","streaks","neon","trippy","2d","canvas","hypnotic"],"loopable":true,"motion":"procedural","durationSeconds":6,"status":"published","media":{"poster":"https://aipixelwizard.com/media/particle-tunnel/1.0.0/poster.webp","preview":"https://aipixelwizard.com/media/particle-tunnel/1.0.0/preview.mp4","sample":"https://aipixelwizard.com/media/particle-tunnel/1.0.0/sample.mp4","sampleBytes":9087402,"sampleNote":"Pre-rendered with the default settings. Customised settings must be exported locally (npm run render)."},"urls":{"page":"https://aipixelwizard.com/visuals/particle-tunnel","manifest":"https://aipixelwizard.com/api/v1/visuals/particle-tunnel/versions/1.0.0","agentMd":"https://aipixelwizard.com/registry/particle-tunnel/1.0.0/agent.md","files":"https://aipixelwizard.com/registry/particle-tunnel/1.0.0/","demo":"https://aipixelwizard.com/registry/particle-tunnel/1.0.0/index.html"},"description":"Thousands of glowing streaks rush towards you down a slowly twisting tunnel, like hyperspace or a neon wormhole. Choose the colours, how fast you fly, how much it twists and how long the light trails are. The motion is designed so the end of the clip flows invisibly back into the start, so it can loop forever.","role":"Full-frame animated background or hero effect (Canvas 2D layer).","useCases":["Seamless looping background","Intro or transition","Music visualiser look","Backdrop for a title"],"synonyms":["hypnotic tunnel","colorful particles","colourful particles","warp speed","star field","light speed","vortex","spiral","flying through space","trippy loop"],"digest":"a563f6c7168273912c18a70e111abb4b2c50f8b28eec7102964750f95b1afd97","implementation":{"target":"canvas2d","runtime":"browser","language":"javascript","module":"esm","entry":"src/particle-tunnel.js","exports":[{"name":"createParticleTunnel","signature":"createParticleTunnel({ count?, speed?, twist?, spiral?, hue?, hueRange?, hueCycles?, trail?, size?, seed?, center? }) => { draw(ctx, info, width, height) }","description":"Canvas 2D layer; draws additively over whatever is already on the canvas."}],"reusable":["src/particle-tunnel.js"],"demo":"demo.js","harness":"index.html"},"dependencies":[{"id":"apw-runtime","version":"1.0.0","scope":"demo","reason":"Demo harness. src/particle-tunnel.js has no dependencies."}],"uses":[],"usedBy":[{"id":"hypnotic-tunnel-title","version":"1.0.0"}],"params":[{"key":"density","label":"Particles","type":"integer","min":200,"max":3000,"step":50,"default":1400},{"key":"speed","label":"Speed","help":"Tunnel lengths flown per loop.","type":"integer","min":1,"max":5,"step":1,"default":2},{"key":"twist","label":"Twist","help":"Turns per loop. Negative turns the other way.","type":"integer","min":-2,"max":2,"step":1,"default":1},{"key":"hue","label":"Colour","help":"Starting hue on the colour wheel (0 red, 120 green, 240 blue).","type":"number","min":0,"max":360,"step":1,"default":265},{"key":"colorSpread","label":"Colour spread","help":"0 is one colour; 360 is the full rainbow.","type":"number","min":0,"max":360,"step":5,"default":160},{"key":"colorCycles","label":"Colour cycling","type":"integer","min":0,"max":3,"step":1,"default":0},{"key":"trail","label":"Trail length","type":"number","min":0.005,"max":0.2,"step":0.005,"default":0.06},{"key":"seed","label":"Variation","type":"integer","min":1,"max":9999,"step":1,"default":11},{"key":"background","label":"Background","type":"color","default":"#04030a"}],"presets":[{"id":"default","label":"Violet warp","params":{}},{"id":"rainbow","label":"Rainbow wormhole","params":{"colorSpread":360,"colorCycles":1,"twist":2}},{"id":"ember","label":"Ember drift","params":{"hue":18,"colorSpread":40,"speed":1,"twist":0,"trail":0.12,"density":900}}],"output":{"width":1080,"height":1080,"fps":30,"durationSeconds":6,"posterSeconds":1,"alpha":false,"motion":"procedural","loop":{"seamless":true,"cycleSeconds":6,"method":"Depth wraps by whole tunnel lengths, twist and colour complete whole cycles; state at progress 1 equals progress 0."},"seed":{"param":"seed","behavior":"Seed places the particles. Same seed, same tunnel."}},"composition":{"inputs":"Canvas 2D context, info.progress (0…1), canvas width and height.","outputs":"Draws additive light streaks onto the canvas. Does not clear the canvas: fill your background first.","coordinates":"Pixels. Vanishing point at center (fractions of width/height).","lighting":"Additive ('lighter') blending; looks best on a dark background.","timing":"Pure function of progress; any frame can be drawn out of order.","compatibleWith":["kinetic-title","gradient-background","rolling-counter"],"notes":["Layer text on top after calling draw (see Hypnotic Tunnel Title)."]},"reuse":["Use it behind a Kinetic Title for an intro (see the Hypnotic Tunnel Title example).","Set twist 0 and colour spread 0 for a calm white star-field background.","Move the vanishing point (center option) off-centre for a dynamic side-on warp."],"integration":{"newProject":"Create a canvas, fill the background each frame, then call tunnel.draw(ctx, { progress: frame / totalFrames }, canvas.width, canvas.height).","existingProject":"Copy src/particle-tunnel.js. In your existing frame loop, call draw after painting your background and before your foreground layers. If you use a WebGL or DOM scene, draw it to a separate 2D canvas behind your content."},"performance":{"notes":"1,400 particles is smooth at 1080p in desktop browsers. Each particle is one stroked line.","limits":"Above ~3,000 particles at 4K, frame time rises; lower density for phones."},"limitations":["2D projection: the tunnel is always viewed straight down its axis."],"license":{"spdx":"MIT","notice":"Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License (see LICENSE in this folder).","thirdParty":[]},"rights":{"approvedForPublicRelease":true},"provenance":"Original code written for AI Pixel Wizard in October 2026.","changelog":[{"version":"1.0.0","date":"2026-10-02","notes":"Initial release."}],"verification":{"testedOn":"2026-10-02","inputs":{"particle-tunnel@1.0.0":"a563f6c7168273912c18a70e111abb4b2c50f8b28eec7102964750f95b1afd97","apw-runtime@1.0.0":"5be859cdac74823ba0bcc32c6daf06688a871104d24db5d4ceaffffd84d7c40d"},"environment":"Chrome 151.0.7922.137 headless on Linux 7.0.0-31-generic (x64), Node 22.14.0","renderer":"Canvas 2D","width":1080,"height":1080,"fps":30,"frames":180,"renderSeconds":50.2,"loopCheck":{"checked":true,"seamless":true,"maxDifference":0,"note":"Frame 0 vs end state (progress 1): mean |Δ| 0.0000, max |Δ| 0 of 255."},"determinism":{"checked":true,"identical":true},"errors":[],"media":{"poster":"/media/particle-tunnel/1.0.0/poster.webp","preview":"/media/particle-tunnel/1.0.0/preview.mp4","sample":"/media/particle-tunnel/1.0.0/sample.mp4","sampleBytes":9087402}},"files":[{"path":"LICENSE","size":1072,"sha256":"8a5f3a96f07e11522ec4bdd0a583356f99bad1245920f9709cee09b995a45153","contentType":"text/plain; charset=utf-8","url":"https://aipixelwizard.com/registry/particle-tunnel/1.0.0/LICENSE"},{"path":"asset.json","size":6909,"sha256":"3021c7b32b61e77f793a145ee9a62cc76ebe6846dcbf4baeadc40618a35502ca","contentType":"application/json; charset=utf-8","url":"https://aipixelwizard.com/registry/particle-tunnel/1.0.0/asset.json"},{"path":"demo.js","size":1054,"sha256":"a086aca50f853a4657d881c3586686fd3af045ebf626c27feb8a0e645f4f929a","contentType":"text/javascript; charset=utf-8","url":"https://aipixelwizard.com/registry/particle-tunnel/1.0.0/demo.js"},{"path":"index.html","size":538,"sha256":"b0ca9c2e88c4de02462b6aec2d2041d2afce3159b3854e38f6650fe9b07b8a4a","contentType":"text/html; charset=utf-8","url":"https://aipixelwizard.com/registry/particle-tunnel/1.0.0/index.html"},{"path":"src/particle-tunnel.js","size":4026,"sha256":"779a15ac1dc9570666d458c128aacff9b0b6d7b0b66a4868b55eb240489fe629","contentType":"text/javascript; charset=utf-8","url":"https://aipixelwizard.com/registry/particle-tunnel/1.0.0/src/particle-tunnel.js"}],"warnings":[]}