Skip to content

Plan ​

The work ahead, in order. docs/CHECKLIST.md tracks each item's state; this page says what we are building and how the parts fit.

What we are building ​

North star: play POD (AGENTS.md, "The goal"): first the original under Wine, made complete; then a playable reimplementation in Rust, native and in the browser, grown out of the viewer. Everything below serves that.

  1. An asset viewer for POD, native and in the browser (wasm). It opens the player's own copy of the game and shows every asset: textures, images, stills, text, sounds, fonts, cars, tracks. It never bundles or uploads the game's files.
  2. Reusable libraries for the game's formats, and for the hardware and quirks the game was built around, so the viewer, mod tools and later projects share one reader per format.
  3. A view for every format, including a 3D track viewer and a car viewer.

Architecture ​

A Rust workspace, as GameFrame recommends for a reimplementation and its viewer (re-browse, re-port): one reader per format, used by every app; wgpu and winit for drawing, egui for the interface; the same code built natively and for wasm32-unknown-unknown.

CrateWhat it holdsDepends on
pod-containerThe block container (keys, blocks, checksums, entry table) and name strings: read and writenothing
pod-formatsOne module per format: img, stills, text, textures, track, car, sound, font, records, lists. Each reads and writes, and names the original function it followspod-container, pixels
pixels (candidate for GameFrame's crates/)Pixel formats and conversions: RGB555, RGB565, 8-bit palettes, Windows DIBnothing
pod-hostHost services shared by the apps: finding and loading the player's files (folder natively, file picker or local dev server in the browser), audio outputpod-formats
apps/viewerThe viewer: a file list by kind, one view per kind, a hex view for everything; a command-line mode that writes views to files for agentsall of the above

Two more modules, decided on 2026-10-23, both reusable beyond POD:

CrateWhat it holds
disc-image (candidate for GameFrame's crates/)Reading CD images directly: CUE sheets, raw BIN (Mode 1 and Mode 2 sectors), ISO 9660 and Joliet, random access to a file's sectors. The viewer then opens POD2_0.CUE without an extracted folder
game-sourceWhere the files come from: a folder, a disc image, files dropped in the browser, or a URL the user gives (with a published checksum to verify), cached on disk natively and in the browser's private file system (OPFS) in chunks fetched by HTTP range requests

Fetching the game from a public archive is the user's choice (AGENTS.md, "The user decides"): the game is still under copyright, and a listing on an archive is not a licence. The module takes a URL; it does not ship one.

Hardware and quirks get their own modules when a format needs them: the 3D cards' texture formats (3dfx Glide, ATI 3D Rage, S3 ViRGE), CD audio track tables, and the sound codec inside .MEG. Anything that would help another game goes to GameFrame's crates/, with a test on GameFrame's own samples.

The Python decoders in decoders/ are the prototypes. Each is proved on every file with GameFrame's validate.py first, then ported to its Rust module with the same tests: every file of the player's copy decodes, writes back byte-identical, and the tests skip with a message when the files are not there.

Views ​

AssetsView
Texture pages (tracks, cars, chrome)Page with sub-textures outlined and named; 8-bit and 16-bit variants side by side
Menu images, stillsEach picture, its slot, palette and size
Text tablesSections and keys per language, side by side
Sounds (.MEG)List of sounds with playback through pod-host
MusicThe CD audio track list (CDAREF.TXT) and playback of the player's disc tracks
Fonts (.BP3)The glyph pages and a text sample drawn with them
Cars (.BV3/.BV4)The 3D model, textured, turned with the mouse; the car's parameters as a table
Tracks (.BL3/.BL4)Track viewer: the 3D track, textured, with a free camera and a fly-along of the racing line; the sky panorama; sector outlines; the per-difficulty entries
Best times, listsTables
EverythingHex view, with the decoded fields marked

Order ​

  1. Finish the asset formats in Python, shown in viewer/build.py: sounds, fonts, best times, lists. (Images, stills, text and texture blocks are done.)
  2. Set up the Rust workspace; port the container, strings and the finished formats; start apps/viewer with the 2D views, natively and in the browser.
  3. Decode the car model; add the car viewer.
  4. Decode the track sections (docs/formats/tracks.md); add the track viewer.
  5. Writers and round trips for every format, then a first mod (a changed texture or string) loaded in the original game.

The wrapper and Un-POD (the user's direction, 2026-10-23) ​

This is GameFrame's idea in its plainest form: a frame around the original game. The original stays at the centre, unchanged; everything else is a layer around it that can be added to, and switched off. Like Un-Banished (GameFrame's docs/case-studies/banished.md): run every version of POD well on today's machines, then rebuild it with a mod layer on top.

Layer 1: a wrapper around the original builds. The original EXEs run unchanged, inside our own runtime, with modern rendering:

BuildWhat it callsWhat the wrapper gives it
WINPOD.EXE (software, 8/16-bit)DirectDraw: a 640 × 480 frameScaling (integer, filtered), windowed or full screen, right colours
PODMMX.EXE (MMX software)DirectDraw, MMX codeAs above; the same game with its MMX routines
WPOD3DFX.EXE, PODX3DFX.EXE (3dfx)Glide 2 (glide2x.dll)A Glide implementation on a modern GPU (wgpu): any resolution, anti-aliasing, the game's own textures, later replaced ones
WPODATI.EXE, PODATIX.EXE (ATI Rage)ATI3DCIFThe same back end
WPODS3D.EXE, PODS3DX.EXE (S3 ViRGE)S3D ToolkitThe same back end

The 3D-card builds pass triangles and textures to a library, so replacing the library gives upscaled hardware rendering without touching the game (as nGlide and dgVoodoo do for Glide). Where it runs: in the emulated PC first (run/vm), Wine on hosts where it works, later our own loader. The gpu-1997 crate and docs/hardware/3d-cards.md already describe the three APIs' texture formats. Also: sound and CD music, input mapping (gamepads), the patches in run/wine/patch_winpod.py made general, and the game's memory read for tools (the race cars at 0x61aad0, the camera at 0x60bba0).

Layer 2: Un-POD, a reimplementation (the road to 1:1, subsystem by subsystem: docs/PORT.md). An exact core in Rust (race rules, physics, the opponents' AI, timing, random draws; traced and measured against the original, re-port, re-verify), with no drawing or sound, grown out of the viewer and the format readers. The recorded runs of the original (positions of all eight cars, lap times, frames) are its ground truth.

Layer 3: tools and mods on top, each an addition behind a build option (working rule 5):

  • a track editor: the 3D track viewer made editable, writing .BL3/.BL4 through the track writer, for both the original game and Un-POD;
  • a vehicle creator: the car viewer and the car parameters (docs/formats/cars.md) made editable, writing .BV3/.BV4;
  • a mod layer: replaced textures, sounds and text loaded over the player's files; rule hooks for Un-POD as sandboxed plugins (as Un-Banished does with WebAssembly).

Next targets ​

Set on 2026-10-23 with playing as the north star, after the original reached its demo race under Wine (docs/running.md) and every format branch was merged. The catalogue reads 230 of 289 files to the last byte. Each target says what it gives a player. In order:

Road 1: the original, playable now

  1. Play a race. Done (2026-10-23): the menu to the results screen in the emulated PC (run/vm), keyboard and a scripted driver (follow.py). Other modes (split screen, championship) still to try. Under Wine on the Mac the menu freezes (docs/running.md).
  2. Sound and music. Sound effects (DirectSound), CD music tracks 2 and 3 (CDAREF.TXT) from the disc image, the Indeo videos (codec from the disc's INSTALL folder).
  3. Settings and saves. Ubi.ini written by the game, best times (.BRT) and car setups (Params\<car>.prb) saved and loaded back; English text if a source for it exists.
  4. The first mods in the game. A text string, a menu image, a track texture, then a changed car (one handling value, driven) with the car parameters' writer. Each needs a writer and a byte-identical round trip first.
  5. Watch it (re-observe): a log of every file the game opens and when, recorded frames and inputs, for the port to be measured against.
  6. Wider support. The MMX build (PODMMX.EXE) under Wine; the 3dfx build through a Glide wrapper; Linux and Windows notes for run/wine.

Road 2: a playable reimplementation

  1. Writers for every format, byte-identical on every file of the disc, then the track records kept as bytes (zones, beacons, start records, positioned records): the port and mod tools need every field.
  2. Drive around a track. The viewer's 3D track with the game's camera, the car on the road, collision with the sectors, the racing line per difficulty: the first thing a player can steer in the port.
  3. The rules of a race, traced and measured: the physics step, the AI following the race paths, laps, checkpoints, timing and the random draws (re-trace, re-emulate, re-port, re-verify). The file-open path (FUN_004ae91c) and which build reads which files.
  4. Sound, menus and the rest in the port: the mixer (measured against both builds' mixers), the menu tree, the HUD, best times; then the renderer profiles of the 3D-card builds.

Along the way: send the pitfalls met here to GameFrame with tests (Watcom PE sections with a VirtualSize of 0, the unbounded EnumDisplayModes table, the 16-bit-desktop windowed mode, the Wine-on-macOS recipe). Publishing the site stays the user's call (gh workflow run site.yml).

Prose CC0 1.0, code Apache 2.0. POD: Planet of Death is © Ubi Soft; none of its files are on this site.