Skip to content
AFM Studio
  • Pages

    AFM Studio
  • Work
  • Lab
  • About
  • CV
  • Contact
  • Projects

    AksaraA searchable library for Otorita IKN's knowledge, where the server checks every reader's access across three levels
  • Daily TaqwaTamper-resistant prayer attendance system for ~2,000 OIKN government employees at Masjid Negara IKN
  • Lantara v2A permit engine for Otorita IKN where administrators add new permit types from a screen, without a developer
  • eKiosk IKNTwo control rooms for Nusantara: kiosk content management and live bus tracking with arrival times that grade themselves
  • E-Monev IKNA monitoring platform for Nusantara's 23-year build, tracking every unit's quarterly progress against 24 national KPIs
  • JDIH OIKNOIKN's public legal document portal, with a controlled publishing workflow and AI summaries that never leave the server
  • Jejak PenanamanA check-in app for IKN tree-planting events that proves each participant was on site with a geofenced selfie
  • Dashboard SAKTIA nightly pipeline and dashboard that replaces OIKN's manual budget downloads for all six of its budget units
  • DoseRxA bedside dose calculator for 127 drugs that rounds each dose to tablets and syrups Indonesian pharmacies sell
  • CubiqA speedcubing trainer with competition-grade timing and a solver I wrote for each of the 8 major puzzles
  • ScimotionAn interactive science library of 86 articles, each explained next to animations the reader can control
  • WA Daily Scrum BotA WhatsApp bot that chases missing standup reports for a 14-person team and flags tasks stuck for days

↑ ↓ to move · Enter to open · Esc to close

Angklung Simulator

A browser angklung that shares a song across a room of players, every note computed from bamboo physics

Screenshots
audio files, every note synthesised
0
playing techniques from one bamboo model
3
cited tunings, each with its caveat
3
bundled melodies, public-domain or my own
5
On this page

The problem

Every angklung app I found online is a soundboard. You tap a picture of bamboo and hear a note. That copies the sound and misses the instrument. In an angklung ensemble, each player holds one or two notes. They spend most of a song waiting, watching a conductor signal numbers by hand. The coordination is the instrument, and nothing on the web lets you try it.

Two smaller gaps followed. The three playing techniques are usually taught as three sounds: kurulung (shake), centok (sharp pull) and tengkep (shake with one tube held). They are three ways of setting the same bamboo ringing. And on an accompaniment angklung, tengkep changes the chord. Four tubes sound a dominant seventh. Hold one with your little finger and it becomes a major triad. No simulator showed that.

What I built

Every note is computed from a model of a bamboo tube

I modelled each tube as a set of resonances that ring and fade, the way struck bamboo does. The site ships no audio files at all, and the build fails if one appears. A tube is closed at one end, so it has almost nothing at twice its main pitch. That gap makes the chord switch provable: the octave tube is the only source of that pitch, so holding it removes the note completely. The three techniques differ only in how the tube is struck. Centok is one hard hit, kurulung is a steady shake, and tengkep is the same shake with some tubes silenced.

The sound is measured by tests

I kept the sound engine free of any browser code, so it can render audio inside the test suite. Tests measure the pitch to within a few cents. They check that the held tube's note is gone under tengkep and present without it, and that centok makes exactly one strike. What you hear in the browser is the same audio the tests measured. Notes are timed against the audio clock itself, so a long piece never drifts.

The ensemble view shows who plays when

The main screen loads a melody, a set of angklung and a number of players. It shows who holds which notes and when each person comes in. Rests are drawn as empty space, because for an angklung player the waiting is the job. You can pick one player and play only that part, or mark players absent and watch the song break. When a song can't be shared out, the solver says why: a note is missing from the set, one player is needed twice at once, or there aren't enough players. It never trims the song to make it fit.

Cultural sources come with their limits

Padaeng is the diatonic-chromatic tuning Daeng Soetigna created in 1938. It ships beside two traditional tunings, salendro and pelog degung, as editable sets of intervals. Each one carries its source and a required note saying where the figure stops being verified. The salendro and pelog numbers are structural models, not measurements, and the build refuses to run if a note is missing. The site names Daeng Soetigna and Udjo Ngalagena on the page, and points to Saung Angklung Udjo and local ensembles.

Result

Angklung Simulator is live and public, in Indonesian and English. It has the rack of swaying angklung, the ensemble view, a technique lab that shows the strikes feeding the bamboo, the chord switch drawn as tubes, a side-by-side tuning comparison and a conductor lane. It also has a diagnostics page that reports how audio behaves on your phone. It runs on three runtime libraries and no audio or sound-processing library. I built it in about 37 hours over 12 and 13 August 2026.

Under the hoodTechnical detail for engineers
  • Each mode is a two-pole resonator, y[n] = g·x[n] + 2r·cos(ω)·y[n-1] − r²·y[n-2], whose impulse response is a decaying sinusoid. The tube behaves as a stopped pipe, so odd partials dominate.
  • Kurulung is a strike train: a 2–3 Hz shake, two strikes per shake, with seeded jitter in timing and strength. Tengkep uses the same train and changes only which resonators are summed. Adding a technique means adding a pattern, not a branch.
  • The synthesis core is (params) → Float32Array, with no Web Audio, DOM, React, clock or module-level state, enforced by tests/synth/purity.test.ts. The same seed renders byte-identically. FFT and onset-detection helpers are hand-written in tests/synth/helpers/dsp.ts.
  • lib/audio/voices.ts plays the rendered Float32Array; it never rebuilds the model in oscillator nodes. Kurulung and tengkep render at a fixed six seconds and fade on release, an approximation kept at the audio boundary.
  • The scheduler computes onsets as startAudioTimeSec + eventTimeSec, never accumulated. Clock and timer are injected so the queue logic is unit-testable in Node.
  • Infeasibility is a discriminated union: nada-di-luar-set, nada-bertumpuk-sendiri, pemain-kurang, with the offending note indexes. The solver also reports the piece's peak instant, so the minimum ensemble size is checkable. It is verified against a brute-force oracle (620 lines, 56 tests).
  • The chord-switch fixture has a 10-cent tolerance that isn't allowed to be relaxed. The technique lab's mode tuner drives the real renderer and emits a TABUNG_MODES literal to paste back into the source.
  • TuningSource.caveat is required and enforced by data:validate. Data: 3 cited tunings, 5 angklung sets, 5 melodies, all validated at build time.
  • The PRD asked for click for centok and hold for kurulung. Telling a tap from a hold would delay every note, so the rack uses a technique selector plus press-and-hold.
  • Warm-up renders one buffer per idle slot so a phone doesn't freeze. The voice budget of 28 came from pnpm bench:voices, which cleared 64 offline voices at about 18× realtime.
  • A silent-playback bug had three causes at once: output level, voice budget, and no way to tell them apart. The fix added visible audio errors, a Safari fallback and the /diagnostik page.
  • scripts/postbuild.mjs fails the build on any audio file. Runtime dependencies are next, react and react-dom. First Load JS is 108–110 KB per page against a 250 KB budget.
  • 7 routes × 2 locales = 14 static pages. 132 tests in 11 files, about 13,100 lines of TS/TSX/JSON, 82 commits.

Screenshots

Beranda
Rak
Ansambel
Laboratorium Teknik
Laras
Aransemen

Hiring, or building something similar?

I'm open to full-time roles and select freelance work.