Budokai Tenkaichi 3 PC Port: BT3-Recomp Status and an Original Arena Build
See what z3xox and collaborators say BT3-Recomp does, check its experimental status and source, then build Aether Clash: an original arena-fighting rules example and a complete AI development plan.
What the creator made

The over-the-shoulder attack view and energy effects illustrate the arena-combat systems discussed here.
z3xox (owner/lead), RexxColder and valenvivaldi, with credited contributors
BT3-Recomp’s README describes a native PC port built on PS2Recomp, translating MIPS code into C++ from the user’s own supported disc image. It credits z3xox, RexxColder and valenvivaldi.
The creator reports title/menu and fight rendering, while listing arena texture, shadow, animation and skipped-video issues. These are creator-reported results; Forge has not executed the commercial game or verified its frame-rate claims.
The checked GitHub releases list is empty. Do not mistake README packaging instructions for an available published release, or treat an experimental source project as a polished supported download.
No published GitHub releases found on 11 October 2026; README build/run claims have not been independently gameplay-tested here · checked 2026-10-11.
AI involvement is not established by the checked creator README/release. This article does not attribute the project to ChatGPT, Claude or Codex.
Creator media remains at the linked original source. The gallery below clearly labels original concepts and actual independent source renders; it is not a recreation of the featured project’s screenshots.
How it works: build-time PS2 static recompilation
The stated pipeline translates the supported PS2 executable at build time and uses a compatible runtime, renderer and front end. The project links PS2Recomp and third-party notices. This is a technical preservation project; the tutorial below writes an independent combat loop instead of copying its game implementation.
- Supported executable
- Build-time translation
- Compatible runtime
- Native renderer
PS2Recomp ↗ · Status and known issues ↗ · Component notices ↗
Recompilation translates instructions; decompilation aims to recover higher-level structure; a mechanics recreation writes a new implementation. An AI tool can help with inspection or coding, but those terms alone do not establish AI use.
The checked repository LICENSE is GPL-3.0; component notices have their own scopes. Commercial game material remains separate and is not supplied by Forge.. Read the original licence ↗. Open-source tool licensing does not license the commercial game’s art, audio, characters or binaries. Forge supplies no ROMs or commercial game downloads.
Learn reverse engineering using permitted practice code → · Explore AI game mashups and creator examples →
What could your game look like?
Aether Clash · arena action fighter
Two original exosuit pilots train with short energy staffs and mechanical pulse gauntlets. Turquoise/copper and violet/cream silhouettes, an original rooftop arena and grounded combat distinguish the game.

Defeat one original sparring sentinel before sixty seconds. Approach for a light strike, spend energy on a heavy pulse or dash aside when it telegraphs a bolt.
The complete MIT reference is a 2D top-down solo combat round with movement, light and heavy attacks, energy/cooldown costs, dash, one simple chase/telegraph/projectile opponent, damage recovery, health, win/loss, timer and pause/restart. 3D lock-on, flight, combos, rigged characters, multiplayer and campaign saving are future systems.



Build your own game: thirteen visual steps
Create your own original game inspired by these gameplay ideas. This tutorial does not reproduce the featured commercial game or imply affiliation with its creators.
Choose the free engine and accepted scope
Run the independent top-down JavaScript round first; it contains the complete combat rules. Use free Godot for a fuller 3D arena with matching CharacterBody3D and animation documentation. The featured PS2 recompiler is not a reusable fighting-game engine for this tutorial.

Genuine existing Forge capture, 10 October 2026. Choose the genre; it does not show the creator’s game. Set up the complete original project
Download the ZIP and extract adventure-lab. Serve every file over HTTP, for example python -m http.server 8080, then open index.html?mode=aether. Modules require JavaScript MIME types. Run node check.mjs first. The download includes 9 complete files and an MIT notice; no private engine or commercial game files are required.
Install compatible free resources
Keep the geometric reference while testing rules. Godot, Kenney UI and covered free KayKit/Quaternius editions offer a later engine/art/animation path. Use original creator downloads; preserve exact licence files, distinguish free/Extra/Source tiers and inspect formats, units, forward axis and skeleton. Import one model or clip into a separate editor scene before adding it to gameplay. These ingredients do not supply the game’s controller, camera or objectives.
Create one player and one rules owner
Create an independent state with position, health and energy. Start/Restart replaces the run while the existing controller keeps one frame owner. Input and rendering cannot secretly award progress. In a 3D adaptation, use the selected engine body and collision API rather than translating JavaScript names into a supposed native project.
Build the environment and reachable objective
Make one uncluttered arena at player scale, with clear edges and an obvious opponent. The small reference has no elevated/flying movement. For 3D, validate collision, camera obstruction and space around attacks before adding a rooftop backdrop.
Implement movement and camera behaviour
Normal movement and the last direction feed a bounded dash. Dash spends energy and grants a short recovery window. For a 3D expansion, prove camera-relative strafing and lock-on/disengage before adding aerial movement; target loss and occlusion need explicit rules.

