feat(RadialProgress): self-animating progress via duration + countdown#33
Merged
Conversation
…tdown UIs A new sibling to LinearGradient / RadialGradient that draws a stroked ring filled to a `progress` value, with a gradient swept along the arc, a background track, and configurable round/butt end caps. Implemented for both WebGL and Canvas2D backends. Single-node, one draw call, animatable via `progress: 0..1`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…n props Add `duration` (ms per cycle) and `countdown` (0 = fill, 1 = drain) props. When `duration > 0` the shader self-animates: WebGL derives `progress` from u_time in GLSL, Canvas2D derives it from node.time in render(). `time: true` on both backends so the stage requests a render each frame and `u_time` is plumbed automatically — no JS-side animation needed for a smooth loop. The static `progress` prop still works when `duration === 0` (the default), so non-animated and JS-animated uses are unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…shader # Conflicts: # examples/tests/shader-radial-progress.ts # src/core/shaders/canvas/RadialProgress.ts # src/core/shaders/templates/RadialProgressTemplate.test.ts # src/core/shaders/templates/RadialProgressTemplate.ts # src/core/shaders/webgl/RadialProgress.ts
…PACE The two self-animating rings now start static (duration: 0) so the example loads in a calm state. A SPACE keypress toggles both rings between duration: 0 and duration: 2000. An instruction line and a status label under the grid document the binding. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #26. Hooks
RadialProgressinto thehasShaderTimeFnmachinery so the shader can drive its own animation without a JS-side tween.duration(ms per cycle,0= disabled) andcountdown(0= fill 0→1,1= drain 1→0).duration > 0: WebGL derivesprogressfromu_timein GLSL; Canvas2D derives it fromnode.timeinrender().time: trueon both backends so the stage marks the node as timed andu_timeis plumbed automatically.duration === 0(default): the existing staticprogressprop is used — non-animated and JS-animated callers are unchanged.Why
A countdown ring updating from a JS animation tween costs a CPU-side prop write and a per-frame uniform repush. With
duration/countdown, the only per-frame work isrequestRender()+ one fragment-shader `fract()` — significantly cheaper for the common "always-on circular timer" UI.API delta
```ts
// before (still works):
node.animate({ shaderProps: { progress: 0 } }, { duration: 2000, loop: true }).start();
// after — equivalent, no JS animation needed:
renderer.createShader('RadialProgress', {
duration: 2000,
countdown: 1, // 1 = drain (countdown), 0 = fill
// ...
});
```
Test plan
durationresolver + a default-shape check)🤖 Generated with Claude Code