4a8abcfString of beads: 3D bead-spring solver, control panel, waveform, spectrogram, wav, displacement viewerJeremy Magland 1# toy-instruments
98ff172Deploy to GitHub Pages via Actions (test, build, deploy on push to main)Jeremy Magland 3Live: https://magland.github.io/toy-instruments/ (deployed from `main` by `.github/workflows/pages.yml`).
4a8abcfString of beads: 3D bead-spring solver, control panel, waveform, spectrogram, wav, displacement viewerJeremy Magland 5A browser gallery of toy physical-model instruments. Pick an instrument, set its geometry, properties and excitation, run the simulation, and get the pickup waveform, a spectrogram, a playable/downloadable `.wav`, and the bead displacements over time. Static site (Vite + TypeScript); the solver runs in a Web Worker.
7```
8npm install
9npm run dev # http://localhost:5173
10npm test # vitest
11npm run build # static site in dist/
12```
14## String of beads (first instrument)
16- `n` point masses on springs with stiffness `k`, spacing `L` at equilibrium, pre-tension `T` (rest length `L0 = L - T/k`). Beads move in 3D and the springs are real (exact length), so geometric nonlinearity is kept: pitch glide at large amplitude, transverse-longitudinal coupling, whirling.
17- Ends: clamped (fixed point), sliding (massless ring on a rod: x fixed, free across, holds tension), or free (no support; only consistent with `T = 0`). Any bead can be pinned.
18- Excitation: pluck (triangle between the nearest supports, released at rest), strike (Gaussian initial velocity), hammer (raised-cosine force pulse). Direction is an angle in the y-z plane.
19- Damping from two decay times: `sigma(omega) = sigma0 + sigma1 omega^2`, fitted to T60 at two frequencies for transverse modes. `sigma0` is mass-proportional; `sigma1` is a dashpot on each spring's relative velocity.
20- Audio: pickup acceleration (forces / mass, at the full-step velocity), from one bead or summed over all beads, along y, z or x. The `.wav` is normalized to -1 dBFS.
21- Solver: velocity Verlet (explicit, symplectic without damping). `dt = cfl * 2 / omega_max` (Gershgorin bound with axial `k` and transverse `T/l`), rounded down to a whole number of steps per audio sample.
d2bfcd73D model view: setup (supports, pins, excitation, pickup) and replay of saved frames on a shared timelineJeremy Magland 22- 3D model view (three.js): Setup shows the beads at rest with supports (wall = clamped, translucent plane + ring = sliding), pinned beads (cubes), excitation (pluck shape, strike velocity arrows, hammer force arrows) and pickup (bead + axis arrow). Replay animates the saved frames ("Replay frames" per second, default 2000) with adjustable exaggeration, on a timeline shared with the 2D side/top views and space-time image.
4a8abcfString of beads: 3D bead-spring solver, control panel, waveform, spectrogram, wav, displacement viewerJeremy Magland 23- Checks shown per run: energy balance (energy + dissipated - work in - initial) relative to peak energy, largest strain. Linear transverse and longitudinal modes (Sturm bisection on the tridiagonal stiffness) are marked on the spectrum.
2cd36faBead drum: hex-lattice round head, felt mallet contact, top view and cross-section; shared instrument pageJeremy Magland 25String tests (`test/string.test.ts`): modes vs the discrete-string formula; small mode-1 motion vs `cos(omega_1 t)`; energy balance with and without damping/forcing; decay at the requested T60.
27## Bead drum
29- Round head: beads on a triangular (hex) lattice in the x-z plane, cut to a circle; every missing neighbour of an edge bead is a fixed rim point. Vibration along y.
30- Inputs are continuum values: diameter, rings (spacing a = R / (rings + 1)), surface density, tension tau (N/m), in-plane stiffness E t (N/m). Lattice: spring tension f = tau a / sqrt(3), stiffness k = sqrt(3) E t / 2 (Poisson ratio 1/3), bead mass = density * sqrt(3)/2 a^2.
31- Excitation: felt mallet (point mass, contact force K delta^p on a Gaussian patch, integrated with the beads; contact time and rebounds come out of the simulation), strike, force pulse, press (initial dent).
32- Damping as for the string (dashpots calibrated to the springs' transverse stiffness f / a).
33- Extra views: top-down displacement map and cross-section along the diameter through the strike point; mallet contact force.
34- Presets: a fast tom with in-plane stiffness softened ~70x (about 8x slower than real time for 571 beads in Chromium) and a realistic Mylar one (~6x more steps).
35- Tests (`test/drum.test.ts`): every bead has six springs; a small centre press rings within 1.3% of the ideal membrane fundamental 2.405 c / (2 pi R); the mallet bounces off and energy balances.
4a8abcfString of beads: 3D bead-spring solver, control panel, waveform, spectrogram, wav, displacement viewerJeremy Magland 36
c696b9aCymbal: plate bending via per-triangle shape operators, felt centre support, stick and mallet with angle and friction, far-field microphoneJeremy Magland 37## Cymbal
39- Thin bronze plate (E = 100 GPa, 8600 kg/m^3, 0.8 mm by default), round, free rim, centre hole; flat by default, optional bow (dome, y = h (1 - (r/R)^2)) and bell (raised cosine). Beads on a triangular lattice lifted to the profile; the mesh is scaled so its area equals the disk's.
40- In-plane: springs with k = sqrt(3)/2 E t / softening (an edge with one triangle gets half). Softening (default 30x in the fast preset) speeds the run; bending is unaffected.
41- Bending: dihedral angles across interior edges (`src/sim/hinge.ts`, Bridson et al. 2003), sign-normalized so a positive change folds toward the upward normal. Each triangle builds a shape operator S = sum_e phi_e l_e / (2A) m_e m_e^T and stores the plate energy A D/2 [(tr S)^2 - 2 (1 - nu) det S] (nu = 1/3) as a 3x3 matrix in its hinge angles, condensed over free edges so they carry no moment. Plain hinge springs get the twisting term wrong on a regular mesh (effective nu = -1/3), which matters for a free rim. Damping uses the same matrices (Rayleigh, sigma1 omega^2).
15fbb00Cymbal: replace felt washers with a minimal rigid hub (pinned beads around the hole), no support dampingJeremy Magland 42- Centre support: a small rigid hub. Beads within the hub radius (default: the first ring around the hole) are held fixed; no springs, no added damping, so the rest rings like a free plate. At least three beads are needed, or the plate can tilt freely about the support.
c696b9aCymbal: plate bending via per-triangle shape operators, felt centre support, stick and mallet with angle and friction, far-field microphoneJeremy Magland 43- Excitation: drumstick (Hertz, K delta^1.5) or felt mallet as a 3D point mass with contact along the surface normal, regularized Coulomb friction and a contact reach; hit angle tilts the stroke toward the rim. Also strike and force pulse.
44- Sound: far-field microphone via the Rayleigh integral, p = rho / (2 pi) sum A_i a_n,i(t - R_i / c) / R_i (baffled-plate assumption: no diffraction around the rim).
45- Tests (`test/cymbal.test.ts`, `test/hinge.test.ts`): hinge gradient vs finite differences; bending energy matches the plate for cylinder, sphere, saddle and twist to 0.1%; a free flat plate's (2,0) mode within 3.4% of Leissa's value on a 9-ring lattice; energy balance with a glancing stick, friction, felts and damping.
46- Limits: about 45x slower than real time for ~370 beads in Chromium; bending is resolved only to ~1.3 kHz at the default resolution, so it sounds like a small gong, not a crash. A single-bead stick contact chatters on this lattice, so presets spread the contact over ~1.5 bead spacings.
4a8abcfString of beads: 3D bead-spring solver, control panel, waveform, spectrogram, wav, displacement viewerJeremy Magland 48## Layout
50- `src/sim/` generic 3D bead-spring system, solver, worker.
51- `src/instruments/<id>/` model (parameters to system), presets, page. Register new instruments in `src/instruments/registry.ts`.
2cd36faBead drum: hex-lattice round head, felt mallet contact, top view and cross-section; shared instrument pageJeremy Magland 52- `src/ui/instrumentPage.ts` the shared page (controls, 3D model, setup, run, audio, plots); an instrument supplies setup rows and extra cards.
d2bfcd73D model view: setup (supports, pins, excitation, pickup) and replay of saved frames on a shared timelineJeremy Magland 53- `src/ui/` reusable controls form, line plot, spectrogram, chain displacement viewer, 3D scene, shared playback timeline, FFT, WAV.