Skip to content
Juozas Žilys
← All projects

Naughty List Bureaucrat

Browser game with a C-to-WebAssembly rules engine, drag-physics on a paper desk, and an ending that depends on how well you did your job.

Role
Solo build for Jame Gam Christmas Edition 2025
Period
Dec 2025

JavaScript · C · WebAssembly · HTML5 Canvas · Web Audio · Emscripten

Problem

A Papers-Please-like — but built for a one-week game jam, in the browser, good enough to feel like “real” work on a desk, fast enough that the rules engine doesn’t block drag physics.

What I built

Three-tier hybrid architecture.

  • Presentation — JavaScript, HTML5 Canvas, Web Audio. 11 modules, ~6,400 lines. Document physics (drag, bounds, collision with the inspection zone, random pickup rotation for feel), CSS 3D perspective on the desk, parallax snow at three depths, dynamic shadows that track document position.
  • Data — JSON configs for cases, rules, documents, dialogue, verdicts. Rule complexity escalates by day. The game is fully re-balanceable without touching code.
  • Logic — C compiled to WebAssembly via Emscripten. Game state, discrepancy detection, rule processing, verdict application, ending calculation. JS and C talk over JSON strings through cwrap — no binary protocol, no marshalling edge cases, easy to debug.

Five in-game days of decreasing shift length (10 → 6 min) as rules get stricter. Performance breakpoints trigger supervisor memos. Multiple endings based on how the player balances quota, accuracy, and mercy.

Interesting bits

  • Why split the game at this boundary. Anything that touches rendering or input stays in JS where it’s cheap to iterate. Anything that has to be provably correct (rule evaluation, verdict, ending logic) lives in C where it’s easier to reason about as a pure function of state and input. The JSON boundary makes the split visible.
  • Game feel from small details. Random ±3° pickup rotation on drag, paper-rustle synthesized from filtered noise on mouse-down, shadow offset and blur that scale with document position — each one is a three-line change, and all of them together are what separate “functional prototype” from “feels good.”
  • Verdict tones are the same oscillator at different frequencies600 Hz for NICE, 200 Hz for NAUGHTY, exponential gain decay over 300ms. The first version used stock click sounds and felt wrong immediately.
  • Day-length and rule escalation are data, not code. Balancing happens by editing JSON between test runs. After the jam, that’s also what makes the game extendable into a longer version without a rewrite.