mrly.net

The default face

A generic CPU renderer in `mrlyui::face`: any app's view - state, actions, canvas - becomes pixels, then a PNG. Terminal-esque, uniform, deliberately plain. It is the agent's eyes: a screenshot of any app on any tick, no browser in the loop.

The two shot kinds

`frame` fact rendered raw. Apps define availability: no frame fact, no shot. Frameless apps fail with "nothing to shoot here". Unchanged.

app. Renders the whole view and embeds the canvas raster in its body when one exists.

Geometry

320 wide, height derived from content and clamped to [160, 512], rendered at scale 3 - PNGs are 960 wide. Pure function of the input: no clock, no RNG, byte-identical across runs.

Layout

beat verb right-aligned muted, hairline rule.

308x192; undecodable, oversized, or empty facts degrade to a muted `frame WxH` row), then state rows in map order (`frame`, `shade`, `md` skipped): scalars as key/value rows, all-scalar arrays inline, number grids as `key 16x16` summaries, object arrays listed capped at 12 with `+ n more`, nested objects one indent level then brief summaries, `data:` strings as `[png Nb]` tokens. A `md` string renders text-only: H1 scale 2, H2 accent, paragraphs pixel-wrapped, lists with hanging indent, code lines on a faint backdrop; emphasis and links strip to plain text.

capped at 8 plus `+ n more`; zero actions reads `no actions`.

Theme

Board and ink follow darkmode; muted and faint are mixes between them. The accent is `ROLLABLE[hash(route) % 13]` - deterministic per app. Text uses the bitmap font; unsupported glyphs (emoji included) draw a hollow box, never blank. No emoji atlas yet - the sprite atlas is a later phase.

Totality

The face never fails: null state renders `no state`, hostile or oversized state truncates with `..` and `+ n more` against the height budget, and every string passes through the same per-char engine. `face_png` is total over anything `peek` returns.

Surfaces

glue in `mrlynet::face::{face_frame, face_rgba, face_png, canvas_rgba}`.

`:face [path]`. `shot` is the canvas kind and is untouched.

`np.frombuffer(buf, np.uint8).reshape(h, w, 4)`.

six lived-in gauntlet shots to `data/face/`.

One pixel pin guards the whole stack (`face_pixels_are_pinned` in mrlyui); re-record it on deliberate layout changes.