A mod loader for PolyTrack, the online 3D racing game. Write a mod, paste it into the portal, and play the game with it running.
Mods are written against a stable API and declarative mixins rather than against the minified game bundle. A mod refers to Car and Car.controlCar, not to whatever one-letter name the minifier picked this week. Those stable names are resolved through a per-build mappings file that is pinned to a bundle hash, so when PolyTrack updates one of two things happens: the mappings still match and mods keep working, or they do not match and every affected surface degrades to vanilla. There is no third case where a mod quietly patches the wrong function. That failure mode is the whole design.
Status: live. The portal at tspml.vercel.app plays a transformed, modded PolyTrack end to end; docs at tspml-docs.vercel.app.
- All 7 Tier-1 events fire inside the running game (
car.control,car.created,race.started,checkpoint.passed,checkpoint.respawn,race.finished,track.afterLoad).- Keybinds, tracks, and audio registries (keybinds survive game-frame reloads).
- Real mod loading: paste a mod or import it by URL, right in the portal — including pasted mixins.
- Mod-declared mixins: Tier-2 patches (
before/after/around/replace/modifyArg/modifyReturn/modifyConstant) targeting stable names resolved fail-closed via@tspml/mappings, with__TSPML_PARAMn__param-ordinal placeholders so injects survive re-minification.- Reload button re-fetches URL-imported mods; share links carry mod URLs (never code) behind a confirm-first prompt.
- Warn-only safety classifier (
classifySafety);create-tspml-modscaffold CLI;@tspml/apitypes package.500+ unit tests + 5 CI smokes, all green. Headlessly verified against the real game via Playwright. See
docs/project/progress.md.
git clone https://github.com/roowus/TSPML.git
node TSPML/tooling/create-tspml-mod/bin/create-tspml-mod.mjs my-cool-mod
cd my-cool-mod
pnpm install && pnpm buildThis scaffolds a working starter mod (mod.json + entrypoint + mixin) that builds
with nothing but typescript — the generated project has no dependency on this
repo or on any unpublished package. See tooling/create-tspml-mod/.
Not
npx create-tspml-modyet. The CLI is not published to npm, so that command 404s — the clone above is the working equivalent (#19). The one-liner lands when the package ships.
MODS ──▶ stable API (events + keybinds) / mixin escape hatch
│ target STABLE names only (resolved via @tspml/mappings, fail-closed)
Loader core (@tspml/loader) + dependency resolution + safety classification
│ resolves stable → concrete locators via:
API bridge (@tspml/api-bridge: EventBus + Keybinds) + MAPPINGS FILE (per build)
│ AST transform (@tspml/transform: before/after/around/replace/...)
PolyTrack (fetched live through the portal proxy, never redistributed)
Three layers:
- Loader core (clean TS) — discovers mod packages, parses
mod.json, semver-resolves, topo-sorts, invokes entrypoints with per-mod error isolation. Includes the warn-only safety classifier. - Mappings file — versioned JSON, one per PolyTrack build, mapping stable names (
Car,Car.controlCar) → concreteTargetSpec(anchor + selector). Fail-closed on bundle-hash mismatch. - API bridge (loader-owned) — the runtime
EventBus+Keybindsregistry, exposed to mods asapi.events+api.keybinds.
See docs/design/architecture.md.
- Delivery: a Vercel-hosted portal website that plays the modded game via a CORS proxy + service worker; browser extension as the resilient fallback (for online features blocked by
vps.kodub.com's bot protection). - Fairness: warn-only (
classifySafetyclassifies + surfaces risks; never hard-blocks). - Language: TypeScript + a publishable
@tspml/apitypes package. - Importing mods from other loaders: a narrow importer covering skins, audio, and blocks. Mixins are not emulated.
See docs/project/decision-log.md (ADR-001 through ADR-013).
docs/ research, design, API specs, project, contributing (docs-first)
source/ loader, api-bridge, transform, mappings, portal, shared,
extension (gate-clear slice only — bundle rewriting not implemented)
tooling/ mappings-pipeline, create-tspml-mod, typecheck,
cli (reserved name, NOT implemented)
environments/ dev-harness (Vite dev server + smokes), demo-mods (@tspml/demo-hud, …)
packages/ @tspml/api (publishable types)
tests/ scripts/ empty on purpose — see their READMEs (#30)
➡️ Start at docs/README.md.
- Not affiliated with, endorsed by, or associated with Kodub or PolyTrack. PolyTrack is © its developer.
- TSPML is a fan-made modding tool. It fetches the user's own live game copy and ships only loader + mappings metadata — it never redistributes the game. Running a modified client and forwarding origin headers are Terms-of-Service gray areas; TSPML keeps a takedown-compliance posture. See
docs/design/safety-and-fairness.md. - Anti-cheat is server-side and still maturing. Physics/speed mods can break deterministic-replay leaderboards; using them risks leaderboard bans. TSPML labels these mods but (by design) does not hard-block uploads.
MIT (our code). The PolyTrack game and its assets are not ours and are not covered by this license.