SOURCE / PINNED RELEASE
Made of little things.
Napplet Machines V8
- Release
- b3f614e739f0…
- Author-recorded commit
- 534f19acb4ba…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-b5572362d4a
Archive hash verified: 0f7feb97e2c3d336…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1,viewport-fit=cover"
/>
<meta name="theme-color" content="#182447" />
<title>Pocket Circuit</title>
</head>
<body>
<main id="app">
<div class="too-small">
Needs at least 280 × 240. Enlarge this pane to drive or edit your track.
</div>
<div class="app-body">
<nav class="toolbar" aria-label="Game views">
<div class="tabs">
<button data-view="garage" class="active">
<svg class="nav-icon" viewBox="0 0 24 24" aria-hidden="true">
<path
d="m4 13 2-7h12l2 7v6H4Z M5 13h14 M7 16h2 M15 16h2 M7 19v2 M17 19v2"
/></svg
><span>Garage</span></button
><button data-view="rooms">
<svg class="nav-icon" viewBox="0 0 24 24" aria-hidden="true">
<path d="M4 8h12l-3-3 M20 16H8l3 3" />
<circle cx="5" cy="16" r="2" />
<circle cx="19" cy="8" r="2" /></svg
><span>Rooms</span></button
><button data-view="editor">
<svg class="nav-icon" viewBox="0 0 24 24" aria-hidden="true">
<path d="m5 19 2-6L17 3l4 4L11 17Z M14 6l4 4 M4 20h8" /></svg
><span>Workshop</span>
</button>
</div>
<div class="race-actions" id="raceActions" hidden>
<button id="pauseButton" title="Pause / resume · Menu button">
Pause
</button>
<button id="reconnectRace" aria-label="Reconnect" hidden>
Retry
</button>
<button
id="recoverButton"
aria-label="Recover car"
title="Recover car · R / Y / △"
>
Recover ↺
</button>
<button id="exitRace" aria-label="Exit race">Exit</button>
</div>
<div class="toolbar-right">
<span
id="controllerState"
title="Press the bottom face button to use a controller"
>PRESS A / ✕</span
>
<span id="modeTag">LOCAL / 6 CARS</span
><button
id="soundButton"
aria-label="Enable sound"
title="Toggle engine sound"
>
♪ Off
</button>
</div>
</nav>
<div class="workspace">
<aside id="panel">
<section id="garagePanel" class="panel-content">
<div class="section-line">
<span>YOUR RIDE</span><span class="muted">01 — 04</span>
</div>
<div id="carPicker" class="car-picker"></div>
<div id="carDetail"></div>
<div class="section-line">
<span>CIRCUIT</span><span class="dot">●</span>
</div>
<label class="sr-only" for="trackSelect">Circuit</label
><select id="trackSelect"></select>
<div class="track-facts">
<span id="trackLength"></span><span>3 LAPS</span
><span id="wallFact"></span>
</div>
<label class="field horizontal"
>Grid size<select id="gridSize">
<option value="6">6 cars</option>
<option value="4">4 cars</option>
<option value="2">2 cars</option>
</select></label
>
<button id="raceButton" class="primary big">
Race with AI <span>↗</span>
</button>
<p class="hint">Trade paint. Catch air. Stay on the road.</p>
<div class="control-guide">
<div><kbd>W A S D</kbd><span>or arrow keys to drive</span></div>
<div>
<kbd>SPACE</kbd><span>handbrake · release to grip</span>
</div>
<div><kbd>S / ↓</kbd><span>brake / reverse</span></div>
<div><kbd>R</kbd><span>recover your car</span></div>
<div>
<kbd>RT / LT</kbd><span>gas / brake · stick to steer</span>
</div>
<div><kbd>B / ○</kbd><span>drift · Menu to pause</span></div>
<div>
<kbd>LB / RB</kbd><span>choose car · D-pad ↑↓ track</span>
</div>
</div>
</section>
<section id="roomsPanel" class="panel-content" hidden>
<div class="section-line">
<span>MULTIPLAYER</span
><span id="networkBadge">ONLINE ROOMS</span>
</div>
<label class="field"
>Driver name<input
id="playerName"
maxlength="18"
value="Racer"
autocomplete="off"
/></label>
<div id="browseRooms">
<label class="field"
>Room name<input
id="roomName"
maxlength="36"
value="Tiny cars, big trouble" /></label
><label class="field horizontal"
>Player limit<select id="roomCapacity">
<option value="6">6 players</option>
<option value="4">4 players</option>
</select></label
><button id="hostButton" class="primary">
Host game <span>+</span>
</button>
<div class="section-line">
<span>OPEN ROOMS</span
><button id="refreshRooms" class="text-button">
Refresh ↻
</button>
</div>
<div id="roomList" class="room-list">
<p class="hint">Refresh to find a race.</p>
</div>
<label class="field"
>Or join by room code<input
id="roomCode"
placeholder="Paste room code"
maxlength="160" /></label
><button id="joinCode">Join room</button>
</div>
<div id="activeRoom" hidden>
<div id="roomTitle" class="room-title"></div>
<input
id="activeCode"
readonly
aria-label="Room code"
data-napplet-select="all"
/>
<p id="connectionState" class="hint">Connecting…</p>
<div id="members"></div>
<button id="readyButton">Ready up</button
><button id="startRoom" class="primary">Start race</button
><button id="leaveRoom" class="subtle">Leave room</button>
<p class="hint">
Empty seats become AI. Choose your car in the garage before
joining. The host’s circuit is used for everyone.
</p>
</div>
</section>
<section id="editorPanel" class="panel-content" hidden>
<div class="section-line">
<span>TRACK WORKSHOP</span><span class="dot">● LIVE 3D</span>
</div>
<label class="field"
>Track name<input id="trackName" maxlength="48"
/></label>
<div class="segmented">
<button id="moveTool" class="active">↖ Edit points</button
><button id="drawTool">✎ Draw loop</button>
</div>
<div class="segmented">
<button id="addPoint" aria-pressed="false">+ Add point</button
><button id="wallTool" aria-pressed="false">▰ Sections</button>
</div>
<p id="editorHint" class="hint">
Drag a point in the plan. The curve closes automatically.
</p>
<p id="curveNotice" class="hint" hidden></p>
<div class="section-line">
<span id="pointLabel">POINT 01</span
><span id="pointCount"></span>
</div>
<label class="field"
>Elevation <output id="heightValue"></output
><input
id="heightInput"
type="range"
min="2"
max="24"
step=".5"
/></label>
<label class="field"
>Point width <output id="widthValue"></output
><input id="widthInput" type="range" min="5" max="20.8" step=".05"
/></label>
<button id="removePoint">− Remove point</button>
<div class="section-line">
<span id="sectionLabel">SECTION 1 → 2</span>
</div>
<label class="check"
><input id="segmentWall" type="checkbox" /> Walls on this
section</label
>
<label class="field"
>Wall thickness <output id="wallThicknessValue"></output
><input
id="wallThicknessInput"
type="range"
min=".3"
max="2"
step=".1"
/></label>
<div class="button-row">
<button id="allWalls">All walls</button
><button id="noWalls">No walls</button>
</div>
<div class="section-line">
<span>DRAFT</span><span id="saveState">UNSAVED</span>
</div>
<div class="button-row">
<button id="saveTrack">Save track</button
><button id="loadTrack">Load saved</button>
</div>
<button id="testTrack" class="primary">
Test drive <span>↗</span>
</button>
<p class="hint">
Z is height. Higher crests launch cars; open edges let them
fall. Up to 32 points in a 260 × 260 m area.
</p>
</section>
</aside>
<div class="stage" id="stage">
<div class="scene-top" id="sceneInfo">
<div>
<span class="scene-kicker">NEXT UP / 3 LAP DASH</span>
<h2 id="sceneTitle">Pinefall Circuit</h2>
<span id="sceneSubtitle"
>Ridgelines, switchbacks & a little bad luck.</span
>
</div>
<div class="scene-badge">03<span>LAPS</span></div>
</div>
<div class="views">
<div id="planWrap" hidden>
<div class="plan-tools">
<button id="fitPlan">Fit track</button
><button id="fullPlan">Full area</button>
</div>
<canvas id="plan" aria-label="Track plan editor"></canvas
><span class="canvas-label" id="planMode"
>PLAN / DRAG POINTS</span
>
</div>
<div class="render-wrap">
<canvas
id="scene"
tabindex="0"
aria-label="3D racing circuit"
></canvas>
<div id="viewTools">
<button id="orbitLeft" aria-label="Rotate view left">↶</button
><button id="orbitRight" aria-label="Rotate view right">
↷</button
><button id="zoomIn" aria-label="Zoom in">+</button
><button id="zoomOut" aria-label="Zoom out">−</button
><button id="cameraButton">Follow</button>
</div>
</div>
</div>
<div id="raceHud" hidden>
<div class="hud-primary">
<strong id="position">1<span>/6</span></strong>
<div>
<span id="lap">LAP 1 / 3</span><b id="raceTime">00:00.0</b>
</div>
</div>
<ol id="raceOrder"></ol>
<div class="speed">
<em id="driftState" hidden>DRIFT</em><b id="speed">0</b
><span>KM/H</span>
</div>
</div>
<div id="countdown" hidden aria-live="polite"></div>
<div id="touchControls" hidden>
<div
id="steeringPad"
role="slider"
tabindex="0"
aria-label="Analog steering"
aria-valuemin="-100"
aria-valuemax="100"
aria-valuenow="0"
aria-valuetext="Centred"
>
<span class="control-caption">STEER</span>
<span class="steering-rail" aria-hidden="true"><i></i></span>
<span class="steering-thumb" aria-hidden="true">↔</span>
</div>
<div
id="pedalPad"
role="group"
aria-label="Slide between gas, brake and drift"
>
<button
data-drive="go"
aria-label="Accelerate"
aria-pressed="false"
>
<b>▲</b> GAS
</button>
<button
data-drive="stop"
aria-label="Brake and reverse"
aria-pressed="false"
>
BRAKE
</button>
<button
data-drive="drift"
aria-label="Accelerate and drift"
aria-pressed="false"
>
≋ DRIFT
</button>
</div>
</div>
<div class="scene-bottom" id="sceneBottom">
<span><i></i> BUMP · JUMP · REPEAT</span
><span>Drag the view to orbit ↔</span>
</div>
<div id="results" hidden>
<div class="result-sheet">
<span class="section-line">CHEQUERED FLAG</span>
<h2 id="resultTitle">Race finished</h2>
<ol id="resultOrder"></ol>
<button id="againButton" class="primary">
Back to garage ↗
</button>
</div>
</div>
</div>
</div>
<output id="status" aria-live="polite">Ready to roll.</output>
</div>
</main>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
