#!/usr/bin/env python3 """Assemble the static browser Space: ``index.html`` + the ``cairn`` wheel. The Space is a plain Pyodide page, not a Gradio-lite one. That was not the first choice; it is the choice that works. Gradio-lite imports ``gradio`` *before* it installs the page's requirements, and gradio 5.x currently cannot be resolved against ``huggingface-hub`` 1.x inside Pyodide: * 5.42+ pin ``huggingface-hub<1.0`` while their bundled ``gradio_client`` asks only for ``>=0.19.3``; micropip gathers the two concurrently, resolves the unbounded one to 1.x, then the capped one raises ``Requested 'huggingface-hub<1.0,>=0.33.5', but huggingface-hub==1.27.0 is already installed``. * Older builds (<= 5.38.2) leave it uncapped, so the install succeeds and the *import* fails instead: ``huggingface_hub`` 1.x does ``import httpcore``, and Pyodide's patched ``httpx`` does not bring httpcore with it. Neither is reachable from ````, because that is installed after the import. Driving Pyodide directly fixes the ordering, and drops gradio's whole dependency stack (pandas, pydantic, orjson, ...) from the download, so the page loads faster as a side effect. python space/build_space.py # writes space/index.html python space/build_space.py --serve # ...and serves it for local testing ``browser_app.py`` stays a real, importable, compile-checked Python file; this script embeds it and refuses to emit HTML if it does not parse. Claim: O -- the free, zero-install path has to be maintainable, or it rots and "anyone can check this" quietly stops being true. """ from __future__ import annotations import argparse import os import shutil HERE = os.path.dirname(os.path.abspath(__file__)) ROOT = os.path.dirname(HERE) WHEEL = "cairn-0.1.0-py3-none-any.whl" # Pinned: a silent bump in a CDN dependency would break the Space with no commit # to point at. Pyodide 0.27.x ships numpy, scipy and pillow as prebuilt wasm. PYODIDE = "0.27.3" TEMPLATE = r""" Cairn — leave, come back, same world

Cairn — leave, come back, same world

An explicit world ledger makes video generation return-consistent, and editable.

Video world models forget. Turn the camera away from a chair for a few seconds and turn back, and it is a different chair, somewhere else, or gone. The usual fixes give the model more implicit memory — a longer context window, or a compressed latent. Both decay with how long you looked away.

Cairn takes the world out of the weights. Objects live in an explicit external ledger — persistent id, pose, appearance, provenance — written by perception on the model's own generated frames, and read back to coerce generation when the camera returns. A table lookup costs the same whether you looked away for 4 frames or 400.

Over 5 seeds, at 128 frames away, every baseline returns a broken world 0% of the time and Cairn 100%, with a flat 3.6 cm error. Try to break it below.

Starting Python in your browser…
Loading Pyodide, numpy, scipy and the cairn package. The first load takes roughly 30 seconds and is cached afterwards. Nothing is sent to a server — the whole benchmark runs on your machine.

Reading the numbers. Moved on return compares where the object is when the camera comes back against where the same run showed it before leaving — self-consistency, measured from generated pixels by the same detector for every condition, never from the ledger. Consistency debt is the per-frame divergence between the video and the committed record; Cairn closes a control loop on it, the baselines can only be measured by it.

What you are watching. A surrogate generator that reproduces how autoregressive video drifts (random walk + prior pull + salience decay), not a real video backbone — that is the trade that buys exact ground truth and a benchmark you can run on a laptop. The same cairn library wraps a real diffusers video pipeline in one line: CairnPipeline.from_pipeline(pipe).

Code · Dataset · full benchmark, ablation and honest limitations are in the README.

""" def build(serve: bool = False, port: int = 8000) -> str: app_path = os.path.join(HERE, "browser_app.py") with open(app_path) as f: app_src = f.read() compile(app_src, app_path, "exec") # fail loudly rather than shipping broken HTML html = TEMPLATE.format(pyodide=PYODIDE, wheel=WHEEL, app=app_src) out = os.path.join(HERE, "index.html") with open(out, "w") as f: f.write(html) wheel_src = os.path.join(ROOT, "dist", WHEEL) if not os.path.exists(wheel_src): raise SystemExit(f"missing {wheel_src}; run `python -m build --wheel -o dist` first") shutil.copy2(wheel_src, os.path.join(HERE, WHEEL)) print(f"wrote {out} ({len(html) / 1024:.0f} KB) and {WHEEL}") if serve: import http.server import socketserver os.chdir(HERE) with socketserver.TCPServer(("", port), http.server.SimpleHTTPRequestHandler) as httpd: print(f"serving {HERE} at http://localhost:{port}/ (ctrl-c to stop)") httpd.serve_forever() return out if __name__ == "__main__": ap = argparse.ArgumentParser(description=__doc__) ap.add_argument("--serve", action="store_true") ap.add_argument("--port", type=int, default=8000) build(**vars(ap.parse_args()))