BINX FORGEALL YOU NEED IS AN IDEA.Support BINX ↗
REVERSE ENGINEERING · ORIGINAL SOURCE INCLUDED

Read a Game Loop: Find Input, Updates and Rendering

Trace the original workshop from a button press to state mutation and a rendered frame.

Actual Beacon Hop gameplay: a playable BINX reference
Beacon Hop · Actual gameplay · Related playable reference

Thumbnail: an actual related playable BINX demo. It is a gameplay reference, not evidence that a save, inventory, network or native reverse-engineering integration has been demonstrated.

Difficulty: beginner to intermediate. Prerequisites: basic variables, functions and a test copy of your project. Reference: Forge workshop 1.0, browser ES modules and Node 24 checks. Engine-specific translation is a separate integration.

What you will learn

Trace the original workshop from a button press to state mutation and a rendered frame.

Download complete MIT workshop
  1. Extract into a new folder and run node check.mjs from that folder.
  2. For the browser games, run python3 -m http.server 8080 with Python 3 and open http://localhost:8080/index.html. Do not open modules with file://.
  3. Read the full setup instructions and the original code licence. Keep your existing game on a separate test branch.

The JavaScript behaviour checks and native C comparison can run independently of the browser. Ghidra UI, physical-phone and your engine integration are separate checks. This is a small reference, not a certification of your project.

Explore the related game idea · Start with Build a Game · Improve your existing game

Five practical steps

Read a Game Loop: Find Input, Updates and Rendering: Choose a question and source → Trace input ownership → Identify one clock owner
Original implementation diagram · not gameplay or a tool screenshot
  1. Choose a question and source

    Open lab.mjs and platformer.mjs from this original MIT workshop. Ask: what controls horizontal speed? Record the source version and the units before reading everything. Source reading is the quickest starting point when legitimate source is available.

    Expected result: A narrow question with a known source file.

    Check it: Locate the speed constant 180 in platformer.step and the input map in lab.mjs.

    fixedStepObserve the inputs → check the state → compare the result
  2. Trace input ownership

    Follow keydown or pointerdown into keys or pointerInput. Neither event directly moves the platformer. The next fixed update samples held actions. Jump differs: it is a press consumed once. Draw this path before changing it.

    Expected result: Input event → action state → sampled update.

    Check it: Release Right while paused, resume and verify the old action is not still held.

  3. Identify one clock owner

    Find requestAnimationFrame(frame), then fixedStep. Accumulated time feeds 1/60-second updates, bounded to 0.1 seconds per rendered frame. A single render may contain zero, one or several updates. Rendering does not own the movement speed.

    Expected result: A timing model with a documented long-stall tradeoff.

    Check it: Feed fixedStep 1/30 second; its callback runs twice, each with 1/60.

  4. Predict before running

    At 180 pixels/second, a 60Hz update adds three pixels right. A one-second interval should add 180 before bounds or outcome rules intervene. Compare at two elapsed-time schedules using the standalone checks, and explain any dropped catch-up time.

    Expected result: A prediction supported by source and observed output.

    Check it: Use the fixed-step accumulator with 30 and 120 rendered frames over one second; update counts agree.

  5. Write a small original equivalent

    Implement the bounded accumulator from your understanding, not from guessed variable names in a decompiler. Compare controlled input sequences and edge cases against the source. Keep a table separating measured behaviour, inference and remaining uncertainty.

    Expected result: A reconstruction that passes stated timing cases.

    Check it: Try a one-second stall, pause, restart and a zero elapsed frame; state the cap rather than claiming wall-clock-perfect physics.

Read and reuse the actual code

systems.mjs: complete source · Standalone behavioural checks · Shared browser runner and input. Original BINX Forge code, MIT; the package includes every required file and its notice.

