Skip to main content

Spatial Runtime

A zero-dependency semantic drawing runtime for Python.

Spatial Runtime combines a persistent scene graph, geometric constraints, atomic editing, versioned documents, reactive rendering, and a local interactive Studio. Drawings are ordinary Python programs, while every object remains addressable through a stable semantic ID.

Use it to build diagrams, illustrations, generated graphics, and machine-editable scenes that retain their structure after rendering.

Why Spatial Runtime?

  • Semantic scenes — address objects by IDs such as hero.head, not by fragile array positions.
  • Structured geometry — preserve hierarchy, styles, anchors, relations, constraints, metadata, dependencies, roles, guides, and z-order.
  • Safe editing transactions — solve and validate before committing, with automatic rollback when an edit is invalid.
  • Multiple outputs — generate deterministic SVG, PNG, PDF, canvas, inspection, and feedback documents.
  • Reactive workflow — watch drawing files and their local imports, retain the last good render after an error, and avoid unchanged artifact writes.
  • Local Studio — inspect, select, drag, edit, preview, undo, and export a scene in the browser.
  • Zero runtime dependencies — install the package without pulling in a third-party runtime stack.

Spatial Runtime requires Python 3.11 or newer.

Installation

Install the package from PyPI:

python -m pip install spatial-runtime

Confirm that the command-line interface is available:

spatial --help

Quick start

Create drawing.py:

from spatial import Circle, Rect, Scene

scene = Scene(600, 400, id="portrait")
scene.group("hero")

scene.add(
    Circle(
        (300, 130),
        55,
        id="head",
        role="structural",
        style={"fill": "#ffd8ad", "stroke": "#17131f", "stroke_width": 4},
    ),
    parent="hero",
)
scene.add(
    Rect(
        245,
        190,
        110,
        150,
        id="body",
        role="structural",
        style={"fill": "#ffb454", "stroke": "#17131f", "stroke_width": 4},
    ),
    parent="hero",
)

scene.relate("attached", "hero.head", "hero.body", at="neck")
scene.constrain("hero.head", horizontally_aligned_with="hero.body")
scene.solve_constraints()

Run the complete construct, render, inspect, and feedback cycle:

spatial cycle drawing.py --out-dir out

Or open the scene in Studio:

spatial studio drawing.py --open

Semantic scenes

A scene is more than a list of drawing commands. Nodes keep their meaning and relationships throughout the drawing workflow:

head = scene["hero.head"]
head.anchor("neck", (300, 180))
head.set_lod(summary="circular face attached to the body")

scene.relate("attached", "hero.head", "hero.body", at="neck")
scene.constrain("hero.head", horizontally_aligned_with="hero.body")

Stable hierarchical IDs make scenes straightforward to inspect, patch, and modify from Python or an automated tool.

Atomic edits and validation

Scene.edit() treats a group of changes as one transaction. Spatial Runtime solves constraints and validates the scene before committing. Solver non-convergence or an error-level validation issue rejects the transaction, restores the previous state, and raises EditRejectedError.

from spatial import EditRejectedError

try:
    with scene.edit("move the head upward") as edit:
        scene["hero.head"].move(dy=-8)
except EditRejectedError as error:
    print(error.result.reason)
    print(error.result.solve_report)
    print(error.result.issues)
else:
    print(edit.result.diff)

Warnings, including out-of-canvas geometry, remain visible without rejecting a valid edit. Use allow_invalid=True when you deliberately need to commit an invalid state while retaining its complete diagnostics.

Undo, redo, and named snapshots are available during the active Python or Studio session.

Rendering and inspection

Render the same semantic scene to several targets:

scene.render_svg("render.svg")
scene.render_blueprint("blueprint.svg")
scene.render_raster("render.png", scale=2)
scene.render_pdf("render.pdf")
scene.save("scene.json")

print(scene.inspect("hero", detail="full"))
print(scene.inspect("hero", detail="full", structured=True))
print(scene.occupancy("hero"))
print(scene.validate())

Portable outputs use explicit, versioned document envelopes:

Document Schema
Scene snapshot spatial.scene
Declarative patch spatial.patch
Canvas commands spatial.canvas
Structured inspection spatial.inspection
Reactive feedback spatial.feedback

For example, Scene.save() writes a lossless snapshot of the current scene:

{
  "schema": "spatial.scene",
  "schema_version": 1,
  "scene": {
    "id": "portrait",
    "width": 600,
    "height": 400,
    "styles": {}
  },
  "nodes": [],
  "constraints": [],
  "relations": []
}

All built-in node types have exact codecs. Materialized custom Component subclasses load as FrozenComponent snapshots that retain their class provenance, layer metadata, hierarchy, and children. Custom Node subclasses can register their own codecs.

