Readiness
view.ready waits for required active-area assets. Use assetStatus(id) and retryAssets() for diagnostics and recovery.
FRONTEND ENGINE GUIDE
jsonCraft validates, simulates, and renders a complete JSON world in the browser. The core needs no server, account, database, or network transport. Your application can load JSON from anywhere when you are ready to add those layers.
A world contains reusable assets, bounded areas, entities and prefabs, actor input bindings, camera state, simulation settings, and serializable runtime state. The format identifier is jsoncraft/2.
{
"format": "jsoncraft/2",
"id": "hello-world",
"assets": { "marker": { "primitive": "sculpture" } },
"areas": {
"main": {
"size": [20, 20],
"entities": {
"hello": {
"components": {
"render": { "asset": "marker", "color": "#78906f" },
"spin": { "rate": [0, 18, 0] },
"text": { "value": "Hello from JSON." }
}
}
}
}
},
"camera": { "area": "main", "position": [0, 6] }
}
Open the JSON Schema ↗. Structural validation is followed by semantic checks for references, inheritance, hierarchy, component versions, geometry, and runtime invariants.
Give the container a height, load a world or exported project, and wait for required assets. The renderer uses an isolated shadow root and scoped controls.
<div id="world" style="height:480px"></div>
<script type="module">
import { mountWorld } from './jsoncraft.js';
const project = await fetch('./project.json').then(r => r.json());
const view = mountWorld(document.querySelector('#world'), project.world, {
resources: project.resources,
onInteraction(detail) {
console.log(detail.action, detail.result);
},
onError(error) {
console.error(error);
}
});
await view.ready;
</script>
Download the browser engine ↓. Export project.json from the playground, or supply your own valid world JSON directly.
The engine does not prescribe sockets, polling, databases, or agent frameworks. Once your application has changed JSON, choose the update level that matches your state ownership.
// Atomic edits to the current engine.
view.engine.apply({
baseRevision: view.engine.revision,
operations: [
{ type: 'entity.update', area: 'main', id: 'hello',
patch: { state: { active: true } } }
]
});
// Replace state in the same engine and component registry.
view.engine.load(nextCheckpoint, {
baseRevision: view.engine.revision
});
// Replace the mounted engine with another complete world.
await view.load(nextWorld, { preserveView: true });
apply() is atomic and supports revision, tick, state-token, entity-version, and idempotency checks. view.load() cancels captured input and keeps the mount's current resources, base URL, and registry; remount when those dependencies change.
Built-in components cover rendering, bodies, vehicle/walk/fly controls, input, spin, text, interactions, and proximity triggers. JSON actions are link, portal, increment, toggle, set, append, and event.
Pointer, keyboard, or touch activation invokes the selected action. The host receives { target, entity, action, result } through onInteraction and the bubbling jsoncraft:interact event. Without a callback, the mount displays a safe built-in content card.
The built-in trigger is proximity-based and supports once, cooldown, and an optional actor. Fixed-tick jobs support wait, move, apply, and invoke. render.when provides state-driven visibility. World JSON never installs arbitrary JavaScript; custom components are trusted host implementations registered separately.
Native world geometry has two forms: editable mesh.parts and detailed model.data triangles. The playground imports OBJ, static glTF/GLB, triangle JSON, voxel JSON, and shape-parts JSON into those forms. Imported model hosts are not runtime dependencies.
Images and web destinations may remain links. Relative resources can come from an exported project resource map. Remote browser fetches omit credentials and require CORS. The runtime also retains direct linked-model support for compatibility and advanced integrations.
Export formats: standalone HTML contains the runtime, world, imported geometry, and owned resources; ZIP contains a static site; project JSON stores { world, resources }. Engine snapshots contain world state only, not project resources.
view.ready waits for required active-area assets. Use assetStatus(id) and retryAssets() for diagnostics and recovery.
setPaused() controls the mount loop. Serialized settings.paused belongs to world state. Offscreen mounts stop simulation and rendering.
Use onSelect, onTransform, camera callbacks, tools, snapping, framing, projection, and gizmo handles to build another editor.
Call view.dispose() when removing a world. It releases animation, observers, event handlers, renderer buffers, asset decoders, and mounted DOM.
The complete browser handle also exposes engine, element, focus, load, select, setMode, setTool, setTransformMode, setSnap, flushCameraChanges, project, frameView, gizmoHandles, and getStats.
Static models support up to 32,000 triangles, 96,000 vertices, and 256 material colors. Source glTF must be static; animation and skinning are rejected. Rich textures, transparency, and double-sided materials are simplified when converted to editable world geometry.
Detailed JSON can exceed browser local-storage quotas, so exported projects are the durable authoring copy. See beta status and verified limitations for current browser and physical-device coverage.
The frontend engine is ready to use without a server. Start with a world, mount it, handle interactions in your page, and call view.load(nextWorld) when another source eventually owns the JSON.
Open a blank world ↗ Inspect JSON-native geometry Run the driving showcase