-
Notifications
You must be signed in to change notification settings - Fork 0
Animation Roadmap
Status: research / planning. No code shipped yet. Lives alongside
Fractal-Expansion-Roadmap.md and
Lighting-FX-Roadmap.md — same "project-wide
roadmap" altitude.
This document covers:
- Whether the Julia-speed animation pattern generalises to every
FractalParametersfield (TL;DR: yes, with a render-gate bus). - A new Animation asset type — saved, recallable, attachable to
regions, parallel to
ColorThemeDatain lifecycle and storage. - A new Animation Slideshow type, plus animation hooks added to the existing Image slideshow.
- Per-parameter animation toggles + a configurable "animated-param ceiling" to keep slow targets (deep zoom, raymarched 3D) usable.
- Two adjacent sub-goals: a real region editor and a cross-asset-type asset manager UI.
Existing extension points to reuse:
-
FractalParameters— already the single source of truth for every per-fractal field. No new model surface required; we animate it, we don't replace it. - Julia animation's render-gate handshake in
FractalParamsViewModel.cs— already proven to keep animation silky-smooth even when individual renders take seconds at ultra-zoom (the only existing param-race synchroniser in the project). - Per-type capability bits in
FractalCapabilityMap— pattern we copy for "which params on this type are animatable." - Singleton JSON library pattern shared by
FractalRegionLibrary,UserColorThemeLibrary,SlideshowConfigLibrary,UserBulbStore,UserEquationStore. We add one more (AnimationLibrary) rather than inventing a new persistence shape. -
SlideshowConfig.FilterFractalTypes/IncludedColorThemeswhitelist pattern — we add anIncludedAnimations/FilterAnimationspeer field rather than a new filter mechanism. -
RenderFrameInfocompletion event already routed back into the param VM — the bus we hang every animator off.
Concrete starting points the design builds on (Avalonia paths only;
WinForms shell is frozen per
CLAUDE.md).
UI.Avalonia/ViewModels/FractalParamsViewModel.cs
fields JuliaAnimating, JuliaAnimateSpeed, JuliaAnimateForward
drive JuliaC by polar rotation. Mechanism:
-
DispatcherTimerat 50 msBackgroundpriority integratestheta += dir * speed * dtevery tick — silent updates. -
_juliaRenderInFlightflag plusNotifyRenderCompleted()(line 289) form the gate: the nextTrigger(params)only fires once the prior render reports back. No mid-render param swaps → no flicker. - 50 ms tick is faster than most render frames at ultra-zoom; updates coalesce against the gate rather than queue.
This is the prototype for every animator we want to add. Generalising it is the work in §Phase 0.
~150 fields in
Abstractions/Models/FractalParameters.cs.
Grouped by which fractal types read them. The full inventory is in
the Animatable parameter inventory
appendix — short version:
- 2D escape-time scalars / complex numbers (Mandelbrot, Julia, Phoenix, Newton, Halley, Secant, Spider, Glynn, Logistic, Magnet 1/2, Multibrot, …) — small primitives, cheapest to animate, no pipeline state invalidation. Top candidates for MVP.
- 3D raymarch params (Mandelbox scale / radii, KIFS fold + scale + offset, Bulb power, quaternion slice plane, Bicomplex slice axis, Kleinian sphere scale) — expensive per frame (raymarched DE + lighting + DoF + volumetric) but produce the most striking visuals.
-
IFS / procedural (
IFSPresetName,LSystemDepth,AttractorA/B/C/D,FlameGamma,FlameVibrancy,DlaParticles,ApollonianDepth,Plasma*) — mixed; some are scalar, some are iteration-count-bound and animating them invalidates the accumulator. Animatable but cost depends on which. -
User-defined fractal source (
UserEquationSource,SandboxSource,UserBulbSource) — not animatable directly. Source swaps trigger Roslyn / CalcGen recompile and JIT, which can take hundreds of ms. TheUserBulbParamsandUserBulbTimeinside a given source body, however, are animatable. -
Shared 3D
Lightingblock — already a struct of floats / colors / angles. Animatable; partially overlaps the Lighting-FX Roadmap.
Per-type "animatable params" can be derived statically from the
existing per-type visibility blocks in
FractalParamsView.axaml.
That XAML is effectively a hand-written registry already.
Abstractions/Models/SlideshowConfig.cs
defines SlideshowType { Image, Video } (line 23) plus filter and
include whitelists. Engine in
UI.Avalonia/Slideshow/SlideshowEngine.cs
drives both. Fractal-type filter dropdown
(FilterFractalTypes, line 184) is the exact UI affordance the
animation-filter dropdown should mirror.
Engine/Models/FractalRegion.cs
already carries optional references to other assets
(CuratedThemes, LightingOverride, EmbeddedWatermark,
UserEquationName, SandboxName, UserBulbName). Adding optional
AnimationName is the same shape of field. No editor exists — users
re-save a region to "edit" it (see §Sub-goal B).
Every asset type rolls its own singleton library + JSON file under
%APPDATA%/FracturingFog/. There is no common asset manager UI
today. See §Sub-goal A.
Goals:
- Animation is an asset, not just a transient UI state — saved, named, recalled, shareable, attached to regions.
- Smooth playback across all fractal types — no flicker, jitter, flashing, or torn frames. Reuse the render-gate that already makes Julia animation flicker-free.
- Animation Slideshow type that picks regions which have an animation attached (or randomly assigns one of the user's animations to a type-compatible region) and cross-fades between region + theme + animation triples.
- Existing Image and Video slideshow types pick up optional animation support — when an animation is attached or randomly assigned, it plays; when not, behaviour is unchanged.
- Per-parameter animation toggles in the UI so users dial back load on slow targets.
- Configurable animated-param ceiling (manual + optional hardware-derived default) to prevent users authoring 30-param animations on a laptop iGPU and then wondering why it stutters.
Non-goals (for this roadmap):
- Animating
UserEquationSource/SandboxSource/UserBulbSourcebodies themselves. Source hot-swap is a separate, much harder problem (CalcGen recompile + JIT warmup + perturbation cache invalidation). Listed in §Deferred. - A keyframe timeline editor with bezier handles. MVP uses procedural
motion (linear / sine / triangle / lissajous between
MinandMaxper param). Keyframes are §Deferred. - Removing or refactoring the WinForms shell. Out of scope —
CLAUDE.mdfreezes WinForms.
Goal: extract Julia animation's render-gate handshake into a reusable animation bus that can drive any number of parameter animators simultaneously, all synchronised against the same render-completion signal.
Why first: without this, every per-param animator would race the renderer independently and the "silky smooth, no flicker" goal would collapse on the second animator the user enables.
Work:
- New
IParameterAnimatorinterface inAbstractions/:Tick(dt)→ mutatesFractalParametersin place;IsEnabled;Name;TargetParams(whichFractalParametersfields it touches). - New
ParameterAnimationBusowned byFractalParamsViewModel. It holds a list of active animators, a singleDispatcherTimer(50 msBackground, matching Julia), and the existing_renderInFlight/NotifyRenderCompletedgate. - Convert the current Julia code path into a
JuliaCAnimator : IParameterAnimatorregistered on the bus. Behaviour stays identical for the user; the bus is purely a refactor. - Bus tick order: integrate every enabled animator silently into the
param record → if
_renderInFlight == false, fire oneTrigger(params)→ wait for completion → repeat. Coalescing preserved. - Tests: a
Server.Tests-style unit test that drives the bus with fake animators + a fake render gate and asserts (a) all enabled animators are integrated before each Trigger, (b) no Trigger fires while the gate is held, (c) integration runs every tick even while the gate is held (so the param record keeps advancing — when the gate releases, the user sees the current state, not the state at the moment of the last Trigger).
Deliver: animation bus shipped, Julia animation reimplemented through it with zero user-visible change. This phase ships behind current behaviour — nothing else turns on yet.
Goal: enumerate which FractalParameters fields are animatable on
which FractalType. Drives UI dropdowns, slideshow compatibility
filters, and animation-asset loading validation ("can this animation
play on this region?").
Why now: without this registry, the asset model from Phase 2 can't validate, and the slideshow code from Phase 4 can't filter.
Work:
- New
FractalAnimatableParamsMap(peer ofFractalCapabilityMapinEnums.cs). For eachFractalType, a static set of animatable param names + their type (scalar, complex, vec3, color, …) + a sensible default Min / Max for procedural motion. - Source of truth: hand-written, derived from the existing
per-type visibility blocks in
FractalParamsView.axaml. ~60 enum values × ~5–15 params each = ~500 entries. Tedious but mechanical. Probably 1–2 day chunk if done by eyeball; could be generated with a Roslyn analyser walking the XAML triggers if we want to keep it permanently in sync (see §Open Questions). - Tests: round-trip — every animatable param the registry claims
exists on a given type can actually be read and written via
reflection on
FractalParameters.
Deliver: registry shipped, but nothing consumes it yet (Phase 2 onward).
Goal: persistable animation as a first-class asset, in the same
shape as ColorThemeData.
Work:
- New
AnimationDataDTO inAbstractions/Models/:-
Name : string— user-visible. -
TargetFractalTypes : List<FractalType>— explicitly which fractal types this animation can play on (validated againstFractalAnimatableParamsMap). -
Tracks : List<AnimationTrack>where each track ={ ParamName, Mode (Linear | Sine | Triangle | Lissajous | Hold), Min, Max, FrequencyHz, PhaseOffsetRadians }. -
Duration : double?— optional total length in seconds; null = loops forever. -
Tags : List<string>— for slideshow filter UI.
-
- Procedural-only for MVP. Keyframes deferred (§Deferred). Procedural is enough for the user's stated goal — "play available animations randomly on a region" doesn't need keyframes, it needs a small library of varied motion profiles.
- New
AnimationLibrarysingleton — parallel toUserColorThemeLibrary. JSON at%APPDATA%/FracturingFog/animations.json. Built-in defaults shipped in-source (similar to how 35 built-in regions ship code-static). - Runtime instantiation:
AnimationData.ToAnimators()returns oneIParameterAnimatorperTrack, all registered on the bus from Phase 0.
Deliver: animations are saveable, loadable, and playable through the bus. No UI to attach them to regions yet — that's Phase 3.
Goal: end users can author an animation, save it, attach it to a region.
Work:
- New
AnimationEditorView.axamlinUI.Avalonia/Views/. Small dialog: target fractal type picker → animatable param list (from Phase 1 registry, filtered by selected types) → per-paramMode / Min / Max / Frequency / Phaserow. "Preview" button activates the animation on the live render so the user sees what they're building. "Save" persists to the library. - Region "Save Region" dialog gets an optional Animation dropdown
(parallel to existing watermark toggle). Stored as
FractalRegion.AnimationName : string?. - Region recall (
LoadRegionFractalParamspath inAvaloniaShellBootstrap.cs) picks up the animation, instantiates animators on the bus, starts the bus. - Editing existing regions still requires re-save (the existing "delete + resave" pattern). A real region editor is §Sub-goal B.
Deliver: full author-save-attach-play loop works for a single region
- animation pair. No slideshow integration yet.
Goal: new SlideshowType.Animation peer of Image and Video.
Work:
- Add
SlideshowType.Animation = 2toSlideshowConfig.csenum (line 23). JSON-compat: enum was already int-serialised, so old configs continue to deserialise as Image / Video. - New
SlideshowConfigfields:-
IncludedAnimations : List<string>?(whitelist; null = all). -
FilterAnimations : List<string>(peer ofFilterFractalTypes). -
RandomizeAnimationsByFractalType : bool— when true, slideshow picks a random animation from the user's library that's compatible with the chosen region's fractal type, ignoring any animation the region itself carries.
-
-
SlideshowEngineper-leg logic for Animation type:- Pick region (existing whitelist / filter logic).
- Pick color theme (existing logic).
- Pick animation: region's attached animation if present and
RandomizeAnimationsByFractalType == false; otherwise random from library filtered byregion.FractalType ∈ animation.TargetFractalTypes. - Cross-fade in. While the leg plays, animation bus is live — params advance per tick. Cross-fade out.
- Stop animation, start next leg.
- Type compatibility hard-stop: if no animation in the library is compatible with the chosen region, slideshow falls back to a static (non-animated) leg for that region. Logged, not popped up.
- Settings dialog gets a new "Animations" tab parallel to the existing "Themes" tab: include/exclude list + filter dropdown.
Deliver: Animation Slideshow type runs end-to-end with the user's library. Falls back gracefully on type-mismatched regions.
Goal: existing slideshow types pick up animation support without breaking any current user's saved configs.
Work:
- Image slideshow per-leg: same animation-pick logic as Phase 4, but the leg-cross-fade timing is unchanged. Animation runs during the static-image leg's hold portion.
- Video slideshow per-leg: animation runs concurrently with the
zoom-leg progression. There's a subtle interaction with
AdaptiveSweep— both are integrating into the same params record every tick. Bus tick order: zoom-leg first, then animation bus, so animation overrides take precedence on conflicting fields. Conflicting fields are rare in practice (zoom only touches center- zoom; animation touches per-type params), but we document the order explicitly.
- Slideshow Settings dialog: "Animations filter" dropdown panel, parallel to existing type-filter panel. Per the user's design ask.
- Backwards compat: old configs default to no animation; behaviour identical to today. Only opt-in.
Deliver: animation available across all three slideshow types.
Goal: keep playback smooth on weak hardware and let users dial back load explicitly.
Work:
- Per-track
Enabled : boolinAnimationTrack. UI: per-row toggle in the animation editor; bus skips disabled tracks on tick. - Global
AnimatedParamCeiling : intsetting (in app settings, not per-animation). Bus enforces: ifenabled-track-count > ceiling, silently drops the lowest-priority tracks for the duration of the leg. Priority order: explicitly-disabled-then-re-enabled tracks first (LRU), then high-cost params (raymarched 3D > 2D escape > scalar), then declaration order. Logged. - Default ceiling: derived from a tiny hardware probe at first
launch (logical CPU count, GPU vendor string already available
via the D3D init path,
IsRunningUnderGpualready a field on the param record). Heuristic:- 2D escape only: ceiling 12.
- 3D raymarched (UserBulb, Mandelbox, KIFS, Kleinian, Quaternion): ceiling 4 default, 6 if discrete GPU detected.
- Override-able in Settings.
- Tests: hardware probe returns reproducible ceilings under controlled fake-hardware inputs.
Deliver: smooth playback on a laptop iGPU, no auto-throttling surprises for users on a 4090.
User ask: a general overall asset manager that surfaces every saved asset and routes to its specific editor.
Each asset type has its own sidebar / dialog / library singleton:
- Regions: sidebar list in main shell.
- Color themes:
ColorThemeEditorfloating window. - User equations: dialog launched from menu.
- Sandbox / UserBulb / SlideshowConfigs: dialogs from menu.
- Watermarks: stored as part of regions, no manager.
- (After this roadmap:) Animations.
There is no top-level "show me everything I've saved" view. Users hunting for an old asset have to remember which dialog it lives in.
Medium effort. The data plumbing is already there — every library singleton already exposes its inventory by name. The work is purely Avalonia view + a routing layer.
- New
AssetManagerView.axaml. Three-pane: type tree on left (Regions / Themes / Animations / Equations / SlideshowConfigs / Watermarks), filterable list in middle, detail / edit pane on right. Same shape as VS Code's Explorer. -
IAssetSourceinterface inAbstractions/: each library implementsEnumerate() : IEnumerable<AssetDescriptor>andOpen(name) : void. Descriptor carriesName / Type / CreatedAt / SizeOnDisk / ThumbnailBytes?. - Wrap each existing singleton with a one-file adapter that returns
IAssetSource. Trivial —FractalRegionLibraryalready enumerates. - Detail pane defers to existing editors via the existing dialog system — Asset Manager is a router, not a new editor.
- Bulk operations: select multiple → export-as-bundle (zip of JSON files) for sharing. Optional, Phase 2.
Probably one focused PR for the read-only view, a second for edit-routing, a third for bulk operations. Each is half-day to one-day shaped.
Low. No persistence changes, no engine touch. Pure UI on top of existing libraries.
User ask: a real region asset manager + editor.
Regions are saved via a dialog and recalled by double-click, but cannot be edited in place. To rename a region or adjust its saved iteration cap, users delete and re-save.
Easy-to-medium. The save path
(AvaloniaShellBootstrap.SaveRegionRequested) already mutates
FractalRegionLibrary and persists. An "edit existing region"
path is the same code path with a "replace by name" branch instead
of "add new."
- Right-click region in sidebar → "Edit". Opens the existing
save-region dialog, pre-populated. Save replaces the existing
record (preserving
RegionTypeso built-ins remain immutable — built-ins should be cloned-on-edit into a user region with a new name). - Edit fields: Name, Description, CuratedThemes whitelist, attached Animation (from Phase 3), LightingOverride toggle, EmbeddedWatermark toggle. Geometry fields (Center, Zoom, Iterations) are not editable here — they're captured from the current view via a "Capture current view" button (same as save flow).
- Built-in regions: edit creates a user-region clone, preserving the built-in as-is.
- Slots into Asset Manager (§Sub-goal A) as the detail-pane editor for Region rows.
Low. The persistence shape doesn't change; the dialog already exists; the library already supports add/remove. Only a "replace by name" code path is new.
These are explicitly out of the initial Animation roadmap. Listed so future-us doesn't re-derive the why.
Procedural motion (Linear / Sine / Triangle / Lissajous between Min / Max) covers the user's stated use cases: random animations applied to regions during slideshow, parameter "twiddle" for live viewing. A real keyframe editor with bezier handles is a separate UI surface roughly the size of the existing color-theme editor. Probably one of the next things after the MVP ships if users ask for it.
Source-level animation (interpolating between two UserBulbSource
bodies, morphing CalcGen DSL trees) is much harder. Requires:
- Roslyn or CalcGen pipeline that can ingest two source bodies
and emit an interpolated calculator without per-frame
recompilation cost. CalcGen's current 5-path pipeline (see
CalculatorGen-Architecture.md) is offline / one-shot, not per-frame. - Probably a "blend amount" param plumbed through every kernel variant.
- Perturbation reference cache invalidation strategy — the deep- zoom reference is recomputed any time the formula changes, and that's seconds-to-minutes at extreme zoom.
Real research project, not a roadmap bullet.
Each leg currently picks one animation. Cross-fading two animations during a leg (so the animation itself fades out as the next fades in, on top of region + theme cross-fade) is doable but the visual reading is muddy in practice — two simultaneously-running animations on the same params produce phase-beat artefacts. Skip unless users specifically ask.
The slideshow already has a SlideshowConfig.AudioReactive toggle
that beat-syncs region cross-fades (see
Slideshow-AudioReactive-Guide.md).
Routing the same beat signal into animation FrequencyHz /
PhaseOffsetRadians is straightforward but earns its own
roadmap entry — interacts with the existing audio band assignment
and would need user-facing config. Deferred to the audio-reactive
roadmap follow-up.
Capture already records the framebuffer. Animation playback is just
frame-by-frame param mutation, so a "record this animation as MP4"
button is mostly UI glue on top of existing
ImageCapture.cs + ffmpeg pipeline. Not in
the initial scope because the slideshow video path already records
animated content; standalone "animation only" export is a smaller
feature than it sounds and ships after the slideshow integration
in Phase 5.
Per CLAUDE.md, out of scope. Animation only ships
in the Avalonia shell. WinForms users keep the existing Julia
animation as-is (the bus refactor in Phase 0 leaves WinForms
unaffected because WinForms doesn't host the bus).
R1 — Per-frame param-record cloning. FractalParameters is a
biggish class. The bus integrates every animator into the live
record on every 50 ms tick. If the calculator reads
FractalParameters by reference (it does — it's a class), animation
ticks that land while a calc is reading mid-iteration could see
torn reads. Mitigation: the existing render-gate already
serialises this for Julia; bus uses the same lock. Verify in Phase 0
tests that read-during-integration is impossible by construction.
R2 — Capability bits don't enumerate animatable fields.
FractalCapabilityMap answers "what does this fractal produce",
not "what does it consume." Phase 1's
FractalAnimatableParamsMap is a peer of it, not an extension.
Risk is that the two drift over time as new fractals land.
Mitigation: add an analyser-style assertion in CI that every
FractalType value has an entry in both maps (or an explicit "no
animatable params" marker for cases like Logistic where it doesn't
make sense).
R3 — UserBulb already has its own animation.
FractalParameters.UserBulbTime (float) is read by the UserBulb
raymarcher as a time uniform and is updated by an internal
animation hook independent of the Julia bus. Mitigation: make
the bus aware — UserBulbTime becomes a registered animator like
any other, with its existing default behaviour preserved by a
shipped-default AnimationData ("UserBulb default time motion").
Do this as part of Phase 0 so we don't fork two animation systems.
R4 — How does the registry stay in sync with FractalParamsView.axaml?
Hand-maintenance of the registry is doable for the 60 current
fractal types but error-prone as new ones land. Options:
(a) Reflection + attributes on FractalParameters fields:
[Animatable(ForTypes = [FractalType.Mandelbox, ...], Min = 0, Max = 5)]. Build registry from reflection at startup. Loses
compile-time guarantees but is single-source-of-truth.
(b) Roslyn analyser that walks the XAML triggers + emits the
registry as generated code. Compile-time guarantees, harder
to write.
(c) Hand-maintained + CI assertion that the registry contains
every type. Simple, requires discipline.
Recommendation: (a) for MVP — attributes are easy and keep the
registry living next to the fields they describe. Revisit after
Phase 1 ships if drift becomes a real problem.
R5 — Color-theme interaction.
Some animations (animating a 3D Lighting.LightDirection) will
fight color themes that bake their own light direction into PBR
material bands. Mitigation: the
FractalAnimatableParamsMap carries a per-param
ConflictsWithThemeKind : ColorThemeKind? field. Slideshow
animation-pick logic filters animations whose conflicting params
are about to be overridden by the picked theme. Documented in the
Animation Editor: editing a conflicting param shows a warning.
R6 — Performance regression risk on the existing Julia animation.
Phase 0 refactors the only ship-proven param animator. If we break
it, every user who runs the slideshow audio-reactive demo notices
immediately. Mitigation: golden test in Server.Tests that
drives a fake render gate at a fixed rate and asserts the
JuliaC value at known intervals matches the legacy
implementation bit-for-bit before / after refactor.
Reference list of every FractalParameters field that's a candidate
for animation, grouped by which FractalType consumes it. Phase 1
turns this into the registry. Source:
FractalParameters.cs +
FractalParamsView.axaml.
| Field | Type | Consumers (FractalType) | Notes |
|---|---|---|---|
JuliaC (Complex) |
Complex | Julia, related Julia variants | The existing animated param. Cheapest. |
MultibrotExponent |
int | Multibrot | Integer; animate in double and round. |
PhoenixP (Complex) |
Complex | Phoenix | Cheap. 2D escape. |
GlynnC (Complex) |
Complex | Glynn | Cheap. |
NewtonExponent |
int | Newton, Halley, Secant | Round-trip via double. |
NewtonRelaxation |
double | Newton, Halley, Secant | Cheap. |
SecantInitialOffset (Complex) |
Complex | Secant | Cheap. |
SpiderCDecay |
double | Spider | Cheap. |
LogisticBurnIn / LogisticSeed
|
int / double | Logistic | Re-render full accumulator each tick — slow. |
IFSIterations |
int | IFS | Cheap if low; accumulator-bound. |
LSystemDepth |
int | L-System | Exponential growth — clamp animation range. |
PlasmaRoughness / PlasmaSeed
|
double / int | Plasma | Cheap; seed changes invalidate cache. |
AttractorA/B/C/D |
double × 4 | Strange Attractors | Per-param; cheap; classic "tweak" target. |
FlameGamma / FlameVibrancy
|
double × 2 | Flame | Cheap; visual sweet spot. |
ApollonianDepth |
int | Apollonian | Recursive — clamp. |
ApollonianMinPixelRadius |
double | Apollonian | Cheap. |
DlaParticles |
int | DLA | Re-runs simulation — slow. |
MandelboxScale |
double | Mandelbox | 3D raymarched — expensive but striking. |
MandelboxFixedRadius / MinRadius
|
double × 2 | Mandelbox | 3D. |
MandelboxIterations |
int | Mandelbox | 3D; high cost. |
KifsFold / KifsScale
|
double × 2 | KIFS | 3D. |
KifsOffsetX/Y/Z |
double × 3 | KIFS | 3D. |
BulbPower |
double | Mandelbulb, UserBulb | 3D classic — power 2 → 8 sweep. |
QJuliaCX/Y/Z/W |
double × 4 | Quaternion Julia | 4D animation — striking. |
QJuliaSliceW / QMandelSliceW
|
double × 2 | Quaternion Julia / Mandelbrot | The "slice through 4D" param. |
BicomplexSliceW |
double | Bicomplex Mandelbrot | 3D. |
BicomplexSliceAxis |
int | Bicomplex Mandelbrot | Discrete; "step" mode rather than smooth. |
KleinianSphereScale |
double | Kleinian | 3D. |
KleinianIterations |
int | Kleinian | 3D; expensive. |
UserBulbTime |
float | UserBulb | Already animated — fold into bus per R3. |
UserBulbParams[*] |
double[] | UserBulb | Per-user-bulb tunables. Variable count. |
UserEquationRotationDegrees |
double | UserEquation | Cheap; 0–360 cycle. |
Lighting.* (sub-block) |
mixed | All 3D types | Direction, color, intensity, etc. |
Iterations (param-level) |
int | All escape-time | Animating this is a perf bomb. Mark off-limits or hard-clamp range. |
Anything not in this list is intentionally excluded (source bodies, quality presets, FractalType itself — switching fractal types mid-animation is a separate feature, not an animation).
| Phase | Scope | Risk | Est. effort | Blocks |
|---|---|---|---|---|
| 0 | Animation bus (Julia refactor) | medium | 2–3 days | every later phase |
| 1 | Per-type animatable param registry | low | 1–2 days | Phase 2, 4, 5 |
| 2 |
AnimationData + library |
low | 1 day | Phase 3, 4, 5 |
| 3 | Editor + region attach UI | medium | 2–3 days | Phase 4 nicety, not required |
| 4 | Animation Slideshow type | medium | 2–3 days | nothing |
| 5 | Image + Video slideshow hooks | low | 1 day | nothing |
| 6 | Per-track toggles + ceiling | low | 1 day | nothing |
| A | Asset manager UI | low | 2–3 days | independent — can ship any time |
| B | Region editor | low | 1 day | independent — can ship any time |
Total core (0–6): ~10–14 working days. Sub-goals (A+B): ~3–4 more. MVP shippable after Phase 4 (animation slideshow works end-to-end); Phase 5 + 6 are polish.
-
Fractal Expansion Roadmap — new
families. New families inherit animation support automatically
once their params are in
FractalAnimatableParamsMap. -
Lighting + FX Roadmap — shares the
Lightingsub-block this roadmap animates. - Performance Roadmap — Phase 6's ceiling defaults depend on the hardware-probe surface from the Performance Roadmap.
- Slideshow + Audio-Reactive Guide — existing slideshow context; this roadmap extends what's there.
- Regions Guide — current region asset behaviour; Sub-goal B updates this.
-
CLAUDE.md— Avalonia-is-canonical rule that bounds scope.