notes on machines

Reading a Damped Oscillator

Every interactive figure on this site is written once and rendered twice.

At build time, the plotting code runs natively and emits an SVG that gets baked into the page. In your browser, the identical code runs as WebAssembly and draws to a canvas, with controls wired up to its parameters.

If WebAssembly never loads — you have JavaScript off, your network dropped the .wasm file, your employer’s content policy blocks it — you see the SVG. It is not a placeholder or an apology. It’s the real figure at its default parameters.

The system

A damped harmonic oscillator, the standard second-order response:

x(t) = e^(-ct) · sin(3t)

where c is the decay constant. At c = 0 it oscillates forever. As c grows the envelope collapses and the system settles.

The drawing code is generic over the output target:

pub fn draw<DB>(area: &DrawingArea<DB, Shift>, decay: f64)
    -> Result<(), Box<dyn std::error::Error>>
where
    DB: DrawingBackend,
    DB::ErrorType: 'static,
{
    let mut chart = ChartBuilder::on(area)
        .build_cartesian_2d(0f64..10f64, -1.1f64..1.1f64)?;

    chart.draw_series(LineSeries::new(
        (0..=1000).map(|i| {
            let x = i as f64 * 0.01;
            (x, (-decay * x).exp() * (3.0 * x).sin())
        }),
        TRACE.stroke_width(2),
    ))?;

    Ok(())
}

build.rs calls it with an SVGBackend. The browser calls it with a CanvasBackend. Neither knows about the other, and there is no second implementation to keep in sync.

Drag the slider — or don’t, and read the static version.

-1.0 -0.8 -0.6 -0.4 -0.2 -0.0 0.2 0.4 0.6 0.8 1.0 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0
0.35
Damped oscillator at decay = 0.35. Enable WebAssembly to vary it interactively.