Skip to content

feat: replace Julia Set and Mandelbrot with Julia Family, a slice of parameter space (#209) - #287

Merged
BernardJen merged 1 commit into
mainfrom
feat/julia-mandelbrot-family
Aug 25, 2026
Merged

feat: replace Julia Set and Mandelbrot with Julia Family, a slice of parameter space (#209)#287
BernardJen merged 1 commit into
mainfrom
feat/julia-mandelbrot-family

Conversation

@BernardJen

Copy link
Copy Markdown
Contributor

Closes #209.

Five 1200×1200 bands on the 5:1 wall, each a complete Julia set, c stepping across a short line
through parameter space centred on a boundary waypoint. The row spans the connected/dust
transition — visible in a single frame, not only over time — and sweeps as the centre travels.

65.2 fps at 6000×1200 on a real GPU. Readable at 12% washout.

The three decisions, and the two that needed qualifying

Composition C needed reinterpreting. Literally — c varying per pixel column — each column
gets one vertical line of its Julia set and the frame is a smear, because a Julia set needs both
dimensions of the z-plane. Built as bands, which is what 5:1 divides into squares anyway.

The dive could not be kept. A Julia iteration adds c to an O(1) z every step, so at 2⁸⁰
the bands' c values differ by ~1e-24 — indistinguishable in float32 from each other and their
shared base. Every band would render the identical set from about the 17th doubling. Recovering it
means perturbation theory per band, five CPU reference orbits, far beyond this issue's scope.

What #121 contributes is its curated boundary coordinates, which is the property that matters:
a window centred on one straddles the boundary, which is what makes the transition exist at all.

mandelbrot.js is deleted and nothing inherits the deep zoom — confirmed explicitly after the
precision limit was known.

One criterion C makes moot: "the c marker is clearly visible and unmistakably tied to the
Julia view". There's no map under C, so there is nothing to mark.

The first render failed the washout criterion outright

A flat saturated orange field with the sets sitting on it — the worst starting point for 12%
ambient, and nothing for bloom to pick out because everything was already bright. Fading the far
exterior to black put the light where the structure is: dark interior, bright boundary filigree.
Classic rendering, survives a lit room, no frame-rate cost.

Re-measuring the baselines found them stale

npm run baselines rewrites every entry, so this re-measured the whole set — and several were
well out of date, all from savers changed earlier today:

saver was now
Flow Field 0.0872 0.1388 #228
Raymarch Fractal 0.0081 0.0186 #230
Reaction Diffusion 0.0149 0.0340
DVD Logo 0.0026 0.0065 #252

Stale baselines make the check under-protective. Raymarch's real density is 0.0186 against a
recorded 0.0081 — it could have halved and still passed.

Two consequences named rather than absorbed:

Julia Family measures 0.0001, under STRUCTURE_MIN_ABS_DROP, so it sits outside the
density-drop rule alongside Plasma and Wave Tank. That is a direct cost of the darkening above.
The uniform-spread rule from #227 exists for exactly this blind spot and still applies, and this
saver has wide spread by construction. Annotated next to the number so a future reader doesn't
think it's broken.

Wave Tank moved from exactly 0 to 0.0007. Both readings mean "no edges" — it landed either
side of zero on two runs, and only the exact zero took the separate zero-baseline branch. That is
what actually broke the pinned "only one saver below the margin" invariant, now updated to the
measured set of three with the reasoning recorded.

Everything that counts savers

registry.js, structure-baselines.js, the guide list renumbered to 29 with Julia Family at
position 5, both count claims in the guide and README, and the shader-saver file list in
screensaver-seed.test.js. 675 tests pass, lint clean including the GLSL template check.

What I could not verify

The rotation actually reaching it in the app, and the waypoint walk over a full ten-minute slot —
both stills here are 5–6 seconds in. The band count adapting to other aspects (2 on 16:9, 1 on
square) is arithmetic I have read but not rendered.

…parameter space (#209)

Five 1200x1200 bands on the 5:1 wall, each a complete Julia set, c stepping across a
short line through parameter space centred on a boundary waypoint. The row therefore
spans the connected/dust transition -- visible in a single frame, not only over time --
and sweeps as the centre travels between waypoints.

Measured at 6000x1200 on a real GPU: 65.2 fps. Readable at 12% washout.

## The three decisions #209 asked to be recorded

Composition C, dive-with-following-Julia, and replace both savers. Two of them needed
qualifying, and both qualifications are in the module header:

**C needed reinterpreting.** Taken literally -- c varying per pixel column -- a Julia
set gets one vertical line per parameter and the frame is a smear, because a Julia set
needs both dimensions of the z-plane. Built as bands instead, which is what the 5:1
aspect divides into squares anyway.

**The dive could not be kept.** A Julia iteration adds c to an O(1) z every step, so at
a 2^80 zoom the bands' c values differ by ~1e-24 and are indistinguishable in float32
from each other and their shared base: every band would render the same set from about
the 17th doubling. Recovering it needs perturbation theory per band, five CPU reference
orbits, far beyond this issue. What #121 contributes is its curated boundary
coordinates, which is the property that matters here -- a window centred on one
straddles the boundary, which is what makes the transition exist at all.

So mandelbrot.js is deleted and nothing inherits the deep zoom. That was confirmed
explicitly after the precision limit was known.

One criterion C makes moot: "the c marker is clearly visible and unmistakably tied to
the Julia view". There is no map under C, so there is nothing to mark.

## The first render failed the washout criterion

It came out as a flat saturated orange field with the sets sitting on top -- the worst
possible starting point for 12% ambient, and nothing for bloom to pick out because
everything was already bright. Fading the far exterior to black put the light where the
structure is: dark interior, bright boundary filigree, which is both the classic
rendering and the one that survives a lit room. No frame-rate cost.

## Re-measuring the baselines found them stale

`npm run baselines` rewrites all entries, so this re-measured the whole set -- and
several were well out of date, all from savers changed earlier today:

  Flow Field          0.0872 -> 0.1388   (#228)
  Raymarch Fractal    0.0081 -> 0.0186   (#230)
  Reaction Diffusion  0.0149 -> 0.034
  DVD Logo            0.0026 -> 0.0065   (#252)

Stale baselines make the check UNDER-protective: Raymarch's real density is 0.0186
against a recorded 0.0081, so it could have halved and still passed.

Two consequences worth naming rather than absorbing:

Julia Family measures 0.0001, which puts it under STRUCTURE_MIN_ABS_DROP and so outside
the density-drop rule, alongside Plasma and Wave Tank. That is a direct cost of the
darkening above. The uniform-spread rule from #227 exists for exactly this blind spot
and does still apply, and this saver has wide spread by construction.

Wave Tank moved from exactly 0 to 0.0007. Both readings mean "no edges"; it landed
either side of zero on two runs, and only the exact zero took the separate
zero-baseline branch. That is what actually broke the pinned "only one saver below the
margin" invariant, which is now updated to the measured set of three with the reasoning
recorded.

## Everything that counts savers

registry.js, structure-baselines.js, the user guide list renumbered to 29 with Julia
Family at position 5, both count claims in the guide and README, and the shader-saver
file list in screensaver-seed.test.js. 675 tests pass.
@BernardJen
BernardJen merged commit 9b78774 into main Aug 25, 2026
1 check passed
@BernardJen
BernardJen deleted the feat/julia-mandelbrot-family branch August 25, 2026 19:22
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.

feat: combine the Julia and Mandelbrot screensavers into one paired view

1 participant