Actual original rules and renderer after scripted input. Concept art is separate. Add the main gameplay rule: Attack ownership, cooldowns and telegraphed combat
Light strike checks short range and a cooldown. Heavy pulse checks longer range, forty energy and its own cooldown. Failed repeated use cannot spend energy twice. Defeating the sentinel owns victory; a hit effect cannot award an unearned win.
Add enemies or hazards without duplicate damage
The reference sentinel approaches, announces a charge and launches a capped moving bolt after the telegraph expires. Player damage has recovery, and expired/out-of-bounds bolts are removed. Test the complete telegraph-to-projectile transition, overlapping hits and defeat before adding more opponents.
Connect menus and desktop/mobile controls
Use real Start, Pause/Resume and action buttons. The reference uses keyboard and multi-pointer touch controls with cancellation/release cleanup. Tab/window leave pauses; resuming is explicit. Keep readable status outside Canvas and verify actual keyboard, touch, focus and mobile layout on the published target. An attack button must not clear another still-held touch movement pointer.
Add animations and bounded visual effects
The native Canvas renderer draws original geometry from state; it does not implement the generated concept art. Add a compatible free sprite or 3D rig only in its matching runtime. Inspect exact clips and retargeting, keep root motion and controller ownership consistent, cap effects and provide a low-motion/low-effects option. No included commercial audio or soundtrack is implied.
Save only validated progression where appropriate
This first arena round does not save progression. Later unlocks need version, known pilot/challenge IDs and verified completion boundaries. Separate editable local practice records from any future authoritative online ranking; cloud saving and multiplayer require their own acceptance.
Test the complete outcome and boundaries
Run node check.mjs. Ten Adventure Lab checks cover both complete exploration and arena wins at four update rates, gates, cooldown/energy, damage, telegraphed bolts, pause and timeout. The source frames execute the actual renderer. Browser input, real phone performance, clipboard/audio and independently generated AI output need separate acceptance; simulation does not prove them.
Publish a playable build and improve one system
Upload every Adventure Lab file to static HTTPS preserving paths. Check the published module MIME types, first load, actual controls, win/loss, tab pause and two restarts. Select the correct mode in the URL or menu. Then use one upgrade prompt. The complete AI brief defines an ambitious fuller game; it does not assert those future systems have already shipped in this small reference.
Complete original code and download
Download complete MIT source ZIP · Run, test and publish instructions · MIT licence
index.html — complete source
Open this file<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Two original complete exploration and arena rules tutorials."><title>Original game Adventure Lab · BINX Forge</title><link rel="stylesheet" href="game.css"><script type="module" src="main.mjs"></script></head>
<body><main><a id="guide" href="https://binxforge.com/guides/ocarina-of-time-ship-of-harkinian-build-adventure">← Follow the BINX Forge guide</a><p class="eyebrow">ORIGINAL 2D RULES EXAMPLES · ADVENTURE LAB 1.0</p><h1 id="name">Lanternwake</h1>
<label for="lesson">Choose a small example</label><select id="lesson"><option value="lantern">Lanternwake · exploration</option><option value="aether">Aether Clash · arena</option></select>
<p id="instructions">Enable JavaScript and start a small game. Source, licence and instructions remain available.</p><div class="hud"><p>Progress: <output id="score">0</output></p><p>Time: <output id="time">90</output></p></div>
<canvas id="game" width="640" height="360" tabindex="0" aria-label="Original game example area" aria-describedby="instructions status">This visual example requires Canvas and JavaScript. Read the guide and source for text instructions.</canvas>
<p id="status" role="status">Ready. Start a new run.</p><div class="actions"><button id="start" disabled>Start a new run</button><button id="pause" disabled>Pause</button></div>
<div class="actions"><button id="action0" disabled>Toggle drift</button><button id="action1" disabled>Reset to last gate</button><button id="action2" hidden disabled>Third action</button></div>
<div class="directions" role="group" aria-label="Movement controls"><button data-direction="up" aria-label="Up / accelerate">↑</button><button data-direction="left" aria-label="Left">←</button><button data-direction="down" aria-label="Down / brake">↓</button><button data-direction="right" aria-label="Right">→</button></div>
<p class="note">Focus the canvas for arrows or W/A/S/D, or hold the direction buttons. Actions also work with keyboard-focused buttons. Leaving the tab pauses and clears input. Resume is explicit. Examples have no accounts, network play, saving, third-party art or sound. Their 2D rules are a learning milestone; native input, phone and assistive-technology acceptance remains to be checked.</p>
<p><a href="adventure-lab.zip">Download all complete files</a> · <a href="README.md">Run and test instructions</a> · <a href="LICENSE.txt">Original MIT source licence</a></p><noscript><p>Enable JavaScript to play. Read or download the complete source without an account.</p></noscript></main></body></html>
worlds.mjs — complete source
Open this file/* Original BINX Forge Adventure Lab 1.0 — MIT. Reuses public Genre Lab lifecycle and input patterns. */
export const W=640,H=360,modes=['lantern','aether'];
export const lessons={lantern:{name:'Lanternwake',guide:'ocarina-of-time-ship-of-harkinian-build-adventure',instructions:'Gather three moonseeds to open the conservatory gate, then light the eastern beacon. Move with arrows/WASD or touch. Staff Strike clears nearby beetles; Lantern Dash costs energy.',buttons:['Staff Strike','Lantern Dash','Light beacon']},aether:{name:'Aether Clash',guide:'budokai-tenkaichi-3-bt3-recomp-build-arena-fighter',instructions:'Defeat one original sparring sentinel in 60 seconds. Move, use light strike up close, heavy pulse at medium range and dash out of telegraphed attacks. This is a small top-down rules example.',buttons:['Light strike','Heavy pulse','Dash']}};
const clamp=(n,a,b)=>Math.max(a,Math.min(b,n)),distance=(a,b)=>Math.hypot(a.x-b.x,a.y-b.y);
export const walls=[{x:210,y:0,w:16,h:120},{x:210,y:240,w:16,h:120},{x:380,y:0,w:16,h:140},{x:380,y:220,w:16,h:140}];
const seedPositions=[{x:100,y:80},{x:260,y:280},{x:310,y:70}];
export function newState(mode='lantern'){if(!modes.includes(mode))throw Error('Choose a supported lesson.');return {mode,status:'ready',age:0,message:'Start a new run.',score:0,remaining:mode==='lantern'?120:60,player:{x:60,y:180},hp:mode==='lantern'?4:8,energy:100,immune:0,attack:0,heavy:0,dash:0,dir:{x:1,y:0},pulse:0,guardClock:0,telegraph:0,seeds:[],enemies:mode==='lantern'?[{x:470,y:100,hp:2},{x:510,y:280,hp:2}]:[{x:480,y:180,hp:10}],bolts:[],finish:{x:570,y:180}};}
function overlaps(p,r){return p.x+10>r.x&&p.x-10<r.x+r.w&&p.y+10>r.y&&p.y-10<r.y+r.h;}
export function hurt(s,amount=1){if(s.status!=='running'||s.immune>0)return false;s.hp=Math.max(0,s.hp-amount);s.immune=.8;if(!s.hp){s.status='lost';s.message='Run ended. Start again.';}return true;}
export function action(s,index){if(s.status!=='running')return false;
if(index===0&&s.attack===0){s.attack=.4;s.pulse=.15;for(const e of s.enemies)if(e.hp>0&&distance(e,s.player)<62)e.hp=Math.max(0,e.hp-1);s.message='Strike!';}
else if(index===1&&s.mode==='aether'&&s.heavy===0&&s.energy>=40){s.heavy=1.4;s.energy-=40;s.pulse=.3;for(const e of s.enemies)if(e.hp>0&&distance(e,s.player)<120)e.hp=Math.max(0,e.hp-2);s.message='Heavy pulse!';}
else if((index===1&&s.mode==='lantern'||index===2&&s.mode==='aether')&&s.dash===0&&s.energy>=25){s.energy-=25;s.dash=.18;s.immune=Math.max(s.immune,.18);s.message='Dash!';}
else if(index===2&&s.mode==='lantern'&&s.seeds.length===3&&distance(s.player,s.finish)<35){s.status='won';s.score=3;s.message='Conservatory restored! Start a new run.';}
else return false;
if(s.mode==='aether'&&s.enemies.every(e=>e.hp===0)){s.status='won';s.score=1;s.message='Sentinel defeated! Start a new run.';}return true;}
export function step(s,input={},dt){if(s.status!=='running'||!Number.isFinite(dt)||dt<=0||dt>.01+1e-9)return;
const telegraphBefore=s.telegraph;s.age+=dt;s.remaining=Math.max(0,s.remaining-dt);for(const key of ['immune','attack','heavy','pulse','guardClock','telegraph'])s[key]=Math.max(0,s[key]-dt);s.energy=clamp(s.energy+12*dt,0,100);
const dx=Number(!!input.right)-Number(!!input.left),dy=Number(!!input.down)-Number(!!input.up),length=Math.hypot(dx,dy)||1;if(dx||dy)s.dir={x:dx/length,y:dy/length};const speed=s.dash>0?330:150,motion=s.dash>0?s.dir:{x:dx/length,y:dy/length};s.dash=Math.max(0,s.dash-dt);
const solids=s.mode==='lantern'?[...walls,...(s.seeds.length<3?[{x:380,y:140,w:16,h:80}]:[])]:[];
for(const axis of ['x','y']){const old=s.player[axis];s.player[axis]=clamp(old+motion[axis]*speed*dt,12,axis==='x'?W-12:H-12);if(solids.some(w=>overlaps(s.player,w)))s.player[axis]=old;}
if(s.mode==='lantern'){seedPositions.forEach((p,i)=>{if(!s.seeds.includes(i)&&distance(s.player,p)<20){s.seeds.push(i);s.score=s.seeds.length;s.message=s.seeds.length===3?'Gate open. Light the eastern beacon.':'Moonseed collected.';}});}
for(const e of s.enemies){if(e.hp===0)continue;const d=distance(e,s.player),speed=s.mode==='lantern'?34:50;if(d>34&&d<(s.mode==='lantern'?150:1000)){for(const axis of ['x','y']){const old=e[axis];e[axis]=clamp(old+(s.player[axis]-old)/(d||1)*speed*dt,12,axis==='x'?W-12:H-12);if(solids.some(w=>overlaps(e,w)))e[axis]=old;}}if(d<26)hurt(s);}
if(s.mode==='aether'&&s.enemies[0].hp>0){const e=s.enemies[0];if(s.guardClock===0){s.guardClock=1.8;s.telegraph=.5;s.message='Sentinel charging — move aside.';}const launch=telegraphBefore>0&&s.telegraph===0;if(launch&&s.bolts.length<8){const d=distance(e,s.player)||1;s.bolts.push({x:e.x,y:e.y,vx:(s.player.x-e.x)/d*170,vy:(s.player.y-e.y)/d*170,life:2});}}
for(const b of s.bolts){b.x+=b.vx*dt;b.y+=b.vy*dt;b.life-=dt;if(b.life>0&&distance(b,s.player)<15){hurt(s);b.life=0;}}s.bolts=s.bolts.filter(b=>b.life>0&&b.x>=0&&b.x<=W&&b.y>=0&&b.y<=H);
if(s.remaining===0&&s.status==='running'){s.status='lost';s.message='Time is up. Start a new run.';}
}
export function advance(s,input,elapsed){if(!Number.isFinite(elapsed)||elapsed<=0)return;const time=Math.min(.1,elapsed),count=Math.ceil(time/.01);for(let i=0;i<count;i++)step(s,input,time/count);}
export const renderSeeds=s=>seedPositions.filter((_,i)=>!s.seeds.includes(i));
render.mjs — complete source
Open this file/* Original geometric art; renderer never changes simulation. MIT. */
import {W,H,walls,renderSeeds,lessons} from './worlds.mjs';
const dot=(c,x,y,r,col)=>{c.fillStyle=col;c.beginPath();c.arc(x,y,r,0,Math.PI*2);c.fill();};
export function render(c,s){c.clearRect(0,0,W,H);c.fillStyle=s.mode==='lantern'?'#173b39':'#202944';c.fillRect(0,0,W,H);
c.strokeStyle='#426465';c.lineWidth=1;for(let x=0;x<W;x+=40){c.beginPath();c.moveTo(x,0);c.lineTo(x,H);c.stroke();}for(let y=0;y<H;y+=40){c.beginPath();c.moveTo(0,y);c.lineTo(W,y);c.stroke();}
if(s.mode==='lantern'){for(const w of walls){c.fillStyle='#94785e';c.fillRect(w.x,w.y,w.w,w.h);}c.fillStyle=s.seeds.length<3?'#e0ac61':'#80d4b4';c.fillRect(380,140,16,80);for(const p of renderSeeds(s)){dot(c,p.x,p.y,10,'#e9cc79');dot(c,p.x,p.y,4,'#fff6bd');}dot(c,570,180,22,'#71ccb8');}
for(const e of s.enemies)if(e.hp>0){dot(c,e.x,e.y,s.mode==='lantern'?13:22,s.telegraph>0?'#ffe99d':'#ee977c');c.fillStyle='#172a35';c.fillRect(e.x-7,e.y-5,5,5);c.fillRect(e.x+3,e.y-5,5,5);c.fillStyle='#fff5d6';c.font='12px sans-serif';c.fillText('HP '+e.hp,e.x-17,e.y-29);}
for(const b of s.bolts)dot(c,b.x,b.y,6,'#f9d174');if(s.pulse>0){c.strokeStyle='#a4faff';c.lineWidth=3;c.beginPath();c.arc(s.player.x,s.player.y,s.pulse>.15?120:62,0,Math.PI*2);c.stroke();}
dot(c,s.player.x,s.player.y,11,s.immune>0?'#ffffff':'#8edbd0');c.fillStyle='#ffcf79';c.fillRect(s.player.x+9,s.player.y-4,7,8);
c.fillStyle='#071625dc';c.fillRect(12,12,330,56);c.fillStyle='#fff2d5';c.font='bold 17px sans-serif';c.fillText(lessons[s.mode].name,24,35);c.font='13px sans-serif';c.fillText('HP '+s.hp+' · Energy '+Math.round(s.energy)+' · '+Math.ceil(s.remaining)+'s'+(s.mode==='lantern'?' · Seeds '+s.seeds.length+'/3':''),24,55);
if(s.status!=='running'){c.fillStyle='#071625ef';c.fillRect(90,138,460,84);c.fillStyle='#fff2d5';c.textAlign='center';c.font='bold 22px sans-serif';c.fillText(s.status==='ready'?'Ready for '+lessons[s.mode].name+'?':s.status.toUpperCase(),320,175);c.font='14px sans-serif';c.fillText(s.status==='paused'?'Resume when ready':'Use the controls below',320,201);c.textAlign='left';}
}
main.mjs — complete source
Open this file/* One frame owner · reuses Pocket Engine input/lifecycle/timing patterns · MIT. */
import {newState,advance,action,modes,lessons} from './worlds.mjs';
import {render} from './render.mjs';
import {createInput} from './input.mjs';
export function createController(doc,win){
const byId=id=>doc.getElementById(id),canvas=byId('game'),ctx=canvas.getContext('2d');
const requested=new URLSearchParams(win.location.search).get('mode');let mode=modes.includes(requested)?requested:'lantern',state=newState(mode),previous=null,frameId=null,pausedFrom='running';
const input=createInput(doc,win,canvas,pause);
function sync(){
const l=lessons[mode];byId('name').textContent=l.name;byId('instructions').textContent=l.instructions;
byId('guide').href='https://binxforge.com/guides/'+l.guide;byId('lesson').value=mode;
if(byId('status').textContent!==state.message)byId('status').textContent=state.message;
byId('score').textContent=state.mode==='creatures'?state.party.length:state.score;
byId('time').textContent=state.remaining===undefined?'—':Math.ceil(state.remaining);
byId('pause').disabled=!['running','battle','upgrade','paused'].includes(state.status);byId('pause').textContent=state.status==='paused'?'Resume':'Pause';
l.buttons.forEach((label,i)=>{const b=byId('action'+i);b.textContent=label;b.hidden=!label;b.disabled=state.mode==='creatures'?state.status!=='battle':state.mode==='survivors'?state.status!=='upgrade':state.status!=='running';if(state.mode==='kart'&&i===0)b.setAttribute('aria-pressed',String(state.drift));else b.removeAttribute('aria-pressed');});
}
function pause(){input.clear();if(['running','battle','upgrade'].includes(state.status)){pausedFrom=state.status;state.status='paused';state.message='Paused. Resume when ready.';}previous=null;sync();}
function draw(){render(ctx,state);sync();}
function loop(now){frameId=null;if(!doc.hidden&&previous!==null)advance(state,input.read(),(now-previous)/1000);previous=now;draw();frameId=win.requestAnimationFrame(loop);}
function schedule(){if(frameId===null)frameId=win.requestAnimationFrame(loop);}
byId('start').addEventListener('click',()=>{input.clear();state=newState(mode);state.status='running';state.message=lessons[mode].instructions;previous=null;canvas.focus();draw();});
byId('pause').addEventListener('click',()=>{if(state.status==='paused'&&!doc.hidden){state.status=pausedFrom;state.message='Resumed.';previous=null;canvas.focus();sync();}else pause();});
byId('lesson').addEventListener('change',()=>{const value=byId('lesson').value;if(!modes.includes(value))return;input.clear();mode=value;state=newState(mode);previous=null;draw();});
for(let i=0;i<3;i++)byId('action'+i).addEventListener('click',()=>{action(state,i);canvas.focus();draw();});
win.addEventListener('pagehide',()=>{pause();if(frameId!==null)win.cancelAnimationFrame(frameId);frameId=null;});
win.addEventListener('pageshow',()=>{previous=null;schedule();});
byId('start').disabled=false;draw();schedule();return Object.freeze({getState:()=>state});
}
if(typeof document!=='undefined')createController(document,window);
input.mjs — complete source
Open this file/* Pocket Engine1.0 · adapted from BINX Forge Coin Dash1.0 · MIT. */
const directions={ArrowUp:'up',ArrowDown:'down',ArrowLeft:'left',ArrowRight:'right',w:'up',s:'down',a:'left',d:'right'};
export function createInput(doc,win,canvas,pause) {
const keys=new Set(),pointers=new Map(),listeners=[];
function listen(target,name,handler){target.addEventListener(name,handler);listeners.push(()=>target.removeEventListener(name,handler));}
const inside=element=>element===canvas||element?.matches?.('[data-direction]');
const direction=key=>directions[key.length===1?key.toLowerCase():key];
function clear(){keys.clear();pointers.clear();}
function leave(){clear();pause();}
listen(doc,'keydown',event=>{const d=direction(event.key);if(!d||!inside(doc.activeElement))return;event.preventDefault();keys.add(d);});
listen(doc,'keyup',event=>{const d=direction(event.key);if(d)keys.delete(d);});
for(const button of doc.querySelectorAll('[data-direction]')){
listen(button,'pointerdown',event=>{if(event.pointerType==='mouse'&&event.button!==0)return;button.setPointerCapture(event.pointerId);pointers.set(event.pointerId,button.dataset.direction);});
for(const name of ['pointerup','pointercancel','lostpointercapture'])listen(button,name,event=>pointers.delete(event.pointerId));
}
listen(doc,'focusout',event=>{if(inside(event.target))keys.clear();});
listen(win,'blur',leave);listen(doc,'visibilitychange',()=>{if(doc.hidden)leave();});
return Object.freeze({read:()=>Object.fromEntries([...keys,...pointers.values()].map(d=>[d,true])),clear,destroy(){clear();for(const remove of listeners)remove();}});
}
game.css — complete source
Open this file:root { color-scheme: dark; font-family: system-ui, sans-serif; background: #101c2b; color: #f3f6fa; }
* { box-sizing: border-box; }
body { margin: 0; padding: 20px; }
main { max-width: 720px; margin: auto; }
a { color: #9be2ff; }
h1 { margin: .4em 0; }
p { line-height: 1.6; }
.eyebrow { color: #8cd8e9; font-size: .75rem; letter-spacing: .1em; }
.hud, .actions { display: flex; flex-wrap: wrap; gap: 16px; }
.hud { justify-content: space-between; }
.hud p { margin: 8px 0; }
canvas { display: block; width: 100%; height: auto; border: 2px solid #53788c; border-radius: 12px; background: #14293a; }
button { min-width: 64px; min-height: 48px; padding: 10px 16px; border: 2px solid #8cd8e9; border-radius: 8px; background: #163b50; color: #fff; font: inherit; cursor: pointer; }
button:disabled { opacity: .55; cursor: default; }
:focus-visible { outline: 3px solid #ffde80; outline-offset: 3px; }
.directions { display: grid; grid-template-columns: repeat(3, 64px); gap: 8px; justify-content: center; margin-top: 20px; }
.directions button { touch-action: none; user-select: none; }
[data-direction="up"] { grid-column: 2; }
[data-direction="left"] { grid-column: 1; grid-row: 2; }
[data-direction="down"] { grid-column: 2; grid-row: 2; }
[data-direction="right"] { grid-column: 3; grid-row: 2; }
.note { color: #b8c9d6; font-size: .875rem; }
select{display:block;max-width:100%;min-height:48px;background:#163b50;color:#fff;border:2px solid #8cd8e9;font:inherit;padding:8px;border-radius:8px}.actions{margin:14px 0}[hidden]{display:none!important}
README.md — complete source
Open this file# Adventure Lab 1.0
Two original independently reproducible MIT browser examples. All nine files are complete; no paid asset or external package is needed. The DOM controller and multi-pointer input reuse existing public BINX Forge Genre Lab patterns; world rules and geometry are original.
Extract adventure-lab, serve it over HTTP (for example python -m http.server 8080), and open index.html?mode=lantern or index.html?mode=aether. .mjs needs a JavaScript MIME type. Run node check.mjs with Node 24.19.0 or compatible recent Node: ten route/boundary checks include actual wins at four simulated update rates.
Lanternwake: use arrows/WASD or touch to collect three moonseeds and open the gate, then approach the eastern beacon and press Light beacon. Staff Strike hits nearby beetles; Lantern Dash costs energy. There are two simple chase beetles, a four-health player, wall/door collision and a 120-second timer.
Aether Clash: approach the original sentinel, use Light strike within 62 units or Heavy pulse within 120, and dash to evade telegraphed bolts. Heavy pulse costs40 energy and has a1.4-second cooldown; dash costs25. Defeat the10-health sentinel before60 seconds. One projectile owner, capped bolts and invulnerability prevent repeated overlap damage.
Pause/Resume and Start a new run use one frame loop. Leaving tab/window pauses and clears held controls; multi-pointer touch maintains independent ownership. No campaign, 3D art/camera, flying, lock-on, multiplayer, sound or save system is implemented. These are proposed extensions in the guides, and concept art shows a future direction. Source/simulation/native Canvas checks are separate from real browser, touch, phone, clipboard/audio and AI-output acceptance.
Publish every file on static HTTPS preserving relative paths. Verify first load, module MIME, both modes, all outcomes, repeat action rejection, pause/tab return and two restarts on the target device. Retain the MIT notice; acquire optional assets at the credited source with exact licence files. Commercial game material and private BINX Engine code are not included.
LICENSE.txt — complete source
Open this fileMIT License
Copyright (c) 2026 BINX Forge
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
check.mjs — complete source
Open this fileimport assert from 'node:assert/strict';
import {newState,advance,action,hurt} from './worlds.mjs';
let n=0;const check=(name,fn)=>{fn();n++;console.log('PASS '+name);};
export function playLantern(rate=60){const s=newState('lantern');s.status='running';const route=[{x:100,y:180},{x:100,y:80},{x:100,y:180},{x:260,y:180},{x:260,y:280},{x:310,y:280},{x:310,y:70},{x:340,y:70},{x:340,y:180},{x:570,y:180}];let next=0;for(let i=0;i<rate*120&&s.status==='running';i++){const target=route[next];if(!target){action(s,2);break;}const dx=target.x-s.player.x,dy=target.y-s.player.y;if(Math.hypot(dx,dy)<5){next++;continue;}action(s,0);advance(s,{right:dx>3,left:dx< -3,down:dy>3,up:dy< -3},1/rate);}return s;}
export function playAether(rate=60){const s=newState('aether');s.status='running';for(let i=0;i<rate*60&&s.status==='running';i++){const e=s.enemies[0],dx=e.x-s.player.x,dy=e.y-s.player.y,d=Math.hypot(dx,dy);action(s,0);action(s,1);advance(s,{right:d>50&&dx>3,left:d>50&&dx< -3,down:d>50&&dy>3,up:d>50&&dy< -3},1/rate);}return s;}
check('real exploration route gathers three seeds, opens gate and finishes at four rates',()=>{for(const r of [15,30,60,120]){const s=playLantern(r);assert.equal(s.status,'won');assert.equal(s.seeds.length,3);assert.equal(s.score,3);assert.ok(s.hp>0);}});
check('real arena approach and both attacks defeat sentinel at four rates',()=>{for(const r of [15,30,60,120]){const s=playAether(r);assert.equal(s.status,'won');assert.equal(s.enemies[0].hp,0);assert.equal(s.score,1);assert.ok(s.hp>0);}});
check('beacon cannot bypass inventory or proximity',()=>{const s=newState();s.status='running';s.player={...s.finish};assert.equal(action(s,2),false);s.seeds=[0,1,2];s.player={x:60,y:180};assert.equal(action(s,2),false);});
check('locked gate blocks movement and gathered seeds open it',()=>{const s=newState();s.status='running';s.player={x:369,y:180};advance(s,{right:true},.1);assert.ok(s.player.x<380);s.seeds=[0,1,2];advance(s,{right:true},.1);assert.ok(s.player.x>380);});
check('same seed cannot award twice',()=>{const s=newState();s.status='running';s.player={x:100,y:80};advance(s,{},.01);advance(s,{},.01);assert.equal(s.seeds.length,1);assert.equal(s.score,1);});
check('heavy attack is energy/cooldown bounded; failed use does not spend twice',()=>{const s=newState('aether');s.status='running';assert.equal(action(s,1),true);assert.equal(s.energy,60);assert.equal(action(s,1),false);assert.equal(s.energy,60);s.heavy=0;s.energy=20;assert.equal(action(s,1),false);assert.equal(s.energy,20);});
check('hurt recovery prevents repeated overlap and eventually ends a run',()=>{const s=newState();s.status='running';assert.equal(hurt(s),true);assert.equal(hurt(s),false);assert.equal(s.hp,3);for(let i=0;i<3;i++){s.immune=0;hurt(s);}assert.equal(s.status,'lost');});
check('telegraphed enemy creates a bounded moving projectile',()=>{const s=newState('aether');s.status='running';for(let i=0;i<70;i++)advance(s,{},.01);assert.ok(s.bolts.length>0);assert.ok(s.bolts.length<=8);const old=s.bolts[0].x;advance(s,{},.01);assert.notEqual(s.bolts[0].x,old);});
check('invalid time, pause and outcomes freeze; excessive elapsed time is capped',()=>{for(const mode of ['lantern','aether']){const s=newState(mode);s.status='running';let before=JSON.stringify(s);for(const dt of [NaN,Infinity,-1,0])advance(s,{right:true},dt);assert.equal(JSON.stringify(s),before);advance(s,{right:true},99);assert.ok(s.age<=.100001);for(const status of ['paused','won','lost']){s.status=status;before=JSON.stringify(s);advance(s,{right:true},.1);action(s,0);assert.equal(JSON.stringify(s),before);}}});
check('timeout is loss and fresh runs own independent state',()=>{const s=newState();s.status='running';s.remaining=.001;advance(s,{},.01);assert.equal(s.status,'lost');const a=newState(),b=newState();a.seeds.push(0);a.player.x=999;assert.equal(b.seeds.length,0);assert.equal(b.player.x,60);});
if(import.meta.url===new URL(process.argv[1],'file://').href)console.log(n+' adventure rule checks passed; browser/phone acceptance is separate.');
Free vs paid resources
| Free first | What it contributes | Licence / compatibility |
|---|---|---|
| Godot Godot Engine contributors | Free, open-source game editor for 2D and 3D projects, with scene, animation and interface tools. | MIT · Creator source ↗ Import one compatible file; art is separate from rules. |
| UI Pack Kenney | Interface artwork for buttons, panels and sliders. | CC0-1.0 · Creator source ↗ Import one compatible file; art is separate from rules. |
| KayKit Adventurers Kay Lousberg | Stylised fantasy characters with weapons and basic movement animation. | CC0-1.0 · Creator source ↗ Import one compatible file; art is separate from rules. |
| Universal Animation Library Quaternius | Humanoid animation library with a free subset and expanded paid editions. | CC0-1.0 · Creator source ↗ Import one compatible file; art is separate from rules. |
Free source code, artwork, engine licences and commercial game files are separate. Check permissions to sell a finished game, resell files and include them in source/template products. An AI opinion is not licence clearance.
COPY TO MAKE GAME
Paste the complete development brief into your AI. It includes the working source, verified resource facts, milestones and target tests. Review it and adapt the identity to your own idea.
Select and copy the text manually if clipboard access is unavailable.
Review the complete game-making prompt
MAKE YOUR GAME EVEN BETTER
Beginner: Clearer attacks and animation
UI Pack · Universal Animation Library
Review or select the upgrade text.
Intermediate: A second rival with fair counterplay
Godot · KayKit Adventurers · UI Pack
Review or select the upgrade text.
Advanced: A tested 3D arena and replay system
Godot · Universal Animation Library · KayKit Adventurers
Review or select the upgrade text.
Questions before you start
Is this an AI Dragon Ball Z: Budokai Tenkaichi 3 remake or a commercial game download?
No. The original project is a separately credited PC port. Our example and AI prompt create Aether Clash, an independent game with its own identity.
Can ChatGPT, Claude or Codex build the full game?
Use an AI tool that can edit and run your chosen project, work through the milestones and review its output. A copied prompt alone is not a tested finished game. Follow the source and licence checks even when the AI sounds confident.
Why free code before paid assets?
A working controller, outcome and restart reveal what the game actually needs. Buy an optional resource only when its files, compatibility and rights solve that need.
More games to build
Sources and creator credit
- Original creator repository ↗
- Checked release or releases status ↗
- Original source/licence status ↗
- PS2Recomp ↗
- Status and known issues ↗
- Component notices ↗
- Godot licence ↗
- Godot CharacterBody3D ↗
- Godot third-person camera obstruction ↗
- KayKit Adventurers ↗
- Universal Animation Library ↗
Project facts checked 2026-10-11. Resource editions carry their own checked dates. No measured search volume, ranking promise or independent AI-output acceptance is claimed. z3xox (owner/lead), RexxColder and valenvivaldi, with credited contributors owns the featured project; no endorsement is implied. Corrections and review policy ↗