Skip to content

feat: animated SVG output from anim_save(".svg") - #143

Merged
schochastics merged 1 commit into
mainfrom
feat/wi11-animated-svg
Aug 1, 2026
Merged

feat: animated SVG output from anim_save(".svg")#143
schochastics merged 1 commit into
mainfrom
feat/wi11-animated-svg

Conversation

@schochastics

Copy link
Copy Markdown
Collaborator

WI-11 (vellumplot half). Adds a third anim_save() output format on top of the existing keyframe-animation feature.

What

Writing an animation to a .svg path emits a single animated SVG — every frame as vector markup, shown in turn by a CSS step animation (vellum's format = "svg", in the required vellum ≥ 0.6.5). It is resolution-independent (crisp at any size, print, retina) and honours prefers-reduced-motion (both handled inside the SVG by the engine).

Mark-count policy

An animated SVG emits every frame in full, so its size grows with marks × frames where a raster format does not. anim_save() therefore advises switching to a raster format when a .svg scene is dense (> ~800 drawn elements per keyframe) — "choose by mark count, not preference", the decision vellum left to vellumplot. The schedule + encode path is factored into .anim_render() so vellumwidget's animated-SVG embed drives identical frames.

Note on branching

The prior feat-animate branch turned out to be a stale parallel copy of the animation feature (which already landed on main separately). This PR re-applies the animated-SVG work cleanly on top of current main; feat-animate should not be merged.

Verification (WI-0)

Rendered an animated SVG and looked at it in real Chrome (chromote) — panel, marks, axes, legends all embed and the frames animate (vellum's own example confirmed frames become visible; forcing all frames visible confirmed my scatter's content). inst/examples/28-animation.R gains a wave SVG and runs end to end.

Tests: test-animate.R (+3). Full suite [ FAIL 0 | WARN 1 pre-existing | SKIP 0 | PASS 2886 ].

🤖 Generated with Claude Code

anim_save() gains a third format alongside GIF and APNG: writing to a `.svg`
path emits a single animated SVG (via vellum's format = "svg") -- every frame
as vector markup, shown in turn by a CSS step animation. It is
resolution-independent and honours prefers-reduced-motion (both handled inside
the SVG by the engine).

Because an animated SVG emits every frame in full, its size grows with marks x
frames where a raster format does not. So anim_save() advises switching to a
raster format when a `.svg` scene is dense enough (> ~800 drawn elements per
keyframe) that GIF/APNG would be smaller -- "choose by mark count, not
preference". The frame-schedule + encode path is factored into `.anim_render()`
so the widget's animated-SVG embed (vellumwidget) drives identical frames.

Consumes vellum >= 0.6.5 (already required), which provides format = "svg".

Docs: NEWS, an Animation-article section, inst/examples/28-animation.R (an
animated-SVG wave), tests in test-animate.R.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@schochastics
schochastics merged commit 500567e into main Aug 1, 2026
2 checks passed
@schochastics
schochastics deleted the feat/wi11-animated-svg branch August 1, 2026 16:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant