Skip to main content

spatial_ui

A Python spatial UI engine with square logical grid units, relative placement, and Python 3.14 t-string templates. Version 0.1.0 is an early release under the MIT license, with no third-party runtime dependencies.

The first milestone includes a responsive dashboard with semantic HTML and Python event handlers. See IMPLEMENTATION_PLAN.md for the architecture, acceptance criteria, and later milestones. Issues and the GitHub Project track current work; pull requests record implementation and verification.

Try the dashboard

Requires Python 3.14 or later.

python -m pip install "spatial-ui==0.1.0"
spatial-ui demo

You can also start it with python -m spatial_ui demo.

Open http://127.0.0.1:8000/. Add actions, switch between compact and wide canvases, type in the scratchpad, and move the tile. The scene uses the same coordinate model as the navigation and cards. Use --port 8001 for another local preview.

Spatial layout

from spatial_ui import Grid, at, below, right_of

layout = Grid(12, 8).resolve({
    "nav": at(0, 0, 12, 2),
    "sidebar": below("nav", width=3, height=6),
    "card": right_of("sidebar", width=6, height=3, gap=1),
})
assert layout.rects["card"].x == 4

Coordinates and sizes use whole logical cells. Adjacent edges can touch; overlapping rectangles require allow_overlap=True. Centering rounds an odd remainder toward the top/left. fit scales one square unit against both container dimensions; reflow uses the container width and optional Breakpoint rules. Each breakpoint overrides the base placements independently, rather than inheriting overrides from smaller breakpoints.

T-string templates

from spatial_ui import Grid, at, html, render

name = "Outside Labs"
page = html(t"""
    <main layout={Grid(4, 3, mode="reflow")}>
        <section key="welcome" place={at(0, 0, 4, 3)}>
            <h1>Hello, {name}</h1>
        </section>
    </main>
""")
result = render(page)  # result.markup and result.css

Strings interpolate as text. Nested html() fragments, t-strings, lists, and tuples compose as children. None omits a child or optional attribute. Format values before interpolation. layout and place require typed values; every direct grid child needs a unique sibling key and a place.

The compiler accepts a conservative HTML fragment vocabulary. It rejects scripts, inline styles, native event attributes, dynamic tag/attribute names, unsafe URL schemes, duplicate attributes, and unsupported nesting. URLs use explicit HTTP(S), relative paths, or (for links) mailto: and tel:; URL whitespace must be percent-encoded. There is no raw-markup escape hatch. A fit grid needs a parent with a definite width and height. Visual order follows placement while reading order follows template order.

Components and state

from spatial_ui import Component, Session, State, html

class Counter(Component):
    count = State(0)

    def increment(self):
        self.count += 1

    def render(self):
        return html(t"""
            <section>
                <p>Actions: {self.count}</p>
                <button type="button" on_click={self.increment}>Add one</button>
            </section>
        """)

session = Session(Counter())
first = session.render()
second = session.dispatch(first.event_ids[0], first.version)
assert "Actions: 1" in second.markup

State defaults are copied per instance. Retain child component instances on the parent to preserve their state, then interpolate them as children. Rendering reevaluates the t-string; it does not make a previously compiled template reactive. Click handlers run synchronously without arguments and return None. They bind only to semantic buttons; disabled buttons register no event. Every render replaces the event allowlist, and session dispatch serializes callbacks and rejects stale versions. Callback exceptions invalidate bindings and require a page refresh. Ordinary Python side effects are not automatically rolled back.

Run your component

from spatial_ui import App

App(Counter, title="My workspace").run()  # Counter from the example above

Pass a factory that creates a fresh root component for each browser session. The bundled server is for loopback development, with synchronous callbacks and in-memory state. Sessions expire after 30 minutes of inactivity; a server restart clears their state. Tabs in the same browser share a cookie and component tree; an update in one tab makes another tab's event bindings stale, requiring refresh. No filesystem directory is served. Custom CSS can be supplied as stylesheet=.

Apply motion={Transition(duration=260, easing="ease-out")} to a container to animate changes in its descendant grid rectangles. Browser layout supplies the positions, and the runtime uses Web Animations to move between them. A zero duration or the system's reduced-motion preference disables transitions. This initial transition API covers placement and container reflow, with advanced movement/timeline composition left to the roadmap.

The browser preserves keyed nodes, focus, and live input/textarea/select values through updates. Supply stable sibling keys (or unique HTML IDs) for controls whose identity matters. Cross-parent moves and server-controlled form editing are future work. Scratchpad text stays in the DOM and is not persisted on reload or sent to Python by the click-only transport.

Compatibility

The public API is early. Before 1.0, minor releases may include breaking changes; patch releases are intended for compatible fixes. Pin the package version when reproducibility matters. See CHANGELOG.md for release notes.

Development

Requires Python 3.14 and uv.

uv sync --locked
uv run spatial-ui --version
uv run spatial-ui demo
uv run python -m unittest discover -s tests -v
uv build

Tests use the Python standard library. CI verifies Linux, macOS, and Windows and installs both built distributions outside the checkout. To run the same distribution checks locally after building:

uv run --locked python scripts/verify_distributions.py --tag v0.1.0

Publishing a GitHub release with a tag matching v<package version> runs .github/workflows/release.yaml. It tests and verifies both distributions, then publishes them to PyPI using trusted publishing in the pypi environment.

Metadata

Release files for spatial-ui 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for spatial-ui 0.1.0
File Size Uploaded
spatial_ui-0.1.0.tar.gz 24.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for spatial-ui 0.1.0
File Interpreter ABI Platform
spatial_ui-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 53.9 kB

Release files / spatial_ui-0.1.0.tar.gz

Download URL spatial_ui-0.1.0.tar.gz
Size 24.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e2e1c1f150c850443903f99b46527e6eff8abc0124060d2c1fd0ed0a1b0133a5
BLAKE2b-256 checksum
How to use checksums
65f2c4091ce93a68e59773514f665681186453dd129f39178c8d4e33858a3813
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / spatial_ui-0.1.0-py3-none-any.whl

Download URL spatial_ui-0.1.0-py3-none-any.whl
Size 29.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5a249e1144ebc391c55d615a79bed7369431c8b7e9bc22a42672963988003b01
BLAKE2b-256 checksum
How to use checksums
f7bebe86d496c63202abcbf1ed1868fdbdadb77b7a8d64ccb0ad9580d291d932
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page