{"id":"prism-dispersion","version":"1.0.0","title":"Prism Dispersion","summary":"A white beam enters a glass prism and fans out into a rainbow, the prism turning slowly so the spectrum swings. Loops perfectly.","kind":"background","target":"three","collections":["backgrounds","hypnotic-loops"],"tags":["prism","dispersion","rainbow","spectrum","light","refraction","glass","physics","optics","science","loop","background"],"loopable":true,"motion":"procedural","durationSeconds":12,"status":"published","media":{"poster":"https://aipixelwizard.com/media/prism-dispersion/1.0.0/poster.webp","preview":"https://aipixelwizard.com/media/prism-dispersion/1.0.0/preview.mp4","sample":"https://aipixelwizard.com/media/prism-dispersion/1.0.0/sample.mp4","sampleBytes":969971,"sampleNote":"Pre-rendered with the default settings. Customised settings must be exported locally (npm run render)."},"urls":{"page":"https://aipixelwizard.com/visuals/prism-dispersion","manifest":"https://aipixelwizard.com/api/v1/visuals/prism-dispersion/versions/1.0.0","agentMd":"https://aipixelwizard.com/registry/prism-dispersion/1.0.0/agent.md","files":"https://aipixelwizard.com/registry/prism-dispersion/1.0.0/","demo":"https://aipixelwizard.com/registry/prism-dispersion/1.0.0/index.html"},"description":"A beam of white light climbs out of the dark, enters a glass prism, is bent and spread into every colour from violet to red and falls across a wall. The optics are traced for real: forty wavelengths are refracted with Snell's law through glass whose index falls with wavelength, carried across the prism and refracted out again, so the spectrum has the true order and spread; as the prism turns the fan swings and, at the extreme, the violet (the most bent) is caught inside by total internal reflection and thrown out of the base as a violet beam. Dust turns in the beam. Choose the glass (crown, flint or diamond), how strongly it spreads the colours, how far the prism turns, the beam width, the haze and dust, whether there is a wall and the glow.","role":"Background (WebGL, full frame): an elegant, physical light scene for science, music, album-art and title content.","useCases":["A backdrop for science and physics explainers on light and colour","A music or album-art style title scene","A calm, elegant loop for presentations"],"synonyms":["light prism","rainbow beam","spectrum animation","newton prism","dark side","light refraction","white light splitting","optics"],"digest":"a02c5cdf36fd71a4d886d3b7e4b6207542862447677d957c5f347d974ca5d084","implementation":{"target":"three","runtime":"browser","language":"javascript","module":"esm","entry":"src/prism-dispersion.js","exports":[{"name":"createPrism","signature":"createPrism({ glass?, dispersion?, rotation?, beam?, haze?, wall?, glow?, aspect? }) => { scene, camera, material, setSize(width, height), update(time, loopSeconds), dispose() }","description":"The whole scene: the physics is traced in update() and drawn by one shader. Render it with its camera, ideally through createBloomPass."},{"name":"traceSpectrum","signature":"traceSpectrum({ centre?, radius?, angle?, glass?, dispersion?, source?, beamAngle?, wallX? }) => { vertices, entry, reflected, rays }","description":"Traces forty wavelengths of a white beam through an equilateral prism: refraction in and out, total internal reflection, and where each colour lands on the wall."},{"name":"wavelengthToRGB","signature":"wavelengthToRGB(nm) => [r, g, b]","description":"The colour of a wavelength in nanometres, dimmer at the ends of the visible range."},{"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":"GLASSES","signature":"GLASSES: { crown, flint, diamond }","description":"Cauchy coefficients (n = A + B / λ², λ in micrometres) of each glass."}],"reusable":["src/prism-dispersion.js"],"demo":"demo.js","harness":"index.html"},"dependencies":[{"id":"three","version":"0.185.1","scope":"source","reason":"Renderer, the full-screen shader and the bloom targets."},{"id":"apw-runtime","version":"1.0.0","scope":"demo","reason":"Demo harness."}],"uses":[],"usedBy":[],"params":[{"key":"glass","label":"Glass","type":"select","default":"flint","options":[{"value":"crown","label":"Crown glass"},{"value":"flint","label":"Flint glass"},{"value":"diamond","label":"Diamond"}]},{"key":"dispersion","label":"Dispersion","help":"How strongly the glass spreads the colours.","type":"number","min":0.5,"max":1.6,"step":0.05,"default":1.1},{"key":"rotation","label":"Turn","help":"How far the prism turns to and fro.","type":"number","min":0,"max":1.6,"step":0.05,"default":1},{"key":"beam","label":"Beam width","type":"number","min":0.6,"max":2,"step":0.05,"default":1},{"key":"haze","label":"Haze and dust","type":"number","min":0,"max":1.6,"step":0.05,"default":1},{"key":"wall","label":"Wall","type":"boolean","default":true},{"key":"glow","label":"Glow","type":"number","min":0.5,"max":1.6,"step":0.05,"default":1}],"presets":[{"id":"default","label":"Flint glass prism","params":{}},{"id":"diamond","label":"Diamond fire","params":{"glass":"diamond","dispersion":1,"rotation":1.4,"haze":1.2}},{"id":"crown","label":"Crown glass, soft haze","params":{"glass":"crown","dispersion":1.6,"rotation":0.6,"beam":1.4,"haze":1.5}},{"id":"open","label":"Open spectrum, no wall","params":{"wall":false,"beam":1.8,"glow":1.3,"haze":1.3}}],"output":{"width":1080,"height":1080,"fps":30,"durationSeconds":12,"posterSeconds":6,"alpha":false,"motion":"procedural","loop":{"seamless":true,"cycleSeconds":12,"method":"The prism's angle and the beam's tilt are sines of the loop phase, and the dust moves on paths of whole numbers of cycles, so the last frame meets the first."},"seed":null},"composition":{"inputs":"Time within the loop; the glass, dispersion, how far the prism turns, beam width, haze, wall and glow.","outputs":"A full frame: forty rays traced once per frame in JavaScript and drawn as soft beams by one shader on a full-screen quad.","coordinates":"Screen space, y from -1 to 1: the prism (an equilateral triangle of circumradius 0.4) centred just above the middle, the beam entering from the lower left, the wall on the right at x = 0.86 (times the aspect when wider).","lighting":"Self-lit: the beam, the spectrum and the glints of the glass add light; the bloom softens them.","timing":"update(time, loopSeconds) traces the rays for that moment, so frames render in any order.","compatibleWith":["kinetic-title","number-reveal"],"notes":["Index of refraction n = A + B / λ² (Cauchy): violet is bent most, red least; the coefficients are exaggerated a little (flint, B = 0.028 µm²) so the fan is wide enough to see.","At the extremes of the turn the violet meets the second face at more than the critical angle and is totally internally reflected out of the base."]},"reuse":["Physics explainer on light and colour: Flint glass prism.","Music or album-art style loop: Diamond fire.","Calm presentation backdrop: Crown glass, soft haze."],"integration":{"newProject":"Create a WebGLRenderer, createPrism({ aspect }) and createBloomPass(renderer, { width, height }); call prism.setSize(width, height), then each frame prism.update(time, loopSeconds) and bloom.render(prism.scene, prism.camera).","existingProject":"Copy src/prism-dispersion.js; render prism.scene with prism.camera into a render target (or through the bloom pass) as the backdrop of your scene; traceSpectrum() can be used on its own."},"performance":{"notes":"Forty rays traced in JavaScript each frame, then one full-screen pass of about 80 distance evaluations and 70 motes per pixel and a small bloom. About 25 ms a frame at 1080p on an integrated Intel GPU.","limits":"A single beam and one equilateral prism."},"limitations":["The scene is two-dimensional: the light travels in the plane of the frame and the prism is a triangle with no depth.","Intensity along each ray is a simple fade; reflections other than the first face and the total internal one are not traced."],"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"}]},"rights":{"approvedForPublicRelease":true},"provenance":"Adapted from the owner's threejs-sketches/light-atmosphere/prism-rainbow (with webgpu-rainbow-prism and light-prism, MIT) and rebuilt for AI Pixel Wizard in October 2026 as an original scene: forty wavelengths traced with Snell's law and a Cauchy index, total internal reflection, soft beams, dust, an exact loop and the frame/time contract.","changelog":[{"version":"1.0.0","date":"2026-10-05","notes":"Initial release."}],"verification":{"testedOn":"2026-10-06","inputs":{"prism-dispersion@1.0.0":"a02c5cdf36fd71a4d886d3b7e4b6207542862447677d957c5f347d974ca5d084","three@0.185.1":"664ca387e5fab46ff2daaa6895e1d015426850891af5ea5082cbbcc3985b068c","apw-runtime@1.0.0":"5be859cdac74823ba0bcc32c6daf06688a871104d24db5d4ceaffffd84d7c40d"},"environment":"Chrome 154.0.8037.97 headless on Linux 7.0.0-38-generic (x64), Node 22.14.0","renderer":"WebGL 2 via SwiftShader (software)","width":1080,"height":1080,"fps":30,"frames":360,"renderSeconds":2566.3,"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/prism-dispersion/1.0.0/poster.webp","preview":"/media/prism-dispersion/1.0.0/preview.mp4","sample":"/media/prism-dispersion/1.0.0/sample.mp4","sampleBytes":969971}},"files":[{"path":"LICENSE","size":1072,"sha256":"8a5f3a96f07e11522ec4bdd0a583356f99bad1245920f9709cee09b995a45153","contentType":"text/plain; charset=utf-8","url":"https://aipixelwizard.com/registry/prism-dispersion/1.0.0/LICENSE"},{"path":"asset.json","size":9810,"sha256":"2229af0d6ee5f4483dda179cee5ba24046bc6f9202a36799ea7b311d871960a6","contentType":"application/json; charset=utf-8","url":"https://aipixelwizard.com/registry/prism-dispersion/1.0.0/asset.json"},{"path":"demo.js","size":1173,"sha256":"dbbb2ee8f3077e57cea77c75b8f3c951d82d1b2c9ba35589180668f531d57ccb","contentType":"text/javascript; charset=utf-8","url":"https://aipixelwizard.com/registry/prism-dispersion/1.0.0/demo.js"},{"path":"index.html","size":530,"sha256":"ce42de87c2fcae855115e0c0addb0b866706be436df71d38a885f31280586013","contentType":"text/html; charset=utf-8","url":"https://aipixelwizard.com/registry/prism-dispersion/1.0.0/index.html"},{"path":"src/prism-dispersion.js","size":21673,"sha256":"4581f8dbdd23f160682138bc4c1818a7c79aab543a819da047626b6e57c22cb0","contentType":"text/javascript; charset=utf-8","url":"https://aipixelwizard.com/registry/prism-dispersion/1.0.0/src/prism-dispersion.js"}],"warnings":[]}