{"id":"dither-animation","version":"1.0.0","title":"Dither Animation (1-Bit Look)","summary":"Turns any animation into crisp, retro dot patterns in two to four colours, with an optional choppy low frame rate, like the dithered videos all over social feeds.","kind":"effect","target":"canvas2d","collections":["hypnotic-loops","backgrounds"],"tags":["dither","dithering","dithered","1-bit","1bit","retro","pixel","bayer","halftone","ordered dithering","black and white","game boy","lo-fi","monochrome","texture","2d","canvas","loop"],"loopable":true,"motion":"procedural","durationSeconds":8,"status":"published","media":{"poster":"https://aipixelwizard.com/media/dither-animation/1.0.0/poster.webp","preview":"https://aipixelwizard.com/media/dither-animation/1.0.0/preview.mp4","sample":"https://aipixelwizard.com/media/dither-animation/1.0.0/sample.mp4","sampleBytes":297287,"sampleNote":"Pre-rendered with the default settings. Customised settings must be exported locally (npm run render)."},"urls":{"page":"https://aipixelwizard.com/visuals/dither-animation","manifest":"https://aipixelwizard.com/api/v1/visuals/dither-animation/versions/1.0.0","agentMd":"https://aipixelwizard.com/registry/dither-animation/1.0.0/agent.md","files":"https://aipixelwizard.com/registry/dither-animation/1.0.0/","demo":"https://aipixelwizard.com/registry/dither-animation/1.0.0/index.html"},"description":"The dithered look: smooth shading becomes a pattern of hard dots in just two colours (or four, Game Boy style), like an old Mac screen or a newspaper photo. Pick the dot pattern (fine checkerboard, round halftone dots or engraving lines), how big the dots are, the colours and how choppy the motion feels. The pattern stays locked in place from frame to frame so it never shimmers. The demo dithers a turning moon under drifting light and falling ash, or an endless tunnel; the same code dithers your own canvas, photo, video frame or 3D scene.","role":"Full-frame finishing effect (Canvas 2D): converts brightness into a dithered pattern.","useCases":["Dithered website hero or background","Retro music video or album visualiser","Lo-fi treatment for AI-generated or real footage","Intro or title card backdrop"],"synonyms":["dither effect","dithering effect","dithered animation","dithered video","1-bit animation","1-bit look","bitmap look","halftone effect","pixel dither","retro mac look","game boy filter","dot pattern effect","dithered website background"],"digest":"baa134bfe90b5ec0f76dd3f8b5fdb5696d84f227c99e033b26d4f82309f737bf","implementation":{"target":"canvas2d","runtime":"browser","language":"javascript","module":"esm","entry":"src/dither-animation.js","exports":[{"name":"createDither","signature":"createDither({ pixelSize?, pattern?, palette?, contrast?, brightness?, invert? }) => { grid(width, height), drawField(ctx, width, height, field), drawBuffer(ctx, width, height, buffer), applyToCanvas(ctx, width, height), pixelSize }","description":"Canvas 2D dither layer. drawField/drawBuffer dither brightness you compute; applyToCanvas dithers what is already on the canvas. Replaces the whole frame."},{"name":"stepTime","signature":"stepTime(info, stepsPerSecond?) => { time, phase }","description":"Holds frames for a choppy low frame rate; phase runs 0..1 over the duration and returns to exactly 0 at the end so whole-cycle loops stay seamless."}],"reusable":["src/dither-animation.js"],"demo":"demo.js","harness":"index.html"},"dependencies":[{"id":"apw-runtime","version":"1.0.0","scope":"demo","reason":"Demo harness and seeded random numbers. src/dither-animation.js has no dependencies."}],"uses":[],"usedBy":[],"params":[{"key":"scene","label":"Demo picture","help":"What the demo dithers. Your own project can dither anything.","type":"select","default":"moon","options":[{"value":"moon","label":"Turning moon"},{"value":"tunnel","label":"Endless tunnel"}]},{"key":"pattern","label":"Dot pattern","type":"select","default":"bayer8","options":[{"value":"bayer8","label":"Fine checker (classic)"},{"value":"bayer4","label":"Chunky checker"},{"value":"halftone","label":"Round halftone dots"},{"value":"lines","label":"Engraving lines"}]},{"key":"pixelSize","label":"Dot size","help":"Screen pixels per dot. Bigger is more retro.","type":"integer","min":1,"max":12,"step":1,"default":4},{"key":"palette","label":"Colours","type":"select","default":"mono","options":[{"value":"mono","label":"Black & paper"},{"value":"gameboy","label":"Game Boy (4 greens)"},{"value":"print","label":"Navy ink on cream"},{"value":"amber","label":"Amber screen"},{"value":"custom","label":"My two colours"}]},{"key":"ink","label":"Dark colour","help":"Used when Colours is set to My two colours.","type":"color","default":"#14002e"},{"key":"paper","label":"Light colour","help":"Used when Colours is set to My two colours.","type":"color","default":"#ff5fa2"},{"key":"choppiness","label":"Frames per second feel","help":"Holds frames for a jumpy, hand-cranked look. 30 is smooth.","type":"integer","min":4,"max":30,"step":1,"default":12},{"key":"contrast","label":"Contrast","type":"number","min":0.5,"max":2.5,"step":0.05,"default":1.15},{"key":"brightness","label":"Brightness","type":"number","min":-0.4,"max":0.4,"step":0.01,"default":0},{"key":"invert","label":"Invert","type":"boolean","default":false},{"key":"seed","label":"Variation","help":"Changes the moon surface, stars and ash.","type":"integer","min":1,"max":9999,"step":1,"default":7}],"presets":[{"id":"default","label":"1-bit moon","params":{}},{"id":"gameboy","label":"Game Boy tunnel","params":{"scene":"tunnel","pattern":"bayer4","palette":"gameboy","pixelSize":6,"choppiness":10}},{"id":"halftone-print","label":"Halftone print","params":{"pattern":"halftone","palette":"print","pixelSize":3,"contrast":1.3}},{"id":"synthwave","label":"Pink 2-colour","params":{"scene":"tunnel","palette":"custom","pattern":"bayer8","pixelSize":3,"choppiness":30}}],"output":{"width":1080,"height":1080,"fps":30,"durationSeconds":8,"posterSeconds":2,"alpha":false,"motion":"procedural","loop":{"seamless":true,"cycleSeconds":8,"method":"Everything is driven by one phase that runs 0..1 over the loop: the moon turns once, ash falls whole screens, stars twinkle whole cycles, the tunnel moves four ring spacings. stepTime returns phase 0 again at the end."},"seed":{"param":"seed","behavior":"Seed shapes the moon surface and places the stars and ash. Same seed, same picture."}},"composition":{"inputs":"Canvas 2D context, width, height, and either a brightness function, a brightness buffer, or whatever is already drawn on the canvas.","outputs":"Replaces the whole frame with the dithered result (opaque).","coordinates":"Brightness field uses u, v from 0..1 across the frame; dots are pixelSize screen pixels square from the top left.","lighting":"None of its own; it reinterprets brightness. Light comes from what you feed it.","timing":"Stateless; pure function of its input. Use stepTime(info, n) for the choppy low-frame-rate feel.","compatibleWith":["particle-tunnel","torus-wave","kinetic-title","hypnotic-tunnel-title","gradient-background"],"notes":["Ordered dithering is used on purpose: unlike error diffusion (Floyd–Steinberg) it does not shimmer between frames.","applyToCanvas reads pixels back, so the source must be same-origin (no tainted canvas). For WebGL, draw the WebGL canvas onto a 2D canvas first.","Draw text after dithering if it must stay sharp, or before it to dither the text too."]},"reuse":["Draw Hypnotic Particle Tunnel or Torus Wave Loop on a 2D canvas, then call applyToCanvas for a dithered version of either loop.","Dither a photo or a frame of AI-generated video for the 'dithered website background' look: draw it, call applyToCanvas, and play frames at 8–12 fps with stepTime.","Dither the background only, then draw Kinetic Title Reveal on top in a clean colour for a retro title card."],"integration":{"newProject":"Create the dither once with createDither(options). Each frame, compute brightness and call drawField or drawBuffer, or draw your scene and then call applyToCanvas(ctx, width, height).","existingProject":"Copy src/dither-animation.js. After your normal 2D drawing for a frame, call dither.applyToCanvas(ctx, width, height). For three.js, render to the WebGL canvas, draw it onto a 2D canvas with drawImage, then apply."},"performance":{"notes":"One pass over (width / dot size) × (height / dot size) values per frame: about 73,000 at 1080×1080 with 4-pixel dots, well under a millisecond for the dither itself. The demo's moon scene costs more than the dither.","limits":"applyToCanvas does a GPU-to-CPU readback each frame; at 4K with 1-pixel dots expect a few frames per second in a browser preview (offline renders are fine)."},"limitations":["Ordered patterns only: no error-diffusion (Floyd–Steinberg, Atkinson) look, which shimmers on video anyway.","Brightness only: colour is replaced by the palette, so a colourful source loses its hues.","Up to four colours, spread evenly from dark to light."],"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 on 2026-10-03 by an automated agent (the daily trend routine), inspired by the dithered-animation trend on social video and the web (see content/trends/2026-10-03-dither-animation.md). Ordered (Bayer) dithering and clustered-dot halftoning are long-standing public techniques; the threshold matrices are generated by this code. The note that ordered dithering stays stable on video while error diffusion boils follows https://modulate.to/effects/dither/. No code, images, fonts or shaders were copied.","changelog":[{"version":"1.0.0","date":"2026-10-03","notes":"Initial release."}],"verification":{"testedOn":"2026-10-03","inputs":{"dither-animation@1.0.0":"baa134bfe90b5ec0f76dd3f8b5fdb5696d84f227c99e033b26d4f82309f737bf","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":"Canvas 2D","width":1080,"height":1080,"fps":30,"frames":240,"renderSeconds":17.8,"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/dither-animation/1.0.0/poster.webp","preview":"/media/dither-animation/1.0.0/preview.mp4","sample":"/media/dither-animation/1.0.0/sample.mp4","sampleBytes":297287}},"files":[{"path":"LICENSE","size":1072,"sha256":"8a5f3a96f07e11522ec4bdd0a583356f99bad1245920f9709cee09b995a45153","contentType":"text/plain; charset=utf-8","url":"https://aipixelwizard.com/registry/dither-animation/1.0.0/LICENSE"},{"path":"asset.json","size":11239,"sha256":"e335cc9f92e0082b0a2606774513099fa1533bbd9d7b275da8a304d826b12bae","contentType":"application/json; charset=utf-8","url":"https://aipixelwizard.com/registry/dither-animation/1.0.0/asset.json"},{"path":"demo.js","size":6544,"sha256":"18d942d92622ab11d6793b2a25811e7c1757d6c022c391133ad44813aeab04d4","contentType":"text/javascript; charset=utf-8","url":"https://aipixelwizard.com/registry/dither-animation/1.0.0/demo.js"},{"path":"index.html","size":530,"sha256":"16410e16d5d89bc952ac128e9565653efa8d9e931b60a692e12174fae1543ca2","contentType":"text/html; charset=utf-8","url":"https://aipixelwizard.com/registry/dither-animation/1.0.0/index.html"},{"path":"src/dither-animation.js","size":8280,"sha256":"3b6620c413157fcf6595566d42ab2be732c1faa6b407af186bbbb4eef17d508f","contentType":"text/javascript; charset=utf-8","url":"https://aipixelwizard.com/registry/dither-animation/1.0.0/src/dither-animation.js"}],"warnings":[]}