Skip to content

Add the Playground: EKO-AMP and EKO hi-fi 1978 - #3

Merged
rodleviton merged 11 commits into
mainfrom
playground-winamp
Oct 15, 2026
Merged

rodleviton merged 11 commits into
mainfrom
playground-winamp

Conversation

@rodleviton

@rodleviton rodleviton commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

What

A Playground area under examples/playground/: a gallery of classic players rebuilt on the engine. Two are live.

  • Gallery (examples/playground/): one card per player in the lineup.
  • EKO-AMP (winamp/): a Winamp 2.x clone.
    • Canvas sprite renderer with draggable, snapping windows.
    • Real buttons and sliders over the pixels for keyboard and screen readers.
    • Gapless playlist and a 10-band EQ insert.
    • Spectrum and oscilloscope displays.
  • EKO hi-fi 1978 (hifi/): a cassette deck, graphic EQ and integrated amp, built in HTML, CSS and SVG.
    • The tape is the queue, and the spools and counter follow the whole side.
    • Every control is live: tone, loudness, filters, mono, balance, speaker voicing, headphone crossfeed and a tape echo.
    • DOLBY NR out adds tape hiss, saturation and wow.
    • INPUT switches to phono crackle, tuner static or aux hum.
    • REC records the amp's output.
    • The VU meters have real ballistics.

Engine change

setInserts now also accepts composite { input, output } stages (new EkoInsert type).

  • The engine wires into input and out of output, and leaves the wiring inside alone. This allows parallel paths and feedback loops inside a stage, which the Hi-Fi needs.
  • The change is additive, and plain nodes behave as before.
  • It is in its own commit, with tests in tests/graph.test.ts.

Notes

  • Buildless ES modules importing dist/. Run npm run build && npm run harness, then open /examples/playground/.
  • Vitest now includes examples/**/*.test.js (80 new tests for the pure modules).

Checks

  • Typecheck, build and Prettier pass, and all 517 tests pass.
  • Both players were driven end to end in headless Chrome: transport, EQ, meters, windows and every Hi-Fi control.
  • Not yet tested in Safari or on iOS.

The Playground is a gallery of classic players rebuilt on the engine.
EKO-AMP is the first: main window, 10-band EQ and playlist drawn by a
canvas sprite renderer, draggable and snapping on a desktop, with real
buttons and sliders laid over the pixels for keyboard and screen readers.
It plays dropped files gapless through the EQ chain as an insert, and
plays a generated demo loop when the playlist is empty.

Vitest now also runs examples/**/*.test.js so the Playground's pure
modules (EQ, vis, geometry, sprites, text, files) are covered in CI.
An insert can now be a whole sub-graph: the engine connects into its
input and out of its output and leaves the wiring inside alone, so a
stage can hold parallel paths or a feedback loop. Plain nodes work as
before. The engine owns the output's outgoing connections; taps and
loops close from inside the stage. Exported as the EkoInsert type.
A cassette deck, graphic EQ and integrated amp, ported from the
concept and scaled as one piece. The tape is the engine's queue, with
spools, tape packs and a counter that follow the whole side. The EQ
and amp are one composite insert, and every control is live: tone,
loudness, filters, mono, balance, speaker voicing, headphone
crossfeed, a tape-monitor echo, Dolby out for tape hiss and wow, an
input selector with phono crackle, tuner static and aux hum, and REC
to record the amp's output. The gallery card now opens it.
@rodleviton rodleviton changed the title Add the Playground with EKO-AMP, a Winamp 2.x clone Add the Playground: EKO-AMP and EKO hi-fi 1978 Oct 14, 2026
Each round is one continuous piece of music cut at a single sample
into two WAV files. Key A or B plays them with two plain <audio> tags
(the second preloaded and started on the first one's ended) or through
the engine, in a random order, with normalization off. An AudioWorklet
records whichever player is sounding, and after the guess the screen
shows the real seams: silence in milliseconds and samples, and a
sample-level zoom of the join. Dropping consecutive tracks from an
album turns them into the rounds. The gallery card now opens it.
Only the player under test is wired to the capture, and only while it
plays, so switching keys mid-audition can no longer record the other
player's fade-out as a gap. The seam is searched for only near where it
should be, silence the music already has there is subtracted, and a
capture that recorded nothing says so instead of reporting 0.

Also: the worklet loads from a real file; failed setup retries; rounds
build once and an old album's round cannot land in a new one; engine
errors and stuck players end the audition; iOS elements are unlocked
in the gesture; held keys do not repeat; the reveal is announced with
both seams and the score.
WebGL 2 feedback in half-float buffers: every frame the last one is
warped (zoom, rotation, swirl, ripple, kaleidoscope) and faded, and the
new waveform and comets are drawn on top. Eight presets are per-frame
equations of the engine's analyser (bass, mid and treble against their
own average, smoothed versions, beats and tempo); they rotate and blend
over 2.7 seconds. PLAY on an empty page renders a 64 second set in four
gapless tracks. The synth voices move to shared/synth.js so the blind
test and the visualizer share them.
A new queue whose first track fails no longer resumes the previous
queue's song, and play() will not start a source left over from a
replaced queue. A track that fails at a gap boundary is stepped over
and the next one plays, instead of the track that just ended replaying
under the failed one's name; a queue of nothing but bad files settles,
even under repeat-all. A manual skip that fails and rolls back no
longer emits trackchange for the track it never reached.
The media-session binding now follows the engine's snapshot as well as
trackchange, so the first track of a queue set after attaching shows
on the lock screen instead of nothing (or the previous queue's song).
Ending the queue or a blocked start now shows paused, Play after the
end starts the queue over, and detach clears what it set.
EKO Classic is a click-wheel player: turn the wheel to browse, press
the centre to choose, and on Now Playing the wheel sets the volume or
scrubs. EKO Mini Player is a Luna-blue window on a rolling-hills
desktop with a taskbar, tray balloons and the media-session binding,
so hardware media keys and the lock screen drive it.
The gallery now uses the site's header, type, tokens and light or dark
theme, with tiles of equal height, and every card opens its player.
export.mjs copies the Playground into a static site with its own copy
of the engine. The Hi-Fi loses its title and inlay card, sits smaller
on the page, and gets more convincing rack handles, screws, transport
keys and toggles, with REC shown in the deck's display.
Windows now move by transform with a box shadow instead of a CSS
drop-shadow filter, which left trails of old frames on the desktop in
some browsers while dragging. export.mjs takes --base so each page
names its own folder, for hosts that drop the trailing slash.
@rodleviton
rodleviton merged commit a43d0aa into main Oct 15, 2026
1 check passed
@rodleviton
rodleviton deleted the playground-winamp branch October 15, 2026 00:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant