Kart Racer: One Saturday

Daniel · Saturday 14 feb 2026, 13:35–23:58

Efter att ha sett ett “vibe-coding” projekt på reddit, undrade jag — vad kan man åstadkomma på en dag egentligen? Om man inte tar hänsyn till tradition utan kör på?

Min grundtanke var att använda JavaScript och Vite, och göra många små projekt, som alla då kan ha var sitt UI — som tex kart-editor, kart-generering, själva spelet. Varje mapp kan vara fristående och blir lättare att hantera, och enkel data kan delas eller kopieras mellan dem till “huvud”-mappen som ändå är spelets runtime.

Efter att egentligen lyckas med allt jag ville göra lade jag till multiplayer i slutet, som till min förvåning faktiskt också fungerade ganska bra.

Resten av rapporten är AI-genererad av Claude Codes interna sparade chat-historik, men visar ganska bra vad jag gjorde.

— Daniel

A browser-based kart racing game, built from scratch in a single Saturday. Started at 13:35 with an empty folder, ended just before midnight with a playable multiplayer-ready racer featuring AI opponents, power-ups, a map editor, and a sprite generator. ~167 messages across 21 sessions, 8 project folders.

The snapshots folder contains project snapshots at five milestones through the day. They were reconstructed by replaying file writes and edits from the chat logs on top of the nearest git commit — so some config files and minor edits may be missing or slightly off, but the source code demonstrates the state of the project at each point.

13:35 — Two projects at once

It started with two parallel Claude sessions. One built the game engine — Three.js, Vite, a ground mesh with hills, and a billboard-sprite kart with keyboard controls. The other built a sprite generator tool for rendering 3D kart models into 2D sprite sheets from 16 directions.

Daniel: so we are going to be making a game for the browser, its a kart racing game. We are using a mesh for the ground, and billboard sprites for the carts

Claude: Let me set up the project and get a solid foundation going.

The game session focused on getting core movement right — gravity tuning, slope physics, shadow rendering. The vel.y bug was a highlight: gravity was being overwritten every frame because vel.copy(forward) zeroed the Y component in physics.js. Once fixed, karts actually flew off ramps with proper parabolic arcs. A debug graph was added to visualize vel.y and pos.y in real time.

Debug graph showing vel.y and pos.y during a jump

The debug graph at 14:13 — red line is vel.y (linear decrease = gravity working), blue is pos.y (parabolic arc = correct jump trajectory).

Meanwhile, kart-gen became a full tool — orthographic camera, 8-direction live preview strip, nearest-neighbor chunky textures on the wonky-kart and firetruck, and an export system that saves sprite sheets to disk via a Vite dev server plugin. The game loaded the sprites and selected the correct directional frame based on camera angle, with turning variants when steering.

kart-gen sprite generator tool

The kart-gen tool — 3D model with steering controls, export buttons, and the 8-direction preview strip at the bottom.

Wonky kart spritesheet — 16 directions

Exported spritesheet — the wonky kart rendered from all 16 directions.

Project at 15:00 — 35 files across 3 folders: game/src (9 files), kart-gen/src, map-editor/src

15:14 — Project consolidation & maps

The scattered project folders got merged under a single kart/ umbrella. A map editor was built from scratch — a dark-themed 2D canvas tool (editor.ts) with terrain painting (tools.ts), height brushes, and a file-based save/load API through a Vite plugin.

A separate session wired the game to read map files via a new map-loader.js and menu.js for level select, terrain-based speed penalties (offroad slowdown), and removing the hardcoded oval track.

Daniel: the "pixel" on the map should be bigger something like trice the size

Claude: Simple fix — add a CELL_SIZE multiplier in track.js.

Driving on the track with debug overlay
Driving over hills with debug graph

Driving the track with the debug overlay — billboard sprite kart on a heightmap terrain with offroad/road distinction.

16:00 — CTR-style power sliding

Steering got a complete overhaul in physics.js — the old indirect "steering wheel" model (input accumulates steerAngle, steerAngle drives rotation) was replaced with direct turn rate. Then the big feature: Crash Team Racing-style power slides with a timing-based boost meter.

Daniel: ok and now we are going big: we want CTR-style sliding and boosting. you know the mechanic?

Claude: Yeah — CTR power sliding: Hold drift + steer, kart hops into a slide. While sliding, a meter fills up — press a boost key when it's in the sweet spot. Chain up to 3 boosts per slide.