Packaged JSON Schemas are available through load_schema("scene"); use "patch", "canvas", "inspection", or "feedback" for the other document types.

Declarative patches

[!NOTE] The patch protocol is experimental and may evolve between releases.

Scene.apply_patch() applies a JSON-compatible set of operations atomically:

result = scene.apply_patch(
    {
        "schema": "spatial.patch",
        "schema_version": 1,
        "label": "Move the head upward",
        "operations": [
            {"op": "move", "target": "hero.head", "dx": 0, "dy": -8}
        ],
    }
)

Patches support:

  • adding, removing, and reparenting nodes;
  • moving, positioning, scaling, rotating, and editing handles;
  • changing styles, metadata, visibility, roles, z-order, and anchors; and
  • adding or removing relations and constraints.

Operations run in order inside one transaction. An unknown operation, malformed payload, missing target, or rejected edit rolls back the entire patch. dry_run=True evaluates the patch on a clone and returns its projected diff, diagnostics, and canvas without changing the live scene.

Reactive rendering

Watch a drawing and rebuild when its source or local Python imports change:

spatial watch drawing.py --out-dir out --debounce 0.15

The reactive runner:

  • waits for file changes to settle before rebuilding;
  • reloads changed local modules;
  • retains the last valid scene and artifacts after execution errors;
  • reports failures as structured feedback and continues watching;
  • writes artifacts atomically; and
  • skips filesystem writes when the generated bytes are unchanged.

SVG fragments and canvas commands are cached by normalized node state. Reloading canonical Python source starts a fresh session and clears undo/redo.

Local Studio

[!NOTE] Studio is experimental and intended for trusted local use.

spatial studio drawing.py --host 127.0.0.1 --port 8765 --open

Studio includes:

  • a searchable semantic hierarchy with role and layer filters;
  • a zoomable SVG viewport with click selection and drag-to-move;
  • geometry, style, anchor, relation, constraint, metadata, and dependency controls;
  • guide, blueprint, bounds, anchor, and role overlays;
  • editable semantic handles and dry-run previews;
  • undo, redo, reload, and JSON snapshot export; and
  • structural diffs, changed-node highlighting, pixel-diff overlays, warnings, and solver status.

Studio edits only the in-memory scene and never rewrites the Python drawing. Reloading the source discards session edits and starts a new undo/redo history.

Studio has no authentication or security boundary. Drawing files execute as fully trusted Python, so run only code you trust and keep Studio bound to 127.0.0.1 unless you intentionally choose otherwise.

Source and history model

Python source is authoritative. Scene JSON captures the complete current scene state for interchange, inspection, and export, but it does not contain snapshots or undo/redo history.

Use Git for durable source history. Spatial Runtime intentionally does not add a sandbox, permission system, authentication layer, or revision-control layer around drawing files.

Documentation

The examples directory contains complete scenes demonstrating primitives, components, constraints, patterns, fields, surfaces, skeletons, perspective, rendering, and inspection.

Development

Clone the repository, then install the development tools:

python -m pip install -e ".[dev]"

Run the main checks:

python -m compileall -q src
ruff check src tests
mypy
coverage run -m unittest discover -s tests -v
coverage report
node --test tests/js/studio.test.mjs

The release suite covers persistence round trips, transaction rollback, patch atomicity, deterministic renderer documents, reactive recovery, Studio endpoints, browser behavior, and performance at 100-, 1,000-, and 10,000-node scene sizes.

Project status

Spatial Runtime 2.0.0 is beta software. The core scene, persistence, transaction, validation, rendering, inspection, and reactive APIs are stable. The patch protocol and Studio are experimental.

Released under the MIT License.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spatial_runtime-2.0.0.tar.gz (94.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spatial_runtime-2.0.0-py3-none-any.whl (91.9 kB view details)

Uploaded Python 3

File details

Details for the file spatial_runtime-2.0.0.tar.gz.

File metadata

  • Download URL: spatial_runtime-2.0.0.tar.gz
  • Upload date:
  • Size: 94.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.3

File hashes

Hashes for spatial_runtime-2.0.0.tar.gz
Algorithm Hash digest
SHA256 25d69b3b592e086ddf53c21981c87d781f08811d490e0d3d7833e7923b4649fc
MD5 d4580a39d627d99fed1e8bdb27b12365
BLAKE2b-256 e8c9393d07c2d628af9d4542d0226f19f11261b25ff002bff9a676ffb57c0940

See more details on using hashes here.

File details

Details for the file spatial_runtime-2.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for spatial_runtime-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f8640d2d66258cf97fcab91dd794c939ae0272dab6feee4713c252e9fe4c6a29
MD5 c6589e81ad8b9a17abf1f4cb38cb5074
BLAKE2b-256 b43b5115f34a053ebf9674109bf7692291513dbad7d1bc00bf2c13dc37bb6f92

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page