# Fractal Explorer — research, predictions and verification

Updated 20 October 2026. The user approved moving from Chain Reaction Builder to this app. Keep work scoped to this app until they approve the next one.

## Sources and decisions

- [Chris Lipa, Cornell Math Explorers’ Club: Introduction to Complex Dynamics](https://pi.math.cornell.edu/~lipa/mec/lesson5.html). The lesson connects complex squaring, Julia pictures and the Mandelbrot parameter map. It explains that squaring changes both distance and angle, and distinguishes a filled Julia set from its boundary. **Design decision:** link the two maps, label which quantity each map varies, and narrate the actual orbit rather than treating the image as decorative scenery.
- [Jim Belk, Cornell: Julia Sets and the Mandelbrot Set](https://e.math.cornell.edu/people/belk/dynamicalsystems/NotesJuliaMandelbrot.pdf). Its worked quadratic examples include the unit disk for c = 0 and the exact 0 ↔ −1 cycle for c = −1. The notes relate the zero orbit to connectedness for the quadratic family. **Design decision:** include independently checkable limiting cases before more intricate boundary views; let a learner compare settings and inspect individual steps.
- [ECMAScript language specification: Number type](https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-ecmascript-language-types-number-type). JavaScript Number uses IEEE 754 double precision. **Design decision:** disclose rounding and finite zoom precision. Never promise unlimited zoom detail or describe a finite escape-time image as an exact set-membership proof.

These sources support the mathematics. The interaction choices below are our design hypotheses; they are not evidence of measured improvements in learning.

## Testable design predictions

1. **Different map, different question.** Showing the Mandelbrot parameter c beside the Julia starting point z₀ should help learners distinguish the two. Test by asking a learner to predict which value stays fixed before clicking each map. The values, crosshairs and orbit readouts must agree.
2. **Show the arithmetic behind the picture.** A point on an orbit diagram and its simultaneous magnitude chart should make escape easier to explain. Check the exact c = 1 sequence: 0, 1, 2, 5. At distance 2 it has touched, not crossed, the radius-2 threshold; escape occurs at step 3.
3. **Compare before increasing detail.** Keeping a journey, then raising only the iteration limit, should make late escape visible. No change is also a valid outcome. A darker image does not establish that more points are mathematically inside.
4. **Start with predictable cases.** The c = 0 disk and c = −1 two-cycle should make the rule comprehensible before the seahorse and dust examples. The disconnected dust preset uses c = 0.285 + 0.01i; its zero orbit must actually escape in the model before the lesson describes that observation.
5. **Preserve the two-dimensional mathematics.** Pan, zoom, numeric coordinates, a linked map and an orbit diagram answer the experimental questions. Artificial height or a decorative 3D landscape would introduce an unsupported quantity, so this design keeps the complex plane two-dimensional.

## Mathematical contract and limits

- The sole dynamical rule is zₙ₊₁ = zₙ² + c. For z = a + bi, the squared value is (a² − b²) + (2ab)i. Squaring each coordinate separately is incorrect.
- The real coordinate is horizontal; the imaginary coordinate is vertical. Magnitude is distance from the origin, not either coordinate alone. These coordinates have no physical units.
- Mandelbrot samples c and begins at zero. Julia holds c fixed and samples z₀. The plotted Julia region approximates the **filled** Julia set; the mathematical Julia set is its boundary.
- A conservative safe escape radius is max(2, |c|). Escape uses a strict greater-than comparison. Equality is not escape. For Julia, a starting point can already exceed this radius at step zero.
- A recorded trace includes the initial point, then each completed iteration through the first detected escape or the finite iteration limit. Narration, chart, table and export should use those recorded values, not animation time.
- A point that has not escaped by the limit remains undecided by this finite test. Exact simple examples can be justified algebraically, but approximate repeated coordinates are not a general proof of periodicity or membership.
- Screen pixels sample points and finite precision rounds operations. Colour encodes escape speed; it is not physical height, energy or temperature. Thin structures can be missed by a finite image.
- The quadratic family can have disconnected Julia sets when the zero orbit escapes. Do not generalize that special criterion to arbitrary polynomials or claim a raster image proves connectivity.
- Connecting orbit points shows their order. The rule is discrete; a point does not physically travel along the drawn segment between iterations.

## Guided investigations

`learning.js` supplies six reproducible settings, each with a story, prediction and observable: the whole Mandelbrot map, seahorse boundary, Julia unit disk, two-cycle, strict escape threshold, and disconnected dust. The module also provides vocabulary and `explainStep(trace, index, view)`, returning `title`, `what`, `why`, and `next` from the actual model trace. Narration clamps out-of-range indices and does not modify the experiment.

## Verification

Learning checks cover distinct reproducible investigations; Mandelbrot/Julia initial-state wording; exact c = 0 and c = −1 stories; c = 1 threshold equality and escape; step-zero Julia escape; finite-limit uncertainty; complex-coordinate arithmetic; the dust preset's observed escape; and non-mutation. Final numerical and browser outcomes are recorded below after the complete app is exercised.

On 20 October 2026, all **12 learning checks passed** against the implemented `FractalModel.traceOrbit`. The dust preset first exceeds radius 2 at step 19 (magnitude approximately 2.009026), matching a separately calculated recurrence. Both the learning module and its tests pass JavaScript syntax checks. These are numerical and explanation checks; they do not establish browser usability or learner outcomes.


### Completed implementation checks — 20 October 2026

- **69 automated checks passed** across the model, saved-state migration, worker/fallback renderer, lesson explanations and real controller handlers. Checks cover strict escape at the final step, the initial Julia point, safe radii, current-job cancellation, independent panels, old saves, exact CSV values and selected-image export gating.
- The catalog validation passed for all 11 app routes and 171 local references after the redesign.
- Browser review at desktop 1440 × 1050, tablet 820 × 1000, phone 390 × 844 and narrow phone 320 × 760 found no horizontal page overflow. Both themes were reviewed. These are emulated viewport checks, not a claim of testing every physical device.
- Real controls verified: linked map selection; independent drag, zoom and reset; numeric c and Julia starting-point edits; exact 0 → 1 → 2 → 5 escape example; 0 ↔ −1 cycle; play, back and outcome controls; current exact-table row; retained comparison; fine controls; Julia fern preset; colour quiz; fullscreen entry/exit; PNG and CSV export feedback. The browser reported no warnings or errors.
- Saved-data compatibility was tested with isolated fixtures; existing user saves were not overwritten during browser testing. Rendering and arithmetic tests do not establish learner outcomes.
- The map has a minimum horizontal span of 10⁻¹⁰ and a maximum 2,000-iteration calculation. Orbit diagrams show the latest 120 points when necessary; the table and CSV retain the complete finite trace.

### Animated first lesson — research and prediction, 20 October 2026

The introduction now starts from a visible geometric rule before connecting it to the existing complex-number workbench. Its six chapters cover a Koch replacement, repeated rounds, self-similarity, uses and limits, the different Mandelbrot rule, and a guided first Julia experiment. These are explanatory drawings rather than photographic or biological simulations.

Additional primary sources:

- [Erin Pearse, Cornell: A Primer on Dimensions](https://pi.math.cornell.edu/~erin/docs/dimension.pdf), sections 3–4. The Koch curve consists of four copies scaled by one third. Its finite constructions have lengths (4/3)ⁿ. **Design decision:** build each displayed round from the replacement geometry, count actual segments, and show a scaled portion alongside the preceding round. Do not equate the entire Mandelbrot set with this exact self-similar construction.
- [Przemyslaw Prusinkiewicz: Self-Similarity in Plants — Integrating Mathematical and Biological Perspectives](https://algorithmicbotany.org/papers/fractals.tip2004.html). The paper distinguishes geometric resemblance from repeated branching relationships, and explains why the latter can matter in plant modelling. **Design decision:** use a small deterministic branching diagram as an analogy, explicitly labelled as a model. Real organisms do not repeat an exact mathematical rule at every scale.
- [Robert L. Cook and Tony DeRose, Pixar: Wavelet Noise](https://research.pixar.com/docs/2005.SiggraphPapers.CD.pdf). This graphics paper uses scaled frequency bands to construct procedural textures and discusses finite sampling and loss of detail. **Design decision:** mention graphics as a concrete use of patterns across scales without claiming that our Koch rule is the algorithm behind every landscape or texture.
- [Arthur Shek and colleagues, Walt Disney Animation Studios: Art-directing Disney’s Tangled Procedural Trees](https://media.disneyanimation.com/uploads/production/publication_asset/54/asset/tangledProcTrees.pdf). The production paper describes artist-controlled branching and procedural twigs/leaves. **Design decision:** explain that a small rule can produce a detailed starting structure while real production tools need further controls. Our symmetric two-branch diagram is not a recreation of Disney’s system.

The earlier Cornell complex-dynamics references support the transition to Mandelbrot and Julia. The lesson explicitly changes rules: the Mandelbrot map is not generated by adding Koch bumps. The first hands-on experiment fixes Julia c = 0, compares starting points 0.5 and 1.2, and asks the learner to predict shrinking versus escape.

**Design prediction:** showing one line transform, then several actual replacement rounds, should make the word “iteration” concrete before it is applied to numbers. A zoomed correspondence should clarify self-similarity. An explicit transition and one-variable Julia task should reduce confusion about c versus z₀. These hypotheses need learner observation; animation alone is not evidence of comprehension.

**Geometry contract:** `FractalIntroModel.koch(level)` returns a fresh polyline from (0, 0) to (1, 0), with bumps above the baseline in screen coordinates (negative y). Integer rounds are clamped to 0–6. At round n there are 4ⁿ segments, each length 3⁻ⁿ, and total length (4/3)ⁿ. The displayed finite polyline is an approximation to the mathematical limiting curve. `branches(depth)` returns a fresh breadth-first array of segments, rooted at (0, 1), with a length-0.3 trunk, two children turned by ±30°, and a 0.68 length ratio per round. Depth 0 is the trunk; depth is clamped to 0–8. These choices are illustrative design parameters, not measured tree growth.

**Verification:** all 10 introduction-model checks passed. They independently check the unit segment and first equilateral bump, endpoints, 4ⁿ segment counts, per-segment and total lengths, scaled-copy correspondence, symmetry, safe limits and fresh results; branching counts, parent connections, shrinking lengths, determinism and level order; concise chapter copy and the model-backed Julia starting experiment. The first four c = 0 iterations from 0.5 are 0.25, 0.0625, 0.00390625 and 0.0000152587890625; starting at 1.2 escapes. Browser controls, animation timing and accessibility require separate checks after integration.

### Animated lesson — integrated verification, 20 October 2026

- **98 automated checks passed**, including 10 intro controller checks, 6 scene checks and 3 first-experiment bridge checks. Catalog validation passed for 175 local references. The two updated controllers pass syntax checks.
- Browser verification covered first-visit autoplay, pause, chapter navigation, scrubbing, replay, skip, and the final start action. The six scenes were reviewed at desktop sizes; phone layouts were reviewed at 390 × 844 and 320 × 760. These are emulated viewports, not every physical device.
- Fixed narrow-phone playback button compression. The footer remains reachable while reading longer chapters; opening or changing a chapter returns to the animation. No horizontal dialog overflow was observed. At 1280 × 720, the complete desktop dialog fits without vertical scrolling.
- Starting the lesson opens Julia with c = 0 and z₀ = 0.5. Actual playback stops after four steps at 0.0000152587890625. Choosing 1.2 preserves c and shows escape at step 2, with value 2.0736. Changing c dismisses the fixed-rule guide. Replaying and skipping the story preserved the edited c value in the browser.
- Reduced-motion behavior, keyboard handling, blocked session storage, hidden-page suspension, browser-history restoration and cleanup are covered by controller tests. Session storage remembers intro dismissal separately from saved experiments. Existing user saves were not overwritten.
- Browser console review found no warnings or errors. These checks verify implementation behavior, not measured learning outcomes.


### Hands-on introduction — 20 October 2026

The six story chapters now share a separate hands-on state, entered with **Try it yourself**. Entering an activity stops the story clock. Chapter changes retain activity settings; watching/replaying the animation is explicit. Closing the lesson never saves over the learner's workbench.

Activities: drag the first Koch peak or use its slider; build/undo up to six construction rounds; select any of the four main pieces and inspect its correctly rotated, enlarged copy; change branching depth, angle and child length; select c numerically, by preset or directly on the Mandelbrot map and apply the rule one step at a time; choose a Julia starting point, predict shrinking/fixed/escape, then test and carry that same point into the full lab.

Design hypothesis: immediate changes to geometry and arithmetic, with one-variable comparisons and predictions before answers, should make the story easier to investigate actively. This is a design prediction, not a measured learning result. Branching controls describe a drawing rule, not biological growth. Only the completed first bump has four equal thirds. Self-similarity views normalize each selected piece using its actual orientation. The final preview and explanation use four steps for seeds at or below one, and up to eight or the first escape for seeds above one. Zero and one are fixed; a near-one seed can require more than eight steps before escape is observed.

Verification: **135 automated checks passed**, including interaction state, all six scene activities, exact selected-c traces, prediction resets, no answer before testing, bounded inputs, preserved chapter settings, stopped animation clocks, saved-workbench isolation and exact transfer of custom seeds. Catalog validation covers 176 local references. Browser checks covered live dragging, build rounds, rotated-piece selection, tree sliders, map picking, c = 1 escape at step 3, matching and nonmatching predictions, and seed = 1 transfer into Julia with c = 0. Desktop 1440 × 900, laptop 1280 × 720, and phone 390 × 844 / 320 × 760 layouts were reviewed with no horizontal dialog overflow observed. No browser warnings or errors were found. Emulated viewport checks do not establish every physical device's behavior.

### Line-to-fractal workspace — 20 October 2026

The lab now opens with a straight editable line on the left and its generated pattern on the right. The learner can select and drag the middle point, move the section edges, or use the equivalent sliders, numeric fields and keyboard controls. Iterations range from 0 to 7; growth playback advances one round every 700 ms. Triangle, valley and leaning presets provide starting rules. A previous-round overlay supports comparison. The story is now opened explicitly, and Mandelbrot/Julia remains available through a separate workspace tab; existing experiment saves are unchanged.

**Geometry contract:** the normalized rule has five vertices and four segments. Every segment is replaced by the entire rule, rotated and scaled to that segment's actual endpoints. At round n the construction contains 4ⁿ segments, up to 16,384. Its total length is the original length multiplied by the sum of the four rule-segment lengths raised to n. A flat rule remains straight at every round. Positive height points upward, and endpoints remain fixed. Both panels fit their own view; their screen scales are not identical. This is a finite construction rather than an infinite-detail image. The earlier Cornell Koch reference supports the triangle preset; arbitrary edited rules use the same explicit geometric replacement.

**Design prediction:** changing a visible middle section while watching every smaller segment repeat that change should connect a learner's action to the meaning of a recursive rule. The displayed piece count and length provide quantities to compare between rounds. These are design hypotheses, not measured learning outcomes.

**Verification:** all **172 automated checks passed**, including 15 new geometry checks, 9 scene checks and 12 builder-controller checks. Coverage includes rotated replacement, exact endpoints and lengths, bounded inputs, fresh model results, pointer-coordinate inversion, narrow canvases, iteration limits, keyboard editing, timed growth, workspace switching and lifecycle cleanup. Catalog validation passed for 11 routes and 180 local references. Browser checks verified live dragging, presets, iteration stepping and playback, the comparison overlay, preserved rules across workspace switches, and the story-to-Julia transition. Desktop 1440 × 1000 and phone 390 × 844 / 320 × 760 layouts were reviewed; no horizontal overflow was observed. Both themes were reviewed, and the browser console reported no warnings or errors. These were emulated viewport checks, not tests of every physical device.

### Extending the builder to 99 iterations — 20 October 2026

The iteration slider, direct numeric input, step buttons and growth playback now support 0–99. Valid typed numbers apply immediately; incomplete input does not interrupt editing. Counts and lengths use compact scientific notation when large, and the count tooltip retains the exact integer from `4n ** BigInt(iterations)`.

The earlier seven-round drawing limit is replaced by adaptive previews. Up to seven rounds the renderer draws every segment. Above that it refines the segment with the largest remaining error until omitted bends are within 0.6 CSS pixels or the 32,768-segment drawing budget is reached. For a segment of length L with r rounds left, absolute rule height h and maximum child scale q, the residual displacement is bounded by Lh(1 + q + … + q^(r−1)). Refinement rotates and scales the actual edited rule; it does not silently substitute a fixed low iteration. Flat rules collapse to their two endpoints exactly. The interface distinguishes a screen-detail preview from a budget-limited simplified preview; calculated count and length still describe the requested round. Viewport changes recalculate preview detail.

Verification includes bounded finite previews at 99, exact theoretical counts, endpoint preservation, asymmetric and extreme rules, residual bounds checked against finite reference curves, drawing-budget disclosure, cache invalidation on resize, numeric validation, immediate input, and playback stopping at 99. Browser checks at 1440 × 1050 and 390 × 844 confirmed typed 99, the matching slider and disabled upper step, comparison, live dragging at 99, and compact readable numbers without horizontal overflow. Browser console review reported no warnings or errors. The automated suites contain 188 passing checks; catalog validation remains 11 routes and 180 local references.

### Exploring finer detail with zoom — 20 October 2026

Your fractal now has 1–128× zoom, drag-to-pan, and Fit controls. Wheel and pinch zoom preserve the point under the pointer or fingers; keyboard controls provide the same operations. The + button follows the nearest curve segment so repeated clicks reveal detail instead of magnifying an empty gap. A visible tip appears above iteration 7 and explains that small bends can hide inside pixels. It also notes that a flat rule stays straight. Iteration changes retain the camera, while presets and Start with a line return to Fit.

Zoom recalculates geometry at the actual view scale. Preview refinement skips a subtree only when its segment bounding box, expanded by the conservative remaining-displacement bound, is entirely outside the visible world rectangle. This preserves segments crossing the screen and descendants that bend back into view. The entire polyline remains bounded by the drawing budget; no full 4^99 expansion is attempted. The initial whole-curve bounds determine Fit independently of subsequent visible-detail refinement. Current and previous rounds share one camera, with geometry clipped beneath fixed labels.

All **209 automated checks pass**, covering boundary-crossing geometry, residual bounds, pointer anchoring after page scroll, zoom limits, centering on the curve, pan/reset, viewport cache changes, the 7→8 hint threshold, mouse/pinch/keyboard controls and gesture cleanup. Catalog validation still passes for 11 routes and 180 references. Browser checks at 1440 × 1100 verified the tip, detailed button zoom, dragging, pointer wheel zoom and Fit; the 390 × 844 viewport showed usable controls and no horizontal overflow. Pinch mechanics were covered by automated tests, not a physical touch-device check. No browser warnings or errors were reported.

### Detail beyond iteration ten — 20 October 2026

The previous 128× camera ceiling was too low to reveal later Koch bends. Zoom now reaches 1,000,000,000×, and the model accepts up to 10¹³ pixels per unit rather than silently clamping at 10⁹. Reveal this iteration follows the evolving curve in at most twenty camera moves of up to 3×, refining between moves. Its target makes representative final segments roughly six pixels long, bounded by the camera limit. It preserves the selected rule, iteration and comparison setting. Flat rules have no smaller bends to reveal.

The visible-detail readout reports the minimum and maximum refinement depth of potentially visible leaves, excluding offscreen connectors. This is distinct from the selected iteration count. At the numeric zoom limit the interface explicitly reports remaining unresolved detail. Logical iteration 99 is supported, but this is not a claim that all 99 levels can be resolved by the global double-precision camera. The tested Koch view reaches roughly level 25 at the maximum zoom; other edited rules can differ or exhaust the drawing budget. Floating-point rounding is separate from the model's geometric omission bound.

To avoid graphics precision problems, visible segments are clipped in JavaScript before reaching Canvas; large offscreen coordinates never enter result paths. Camera changes preserve the focused world point through iteration changes, comparison toggles and resizing. The caption correctly identifies final visible segments when only offscreen parts remain coarse.

All **221 automated checks pass**. New checks prove a visible geometric difference between rounds 10 and 12 beyond the old cap, actual level-20 detail, bounded high-depth previews, visible-depth reporting, clipped path coordinates, deep focus stability and the reveal controls. Browser verification revealed round 20 at approximately 34.24 million× on a 1440 × 1100 desktop viewport and 71.09 million× at 390 × 844, with the readout confirming iteration 20 of 20. A desktop round-99 check reached the 1-billion× ceiling and correctly reported visible level 25 rather than 99. Comparison and Fit remain available; the phone layout showed no horizontal overflow and the browser reported no warnings or errors. Catalog validation remains 11 routes and 180 local references.

## 2026-10-21 audit: smooth colouring, precision, stale previews and share links

**External evidence.** The renormalised escape count ν = n + 1 − log₂(ln|zₙ|) is continuous only when the bailout radius is large, because it assumes |zₙ₊₁| ≈ |zₙ|² (Linas Vepstas, "Renormalizing the Mandelbrot Escape", linas.org/art-gallery/escape/escape.html). IEEE 754 doubles have a 52-bit fraction, so the spacing of representable numbers near x is 2^(⌊log₂|x|⌋−52) (ECMAScript Number type, already cited above).

**Bug found.** Escape was proved at radius max(2, |c|) and the smooth count was taken at that same small radius with `ln|z|` clamped to at least 1. For |z| between 2 and e the count stayed at n + 1, so colours jumped by a whole band between neighbouring pixels (measured maximum jump: exactly 1.0 along a test line).

**Design decision.** The proved escape step, radius and inside/outside decision are unchanged. For colour only, an escaped orbit continues up to 12 extra steps until |z| > 256, then uses the renormalised count (shifted by 2 so palettes keep roughly their earlier hues). Measured maximum jump across escape-step boundaries is now below 0.001.

**Precision, stated plainly.** The minimum view width stays 1e-10. At 1,000 pixels that is 1e-13 per pixel, about 900 double-precision spacings near |x| ≈ 0.75: pixels stay distinct, but repeated squaring amplifies rounding, so boundary detail at that depth can be distorted. The map footer now reports "near precision limit" once a pixel is fewer than 100,000 spacings wide (around a 1e-8 view), and its tooltip gives the pixel size and spacing. This is a heuristic warning, not an error bound. No perturbation or arbitrary-precision arithmetic is used.

**Stale tiles.** Workers already discarded cancelled jobs. But during a progressive redraw, the rows already on screen had been drawn for the previous camera, so new rows appeared beside a picture in the wrong place. The renderer now remembers which camera its pixels show. It moves them to the new camera before the first new row, and wheel zoom does the same right away. Gesture previews use the same transform, so they are never moved twice. The picture stays "not ready" and export stays disabled until the new calculation finishes.

**Share links.** The URL hash holds both cameras, c, the Julia start, the limit, palette, colour shift, quality and experiment id. Numbers are written with `String(number)`, which gives the shortest form that converts back to the same double. The private prediction note is never included. Links are validated through the same `FractalState.clean` as saved setups. Malformed links are ignored, out-of-range values are clamped, and opening a link never overwrites the saved setup. The address updates when a calculation or journey starts, not on every drag frame, and is cleared when the learner returns to the line builder.

**Verified.** 232 automated checks pass. New checks cover band continuity, an unchanged escape step, precision figures, exact link round-trips, rejection or clamping of bad links, the preview transform, the absence of a double transform, the link-opening controller and the clipboard fallback. Chromium at 390 × 844 and 1440 × 900 in both themes: no horizontal overflow, no axe WCAG A/AA violations in the complex lab, and no console errors. A CDP two-finger pinch zoomed the map 5× about the pinch midpoint and showed the moved preview mid-gesture. A copied URL opened in a new tab reproduced c and zoom. Not checked on a physical touch device.
