Skip to content

feat: graphics substrate (registry, tier engine, cell integration) - #141

Draft
natemoo-re wants to merge 4 commits into
spec/graphicsfrom
feat/graphics-substrate
Draft

natemoo-re wants to merge 4 commits into
spec/graphicsfrom
feat/graphics-substrate

Conversation

@natemoo-re

Copy link
Copy Markdown
Member

Implements the Graphics Specification engine in C (stacked on the spec PR; the public TypeScript surface + test suite land in the img PR after this).

What lands here

Memory (§5). The engine gains a second, dimension-independent carve beside the per-dimension clayterm carve: [gfx: entry table (256) | pixel pool (4 MiB default) | placements tables (64×2 double-buffered)]. Because the region never moves or re-initializes, the registry survives resize untouched (§10.5) — and this is exactly the property §4.5 calls out for the future zero-copy canvas surface views. setImage/removeImage MUST NOT grow linear memory (INV-I8); capacity failures are closed RangeError codes, compaction is the only reclamation.

Registry surface (§7.2). Two-phase native calls: image_begin validates and reserves (returning the absolute address the host writes pixels at — video's same-size-per-frame path allocates nothing), image_commit bumps the data version. image_remove emits the protocol's data-freeing d=I deletion block into the output buffer and reconciles covered cells to their blank state (INV-I6) so the next diff emits nothing redundant.

Tier engine (§9). Pre-layout resolution (variant, omission, liveness, evidence mirror, line-mode cap) expands the void img op into a Clay element: the alt tier is a wrapped, vertically-clipped text child (so alt's fit sizing and wrap come from the layout engine's own text machinery); pixel tiers attach the op's wire address as customData. The render-command walk then applies the four footprint-preserving demotions (clip containment §8.5, placement-id collision §9.2.1, pixel-overlap §10.3, table capacity §5.4) — kitty→ascii only, same painted footprint, no re-measurement — then records the placement or paints the art.

Frame phases (§9.2.6). Coverage pass (pixel coverage asserts blanks over the back buffer, later element wins shared cells) → repair precheck (a placement whose covered cells will receive writes re-places; runs before any dirty-marking) → scoped stale deletions (lowercase d=i,i=…,p=…, data retained) → delete-before-re-transmit chunked transmission (4096-char base64 chunks, m=1/m=0, q=2 on every block) → cell writes (the ordinary diff) → placements after, with the §7.6 cursor-restore carve-out. Steady state is byte-silent.

Ascii art (§9.3). Per-cell circle sampling (6 internal + 10 external, geometry in the source and mirrored in the generator), directional-then-global contrast with power-of-two exponents (γd=4, γg=2 — exact repeated squaring, no libm, bit-identical everywhere), 95-character nearest-match against shape vectors generated at build time from the public-domain font8x8 bitmap font (deno task gen-shape, golden-lockable).

Capability mirror. graphics_capability(ct, kitty) — the renderer's private capability state (terminfo-spec §4.2); the true→false transition emits the §11.2 denial bytes immediately (TINV-5). Wired to the update() capability fold in the img PR.

Verification

  • make builds clean; the full existing suite passes (27 tests / 328 steps — post-feat: term.update() folds CapabilityEvents into runtime capabilities #133 main, this branch is rebased onto it).
  • Engine exercised end to end against the real wasm (scratch smoke, not committed): registry two-phase set → ascii art cells with sampled colors → capability grant → exact kitty transmission/placement blocks → byte-silent steady state → d=I removal bytes.
  • Spec touch (pre-approved by the spec PR's Appendix A): current-surface notes A5/A6 — renderer-spec §12.1/§12.2/§12.3 now describe the img opcode, props, and the three image error types that exist with this PR.
  • No changeset: no public TypeScript API yet; the img PR carries it.

@bombshell-cooper

bombshell-cooper Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

No changeset needed

This pull request is classified as no_release_impact: no published package

Comment thread .changeset/cooper-approved-132.md
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown

Size Increased — +11.5 KB

134.2 KB unpacked

@pkg-pr-new

pkg-pr-new Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@bomb.sh/tty@141

commit: 47b70e5

The Graphics Specification's engine, in C:

- Memory carve (§5): a dimension-independent graphics region beside the
  per-dimension clayterm carve - fixed-capacity entry table (256),
  compaction-only pixel pool (imagePoolBytes, 4 MiB default), double-
  buffered placements tables (64). setImage/removeImage never grow
  linear memory; the region survives resize untouched, which is what
  makes future zero-copy surface views sound (§4.5).
- Registry surface (§7.2): two-phase image_begin/image_commit (the host
  writes pixels at the reserved absolute address between calls; video's
  same-size path allocates nothing), image_remove emitting the data-
  freeing d=I block and reconciling covered cells, graphics_capability
  with immediate deletion bytes on capability denial (§11.2), and
  graphics_resize_prepare emitting deletions before the dimension state
  is discarded (§10.5).
- Tier engine (§9): pre-layout resolution (variant/omission/liveness/
  evidence/line-mode cap) into a Clay element - the alt tier expands to
  a wrapped, clipped text child; pixel tiers attach the op wire as
  customData. The render-command walk then applies the footprint-
  preserving demotions (clip containment §8.5, placement-id collision
  §9.2.1, overlap §10.3, table capacity §5.4), records kitty
  placements, and paints ascii art.
- Frame phases (§9.2.6): coverage pass, repair precheck, scoped stale
  deletions (lowercase d=i,p=), delete-before-re-transmit chunked
  transmission (4096-char chunks, q=2 everywhere), placements after
  cell writes with the §7.6 cursor restore, byte-silent steady state.
- ASCII art (§9.3): per-cell circle sampling from the pool, pinned
  power-of-two contrast exponents (exact repeated squaring, no libm),
  and build-time shape vectors generated from the public-domain 8x8
  bitmap font by tasks/gen-shape-vectors.ts (deno task gen-shape).

Existing 328 test steps pass; the engine is exercised end to end
(ascii art, kitty transmission/placement/steady state/removal) in a
scratch smoke run; the public TypeScript surface and the §14 test
suite land in the img PR.
- input.c: the kitty graphics APC recognition required the response
  shape - replies never carry an action key, so frames beginning with
  a= (the renderer's own quiet q=2 emissions relayed through a mux,
  or another client's commands) no longer surface as spurious
  CapabilityEvents. INV-I5's input-stream cleanliness now holds even
  when output bytes reach the input parser.
- clayterm.c: the img element's declared bg forces the color's alpha
  to opaque at decode (cells cannot be transparent; the value space
  is open({bg})'s rgba()) - Clay skips a=0 rectangles, which silently
  dropped the declared background.
@natemoo-re
natemoo-re force-pushed the feat/graphics-substrate branch from 8813820 to 30aa8fa Compare October 9, 2026 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant