Oscilloscope · How it works & code
Oscilloscope with trigger: stable display of periodic waveforms, or switch to XY Lissajous mode.
Runtime logic
Visiting `/audio/scope`, DemoHost lazy-loads `demos/kits/kit-audio.js` (registry `mod: 'kit-audio'`) and calls `mount(host, { variant: 'scope' })`. mount resolves the variant to family `scope`; `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. Pointer down/drag/move updates the interaction (drag handles, hover readouts); when untouched and auto-demo is on, the pointer follows a Lissajous path. With the top-right Sound switch on, sound plays through the shared AudioContext; off = muted. 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.onMove — Pointer move; S.get — Reads current control values; S.clear — Clears with the background colour (translucent = trails); S.onDown — Pointer down; 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.lineTo() — Adds a straight line to a point; ctx.stroke() — Strokes the current path; ctx.closePath() — Closes the current sub-path; ctx.fill() — Fills the current path; ctx.setLineDash() — Sets the dash pattern for strokes; ctx.arc() — Adds a circular arc (center, radius, start/end angle); ctx.arcTo() — Adds an arc using tangent lines; ctx.fillText() — Draws filled text; ctx.measureText() — Measures text width
Source code
frontend/src/demos/kits/kit-audio.js: FAM.scope (L502-L551)
Code walkthrough
L504-504: Canvas cursor style. L505-505: Control definitions (colour/speed/size/count/extras): Trace color, Line width, Time per division ms, Amplitude per division, Trigger level, XY Lissajous mode. L506-506: Preset buttons: name → parameter overrides (6). L507-515: Info-panel content: live rows(v), formula, notes, params, steps. L516-550: Init function: sets up state and returns the per-frame callback: registers pointer handlers `S.onMove`; draws with Canvas 2D `beginPath`, `moveTo`, `lineTo`, `stroke`, `closePath`, `fill` …; produces/reads sound via `A.voices`; math via `Math.round`, `Math.pow`, `Math.floor`, `Math.min`, `Math.max`; returns readouts `fs`, `x0`, `y0`, `gw`, `gh`, `sig`, `td` … to the info panel.
Principles
Horizontal: 1 g = time / Grid (ms), 10 Grids on screen Vertical: 1 g = Submitted by / Grid, 8 sets of screen Trigger: Find first in the buffer zone x[i−1] Oscilloscope Draws a curve of voltage over time. The problem is that the sound is constantly changing, and if each frame starts at any position, the wave shape will run around. Trigger It's the role of every time"The signal goes up through some level"的那一刻开始画,于是周期性的波形就像被钉住一样静止。 The signal here is two sounds 3:2 The pure five degrees) superimposed. We can change the up and down Trigger level (Right little triangle)"Time/格"Decide how long a screen will be displayed. Open XY Mode After that, the crossaxis were drawn with the first sound and the second sound Lisa's graphics , The frequency is more stable than the simpler graphic.