The implementation used Z/X keys as dual hop buttons (tap to hop, hold through landing to slide, tap the opposite key in the sweet spot to charge boosts). Camera Y-damping was added to camera.js so hops didn't jerk the view, and the kart got a visual rotation offset during slides.

Project at 16:40 — 37 files. New: gamepad-test/

16:44 — Debugging and controllers

The boost system worked in theory but was hard to trigger — turned out the keyboard had ghosting issues that prevented pressing 3 keys simultaneously. Solution: build a gamepad test tool, map a PS/Xbox-style controller, and integrate it into input.js.

Daniel: i think my keyboard dont allow me pressing 3 buttons at once.... we will need to use a controller. lets work on that.

Claude: LB = hop Z, RB = hop X, A = accelerate, B = brake, Left stick/D-pad = steer, Right stick = camera rotate.

Gamepad test tool

The gamepad test tool — built to diagnose which raw button indices mapped to what on the controller.

18:30 — Bot AI & the race system

With a detailed plan in place, the race system came together in one session — five new files added to game/src:

The finish line alone needed several iterations — it started as an infinite-width crossing detector, then got bounded to match the visual decal, then the crossing direction check turned out to be inverted. Boost pads and a reusable ground-decal.js system were added to both the editor and game.

Level select screen
Race start with bots and checkerboard line
Racing in 4th place with minimap

Level select, race start with checkerboard finish line and bot opponents, and racing in 4th with the minimap and position HUD.

Project at 19:00 — 44 files. game/src grew from 9 to 16 files

20:00 — Items and combat

The item system landed across two sessions, touching 11 files between the game and editor. Floating item boxes (with shadows, bob animation, respawn timers) give random power-ups: speed boosts, TNT bombs you drop behind you, and homing missiles with a 120° forward cone.

Daniel: ok now add missiles that you can shoot, they turn slightly against the closest kart.

Claude: The missile only homes toward karts within a 120° forward cone. If nothing is in the cone, it flies straight.

Item boxes floating on the track
Skid marks and boost pad on the road

Floating item boxes with shadows along the track, and skid marks left behind from a power slide with a green boost pad ahead.

Visual polish in the same sessions: black skid marks from power-sliding tires (4 strips per kart, sliding-window buffer geometry), boost flames, and a full shadow system overhaul — flat sprites were replaced with subdivided mesh planes that conform to terrain height, fixing the persistent z-fighting and clipping issues. Physics got separated from visuals to prepare for multiplayer.

Project at 21:30 — 52 files. game/src grew to 22 files: +item-boxes, tnt, missile, skid-marks, boost-visual, kart-visuals

21:30 — Map editor upgrades

The map editor session added a Three.js 3D preview panel (floating box in the corner, orbit controls), custom per-terrain-type color pickers, and a full per-pixel color painting layer with its own brush. The height brush got a redesign — instead of just raise/lower, it now paints toward a target height value with a slider.

Map editor with tooth map, 3D preview, and all editing modes

The map editor showing the "tooth" track — terrain types, numbered checkpoints, boost pads, item box positions, start line, and the 3D preview in the corner.

22:00 — Multiplayer & late-night push

Then the multiplayer push started. A whole server/ appeared — index.js, room.js, lobby.js — plus server-side versions of the game systems (items, TNT, missiles).

The client got a net/ folder with connection, client prediction, interpolation, and a lobby UI. The session ended just before midnight struggling with camera jitter from state reconciliation.

Daniel: ok now this is a big one: multiplayer. we are going to need a server and everything. tell me what you think would be a good approach

Claude: WebSocket server, authoritative with client prediction. The server runs the physics tick, clients send inputs and render ahead, reconcile on state updates.

In parallel, a decal system session added the ability to stamp, rotate, and scale decorative elements onto the map through the editor.

Final state — 71 files. game/src: 29 files. New: server/ (9 files), game/src/net/ (5 files), game_decals/

What got built

In about 10 hours, from empty folder to 71 files:

About this report

Auto-generated from Claude Code chat history (~/.claude). The 21 session logs are browsable in the chat sidebar. The snapshot folders were reconstructed by replaying 607 Write/Edit operations from the JSONL files onto the nearest git baseline. They are not perfect — ~5% of edits couldn't be replayed due to files created outside of tool calls (npm init, manual edits) — but the source code is representative of each milestone.