Skip to content

Commit 6c78677

Browse files
authored
Merge pull request #5 from thefrontside/docs/add-clayterm-spec
Add Clayterm current-state specification
2 parents a6b1ee1 + e75b49a commit 6c78677

2 files changed

Lines changed: 982 additions & 0 deletions

File tree

specs/input-spec.md

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# Clayterm Input Specification
2+
3+
**Version:** 0.1 (draft) **Status:** Current-state specification. Descriptive
4+
for the input parsing surface.
5+
6+
---
7+
8+
## 1. Purpose
9+
10+
This specification describes Clayterm's terminal input parsing surface: the API
11+
for decoding raw terminal byte sequences into structured events.
12+
13+
Input parsing is architecturally independent from rendering (see
14+
[Renderer Specification](renderer-spec.md), INV-8). The two concerns share a
15+
compiled WASM binary for loading efficiency, but neither depends on the other's
16+
state, types, or API surface.
17+
18+
This specification is currently non-normative. The input API has clear design
19+
intent but has undergone more revision than the rendering core and faces known
20+
upcoming forces that will reshape it (Kitty progressive enhancement field
21+
surfacing, terminfo binary parsing). It is written to document the current
22+
surface and guide future stabilization.
23+
24+
---
25+
26+
## 2. Scope
27+
28+
### In scope (descriptive)
29+
30+
- The input parser creation and lifecycle
31+
- The scan API and its return type
32+
- The `InputEvent` discriminated union and its variants
33+
- The ESC timeout resolution model
34+
35+
### Out of scope
36+
37+
- Rendering (see [Renderer Specification](renderer-spec.md))
38+
- Pointer hit detection (owned by the render loop; see Renderer Specification,
39+
Section 12.4)
40+
- Higher-level event routing, focus management, or keybinding systems
41+
42+
---
43+
44+
## 3. Terminology
45+
46+
**Input parser.** A WASM-backed instance that accepts raw terminal bytes and
47+
produces structured events. Each parser maintains its own internal state for
48+
multi-byte sequence buffering and ESC timeout tracking.
49+
50+
**Scan.** A single invocation of the parser. The caller provides raw bytes (or
51+
no bytes, for timeout resolution), and the parser returns any events it can
52+
produce along with pending-timeout information.
53+
54+
**InputEvent.** A discriminated union representing a single parsed terminal
55+
event. Discriminated on a `type` field.
56+
57+
---
58+
59+
## 4. Input Parser API
60+
61+
### 4.1 Parser creation
62+
63+
```
64+
createInput(options?): Promise<Input>
65+
```
66+
67+
Creates an input parser instance. The returned promise resolves when the WASM
68+
module is ready.
69+
70+
Options:
71+
72+
- **`escLatency`** — Milliseconds to wait before resolving a lone ESC byte as
73+
the Escape key. Default: 25ms. This controls the tradeoff between
74+
responsiveness (lower values) and correct disambiguation of ESC-prefixed
75+
sequences (higher values).
76+
77+
- **`terminfo`** — A `Uint8Array` of raw terminfo binary. Accepted but C-side
78+
parsing is not yet implemented.
79+
80+
### 4.2 Scan
81+
82+
```
83+
input.scan(bytes?: Uint8Array): ScanResult
84+
```
85+
86+
Feeds raw terminal bytes into the parser and returns parsed events. The `bytes`
87+
parameter is optional; calling without arguments triggers a rescan for ESC
88+
timeout resolution.
89+
90+
The parser is synchronous: it processes all provided bytes in a single call and
91+
returns immediately.
92+
93+
### 4.3 ScanResult
94+
95+
```
96+
{ events: InputEvent[], pending?: { delay: number, deadline: number } }
97+
```
98+
99+
- **`events`** — An array of parsed events produced from the provided bytes (and
100+
any previously buffered bytes that could now be resolved).
101+
102+
- **`pending`** — When present, indicates that an ambiguous ESC byte is buffered
103+
and the parser cannot yet determine whether it begins an escape sequence or is
104+
a standalone Escape keypress. The caller SHOULD schedule a rescan (calling
105+
`scan()` with no arguments) after the indicated delay. The `delay` field is a
106+
relative duration in milliseconds. The `deadline` field is an absolute
107+
timestamp (milliseconds since epoch) for the same point in time.
108+
109+
---
110+
111+
## 5. InputEvent Types
112+
113+
The `InputEvent` discriminated union is discriminated on a `type` field. The
114+
current variants are:
115+
116+
- **`KeyEvent`** (`type: "keydown" | "keyup" | "keyrepeat"`) — A keyboard event
117+
for special keys, control sequences, and modifier combinations. Fields include
118+
`key` (logical key name), `code` (physical key identifier), and modifier flags
119+
(`shift`, `ctrl`, `alt`, `meta`).
120+
121+
- **`MouseEvent`** (`type: "mousedown" | "mouseup"`) — A mouse button press or
122+
release. Fields include `x`, `y` (cell coordinates), `button`, and modifier
123+
flags.
124+
125+
- **`WheelEvent`** (`type: "wheel"`) — A scroll event. Fields include `x`, `y`,
126+
and scroll direction.
127+
128+
- **`ResizeEvent`** (`type: "resize"`) — A terminal resize notification. Fields
129+
include `columns` and `rows`.
130+
131+
The discriminant values and the type splits are deliberate design decisions.
132+
However, the field sets within each variant are expected to grow when Kitty
133+
progressive enhancement types are surfaced in the TypeScript layer (the C struct
134+
has already been extended with fields that are not yet mapped to the TS types).
135+
136+
---
137+
138+
## 6. Deferred / Future Areas
139+
140+
_These topics are explicitly excluded from this specification. Their omission is
141+
intentional, not an oversight._
142+
143+
**Full Kitty progressive enhancement event types.** The C-side input parser
144+
struct has been extended for progressive enhancement fields. The TypeScript
145+
event types have not been updated to surface them.
146+
147+
**Terminfo binary parsing.** The input API accepts a `terminfo` option, but
148+
C-side parsing is not implemented.
149+
150+
**Whether input parsing should be a separate package.** Architecturally
151+
independent from the renderer but currently co-located. The distribution
152+
decision is open.
153+
154+
---
155+
156+
## Open Decisions
157+
158+
1. **What are the normative Kitty progressive enhancement event types?** The
159+
C-side struct has been extended. The TypeScript types have not been updated.
160+
This specification does not attempt to predict the final shapes.
161+
162+
2. **Should the input API be a separate package?** It is architecturally
163+
independent from the renderer (INV-8) but currently co-located in the same
164+
module.
165+
166+
3. **Is the input API ready for normative specification?** The API has clear
167+
design ownership but has undergone more revision than the rendering core.
168+
This specification documents the current surface without freezing it.

0 commit comments

Comments
 (0)