Study 01 / Sparks

A catalog, rebuilt as a force field

Sixty-five library entries become particles that gather, repel, connect, and settle. The study follows the choices that keep a data-shaped hero expressive without turning navigation into noise.

Can an index reveal its structure before a visitor begins to browse it?

Open the live system
Sparks force-field diagramA constellation of connected particles inside an interaction radius, annotated with the current population and distance thresholds.POPULATION / 65LINK / 92 PXINPUT / 190 PX
One point per catalog record. Connections describe proximity; they do not apply force.
Published
Jul 12, 2026
Updated
Jul 12, 2026
Reading
10 min
On this page
  1. Observable system
  2. Catalog to coordinates
  3. Force model
  4. Scroll choreography
  5. Frame budget
  6. Reduced motion
  7. Use with restraint

01 / Sparks / Observable system

The useful behavior is the return.

The first impression is a constellation, but the interaction is really about recovery. Move across the open field and nearby points step away. Press and the direction reverses: the same points gather toward the pointer. Let go, and every displaced particle has a place to return to.

That resting place matters more than the burst of response. Ambient motion occupies the same visual field as the headline and primary action; if it never yields, it asks the visitor to keep paying attention to decoration. The Sparks system is designed to accept a short interruption, expose cause and effect, and then become quiet enough to read through.

Scroll adds a second layer of meaning. The population begins as a loose orbit, resolves into the word “MOTION,” and finally approaches a catalog-like grid. No new particles are introduced between those states. The scene changes what the same records mean by changing only their arrangement.

One population, three spatial readings
  1. A
    Orbit

    Independent phase offsets keep the opening field loose and visibly unsettled.

  2. B
    Word

    Sampled pixels pull the same points into the silhouette of “MOTION.”

  3. C
    Grid

    The closing state exchanges spectacle for the order of an index.

02 / Catalog → coordinates

One record becomes one point—symbolically, not semantically.

The component receives the live catalog count from the server. Today that produces 65 particles, so the population increases or decreases with the library rather than drifting into a decorative hard-coded number. Population and layout seed are now separate inputs: the authored default seed is 65, while the live count still owns only how many points and word targets are created.

The mapping is intentionally modest. Array position creates one point per record, but a point does not yet carry a stable slug, category, or popularity value. Color is assigned by cycling through five palette values; every seventh point is simply larger. Calling this a data visualization would overstate the implementation. It is a data-shaped composition: the quantity is truthful, while visual attributes remain art direction.

Catalog quantity and repeatable initial condition stay independent.
const random = createSeededRandom(settings.seed);
const targets = createWordTargets(width, height, patternCount);

return targets.map((target, index) => ({
  x: random() * width,
  y: random() * height,
  targetX: target.x,
  targetY: target.y,
  size: index % 7 === 0 ? 2.5 : 1.35 + random() * 0.8
}));

The word target is built in a small offscreen Canvas measuring 960 by 260 pixels. “MOTION” is drawn at 190px, then the alpha channel is sampled every seven pixels. Samples above an alpha value of 120 become candidates. The engine walks evenly through that candidate list until it has exactly 65 destinations, then scales the result to at most 76% of the viewport width and 34% of its height.

This raster sampling avoids storing a logo path, but it also means the exact silhouette depends on text rendering. The output is a transient target, not a brand asset. If the sampling context cannot be created, the fallback is an ellipse—less expressive, but still a coherent resting arrangement.

03 / Force model

A spring to a destination, plus one local disturbance.

Despite the constellation appearance, Sparks is not an n-body simulation. Particles do not attract or repel one another. Each point accelerates toward its own desired position; the pointer adds a temporary local force; damping removes energy. The connecting lines are drawn afterward as a proximity cue and never feed back into velocity.

Return force
Position error is multiplied by 3.2 × delta and added to velocity.
Pointer field
Only particles within 190px respond. Hover uses −0.48 to push away; press uses +1 to pull inward.
Damping
Velocity is multiplied by e^(−3.1 × delta), so decay remains tied to time rather than display refresh rate.
Integration
The damped velocity advances position with a delta × 58 scale.

Those numbers describe intensity 50, the authored baseline. The controller keeps damping and integration fixed while mapping intensity 0–100 to a return coefficient of 2.4–4.0 and a pointer-response multiplier of 0.35–1.65. Reset keeps the chosen seed and intensity, rebuilds this transient field, and returns the Sparks scene clock to zero.

The pointer strength combines a linear falloff with an inverse-distance term. Distance squared is clamped to at least 120 so the force cannot approach infinity when a point and pointer nearly coincide. This is not a claim of physical realism; it is a bounded response curve tuned for a legible interface gesture.

