workshop private

← all creations

Undercut

mechanics · created 2026-09-16

Tune a marimba bar by removing wood you can never put back. A rectangular blank rings at 1 : 2.76 : 5.40 and has to end at 1 : 4 : 10, and the arch everyone thinks raises the second partial does not touch it — it lowers the first one past it. Cut 1 mm too deep at the throat and the bar is scrap; the identical millimetre anywhere else costs nothing.

physicssimulationcanvasgame-feel

A rectangular stick of rosewood is not a note. Struck, it rings at

1 : 2.7565 : 5.4039 : 8.9330

which is a fundamental, something a minor seventh and a half above it, something a fifth above that, and so on up — an interval set with no name, because nothing in music wanted it. A marimba bar rings at 1 : 4 : 10: two octaves, then two octaves and a major third. The difference between those two lists is a hollow cut in the underside of the bar, and putting it there is a craft.

The mechanic is that cut. You have a router, a blank, and one rule: wood only goes one way.

Where the numbers come from

A bar lying on cords is a free-free beam, so its partials are the roots of

cos(βL)·cosh(βL) = 1        βL = 4.73004, 7.85320, 10.99561, 14.13717, …

and ω ∝ (βL)², which is where 2.7565 comes from — it is (7.85320/4.73004)², and it is a fact about rectangles rather than about wood. The demo does not use that formula. It assembles the beam out of 24 Hermite cubic elements with a thickness that varies element by element, and solves K φ = ω² M φ for real, because the moment you cut an arch into the bar there is no closed form left. The closed form is what the solver is checked against:

elementsDOFpartial 1 ¢partial 2 ¢partial 3 ¢partial 4 ¢ms/solve
12260.02840.21120.79162.09911.29
16340.00910.06810.25820.69426.39
20420.00370.02810.10720.29003.23
24500.00180.01360.05210.14145.08
32660.00060.00430.01660.045212.48
48980.00010.00090.00330.009057.77

Errors in cents, against the transcendental roots. The shipped mesh is wrong by a seventh of a cent on a partial you can barely hear, and solves in five milliseconds — which is the whole reason the meters can follow the router instead of updating when you let go.

The one line the mechanic is made of

Rayleigh’s quotient, differentiated. For a mode with eigenvalue λ and shape φ normalised so φᵀMφ = 1, element e holds strain energy Uₑ = φᵀKₑφ and kinetic Tₑ = φᵀMₑφ. Stiffness goes as thickness cubed and mass goes as thickness linearly, so

dλ/dhₑ = (3Uₑ − λTₑ)/hₑ            df/f = dλ/2λ

Read that as a sentence: removing wood lowers a partial where that partial stores strain, and raises it where that partial only carries mass. Both are properties of the mode shape. Different partials have different mode shapes. So one cut, at one place, moves every partial by a different amount and sometimes in a different direction — and that is not a quirk of bars, it is the entire reason tuned percussion is possible at all.

It also costs nothing to compute. The eigenvectors are already in hand, so the demo draws the sensitivity of all three partials at all 24 stations, live, every frame, for free.

Why the arch is where it is

partialnodes (fraction of length)strain peakmass peakstrain share at centredf/f per mm cut at centre
10.2246, 0.77540.4790.9790.10406−0.0063
20.1326, 0.5000, 0.86740.7290.9790.00308−0.0002
30.0953, 0.3557, 0.6443, 0.90470.1880.0210.07678−0.0038

The second partial is antisymmetric. Its centre node is at exactly 0.5, and a node of an antisymmetric mode carries no bending moment either — so at the middle of the bar, partial 2 stores 0.3% of its strain and partial 1 stores more than anywhere else. The ratio of the last column is thirty to one.

That is the lever. Cut at the middle and the fundamental falls thirty times faster than the partial above it:

gouge depththinnestf₁ Hzpartial 2partial 3f₁ moved by
0.0 mm20.0 mm564.12.75665.40410
2.0 mm18.0 mm519.82.91075.7097−142 ¢
4.0 mm16.0 mm472.13.09656.1202−308 ¢
6.0 mm14.1 mm421.03.32376.6807−507 ¢
8.0 mm12.1 mm366.63.60627.4664−746 ¢
10.0 mm10.1 mm309.03.96688.6139−1042 ¢
11.5 mm8.6 mm263.84.31139.8679−1316 ¢
13.0 mm7.1 mm217.04.750911.7061−1654 ¢

