{"id":"doppler-siren","version":"1.0.0","title":"Doppler Siren","summary":"A siren moving through the dark, its sound rings bunching up and turning blue ahead of it and stretching out red behind. Loops perfectly.","kind":"background","target":"three","collections":["backgrounds","hypnotic-loops"],"tags":["doppler effect","sound waves","siren","wavefronts","physics","shock wave","sonic boom","rings","science","glow","loop"],"loopable":true,"motion":"procedural","durationSeconds":10,"status":"published","media":{"poster":"https://aipixelwizard.com/media/doppler-siren/1.0.0/poster.webp","preview":"https://aipixelwizard.com/media/doppler-siren/1.0.0/preview.mp4","sample":"https://aipixelwizard.com/media/doppler-siren/1.0.0/sample.mp4","sampleBytes":2685366,"sampleNote":"Pre-rendered with the default settings. Customised settings must be exported locally (npm run render)."},"urls":{"page":"https://aipixelwizard.com/visuals/doppler-siren","manifest":"https://aipixelwizard.com/api/v1/visuals/doppler-siren/versions/1.0.0","agentMd":"https://aipixelwizard.com/registry/doppler-siren/1.0.0/agent.md","files":"https://aipixelwizard.com/registry/doppler-siren/1.0.0/","demo":"https://aipixelwizard.com/registry/doppler-siren/1.0.0/index.html"},"description":"The Doppler effect made visible. A siren moves along a closed path and sends out a ring of sound at regular moments; every ring keeps its own centre, where the siren was when it left, so the rings crowd together and turn blue ahead of the siren and stretch apart and turn red behind it. Make the siren faster than the sound and the rings pile up into a shock cone. Choose the siren's speed against the sound, the number of rings, the path (circle, sweep or figure eight), the colours, the line thickness, the brightness and the size of the path.","role":"Shader background (three.js): a physics showpiece for science, sound and motion content.","useCases":["A physics or acoustics explainer","A music or audio brand backdrop","A hypnotic ring pattern loop"],"synonyms":["doppler shift","sonic boom","sound waves","moving source","mach cone","wave propagation","red shift blue shift"],"digest":"dd591cfa52462ecd14eccc48b1d5f74b78995b588f4df43ba1fef43830781b74","implementation":{"target":"three","runtime":"browser","language":"javascript","module":"esm","entry":"src/doppler-siren.js","exports":[{"name":"createDopplerSiren","signature":"createDopplerSiren({ mach?, waves?, path?, palette?, thickness?, brightness?, radius? }) => { scene, camera, setSize(width, height), update(time, loopSeconds), dispose() }","description":"The rings 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 tone mapping and a fixed grain."},{"name":"PALETTES","signature":"PALETTES: { classic, neon, gold, mono }","description":"Colours for the stretched and compressed rings and the siren's lamp."}],"reusable":["src/doppler-siren.js"],"demo":"demo.js","harness":"index.html"},"dependencies":[{"id":"three","version":"0.185.1","scope":"source","reason":"Renderer and a full-screen shader material."},{"id":"apw-runtime","version":"1.0.0","scope":"demo","reason":"Demo harness."}],"uses":[],"usedBy":[],"params":[{"key":"mach","label":"Speed vs sound","help":"The siren's speed over the speed of the waves; above 1 the rings pile into a shock cone.","type":"number","min":0.2,"max":1.8,"step":0.05,"default":0.6},{"key":"waves","label":"Rings per loop","type":"integer","min":12,"max":48,"step":1,"default":32},{"key":"path","label":"Path","type":"select","default":"circle","options":[{"value":"circle","label":"Circle"},{"value":"sweep","label":"Sweep"},{"value":"eight","label":"Figure eight"}]},{"key":"palette","label":"Colours","type":"select","default":"classic","options":[{"value":"classic","label":"Red and blue"},{"value":"neon","label":"Neon"},{"value":"gold","label":"Gold"},{"value":"mono","label":"Mono"}]},{"key":"thickness","label":"Line thickness","type":"number","min":0.006,"max":0.04,"step":0.002,"default":0.012},{"key":"brightness","label":"Brightness","type":"number","min":0.5,"max":2,"step":0.1,"default":1},{"key":"radius","label":"Path size","type":"number","min":0.2,"max":0.8,"step":0.05,"default":0.45}],"presets":[{"id":"default","label":"Circling siren","params":{}},{"id":"shock","label":"Shock cone, sweep","params":{"mach":1.5,"path":"sweep","palette":"gold"}},{"id":"neon","label":"Neon figure eight","params":{"path":"eight","palette":"neon","waves":40}},{"id":"mono","label":"Mono, slow","params":{"palette":"mono","mach":0.35,"waves":24,"brightness":1.3}}],"output":{"width":1080,"height":1080,"fps":30,"durationSeconds":10,"posterSeconds":3,"alpha":false,"motion":"procedural","loop":{"seamless":true,"cycleSeconds":10,"method":"The siren's path repeats every loop and each ring's centre, radius and fade are functions of its age since it left, with rings born at fixed moments of the loop, so the last frame meets the first."},"seed":null},"composition":{"inputs":"Time within the loop; the speed, ring count, path, colours, thickness, brightness and path size.","outputs":"A full-frame shader image through a bloom pass.","coordinates":"Screen-centred, ±1 vertically; the siren moves on a path of the chosen radius around the origin; a ring's radius is the wave speed times its age.","lighting":"Self-lit lines; the bloom provides the glow.","timing":"update(time, loopSeconds) sets the loop phase; frames render in any order.","compatibleWith":["kinetic-title","number-reveal"],"notes":["Up to 44 rings are evaluated per pixel; each is tinted by how much the pixel lies in the direction the siren was moving when the ring was born."]},"reuse":["Physics explainer: Circling siren.","Sonic boom: Shock cone, sweep.","Nightclub backdrop: Neon figure eight."],"integration":{"newProject":"Create a WebGLRenderer, createDopplerSiren() and createBloomPass(renderer, { width, height }); call siren.setSize(w, h) and each frame siren.update(time, loopSeconds) then bloom.render(siren.scene, siren.camera).","existingProject":"Copy src/doppler-siren.js and render siren.scene with siren.camera into your own target."},"performance":{"notes":"One full-screen fragment shader looping over up to 44 rings, plus the bloom: about 3 ms a frame at 1080² on an integrated Intel GPU.","limits":"Software WebGL renders in about a second a frame."},"limitations":["Rings are drawn as lines, not as a physical pressure field; intensity does not fall off with distance as it would in air.","Above Mach 1 the shock cone appears only as the envelope of the rings."],"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":"Adapted from the owner's threejs-sketches/physics-forces/doppler-siren (MIT) and rebuilt for AI Pixel Wizard in October 2026 as an original shader: rings born at fixed moments along a periodic siren path, each with its own centre, tinted by the direction of travel, with an exact loop.","changelog":[{"version":"1.0.0","date":"2026-10-05","notes":"Initial release."}],"verification":{"testedOn":"2026-10-06","inputs":{"doppler-siren@1.0.0":"dd591cfa52462ecd14eccc48b1d5f74b78995b588f4df43ba1fef43830781b74","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":300,"renderSeconds":657.7,"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/doppler-siren/1.0.0/poster.webp","preview":"/media/doppler-siren/1.0.0/preview.mp4","sample":"/media/doppler-siren/1.0.0/sample.mp4","sampleBytes":2685366}},"files":[{"path":"LICENSE","size":1072,"sha256":"8a5f3a96f07e11522ec4bdd0a583356f99bad1245920f9709cee09b995a45153","contentType":"text/plain; charset=utf-8","url":"https://aipixelwizard.com/registry/doppler-siren/1.0.0/LICENSE"},{"path":"asset.json","size":8245,"sha256":"d83d0c0ed43f3e7d9e94ec8b41efe9665850ec55543b69cd69110a7aa71072d8","contentType":"application/json; charset=utf-8","url":"https://aipixelwizard.com/registry/doppler-siren/1.0.0/asset.json"},{"path":"demo.js","size":1082,"sha256":"feecda200b259aacd5a3a4678f7d694b181607a8dd4b99da1a40fc9aef43bf5c","contentType":"text/javascript; charset=utf-8","url":"https://aipixelwizard.com/registry/doppler-siren/1.0.0/demo.js"},{"path":"index.html","size":527,"sha256":"18108658eefe44797ef41d7f2b857d99384bd349df069e28efd1f7d0dd20e5c7","contentType":"text/html; charset=utf-8","url":"https://aipixelwizard.com/registry/doppler-siren/1.0.0/index.html"},{"path":"src/doppler-siren.js","size":11396,"sha256":"82a5080ca30cea61a5b7a982cdc1788beb5f58f1c1005667f99a3b9099414246","contentType":"text/javascript; charset=utf-8","url":"https://aipixelwizard.com/registry/doppler-siren/1.0.0/src/doppler-siren.js"}],"warnings":[]}