Drag speed is not part of the Sparks force. Dragging only relocates the attractor. Touch has no hover phase, so it reaches the inward press behavior directly. Pointer response is also suspended over links, controls, and the reading surface, preventing a text selection or button press from becoming an accidental Canvas gesture.

Pointer and connection distance comparisonA 190 pixel pointer radius surrounds a smaller 92 pixel connection threshold. Line opacity falls as two points approach the outer connection threshold.190 PX / INPUT92 PX / LINKOPACITY → 0 AT 92 PX
The interaction radius and the visual-link threshold solve different problems and stay intentionally separate.

04 / Scroll choreography

Scroll changes the target, not the simulation.

The engine finds the chapter nearest the midpoint of the viewport and normalizes that section’s progress from zero to one. Sparks uses the value to blend destinations. The transition toward the sampled word begins after progress 0.12 and finishes at 0.74. At 0.72, a second blend begins toward a 13-column desktop grid or a five-column mobile grid. The slight overlap avoids a hard handoff between “word” and “index.”

Word target
0.12 → 0.74, eased out
Grid target
0.72 → 1.00, eased out

Scroll is therefore choreography, not navigation. The scene may suggest that a catalog is becoming ordered, but it does not replace a list, search control, or link. The title, explanation, chapter navigation, and Pattern library action remain ordinary HTML above the visual layer. That separation lets the Canvas be interpretive without making the site depend on the interpretation.

05 / Frame budget

Sixty-five points permit a simple connection pass.

After updating positions, the renderer compares every unique particle pair and draws a line when their distance is below 92px. With 65 points that is 2,080 comparisons per frame: small enough to keep the code direct and easy to inspect. The same approach would be a poor default for several thousand points, where a spatial hash or nearest-neighbor structure should replace the quadratic scan.

Current engine safeguards and their purpose
GuardrailCurrent valueWhat it protects
Device-pixel ratioMaximum 2×Prevents very dense displays from multiplying the fill cost without bound.
Frame deltaMaximum 34msStops a delayed tab or stalled frame from injecting one enormous physics step.
Canvas alphaDisabledThe opaque scene does not ask the browser to composite a transparent backing.
VisibilityDocument + intersectionThe loop stops when the page is hidden or the landing leaves the viewport.

A material geometry resize reconstructs topology-dependent runtime from the current controller settings; a DPR-only change keeps the simulation state. Garden remains lazy, while a released custom Gesture path is scaled into the new field. Product seed and intensity stay outside that transient rebuild.

06 / Reduced motion

A fallback should be composed, not merely frozen.

When `prefers-reduced-motion: reduce` is active, the requestAnimationFrame loop does not start. Sparks renders a deliberate static arrangement instead: the target blend is fixed at 0.78, the grid blend stays at zero, and every point is placed directly at its desired position without velocity or pointer force. This preview does not rewrite the live particle array. The result communicates the constellation without requiring the viewer to wait for it to settle.

The Canvas itself is `aria-hidden`. That choice is valid only because the meaningful claims live elsewhere: the catalog count comes from visible text, interaction instructions are written in HTML, chapter navigation uses links, and the pattern library remains available without the scene. A `noscript` message states the same contract when JavaScript is unavailable.

The Atlas now also exposes a visible Pause / Resume transport outside that hidden Canvas. User pause keeps the current particle field and pixels intact, freezes the active scene clock, and cancels RAF until the visitor resumes. That tab-scoped choice is independent from the system reduced-motion setting, hidden document, and offscreen landing reasons.

07 / Use with restraint

Use a force field when relationships can remain approximate.

This pattern fits a small exploratory index, an ambient brand surface, or an editorial transition where visitors benefit from sensing quantity and connectedness before reading details. It works because the population is bounded, the response is local, the resting state is calm, and a conventional destination sits one action away.

It earns its place when…

  • the count is small enough to remain a composition rather than a cloud;
  • the field can return to rest without hiding content;
  • the interaction reveals a real principle such as grouping or hierarchy;
  • the same destination remains available through semantic navigation.

Stillness is better when…

  • point position or color would be mistaken for precise data;
  • the task demands comparison, scanning, or exact selection;
  • motion follows the pointer continuously while the visitor is trying to read;
  • the visual exists only to make an otherwise empty hero look busy.

The distinction is the difference between an interface that contains particles and an interface that has a reason to behave like a field. Sparks is successful only if the second idea survives after the novelty of the first has passed.

Method

References and implementation sources

This article documents the live implementation running on this site. These primary standards and publication records were used to verify API behavior and technical terminology.

  • HTML Canvas 2D ContextWHATWG HTML Living Standard

    Canvas sizing, drawing state, paths, and the 2D rendering context used by the field.

  • Pointer Events Level 3W3C

    Primary-pointer handling and capture behavior for direct field input.