✨Transitions (#27)
* 📝 add transitions design specification
Design spec for clayterm transitions: frame-snapshot-compatible interpolation
of element position, size, and color properties. Defines the deltaTime
convention, the animating signal on RenderResult, declarative enter/exit
semantics that replace Clay's function-pointer callbacks, and cancellation
as a structural consequence of re-describing state. Implementation is
gated on bumping the Clay submodule past the upstream transition commit.
* ⬆️ bump Clay submodule to latest main (transitions API)
* 🔧 adapt clayterm to new Clay signatures (OpenTextElement, EndLayout)
* ⬆️ pin Clay to 938967a (work around upstream CLAY_WASM_EXPORT typo)
* ✨ add deltaTime parameter to reduce()
* 🔧 add deltaTime to Native.reduce signature
* ✨ track deltaTime on Term, accept deltaTime override
* ✨ add animating_count to Clayterm context
* 🔧 expose animating() via Native binding
* ✨ surface animating: boolean on RenderResult
* 📝 rewrite transitions spec for v1 (Clay-supported subset)
Scope v1 to what Clay currently supports without userData on transition
callbacks: one duration and one easing per element, applied to all listed
properties. Drop per-property longhand, enter/exit deltas, cubicBezier,
and corner radius — each with an explicit "Deferred Until Upstream Clay"
entry in §13 referencing nicbarker/clay#603 and the forthcoming exit-flag
work. Easings are plain string literals ("linear" | "easeIn" | "easeOut"
| "easeInOut") since v1 has no parametric easings.
* ✨ add transition property names, bitmask helpers, and Easing
* ✨ add transition field type to OpenElement
* ✨ encode transition block in pack()
* ✨ register Clay handlers, interpolate on property change
Co-Authored-By:
* ✨ reset deltaTime to 0 after idle (preserve transitions across long gaps)
* ✅ verify color transitions work in line mode
* 🎨 apply deno fmt and clang-format
* ✨ add transitions demo (collapsing sidebar)
* 📝 reference transitions-spec from renderer-spec
* ✨ rewrite transitions demo as interactive full-screen menu
* ✨ add clay-transitions demo port (v1-compatible subset)
Ports the spirit of the raylib-transitions demo to clayterm: a 4×4 grid
of colored boxes that animate position, size, and bg color. Shuffle (s)
animates positions via Clay's transition system; recolor (c) toggles
between two palettes with animated bg interpolation; hover tints each
box by blending its bg toward white (overlay-color field is not yet in
the v1 command buffer, so lighten-on-hover substitutes). Full mouse
tracking is wired via mouseTracking() + pointer state from input events.
* 🎨 let clay-transitions demo rows fill available height
* 🎨 remove modeline from clay-transitions demo
* 📝 note ct_active_context is a workaround for Clay userData PR
* 🎨 use border-only boxes in clay-transitions demo
* 🎨 prevent menu text from wrapping during sidebar transition
* 🔥 drop unused grow import in transitions-run test
* Update transitions branch with upstream changes (#53)
* ✨ add snapshot() for pre-packing directive subtrees
Introduces a new `snapshot(ops)` constructor that pre-packs a directive
array into its transfer encoding. The returned opaque `Op` can be
spliced into any directive array, and during packing its bytes are
copied directly into the command buffer without re-encoding.
This enables higher-level frameworks to implement dirty tracking:
unchanged component subtrees can reuse a cached snapshot, skipping
the per-frame packing cost entirely.
* docs: add maintainer build guide
* 💄 format build docs
* 🐛 improve pack string overflow errors
* os matrix test in ci (#36)
* 🧼 optimize build
* 🧼 compress bundled wasm
* 🧼 optimize wcwidth.c size
* ⚙️ update npm settings
* 🐛 install wasm-opt in ci
* ⚡ use brotli-11 + z85 wasm encoding
* 📌 pin @types/node to v22
* 🧼 apply @ghostdevv review suggestions from PR #35
Co-Authored-By: ghostdevv <git@willow.sh>
* 🔨 add type to bundle-wasm
* 💌 signed, sealed, delivered
* chore: use hashes for versions
* chore: don't save git credentials
* chore: use array syntax
for some reason the schema for the actions wants it to be an array
* perf: set concurrency limits to reduce cost and improve dx
Without this it means that, for example, if I push a change to a PR then
shortly push again this workflow will be running twice. This change will
cancel the old run before starting the new one, which reduces the
overall actions cost and DX as you don't have extra runs
* chore: use hashes for versions
* chore: update node version
* perf: set concurrency limits to reduce cost and improve dx
Without this it means that, for example, if I push a change to a PR then
shortly push again this workflow will be running twice. This change will
cancel the old run before starting the new one, which reduces the
overall actions cost and DX as you don't have extra runs
* chore: don't save git credentials
* chore: mitigate potential template injection
See https://docs.zizmor.sh/audits/#template-injection
* chore: update ::set-output command to new syntax
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
* chore: use hashes for versions
* chore: don't save git credentials
* chore: limit id-token permission to the publishing steps
* chore: explicitly disable npm cache to mitigate cache poisoning attacks
* chore: mitigate potential template injection
See https://docs.zizmor.sh/audits/#template-injection
* chore: use oidc
This should be using OIDC for publishing
* chore: update ::set-output command to new syntax
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
* 🙅 revert aggressive optimization experiments pending benchmark
Reverts three changes that need benchmarks before landing:
- -Oz / wasm-opt
- brotli+Z85 wasm compression
- wcwidth.c rewrite
* Add CodSpeed performance benchmarks
* 🔨 use deno
* 🧼 deno fmt
* ⚙️ vitest -> tinybench
* 🧼 remove codspeed assets
* 🔨 fix ci
* add type module
* fmt
* chore: update github url (#38)
* downgrade to tinybench@5
* move to examples folder with readme
* 🔧 export animating from wasm build
* 🧪 cover transitions in snapshots and validation
* ✅ enforce nonnegative transition duration
---------
Co-authored-by: Charles Lowell <cowboyd@frontside.com>
Co-authored-by: Jacob Bolda <me@jacobbolda.com>
Co-authored-by: Nate Moore <nate@natemoo.re>
Co-authored-by: ghostdevv <git@willow.sh>
Co-authored-by: Nate Moore <git@natemoo.re>
Co-authored-by: codspeed-hq[bot] <117304815+codspeed-hq[bot]@users.noreply.github.com>
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
* remove uncecessary note
* clean up and consolidate
* re-organize transitions examples
* 🔥remove redundant cast
---------
Co-authored-by: Ryan Rauh <rauhryan@users.noreply.github.com>
Co-authored-by: Jacob Bolda <me@jacobbolda.com>
Co-authored-by: Nate Moore <nate@natemoo.re>
Co-authored-by: ghostdevv <git@willow.sh>
Co-authored-by: Nate Moore <git@natemoo.re>
Co-authored-by: codspeed-hq[bot] <117304815+codspeed-hq[bot]@users.noreply.github.com>
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
Co-authored-by: Ryan Rauh <rauh.ryan@gmail.com>
benchmark: replace simulation with walltime macro benches + e2e correctness (#91)
* test: add input event-loop integration test
Drives createInput as a consumer would (read chunk, scan, flush a pending ESC, dispatch) and asserts the same event stream whether input is fed whole, byte-by-byte, or split mid-sequence. Covers the lone-ESC flush path.
* bench: add macro throughput WallTime bench
In-process bench over a large mixed corpus, measured in WallTime where real work dominates placement/JIT/alloc noise (the Simulation micro-benches sit on codegen cliffs). Feeds the corpus in small reads: a single scan() drains at most 256 events (the wasm event-buffer cap), so small reads keep every call under the cap and process the whole corpus.
* bench: remove input micro-suite (codegen-cliff artifacts)
The Simulation input micro-benches (long input burst, printable ASCII single char) move by 50-90% on unrelated changes, even a test-only rename, because their simulated cost snaps to a different value when the combined wasm shifts. Input perf is now gated by the throughput WallTime bench; correctness by the event-loop integration test.
* ci(bench): pin build runner and drop wasm cache
Pin ubuntu-24.04 so the wasm toolchain is stable and drop the wasm cache so main and PRs always rebuild identically. The cache froze main's baseline on a stale build, so every PR compared a fresh build against a stale baseline and produced phantom regressions.
* fix(ci): return a promise from throughput bench for CodSpeed walltime
CodSpeed's walltime tinybench plugin only populates result.latency on its async path; a sync task fn leaves it undefined and crashes (Cannot destructure 'min' of result.latency). startup.bench works because its tasks return a promise (spawnFixture). Return Promise.resolve() from the throughput task so the plugin takes the async path — a bare async fn with no await would trip deno's require-await lint. The walltime job runs startup and throughput as separate node processes.
* bench: move render/ops to WallTime macro benches, drop the simulation job
CodSpeed Simulation (Valgrind) is unviable for CI here: flaky measurements (dashboard layout swung 20x, diff render 17% on changes that touch no render code) and unpredictable runtime — the same commit's simulation job finished in ~2 min one run and hung past 30 min the next. Convert render/ops to ms-scale WallTime macro benches (looped, promise-returning, ~7-11ms at <1% variance) run as separate node processes in the walltime job, and drop the simulation job entirely. mod.ts is now a local aggregator for deno task bench.
* ref(test): use built-in
* ref(bench): centralize withCodSpeed workaround
* ref(test): use semantic util functions
✨Transitions (#27)
* 📝 add transitions design specification
Design spec for clayterm transitions: frame-snapshot-compatible interpolation
of element position, size, and color properties. Defines the deltaTime
convention, the animating signal on RenderResult, declarative enter/exit
semantics that replace Clay's function-pointer callbacks, and cancellation
as a structural consequence of re-describing state. Implementation is
gated on bumping the Clay submodule past the upstream transition commit.
* ⬆️ bump Clay submodule to latest main (transitions API)
* 🔧 adapt clayterm to new Clay signatures (OpenTextElement, EndLayout)
* ⬆️ pin Clay to 938967a (work around upstream CLAY_WASM_EXPORT typo)
* ✨ add deltaTime parameter to reduce()
* 🔧 add deltaTime to Native.reduce signature
* ✨ track deltaTime on Term, accept deltaTime override
* ✨ add animating_count to Clayterm context
* 🔧 expose animating() via Native binding
* ✨ surface animating: boolean on RenderResult
* 📝 rewrite transitions spec for v1 (Clay-supported subset)
Scope v1 to what Clay currently supports without userData on transition
callbacks: one duration and one easing per element, applied to all listed
properties. Drop per-property longhand, enter/exit deltas, cubicBezier,
and corner radius — each with an explicit "Deferred Until Upstream Clay"
entry in §13 referencing nicbarker/clay#603 and the forthcoming exit-flag
work. Easings are plain string literals ("linear" | "easeIn" | "easeOut"
| "easeInOut") since v1 has no parametric easings.
* ✨ add transition property names, bitmask helpers, and Easing
* ✨ add transition field type to OpenElement
* ✨ encode transition block in pack()
* ✨ register Clay handlers, interpolate on property change
Co-Authored-By:
* ✨ reset deltaTime to 0 after idle (preserve transitions across long gaps)
* ✅ verify color transitions work in line mode
* 🎨 apply deno fmt and clang-format
* ✨ add transitions demo (collapsing sidebar)
* 📝 reference transitions-spec from renderer-spec
* ✨ rewrite transitions demo as interactive full-screen menu
* ✨ add clay-transitions demo port (v1-compatible subset)
Ports the spirit of the raylib-transitions demo to clayterm: a 4×4 grid
of colored boxes that animate position, size, and bg color. Shuffle (s)
animates positions via Clay's transition system; recolor (c) toggles
between two palettes with animated bg interpolation; hover tints each
box by blending its bg toward white (overlay-color field is not yet in
the v1 command buffer, so lighten-on-hover substitutes). Full mouse
tracking is wired via mouseTracking() + pointer state from input events.
* 🎨 let clay-transitions demo rows fill available height
* 🎨 remove modeline from clay-transitions demo
* 📝 note ct_active_context is a workaround for Clay userData PR
* 🎨 use border-only boxes in clay-transitions demo
* 🎨 prevent menu text from wrapping during sidebar transition
* 🔥 drop unused grow import in transitions-run test
* Update transitions branch with upstream changes (#53)
* ✨ add snapshot() for pre-packing directive subtrees
Introduces a new `snapshot(ops)` constructor that pre-packs a directive
array into its transfer encoding. The returned opaque `Op` can be
spliced into any directive array, and during packing its bytes are
copied directly into the command buffer without re-encoding.
This enables higher-level frameworks to implement dirty tracking:
unchanged component subtrees can reuse a cached snapshot, skipping
the per-frame packing cost entirely.
* docs: add maintainer build guide
* 💄 format build docs
* 🐛 improve pack string overflow errors
* os matrix test in ci (#36)
* 🧼 optimize build
* 🧼 compress bundled wasm
* 🧼 optimize wcwidth.c size
* ⚙️ update npm settings
* 🐛 install wasm-opt in ci
* ⚡ use brotli-11 + z85 wasm encoding
* 📌 pin @types/node to v22
* 🧼 apply @ghostdevv review suggestions from PR #35
Co-Authored-By: ghostdevv <git@willow.sh>
* 🔨 add type to bundle-wasm
* 💌 signed, sealed, delivered
* chore: use hashes for versions
* chore: don't save git credentials
* chore: use array syntax
for some reason the schema for the actions wants it to be an array
* perf: set concurrency limits to reduce cost and improve dx
Without this it means that, for example, if I push a change to a PR then
shortly push again this workflow will be running twice. This change will
cancel the old run before starting the new one, which reduces the
overall actions cost and DX as you don't have extra runs
* chore: use hashes for versions
* chore: update node version
* perf: set concurrency limits to reduce cost and improve dx
Without this it means that, for example, if I push a change to a PR then
shortly push again this workflow will be running twice. This change will
cancel the old run before starting the new one, which reduces the
overall actions cost and DX as you don't have extra runs
* chore: don't save git credentials
* chore: mitigate potential template injection
See https://docs.zizmor.sh/audits/#template-injection
* chore: update ::set-output command to new syntax
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
* chore: use hashes for versions
* chore: don't save git credentials
* chore: limit id-token permission to the publishing steps
* chore: explicitly disable npm cache to mitigate cache poisoning attacks
* chore: mitigate potential template injection
See https://docs.zizmor.sh/audits/#template-injection
* chore: use oidc
This should be using OIDC for publishing
* chore: update ::set-output command to new syntax
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
* 🙅 revert aggressive optimization experiments pending benchmark
Reverts three changes that need benchmarks before landing:
- -Oz / wasm-opt
- brotli+Z85 wasm compression
- wcwidth.c rewrite
* Add CodSpeed performance benchmarks
* 🔨 use deno
* 🧼 deno fmt
* ⚙️ vitest -> tinybench
* 🧼 remove codspeed assets
* 🔨 fix ci
* add type module
* fmt
* chore: update github url (#38)
* downgrade to tinybench@5
* move to examples folder with readme
* 🔧 export animating from wasm build
* 🧪 cover transitions in snapshots and validation
* ✅ enforce nonnegative transition duration
---------
Co-authored-by: Charles Lowell <cowboyd@frontside.com>
Co-authored-by: Jacob Bolda <me@jacobbolda.com>
Co-authored-by: Nate Moore <nate@natemoo.re>
Co-authored-by: ghostdevv <git@willow.sh>
Co-authored-by: Nate Moore <git@natemoo.re>
Co-authored-by: codspeed-hq[bot] <117304815+codspeed-hq[bot]@users.noreply.github.com>
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
* remove uncecessary note
* clean up and consolidate
* re-organize transitions examples
* 🔥remove redundant cast
---------
Co-authored-by: Ryan Rauh <rauhryan@users.noreply.github.com>
Co-authored-by: Jacob Bolda <me@jacobbolda.com>
Co-authored-by: Nate Moore <nate@natemoo.re>
Co-authored-by: ghostdevv <git@willow.sh>
Co-authored-by: Nate Moore <git@natemoo.re>
Co-authored-by: codspeed-hq[bot] <117304815+codspeed-hq[bot]@users.noreply.github.com>
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
Co-authored-by: Ryan Rauh <rauh.ryan@gmail.com>
✨Transitions (#27)
* 📝 add transitions design specification
Design spec for clayterm transitions: frame-snapshot-compatible interpolation
of element position, size, and color properties. Defines the deltaTime
convention, the animating signal on RenderResult, declarative enter/exit
semantics that replace Clay's function-pointer callbacks, and cancellation
as a structural consequence of re-describing state. Implementation is
gated on bumping the Clay submodule past the upstream transition commit.
* ⬆️ bump Clay submodule to latest main (transitions API)
* 🔧 adapt clayterm to new Clay signatures (OpenTextElement, EndLayout)
* ⬆️ pin Clay to 938967a (work around upstream CLAY_WASM_EXPORT typo)
* ✨ add deltaTime parameter to reduce()
* 🔧 add deltaTime to Native.reduce signature
* ✨ track deltaTime on Term, accept deltaTime override
* ✨ add animating_count to Clayterm context
* 🔧 expose animating() via Native binding
* ✨ surface animating: boolean on RenderResult
* 📝 rewrite transitions spec for v1 (Clay-supported subset)
Scope v1 to what Clay currently supports without userData on transition
callbacks: one duration and one easing per element, applied to all listed
properties. Drop per-property longhand, enter/exit deltas, cubicBezier,
and corner radius — each with an explicit "Deferred Until Upstream Clay"
entry in §13 referencing nicbarker/clay#603 and the forthcoming exit-flag
work. Easings are plain string literals ("linear" | "easeIn" | "easeOut"
| "easeInOut") since v1 has no parametric easings.
* ✨ add transition property names, bitmask helpers, and Easing
* ✨ add transition field type to OpenElement
* ✨ encode transition block in pack()
* ✨ register Clay handlers, interpolate on property change
Co-Authored-By:
* ✨ reset deltaTime to 0 after idle (preserve transitions across long gaps)
* ✅ verify color transitions work in line mode
* 🎨 apply deno fmt and clang-format
* ✨ add transitions demo (collapsing sidebar)
* 📝 reference transitions-spec from renderer-spec
* ✨ rewrite transitions demo as interactive full-screen menu
* ✨ add clay-transitions demo port (v1-compatible subset)
Ports the spirit of the raylib-transitions demo to clayterm: a 4×4 grid
of colored boxes that animate position, size, and bg color. Shuffle (s)
animates positions via Clay's transition system; recolor (c) toggles
between two palettes with animated bg interpolation; hover tints each
box by blending its bg toward white (overlay-color field is not yet in
the v1 command buffer, so lighten-on-hover substitutes). Full mouse
tracking is wired via mouseTracking() + pointer state from input events.
* 🎨 let clay-transitions demo rows fill available height
* 🎨 remove modeline from clay-transitions demo
* 📝 note ct_active_context is a workaround for Clay userData PR
* 🎨 use border-only boxes in clay-transitions demo
* 🎨 prevent menu text from wrapping during sidebar transition
* 🔥 drop unused grow import in transitions-run test
* Update transitions branch with upstream changes (#53)
* ✨ add snapshot() for pre-packing directive subtrees
Introduces a new `snapshot(ops)` constructor that pre-packs a directive
array into its transfer encoding. The returned opaque `Op` can be
spliced into any directive array, and during packing its bytes are
copied directly into the command buffer without re-encoding.
This enables higher-level frameworks to implement dirty tracking:
unchanged component subtrees can reuse a cached snapshot, skipping
the per-frame packing cost entirely.
* docs: add maintainer build guide
* 💄 format build docs
* 🐛 improve pack string overflow errors
* os matrix test in ci (#36)
* 🧼 optimize build
* 🧼 compress bundled wasm
* 🧼 optimize wcwidth.c size
* ⚙️ update npm settings
* 🐛 install wasm-opt in ci
* ⚡ use brotli-11 + z85 wasm encoding
* 📌 pin @types/node to v22
* 🧼 apply @ghostdevv review suggestions from PR #35
Co-Authored-By: ghostdevv <git@willow.sh>
* 🔨 add type to bundle-wasm
* 💌 signed, sealed, delivered
* chore: use hashes for versions
* chore: don't save git credentials
* chore: use array syntax
for some reason the schema for the actions wants it to be an array
* perf: set concurrency limits to reduce cost and improve dx
Without this it means that, for example, if I push a change to a PR then
shortly push again this workflow will be running twice. This change will
cancel the old run before starting the new one, which reduces the
overall actions cost and DX as you don't have extra runs
* chore: use hashes for versions
* chore: update node version
* perf: set concurrency limits to reduce cost and improve dx
Without this it means that, for example, if I push a change to a PR then
shortly push again this workflow will be running twice. This change will
cancel the old run before starting the new one, which reduces the
overall actions cost and DX as you don't have extra runs
* chore: don't save git credentials
* chore: mitigate potential template injection
See https://docs.zizmor.sh/audits/#template-injection
* chore: update ::set-output command to new syntax
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
* chore: use hashes for versions
* chore: don't save git credentials
* chore: limit id-token permission to the publishing steps
* chore: explicitly disable npm cache to mitigate cache poisoning attacks
* chore: mitigate potential template injection
See https://docs.zizmor.sh/audits/#template-injection
* chore: use oidc
This should be using OIDC for publishing
* chore: update ::set-output command to new syntax
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
* 🙅 revert aggressive optimization experiments pending benchmark
Reverts three changes that need benchmarks before landing:
- -Oz / wasm-opt
- brotli+Z85 wasm compression
- wcwidth.c rewrite
* Add CodSpeed performance benchmarks
* 🔨 use deno
* 🧼 deno fmt
* ⚙️ vitest -> tinybench
* 🧼 remove codspeed assets
* 🔨 fix ci
* add type module
* fmt
* chore: update github url (#38)
* downgrade to tinybench@5
* move to examples folder with readme
* 🔧 export animating from wasm build
* 🧪 cover transitions in snapshots and validation
* ✅ enforce nonnegative transition duration
---------
Co-authored-by: Charles Lowell <cowboyd@frontside.com>
Co-authored-by: Jacob Bolda <me@jacobbolda.com>
Co-authored-by: Nate Moore <nate@natemoo.re>
Co-authored-by: ghostdevv <git@willow.sh>
Co-authored-by: Nate Moore <git@natemoo.re>
Co-authored-by: codspeed-hq[bot] <117304815+codspeed-hq[bot]@users.noreply.github.com>
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
* remove uncecessary note
* clean up and consolidate
* re-organize transitions examples
* 🔥remove redundant cast
---------
Co-authored-by: Ryan Rauh <rauhryan@users.noreply.github.com>
Co-authored-by: Jacob Bolda <me@jacobbolda.com>
Co-authored-by: Nate Moore <nate@natemoo.re>
Co-authored-by: ghostdevv <git@willow.sh>
Co-authored-by: Nate Moore <git@natemoo.re>
Co-authored-by: codspeed-hq[bot] <117304815+codspeed-hq[bot]@users.noreply.github.com>
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
Co-authored-by: Ryan Rauh <rauh.ryan@gmail.com>