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

Mixed Traffic Simulator

A traffic simulator showing that Indonesia's rule of one motorcycle as 0.25 cars depends on how it's measured

Screenshots
estimation methods tested against one ground truth
5
published motorcycle factor reproduced, and shown
−0.11
measured speed of a phantom traffic jam
−8.6 km/h
spread between methods, against one flat truth
+16 to −30
On this page

The problem

Indonesian road planners size roads with a 1997 capacity manual, MKJI. It converts every vehicle into car equivalents with a fixed factor, and a motorcycle counts as 0.25 or 0.5 of a car depending on road type. Two decades of Indonesian field studies have measured that "fixed" factor at 0.198, 0.32, 0.35, 0.4 and 0.84. One regression study in Denpasar got −0.11 at one-hour aggregation, which means nothing physically.

This decides budgets. At one roundabout, the same peak hour rates level of service C by one method and F by another. Acceptable or failed depends on which method someone chose, and that decides whether an intervention gets funded. A field study can't settle it, because nobody can replay the same hour of traffic with the motorcycles taken out.

What I built

A controlled experiment no street allows

The simulator runs a traffic stream with a known share of motorcycles. Then it replays the identical scenario with every motorcycle swapped for a car, and compares capacity. That comparison is the true answer. Next, it applies each published estimation method to the same stream and shows the methods disagreeing with each other and with the answer already in hand.

The estimators only see what a roadside observer sees

The argument falls apart if the estimation methods can cheat. I walled them off from the simulation code, and the build fails if they try to reach into it. They receive only what a field engineer could record: when a vehicle crossed a line, its type judged by eye, its spot speed, how long it occupied the detector and where it was across the road. A method that knows true speeds and identities isn't the method engineers used. The only exception is the car-swap experiment, because ground truth is exactly what an observer can't get.

Any result can be shared and replayed exactly

The physics runs in fixed 0.05-second steps, separate from drawing, so results never depend on the viewer's hardware. All randomness comes from one seeded source. The whole state, including scenario, parameters, seed and aggregation window, fits in the link. A surprising result becomes a URL that reproduces it, and a batch sweep can be regenerated from its seed.

The modelling choice is named on screen

There is no agreed model for traffic that ignores lane lines, as Indonesian motorcycles do. So I shipped three rules for sideways movement: strict lanes, gap-seeking and a social-force model. The active one is always named on screen. The social-force rule has no citation in the traffic literature, and the interface says so as a caveat.

Impossible results stay on the chart

When an estimator returns a negative motorcycle factor, I plot it below the axis with a warning. I don't hide it or clamp it to zero. That number is the most persuasive result the app has.

Result

The simulator is live and public. The phantom-jam scenario puts 22 vehicles on a 230-metre ring with no bottleneck. A jam still forms from reaction delays alone and travels backward, measured in the app at −8.6 km/h, reproducing a published experiment. The equivalence bench plots five methods against the motorcycle proportion in traffic. Ground truth stays nearly flat, while the regression and speed methods swing from +16 to −30 and reproduce the published −0.11 at wide aggregation. An inspector shows the live driving arithmetic of any vehicle you select. I built the first version alone over two days in September 2026, then kept working through the rest of the month on a redesign, an accessibility pass, and mobile and keyboard support.

The app states plainly that it is not a calibrated model of any specific road and not a replacement for professional traffic software. Its job is to show an assumption failing.

Under the hoodTechnical detail for engineers
  • src/estimators/ can't import src/sim/, enforced by an ESLint no-restricted-imports rule in CI before deploy. Estimators consume one type, DetectorRecord. src/truth/substitution.ts is the documented exception.
  • Five methods: ground-truth substitution, time headway, multiple regression, speed regression and occupancy time. Aggregation windows are 3, 5, 15 and 60 minutes.
  • Car-following uses the Intelligent Driver Model. Lateral rules are strict lanes with MOBIL, gap-seeking sublane and social-force potentials; the social-force citation field is null.
  • Math.random is banned repo-wide by lint; the seeded PRNG lives in src/sim/rng.ts.
  • The phantom jam reproduces Sugiyama et al. (2008) and is both a build gate and a regression test. The Tirosa roundabout (LOS C by occupancy-time equivalence, F by MKJI) is cited in the spec.
  • A non-overlap assertion runs every step, with iterative lateral clearance at contact. Three commits went to collision fixes.
  • Canvas draws the road, time–space diagram and speed heatmap; the time–space diagram paints one pixel column per interval to an offscreen canvas. SVG draws the fundamental diagram, equivalence bench, discharge plot and cross-section, with hand-computed axes in src/views/render/axis.ts.
  • Interactive simulation stays on the main thread at 400 vehicles; batch sweeps run in a cancellable Web Worker. Trajectories export as CSV.
  • Six scenarios (phantom jam, corridor, bottleneck, signalised, angkot, bench), four vehicle classes (MC, LV, HV, PU) and a Ruang Henti Khusus toggle with a discharge plot for saturation flow and headway.
  • Speed is luminance and vehicle type is shape; hue is reserved for the five estimators. The road view's across-road stretch is capped and printed in the corner.
  • Four runtime dependencies: React 18.3, React DOM and two Overpass font packages. No physics, chart, simulation or state library. About 91 KB of main JS gzipped plus a 7 KB baked-sweep chunk, and 9.5 KB CSS gzipped, against a 300 KB budget; the sweep-worker chunk loads lazily and isn't counted in that figure.
  • 170 tests across 15 files. The engine in src/sim/ is 4,915 lines, pure and headless; the estimator module is a separate 759 lines. About 15,500 lines in src/ and 67 commits between 2 and 28 September 2026.

Screenshots

Phantom Jam
Corridor
Bottleneck
Signalised Approach
Angkot
Equivalence Bench

Hiring, or building something similar?

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