Capabilities

Every system, shown as the code you'd actually write.

JGengine is a stack of deep primitives behind narrow surfaces — worlds, entities, combat, netcode, authored scenes, HUDs, assets. Each one is a few lines of intent, not a subsystem you build. Here they are, for real.

Live specimens

Alive, not annotated.

Each demo below is the actual zero-dependency @jgengine/core function running in this tab, feeding three.js — exactly how @jgengine/shell consumes core in a real game. The code beside each one isn't a description of the canvas; it's what the canvas runs. Drive the dials.

windField().atPoint(x, z, t) — sampled on a 12×8 grid, bilinear per blade

meadow look: kudos to achrefelouafi's GrassSystemThreeJS — go star it

world/wind · world/scatter

Wind that moves the grass

The blades are placed by the real scatter() and lean, every frame, toward the real windField sample. The gust fronts rippling across the meadow are the field's own turbulence — no shader fakery, no baked animation.

meadow.wind.ts
import { windField } from "@jgengine/core/world/wind";
import { scatter } from "@jgengine/core/world/scatter";
const blades = scatter({ area: { w: 60, d: 40 }, count: 2600, seed: "meadow" });
const wind = windField({ speed: 2.6, gust: 1.6, turbulence: 0.6 });
// per frame, lean each blade by the real field vector at its point
const [wx, wz] = wind.atPoint(blade.x, blade.z, elapsed);
// ↑ the meadow beside this code runs exactly this call, per blade

drag either pole — catenaryCurve() re-solves from the live anchors

poles + festoon look: kudos to achrefelouafi's PoleGeneratorThreeJS — go star it

world/catenary

A cable that actually hangs

Drag either pole. The festoon cord between the tips is the true hyperbolic cosh curve a uniform cable takes under gravity — not a bezier approximation — re-solved from the live anchor positions the moment you move one.

festoon.cable.ts
import { catenaryCurve } from "@jgengine/core/world/catenary";
// true cosh catenary between the two live pole tips
const points = catenaryCurve(
[poleA.x, 6, poleA.z],
[poleB.x, 6, poleB.z],
slack, // extra length as a fraction: 0.1 = 10% longer than taut
56,
);
// drag a pole in the demo → the cable re-solves from these anchors
ridged
reseed

fractalNoise(x, z, cfg) — displacing all 91×91 vertices in place

world/terrain

Terrain from a single seed

Every vertex height is one call into the core value-noise fractal. Turn octaves, frequency, and ridged, or reseed, and the whole field is rebuilt in place from the same function a shipped game bakes into its heightfield.

terrain.noise.ts
import { fractalNoise } from "@jgengine/core/world/terrain";
const cfg = { seed, frequency, octaves, lacunarity: 2, persistence: 0.5, ridged };
// displace every plane vertex by real fractal value noise
for (const v of vertices) {
v.y = fractalNoise(v.x, v.z, cfg);
}
// the terrain in the demo is this loop, over 91×91 vertices

🎮Runtime

Define a whole game as data

One call wires the runtime: assets, world, physics, input, save, and the lifecycle loop. No engine boilerplate, no scene graph to hand-assemble.

game.config.ts
import { createAssetCatalog } from "@jgengine/core/scene/assetCatalog";
import { defineGame } from "@jgengine/shell/defineGame";
import { world, physics } from "./world";
export const game = defineGame({
name: "Meadow Run",
assets: createAssetCatalog(),
world,
physics,
save: "none",
loop: { onInit, onNewPlayer, onTick },
});

⛰️World & procedural

A world is a place: substrate + laws

Declare the place you play in — flat, round, voxel, or board ground with its own physics. Sky look, foliage, and props are authored in the editor's scene document, not coded onto the world.

world.ts
import { world } from "@jgengine/core/world/place";
export const moon = world({
id: "moon",
ground: { mode: "round", size: { radius: 300 } },
physics: { gravity: -4 },
});
// Sky + scatter live in editor.scene.json; seeds derive from id + save.

🧩Scene & entities

Spawn and simulate entities

A per-world entity store you spawn into and tick. State serializes cleanly and scales to many entities and many players — no module-global maps.

loop.ts
export function onNewPlayer(ctx: GameContext) {
ctx.scene.entity.spawn("player", { id: ctx.player.userId, position: SPAWN });
}
export function onTick(ctx: GameContext, dt: number) {
for (const mob of ctx.scene.entity.list()) {
if (mob.role !== "npc") continue;
const [x, y, z] = mob.position;
ctx.scene.entity.setPose(mob.id, { position: [x + mob.velocity[0] * dt, y, z], dt });
}
}

⚔️Combat

Abilities, projectiles, and death

Cast runners, resource meters, auto-target, projectiles, and a death system — feel and resistance included. Opt in per game; a puzzle game never carries it.

combat.ts
import { createAbilityKit } from "@jgengine/core/combat/abilityKit";
import { createDeathSystem } from "@jgengine/core/combat/death";
const abilities = createAbilityKit([
{ id: "fireball", cooldownMs: 1500, resourceCost: 20, castType: "projectile" },
]);
// canCast/cast track cooldowns, charges, and resource spend for you
if (abilities.canCast("fireball").ok) abilities.cast("fireball");
const death = createDeathSystem({
resolveOnDeath: (id) => ({ drops: "goblin-loot" }),
resolveIdentity, loot, events,
despawn: (id) => scene.entity.despawn(id),
});

🌐Multiplayer

Authoritative host, one protocol

A browser-safe authoritative host and client backend over a pluggable transport pipe — WebSocket, WebRTC P2P, or loopback — with Postgres/Convex persistence behind the same seam.

net.ts
import { createWsBackend } from "@jgengine/ws/createWsBackend";
const backend = createWsBackend({
url: "wss://your-host.example/game",
userId: player.id,
});
const { serverId } = await backend.createSession({ gameId: "meadow-run" });
// Reconnect, snapshot sync, and save cadence are handled for you.

🗺️Authored scenes

Place it once, render it generically

Author paths, foliage, and gameplay spots in the 3D editor, save editor.scene.json, and drape it at runtime — the render and the gameplay read the same document.

Scene.tsx
import { AuthoredScene } from "@jgengine/shell/scene";
<AuthoredScene document={doc} field={ctx.world.ground} />;
// Enemy waypoints and tower plots derive from the same doc —
// coordinates live once, editable in the editor.

🎛️UI & HUD

Headless HUDs, drag-to-place

React hooks expose game state; HudPanels auto-stack, clear the touch dock, and are laid out live with the F2 canvas editor. No fixed overlay is ever forced on your game.

Hud.tsx
import { useCurrency, useAbilitySlot } from "@jgengine/react/hooks";
function Hud() {
const gold = useCurrency("gold");
const fireball = useAbilitySlot(abilities, "fireball");
const cd = Math.ceil((fireball?.cooldownRemainingMs ?? 0) / 1000);
return <HudPanel anchor="top-right">{gold} · {cd}s</HudPanel>;
}

📦Assets

License-verified CC0 models

A typed, license-checked index of CC0 3D packs. Pull the models you name, register them in a catalog, and place them — no hunting for assets or licenses.

terminal
# discover and pull CC0 packs, license-verified
npx jgengine assets search "tree"
npx jgengine assets pull quaternius-stylized-nature

And the rest

Loot, quests, economy, crafting, turns, inventory, social…

Genre systems are all opt-in primitives on the same core. Your agent pulls in only the domains your game needs — and nothing it doesn't.

lootquestseconomycraftingcardsturnsinventoryleaderboardschatpresencevoxelsvehicles