Commits
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chore: update preview workflow
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
See https://docs.zizmor.sh/audits/#template-injection
Without this it means that, for example, if I push a change to a PR then
shortly push again this workflow will be running twice. This change will
cancel the old run before starting the new one, which reduces the
overall actions cost and DX as you don't have extra runs
Without this it means that, for example, if I push a change to a PR then
shortly push again this workflow will be running twice. This change will
cancel the old run before starting the new one, which reduces the
overall actions cost and DX as you don't have extra runs
for some reason the schema for the actions wants it to be an array
docs: add maintainer build guide
📄 Add MIT license
Surface Clay layout errors on RenderResult
Clay reports errors (duplicate IDs, capacity exceeded, etc.) via a
callback during layout. These were previously silently discarded.
Collect them per-render on the Clayterm struct and expose them as
`errors: ClayError[]` on RenderResult.
Add RenderInfo with lazy element bounds lookup
Adds an `info: RenderInfo` field to RenderResult that provides
on-demand access to element bounding boxes after layout. Callers
query by element id via `info.get(id)`, which calls into WASM to
hash the id and look up the computed bounds via Clay_GetElementData().
A single WASM export handles the lookup — no tables or globals.
Uses the typedef struct infrastructure for BoundingBox field offsets.
Rename Op discriminant to directive, open() name to id
Restructures the Op type so the discriminant field is `directive`
instead of `id`, freeing `id` for the element identity string. The
`name` parameter on `open()` and `OpenElement` becomes `id`, aligning
with Clay's terminology.
Drops the `idx++` seed from Clay_HashString — element IDs are now
hashed with seed 0 and uniqueness is the caller's responsibility.
Duplicate IDs within a frame are undefined behavior.
Removes INV-7 (element identity disambiguation) from the spec and
updates Sections 8.3.1, 9.3, and 10.3 accordingly.
Closes #16
Add Clayterm current-state specification
Separate the combined spec into two documents aligned with INV-8
(architectural independence of rendering and input parsing):
- renderer-spec.md: rendering contract, directive model, rendering
modes (cursor update + line mode), pointer hit-testing
- input-spec.md: input parser API, scan model, InputEvent types
Also adds normative specification of cursor update mode (default)
and line mode with row offset to the renderer spec.
- Replace "descriptor" terminology with "directive" throughout
- Rename open() `name` parameter to `id` in spec
- Fix buffer diffing description: cells are copied, not swapped
- Add note that pointer hit detection requires render loop participation
- Reframe border-layout interaction as Clay's intended behavior
- Update WASM loading to reflect inlined base64 binary
- Move output buffer lifetime guarantee to normative section
- Clarify pack() is internal, validate() is public API
Decouple alternate buffer switching from clearing
Add `{ clear?: boolean }` option to `ALTSCREEN()` and
`alternateBuffer()`. When `clear` is false, uses xterm private mode 47
to switch without clearing the alternate buffer contents.
Closes #13
Adds the v0.1 draft specification covering the architectural model,
core invariants, public rendering API, descriptor model, and boundary
responsibilities. Non-normative sections document settling surfaces
(transfer encoding, input parsing, pointer events) separately from
the stable rendering core.
Add line rendering mode, termcodes, and inline region demo
Rename csi.ts to termcodes.ts and add ESC(), SHOWCURSOR(),
HIDECURSOR(), ALTSCREEN(), and MAINSCREEN() helpers. Make
CursorEvent.row/column 1-based to match DSR native format.
Replace all raw escape sequences in the demo with termcodes.
Use DECSC/DECRC (ESC 7/8) for cursor save/restore instead of
SCO (CSI s/u).
Move the row offset from a constructor parameter to a render-time
option. Row is now 1-based (matching ECMA-48 DSR/CPR format) so
callers can pass the queried cursor position directly without
conversion. Remove line mode from the inline region demo in favor
of raw newline allocation followed by CUP rendering for all frames.
This forces a render of all cells on the very first frame, which is
perfectly acceptable.
Add { mode: "line" } option to render() that emits newline-separated
rows instead of CUP positioning sequences. Line mode writes every cell
and primes the front buffer, so subsequent diff renders work without
a full redraw.
Inline WASM binary into generated TypeScript module
Replace runtime filesystem read of clayterm.wasm with a build step
that base64-encodes the binary into wasm.ts. This removes the
node:fs/promises dependency and --allow-read requirement for the
WASM file.
Accept signed int32 colors in validator
The rgba() function returns signed int32 when alpha >= 128 (bit 31
set). The validator's u32 type rejected these negative values. Add
a color type that accepts the full signed-to-unsigned 32-bit range.
The rgba() function returns signed int32 when alpha >= 128 (bit 31
set). The validator's u32 type rejected these negative values. Add
a color type that accepts the full signed-to-unsigned 32-bit range.
Add CursorEvent with 0-based top/left coords by parsing the terminal's
DSR response (\x1b[row;colR). Rename createTerm's row option to top
so cursor.top feeds directly into createTerm({ top: cursor.top }).
Add a `row` option to TermOptions that offsets all CUP sequences by
the given number of rows, enabling rendering into a region below
existing terminal content rather than always starting at row 1.
Introduce a Setting type that pairs apply/revert escape sequences,
ensuring terminal state is always cleanly restored. Refactor the
keyboard demo to use settings() for alternate buffer, cursor, mouse
tracking, and progressive input.
Adds an `info: RenderInfo` field to RenderResult that provides
on-demand access to element bounding boxes after layout. Callers
query by element id via `info.get(id)`, which calls into WASM to
hash the id and look up the computed bounds via Clay_GetElementData().
A single WASM export handles the lookup — no tables or globals.
Uses the typedef struct infrastructure for BoundingBox field offsets.
Restructures the Op type so the discriminant field is `directive`
instead of `id`, freeing `id` for the element identity string. The
`name` parameter on `open()` and `OpenElement` becomes `id`, aligning
with Clay's terminology.
Drops the `idx++` seed from Clay_HashString — element IDs are now
hashed with seed 0 and uniqueness is the caller's responsibility.
Duplicate IDs within a frame are undefined behavior.
Removes INV-7 (element identity disambiguation) from the spec and
updates Sections 8.3.1, 9.3, and 10.3 accordingly.
Closes #16
Separate the combined spec into two documents aligned with INV-8
(architectural independence of rendering and input parsing):
- renderer-spec.md: rendering contract, directive model, rendering
modes (cursor update + line mode), pointer hit-testing
- input-spec.md: input parser API, scan model, InputEvent types
Also adds normative specification of cursor update mode (default)
and line mode with row offset to the renderer spec.
- Replace "descriptor" terminology with "directive" throughout
- Rename open() `name` parameter to `id` in spec
- Fix buffer diffing description: cells are copied, not swapped
- Add note that pointer hit detection requires render loop participation
- Reframe border-layout interaction as Clay's intended behavior
- Update WASM loading to reflect inlined base64 binary
- Move output buffer lifetime guarantee to normative section
- Clarify pack() is internal, validate() is public API
Add `{ clear?: boolean }` option to `ALTSCREEN()` and
`alternateBuffer()`. When `clear` is false, uses xterm private mode 47
to switch without clearing the alternate buffer contents.
Closes #13
Rename csi.ts to termcodes.ts and add ESC(), SHOWCURSOR(),
HIDECURSOR(), ALTSCREEN(), and MAINSCREEN() helpers. Make
CursorEvent.row/column 1-based to match DSR native format.
Replace all raw escape sequences in the demo with termcodes.
Use DECSC/DECRC (ESC 7/8) for cursor save/restore instead of
SCO (CSI s/u).
Move the row offset from a constructor parameter to a render-time
option. Row is now 1-based (matching ECMA-48 DSR/CPR format) so
callers can pass the queried cursor position directly without
conversion. Remove line mode from the inline region demo in favor
of raw newline allocation followed by CUP rendering for all frames.
The rgba() function returns signed int32 when alpha >= 128 (bit 31
set). The validator's u32 type rejected these negative values. Add
a color type that accepts the full signed-to-unsigned 32-bit range.