pure-TypeScript game framework SDK — npm jgengine / @jgengine/* · site jgengine.com. The whole product surface for people is one sentence said to a coding agent: Make a game that … with jgengine. Agent skills ship inside every package tarball (node_modules/@jgengine/<pkg>/skills/).
Not related to automotive “JG Engines” / “JG Engine Dynamics”. This is software — a pure-TypeScript framework (entity stores, commands, catalogs, multiplayer seams, R3F shell), not an ECS and not a general-purpose 3D engine.
@jgengine/core has no React, no renderer, and no backend dependency — adapters connect it to React, Convex, WebSockets, Node hosting, and Postgres (socket.io, WebRTC P2P, and LAN share the same protocol). Domains are opt-in at runtime via defineGame({ features }); the monorepo ships a wide primitive set. Coding agents build whole games on it from that one sentence: skills provide design playbooks, intake, focused API guidance, and verification, and route selectively so agents do not load every domain by default.
Every game interaction should compose shared JGengine capabilities. Adopt an existing API first; when reusable behavior is missing or broken, improve its upstream package with a real game adopter and remove the superseded local implementation. Games own their rules, stories, items, assets, authored worlds and presentation. The engine owns the common machinery that makes those choices work. Shared behavior must preserve different art directions and gameplay, not impose a common game or asset kit.
A compatible framework fix reaches consumers as a package upgrade, not an implementation
in every game; breaking API changes still need explicit migrations. A
merge to beta alone changes nothing installed: bun run release cuts the changelog
and bumps the lockstep versions, that commit fast-forwards main, and publish.yml
publishes the versions npm does not already have — next for a prerelease, latest
for a release — after bun run check-release-set proves the publish order matches the
manifests. The games repository centralizes SDK versions in one root workspace
catalog. The development and
adoption rules live in AGENTS.md.
Versions: the lockstep game SDK set is @jgengine/{core,rapier,react,ws,node,sql,convex,shell,assets,editor,navbake} - bump together. Package manifests own the current versions. Separate cadences: CLI package jgengine and @jgengine/github (may lag; not part of that lockstep set).
| Package | What it is |
|---|---|
@jgengine/core |
Framework core: GameContext, entity/object stores, commands, combat, inventory, multiplayer contracts, world features. Zero dependencies. Import by deep path. |
@jgengine/rapier |
Rapier physics adapter for PhysicsBackend, providing native capsules, shapecasts, rotation, CCD, and joints. |
@jgengine/react |
React UI layer: GameProvider, hooks, headless primitives. |
@jgengine/ws |
Browser-safe game backend over a pluggable transport pipe (WebSocket/socket.io/WebRTC/loopback): protocol codec, createWsBackend, createHttpReads, a browser-safe authoritative host + router, and WebRTC P2P sessions. |
@jgengine/node |
Node bindings over @jgengine/ws's host: WebSocket server, socket.io server attach, memory/file persistence, save-cadence flush. |
@jgengine/sql |
HostPersistence on Postgres through a structural pool interface (no hard pg dependency). |
@jgengine/navbake |
Deterministic indexed-geometry navigation-mesh baking. |
@jgengine/convex |
Convex adapters: game transport, presence transport. |
@jgengine/shell |
Game player shell: R3F canvas, orbit camera, input tracking, HUD mounting, GameUiPreview, demo game. You supply a GameRegistry. |
@jgengine/assets |
Self-generating, license-verified index of CC0 3D models: ships the typed index + pull CLI, not the GLB bytes. |
@jgengine/editor |
Scene/world/asset editor, loaded lazily by the runner; runs standalone on any folder via npx jgengine editor or the desktop app (StandaloneEditor); agent bridge via jgengine editor-mcp. |
@jgengine/github |
GitHub data source: contribution calendar fetch for games that render real profile data. Zero dependencies. Own version line. |
jgengine |
Agent-side CLI (npx jgengine) — create, skills, doctor, desktop. Own version line. People tell an agent Make a game that … with jgengine. |
bun add @jgengine/core
# plus the adapters you need:
bun add @jgengine/react @jgengine/shell @jgengine/ws
bun add @jgengine/node @jgengine/sql # server host
bun add @jgengine/convex # Convex backendModules are imported by path, e.g.:
import { createGameContext } from "@jgengine/core/runtime/gameContext";
import { createWsBackend } from "@jgengine/ws/createWsBackend";One interface. Open any coding agent and say:
Make a game that ... with jgengine
Examples: Make a game that is Mario Party with goo characters, with jgengine · Make a game that is a first-person voxel miner, with jgengine.
That is the whole product surface for humans. No install checklist, no “run skills first,” no required CLI.
Under the hood the agent uses npx jgengine (create, skills, doctor) and the skills in .claude/skills/ — an intake router, game/level design playbooks, and focused API domains, staged into published tarballs at skills/ so they travel with node_modules. Power users may call the CLI themselves; that is optional, not the entry.
The game the agent builds is its own project in its own repo/directory, on the published npm packages. Agents must never clone this monorepo to build a game, and must never copy code, assets, or content from the probe games in Noisemaker111/JGengine-games — those are private probe games (some recreate well-known commercial titles for engine-gap probing), not templates, and their content is not licensed for reuse. npx jgengine create is the only starting point.
Website — jgengine.com
apps/web is a TanStack Start app: landing for humans (the prompt) and skill/API pages for agents. Skill pages are rendered from .claude/skills/jgengine-*, with no separate content to maintain.
It deploys to Cloudflare Workers through the official Cloudflare Vite plugin. Because the site is built from .claude/skills/ and packages/, shipping an engine or skill change redeploys the site with it — the deploy of the engine is the deploy of the website. Setup in apps/web/README.md.
The probe games in Noisemaker111/JGengine-games are also playable on jgengine.com at /games/<id> — the page embeds the apps/dev runner, which the site bundles as a static build. The website clones the games repo at build time into an ephemeral ./Games at the commit pinned in scripts/games-ref.txt (see scripts/ensure-games.ts / bun run games:clone; bun run games:bump moves the pin); the clone is gitignored and never committed. Root bun dev serves that same runner build locally (content-hash cached, rebuilt when game or engine sources change), so the games are playable at /games/<id>. To play one standalone, run bun run --cwd Games/<id> dev after cloning, or the dev harness inside any external game scaffolded per jgengine's dev harness.
core imports nothing. ws and sql import only core. react adds React, convex adds Convex + React, node adds Node builtins + ws, shell adds React + three.js (the only package that renders). editor sits on top of shell/react/core; assets and github are standalone data packages games opt into.
bun install
bun run check-types # @jgengine/* resolves to package source; no build needed
bun run test
bun scripts/test-shard.ts a # one CI test shard locally (a-i); --check counts files, --print lists them
bun scripts/type-shard.ts # what the CI `types` job runs: check-types two stages at a time, then the tsc fan-out alone
bun run gate # the whole local verdict in one run: build, then check-types and every test
bun run build # tsgo + import-extension rewrite, per package; only for pack/publish and the Node CLI
bun run gen # regenerate every committed derived artifact, in dependency order
bun run verify:fast # seconds: the branch diff vs origin/beta mapped to the packages, tests and quick gates it reaches
bun run lane:close # verify:fast, land, one ci:status read, then refuse a lane that slept or watched
bun run games:clone # once: clone Noisemaker111/JGengine-games into ephemeral ./Games at the pinned commit
bun run games:update # move an existing clone to the pin; games:bump pins the latest stable
bun run games:check # type-check + test every game in ./Games against THIS checkout's sources (no build, no copying dist)
# games:check <id> for one game; --published re-runs against the games' installed @jgengine/*
bun dev # jgengine.com locally, games playable at /games/<id> when Games/ is present
bun run perf <game> # frame times, draws, triangles, node/GL counts and top self-time functions as JSON (--help; --state pins the scene, --param k=v pins a spawn/seed, --set key=value prices a setting)
bun run debug <game> # the same JSON for a game already open in a browser, ~0.3 s, fails on a budget breach
bun run perf:gate # CI gate: plays all 8 reference games and fails on draws/triangles/nodes over Games/<id>/perf-budget.json (scripts/perf-budget.json when a game has none), or any program/framebuffer created after warmup (--help)
bun run bench:cpu # the CPU timing gate: re-runs the benchmarks that carry wall-clock budgets (nav crowd, perception, utility, visibility, off-screen, flock, paths) and fails when one exceeds it
# a cloned game standalone:
bun --cwd=Games/harbor-heat run devWindows: if bun is not recognized after installing, its install directory is missing from PATH — add %USERPROFILE%\.bun\bin (PowerShell: [Environment]::SetEnvironmentVariable("Path", "$env:Path;$env:USERPROFILE\.bun\bin", "User")) and reopen the terminal.
bun run host:fixture builds and serves the anonymous Relay Courtyard authority fixture from a clean owned checkout: compiled frontend on 4624, realm on 4625, driven by normal shell commands and keyboard input. Build artifacts, logs and saves live under the repository home's .scratch/authority-fixture/; --allow-dirty labels development builds explicitly. Each /__version reports the revision embedded in its compiled artifact. services.json registers both components for fresh-services.mjs; reload executes the landed launcher and requires the recorded source checkout at that exact revision. This fixture does not publish packages or serve game accounts.
Public export surface. Every @jgengine/* package ships a broad "./*" wildcard export, so every built dist file is an importable subpath. scripts/export-manifest.json is the reviewed record of that surface — the exact set of subpaths a consumer can import, computed from the source files each package's tsconfig.build.json emits and regenerated by bun run gen, so rerun and commit after adding, removing or renaming public source. scripts/exportManifest.test.ts fails when the real subpaths drift from the manifest, so an accidental new public path (or a test fixture leaking out) is caught in review; bun run ship:preflight fails with the fix when any generated artifact is stale. scripts/tarballInstall.test.ts packs each package (npm pack) and imports it from a clean consumer dir with no workspace aliases — proving the published tarball resolves and that build-excluded internals (testFixtures, *.test, testkit) are never importable; it requires bun run build first (it reads dist).
JGengine's procedural buildings, water, rain, and snow renderers were shaped from achrefelouafi's MIT-licensed Three.js reference projects. See CREDITS.md for the full mapping — and go star his work.
Apache-2.0, with a NOTICE attribution file. Full FAQ: LICENSING.md.
In short. Apache-2.0 permits commercial and closed-source use — ship a paid game on the engine, no dual-license conversation needed. The one condition: keep the NOTICE. Apache §4(d) requires derivative works to retain it, and it credits jgengine.com. This replaces the project's prior AGPL-3.0 copyleft. Third-party and ported code and assets keep their own licenses — see CREDITS.md.