The arch does not raise the second partial to four. It lowers the first one past a second partial that is barely listening. The interval opens as a side effect, and the price is 1300 cents of pitch — which is why the blank has to start an octave and a half sharp, and why the deep throat under a marimba bar is not what it looks like it is for.

There are places where cutting makes it sharper

The same gouge, taken symmetrically at five stations:

cut atf₁ moves ¢f₂ moves ¢f₃ moves ¢partial 2partial 3
0.0600+92.3+16.9−54.82.63904.9638
0.1500−14.2−170.3−234.02.51894.7598
0.2243−144.3−294.0−242.72.52815.1055
0.3200−286.6−302.0−143.82.73215.8685
0.5000−602.9−117.3−149.53.64917.0219

Cut near the end of the bar and the fundamental goes up almost a semitone. The ends are where mode 1 has its displacement antinodes and almost no bending: the wood there is ballast, not spring, and taking ballast off a spring makes it faster. Every station in the first two columns is a sign change looking for a place to happen, and the demo draws all of them as a strip you can read before you commit.

What it costs to be wrong

The bar roughed to an 8.5 mm arch, then over-cut by 1 mm at one station, then tuned as hard as a solver can tune it from there:

slip atwhich isbest pitch ¢best partial 2 ¢best partial 3 ¢verdict
0.5000the throat−0.3725.73−52.44scrap
0.3500the shoulder−0.031.77−4.42recovers
0.2243a node of partial 1−0.022.53−4.83recovers
0.1200the shoulder−0.032.15−5.74recovers
0.0300the end−0.052.05−5.40recovers

One station in five is fatal, and it is the one the arch was going to be cut at anyway. The throat is the useful place to cut for exactly the reason it is the dangerous one: it is the only station with a thirty-to-one lever on it, so an extra millimetre there moves the fundamental and the ratio together, by an amount that no other station has the authority to answer. A slip at the end is nothing — there is still a throat left to spend.

How much is too much, at the throat:

over-cutbest pitch ¢best partial 2 ¢best partial 3 ¢verdict
0.20 mm−0.031.39−2.93recovers
0.50 mm−0.011.07−2.47recovers
0.70 mm−0.126.67−18.64scrap
0.90 mm−0.2715.95−39.85scrap
1.00 mm−0.3725.73−52.44scrap
2.00 mm−7.57231.30−452.60scrap
3.00 mm−271.50−145.80−1208.85scrap

Between half a millimetre and seven tenths, at one station, after everything else has gone right. The gouge cuts at 8.1 mm a second, so it crosses that margin in 74 milliseconds — less than a reaction time. The scraper cuts at 0.99, and takes 0.61 seconds to do the same damage. That factor of eight is the entire argument for having two tools: not that the fine one is more accurate, but that it is slow enough for the mistake to be interruptible.

That is the shape of the whole mechanic. The strength of a control and the cost of misusing it are the same number, read twice.

What is physics here, and what isn’t

Reuse

src/undercut.mjs is framework-free with no canvas in it.

The demo is demo/index.html with its own copy of the module (ADR-0002). Drag on the bar to cut, or / to move the router and space to cut (hold shift for fine steps). g swaps the gouge for the scraper, 1/2/3 pick which partial the overlay is about, s strikes it, n is the next blank, r starts over. It sizes itself to its viewport, so the site’s full-screen button just works.

It makes a sound, and the sound is the four frequencies the eigensolver just returned, additively, with higher partials quieter and shorter — no samples and no fudge factors. A blank thuds. A half-cut bar is a marimba with something wrong with it. A tuned one is a marimba. That is the readout that needs no legend, and it is the reason to build this as a thing you can hold rather than a chart.

node scripts/measure.mjs regenerates every table above. node scripts/screenshot-demo.mjs regenerates the thumb and media and is the smoke test: 13 assertions, any page error fails the run, and it checks the live demo’s own readouts against the closed forms — that the blank in the browser rings at 2.75656 against the analytic 2.75654, that there exist stations where cutting raises the fundamental and stations where it lowers it, and that the demo can be driven to 1 : 4 : 10 with the fundamental inside 0.4% of the note.