{"id":"rolling-counter","version":"1.1.0","title":"Rolling Number Counter","summary":"A number that counts up like a mechanical odometer, every digit rolling into place.","kind":"text","target":"canvas2d","collections":["kinetic-text","product-reveals","satisfying"],"tags":["counter","number","odometer","count up","stats","milestone","digits","rolling","text","2d","canvas"],"loopable":false,"motion":"procedural","durationSeconds":5,"status":"published","media":{"poster":"https://aipixelwizard.com/media/rolling-counter/1.1.0/poster.webp","preview":"https://aipixelwizard.com/media/rolling-counter/1.1.0/preview.mp4","sample":"https://aipixelwizard.com/media/rolling-counter/1.1.0/sample.mp4","sampleBytes":255078,"sampleNote":"Pre-rendered with the default settings. Customised settings must be exported locally (npm run render)."},"urls":{"page":"https://aipixelwizard.com/visuals/rolling-counter","manifest":"https://aipixelwizard.com/api/v1/visuals/rolling-counter/versions/1.1.0","agentMd":"https://aipixelwizard.com/registry/rolling-counter/1.1.0/agent.md","files":"https://aipixelwizard.com/registry/rolling-counter/1.1.0/","demo":"https://aipixelwizard.com/registry/rolling-counter/1.1.0/index.html"},"description":"Show off a big number the satisfying way: digits roll like a car's odometer from a starting value to your target, slowing down as they arrive. Add a prefix like $ or a suffix like + or 'users', choose the colour and how long it counts. Great for milestones, stats and results.","role":"Foreground number layer (Canvas 2D).","useCases":["Milestone announcement (users, revenue, downloads)","Stats in a launch video","Countdown-style reveals"],"synonyms":["number animation","count up","counting numbers","animated number","stat reveal","rolling digits","slot machine numbers","ticker"],"digest":"8aef2813305461b0ad6ffd82c09e36322f72efdc241642d078fd6c4458fb075c","implementation":{"target":"canvas2d","runtime":"browser","language":"javascript","module":"esm","entry":"src/rolling-counter.js","exports":[{"name":"createRollingCounter","signature":"createRollingCounter({ from?, to?, delay?, duration?, ease?, prefix?, suffix?, separator?, color?, fontFamily?, weight?, size?, x?, y?, align? }) => { draw(ctx, info, width, height), valueAt(t) }","description":"Canvas 2D odometer driven by info.time (seconds)."}],"reusable":["src/rolling-counter.js"],"demo":"demo.js","harness":"index.html"},"dependencies":[{"id":"apw-runtime","version":"1.0.0","scope":"demo","reason":"Demo harness. src/rolling-counter.js has no dependencies."}],"uses":[],"usedBy":[{"id":"number-reveal","version":"1.1.0"}],"params":[{"key":"from","label":"Start at","type":"integer","min":0,"max":999999999,"step":1,"default":0},{"key":"to","label":"Count to","type":"integer","min":0,"max":999999999,"step":1,"default":1250000},{"key":"countSeconds","label":"Counting time (s)","type":"number","min":0.5,"max":10,"step":0.1,"default":3},{"key":"ease","label":"Feel","type":"select","default":"outExpo","options":[{"value":"outExpo","label":"Fast then slow"},{"value":"outCubic","label":"Gentle slow-down"},{"value":"inOutCubic","label":"Slow, fast, slow"},{"value":"linear","label":"Steady"}]},{"key":"prefix","label":"Before the number","type":"text","default":"$","maxLength":6,"sensitive":true},{"key":"suffix","label":"After the number","type":"text","default":"","maxLength":12,"sensitive":true},{"key":"separator","label":"Thousands commas","type":"boolean","default":true},{"key":"color","label":"Colour","type":"color","default":"#ffffff"},{"key":"background","label":"Background","type":"color","default":"#101418"}],"presets":[{"id":"default","label":"Revenue","params":{}},{"id":"users","label":"Users","params":{"to":50000,"prefix":"","suffix":"+","ease":"outCubic","background":"#1a1030","color":"#ffe9a8"}},{"id":"small","label":"Small number","params":{"to":99,"prefix":"","suffix":"%","countSeconds":2,"background":"#0e2b22","color":"#dffff2"}}],"output":{"width":1080,"height":1080,"fps":30,"durationSeconds":5,"posterSeconds":4.5,"alpha":false,"motion":"procedural","loop":{"seamless":false,"method":"Counts once and holds the final number."},"seed":null},"composition":{"inputs":"Canvas 2D context, info.time (seconds), width, height.","outputs":"Draws the number on the canvas. Does not clear it.","coordinates":"Centre point as fractions of width/height; size as a fraction of the shorter side.","lighting":"None.","timing":"Pure function of time; valueAt(t) gives the exact value at any moment.","compatibleWith":["gradient-background","spring-motion","kinetic-title","particle-tunnel"],"notes":["Prefix and suffix are treated as private and are not stored in shared packs unless you choose to include them."]},"reuse":["Combine with Soft Moving Gradient and a spring pop-in label (see Minimal Animated Number Reveal).","Use valueAt(t) alone to drive a progress bar or a 3D bar chart.","Place several counters (x/y options) for a stats grid."],"integration":{"newProject":"Create the counter once; each frame draw your background then counter.draw(ctx, { time: frame / fps }, width, height).","existingProject":"Copy src/rolling-counter.js and call draw from your existing frame loop where the number should appear."},"performance":{"notes":"Two fillText calls per digit per frame.","limits":"Up to 15 digits."},"limitations":["Whole numbers only (no decimals)."],"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. Uses the viewer's system font. Demo and typography rebuilt in October 2026 to the catalog quality bar (docs/QUALITY.md).","changelog":[{"version":"1.1.0","date":"2026-10-03","notes":"Counter card typography: flush-left on a margin with a rule, deliberate type stack, colour field with vignette and grain. New option align; defaults keep the 1.0.0 behaviour."},{"version":"1.0.0","date":"2026-10-02","notes":"Initial release."}],"verification":{"testedOn":"2026-10-03","inputs":{"rolling-counter@1.1.0":"8aef2813305461b0ad6ffd82c09e36322f72efdc241642d078fd6c4458fb075c","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":150,"renderSeconds":12.4,"loopCheck":{"checked":false,"seamless":null,"maxDifference":null,"note":"Asset does not claim a seamless loop."},"determinism":{"checked":true,"identical":true},"errors":[],"media":{"poster":"/media/rolling-counter/1.1.0/poster.webp","preview":"/media/rolling-counter/1.1.0/preview.mp4","sample":"/media/rolling-counter/1.1.0/sample.mp4","sampleBytes":255078}},"files":[{"path":"LICENSE","size":1072,"sha256":"8a5f3a96f07e11522ec4bdd0a583356f99bad1245920f9709cee09b995a45153","contentType":"text/plain; charset=utf-8","url":"https://aipixelwizard.com/registry/rolling-counter/1.1.0/LICENSE"},{"path":"asset.json","size":6756,"sha256":"e0169977302b6a3bba8d6778cb63f6fbaf7d4646503f409b2fed19b490dcb2c6","contentType":"application/json; charset=utf-8","url":"https://aipixelwizard.com/registry/rolling-counter/1.1.0/asset.json"},{"path":"demo.js","size":2658,"sha256":"0a661942d795b845e61b1d1a328e085c309eeeacc0da3b28d19dd965d20b38a5","contentType":"text/javascript; charset=utf-8","url":"https://aipixelwizard.com/registry/rolling-counter/1.1.0/demo.js"},{"path":"index.html","size":536,"sha256":"0fce590e87f3f824de6e91e44b9bae69582ee50e1811c388ec62e73d3b518d63","contentType":"text/html; charset=utf-8","url":"https://aipixelwizard.com/registry/rolling-counter/1.1.0/index.html"},{"path":"src/rolling-counter.js","size":5735,"sha256":"e5efe8a13c6400df35255a7f6d34eb6f8a47e35261b1c1c749401c5f9c67e78b","contentType":"text/javascript; charset=utf-8","url":"https://aipixelwizard.com/registry/rolling-counter/1.1.0/src/rolling-counter.js"}],"warnings":[]}