Fiber-optic Strands · How it works & code
A bundle of fibers diverges from a single point at the bottom, each fiber being a quadratic Bézier curve with control points swaying with the wind and attracted to the pointer.
Runtime logic
Visiting `/generative/fiber`, DemoHost lazy-loads `demos/kits/kit-generative.js` (registry `mod: 'kit-generative'`) and calls `mount(host, { variant: 'fiber' })`. mount resolves the variant to family `fiber`; `withControls` builds the control panel (6 presets + sliders). `createCanvasStage` creates the `<canvas>` (HiDPI ≤ 2×, ResizeObserver) and the info panel. The family’s `build(S)` initialises state and returns the per-frame callback. Every `requestAnimationFrame`: read controls, advance a speed-scaled clock (dt ≤ 50 ms), run the frame callback; returned readouts go to the info panel. Changing parameters: colour/speed/size apply live; structural ones remount; leaving the page cancels rAF, removes listeners and frees resources.
Environment
Canvas 2D: 2D canvas drawing; requestAnimationFrame: Display-synced animation loop; ResizeObserver: Canvas follows container size; Pointer Events: Unified mouse/touch/pen events; devicePixelRatio: Crisp HiDPI rendering (capped at 2×) · react 18.3.1, react-router-dom 6.30.6, vite 5.4.21
Dependencies
react 18.3.1
Imported APIs
withControls — Wraps the demo in the shared control panel (presets, sliders, reset); hot-updates or remounts on change; paramsFromSpec — Turns the spec (colour/speed/size/count/extras) into control-panel parameter definitions; createCanvasStage — Shared Canvas 2D stage: canvas + info panel, HiDPI, one rAF loop, pointer state, idle auto-pointer; hueOf — Hue of a colour (0–360°); clamp — Clamps a value to a range; TAU — Constant 2π; fmt — Number formatting (fixed decimals); F — Formula block HTML; S.clear — Clears with the background colour (translucent = trails); S.onFrame — Registers a per-frame callback; its return value feeds the info panel; ctx.beginPath() — Starts a new path; ctx.moveTo() — Moves the pen without drawing; ctx.quadraticCurveTo() — Adds a quadratic Bézier segment; ctx.stroke() — Strokes the current path; ctx.arcTo() — Adds an arc using tangent lines; ctx.closePath() — Closes the current sub-path; ctx.fill() — Fills the current path; ctx.fillRect() — Fills a rectangle; ctx.arc() — Adds a circular arc (center, radius, start/end angle); ctx.drawImage() — Draws an image or offscreen canvas; ctx.save() — Saves the drawing state (transform, styles, clip); ctx.rect() — Adds a rectangle to the path; ctx.clip() — Turns the current path into the clipping region; ctx.restore() — Restores the saved drawing state
Source code
frontend/src/demos/kits/kit-generative.js: FAM.fiber (L447-L461)
Code walkthrough
L447-461: Calls the factory `gFam()` to produce the full definition (spec + doc + build) from the options below. L447-447: Title shown in the info and control panels: “Fiber-optic strands”. L447-447: Range/default of the size slider: Dot size. L447-447: Range/default of the count slider: Number of fibers. L448-448: Extra demo-specific slider/toggle: Curvature. L448-448: Default main colour. L448-448: Preset buttons: name → parameter overrides (5). L449-449: Body of the “Notes” section. L449-449: Main formula of the “Formula” section. L449-449: Second formula line. L450-461: Per-frame draw function: draws with Canvas 2D `beginPath`, `moveTo`, `quadraticCurveTo`, `stroke`; math via `Math.sin`, `Math.cos`; returns readouts `cell` to the info panel.
Principles
B(u) = (1−u)²·P₀ + 2u(1−u)·P₁ + u²·P₂ Pulse position u = condition (0.3t + seed) Fibre lamps: A line of fibers spread from the bottom to the same point, each of which is a double Bézier curve, and the control point moves with the wind and is attracted by the pointer. The pulsation runs from the bottom to the end of the fibre, which sends bright light. Generative Art = a simple mathematical rule + Random number/噪声,让电脑自己「画」出图案;改变参数就是改变规则。