Inspect complete systems.mjs
// Original BINX Forge practice code. MIT; see LICENSE.txt.
export function readSave(raw) {
  const s = JSON.parse(raw);
  if (!s || s.version !== 1 || !Number.isInteger(s.coins) || s.coins < 0 || s.coins > 9999 || !['room-a','room-b'].includes(s.room)) throw Error('Invalid save');
  return {version:1, coins:s.coins, room:s.room};
}
export function transfer(from, to, id, count, capacity=10) {
  if (!Number.isInteger(count) || count < 1 || !Number.isInteger(from[id]) || from[id] < count || Object.values(to).reduce((a,b)=>a+b,0)+count > capacity) return false;
  from[id]-=count; to[id]=(to[id]||0)+count; return true;
}
export function pointerInput() {
  const owners=new Map();
  return {press:(id,action)=>owners.set(id,action),release:id=>owners.delete(id),clear:()=>owners.clear(),held:action=>[...owners.values()].includes(action)};
}
export function enemyMode(distance, hp, cooldown) {
  if (hp<=0) return 'dead';
  if (cooldown>0) return 'recover';
  if (distance<24) return 'attack';
  return distance<180?'chase':'idle';
}
export function frameSummary(samples) {
  const s=samples.filter(Number.isFinite).filter(x=>x>=0).sort((a,b)=>a-b);
  if (!s.length) throw Error('No samples');
  return {median:s[Math.floor((s.length-1)*.5)],p95:s[Math.ceil(s.length*.95)-1],count:s.length};
}
export function fixedStep(clock, elapsed, update) {
  clock.carry+=Math.max(0,Math.min(.1,elapsed));
  while(clock.carry>=1/60){update(1/60);clock.carry-=1/60;}
}
// Owned protocol specimen: version:u8, coins:u16 little-endian, room:u8.
export function decodeRecord(bytes) {
  if(bytes.length!==4)throw Error('Expected four bytes');
  const v=new DataView(bytes.buffer,bytes.byteOffset,bytes.byteLength);
  if(v.getUint8(0)!==1||v.getUint8(3)>1)throw Error('Unknown record');
  return {version:1,coins:v.getUint16(1,true),room:v.getUint8(3)};
}
export function applyInput(player, packet) {
  if(!packet||!Number.isInteger(packet.seq)||packet.seq<=player.seq||![-1,0,1].includes(packet.dx))return false;
  player.seq=packet.seq;player.x=Math.max(0,Math.min(100,player.x+packet.dx*2));return true;
}
export function jumpTrace(speed=300,gravity=900,dt=1/120) {
  let y=0,vy=-speed,t=0,peak=0;
  const rows=[{t,y,vy}];
  while(t<3){vy+=gravity*dt;y+=vy*dt;t+=dt;peak=Math.min(peak,y);rows.push({t,y,vy});if(y>=0)break;}
  return {rows,height:-peak,airtime:t};
}

Code rights: the included MIT notice permits use, modification and distribution, including commercial games and source products, with the copyright and licence notice. Added third-party files have their own terms. Read the official licence & usage terms.

Common failures and fixes

The render function looks like the game logic

Follow the mutation; drawing coordinates does not establish movement ownership.

A decompiler name seems authoritative

Generated names are clues; callers, types and experiments establish the meaning.

A long stall changes the result

This lab intentionally caps catch-up; record that policy and test it explicitly.

Make Your Game Better

Change one system after the baseline works. Keep the free reference and compare the same inputs before and after.

Licensing summary, not legal advice. Before publishing or selling, check exact terms for finished-game use, reselling files and including files in a source/template product separately.

Learn at the original sources

Sources checked 11 October 2026. The numbered plan is original Forge instruction; linked documentation does not imply every engine or device has been tested.

Take this guide to your AI

Review and copy into your assistant. Nothing is sent automatically. These prompts include the complete focus source, full-package links, checks and compatibility limits.

Review a prompt or select its text manually.

Review build prompt
Review debug prompt
Review upgrade prompt

Read the complete guide and prompts as Markdown →

Keep learning

Original reverse-engineering practice lab · Sonic Unleashed creator-project study · SpaghettiKart creator-project study

Browse every guide and recipe →