Skip to content

Web

A Web host is the browser counterpart to Terminal. It runs an offscreen runtime, serves a small HTTP shell, and streams cell frames to the client. Browser key, mouse, and resize input re-enter the same @on_* path a terminal session uses.

There is no separate HTML paint backend. Grids, fields, components, and hooks are the same objects on both hosts.

Running a web app

Web().run(...) binds a stdlib HTTP server and keeps serving until interrupted. This needs a normal Python process — not Pyodide.

Running a Web App
from xnano import BaseGrid, Field, Web

class App(BaseGrid):
    body: str = Field(default="hello, web!")

Web().run(App(), port=8000) # (1)!
  1. Optional: host=, Web(state=..., width=..., height=..., title=...).
Output
xnano web  http://127.0.0.1:8000

The default host uses Python's stdlib HTTP server via serve_native.

One grid, two hosts

Same Grid, Either Host
from xnano import BaseGrid, Field, Terminal, Web

class App(BaseGrid):
    body: str = Field(default="hello!")

Terminal().run(App())   # terminal session
Web().run(App())        # browser session

Only one of these runs at a time in a given process. The grid class does not change.

Shared vs. per-visitor grids

Passing a BaseGrid instance reuses that object for every connection. Passing the class (or a factory) builds a fresh root per visitor.

Web().run(Dashboard())   # shared
Web().run(Dashboard)     # new instance per visitor

Request hooks

HTTP handlers are declared with decorators from xnano.requests on grid methods. When that grid is served under Web (or a request server), those routes are registered. They are not Terminal APIs — see Requests.

What does not carry over

Some device and cursor controls only apply to a real terminal (raw mode, alternate screen, moving the caret to a cell). On Web they are no-ops. Grids, fields, components, and hooks still mean the same thing.

Next

API

Web · serve_native · xnano.requests · Terminal