Commit Graph

195 Commits

Author SHA1 Message Date
Julien Calixte
a848c05afa docs: redesign v0.1 screen as side panel + writing column
Replace the header/status-bar layout with a full-height writing column
plus an always-visible side panel holding all metadata. Canonicalize the
new region vocabulary in CONTEXT.md (Writing column, Side panel) and retire
header / status line / edit area as terms-to-avoid.

Consequent sweeps: rewrite the Error UX section in side-panel terms and
give keyboard-disconnect a home (⌨ ✗, disconnect-only); drop the "line N"
readout; reconcile the render module ops and region shadow; sweep the
status-line/edit-area wording across the technical, roadmap, qfd, notes,
README, and ADR-003 docs (incl. the ~11→~13 line-count figure).
2026-07-05 17:27:25 +02:00
Julien Calixte
d3fd6f6ed1 fix(docs): open v0.1 working file from /sd/repo not /sd/local
The product doc opened notes.md from /sd/local, the permanently-private
scope where Publish is unavailable — contradicting the headline Ctrl-G
flow and every other doc. Point it at the Tracked working copy.
2026-07-05 17:26:00 +02:00
Julien Calixte
c12539d933 docs(firmware): record Spike 6 Wi-Fi + TLS verification 2026-07-05 09:22:36 +02:00
Julien Calixte
f8a4d53851 feat(firmware): add Wi-Fi + TLS spike (Spike 6)
Standalone `wifi_tls` binary: station assoc, SNTP, then a validated
HTTPS GET to api.github.com against the esp-idf cert bundle. Gates
Spike 7 (gitoxide push). Creds come from firmware/.env via build.rs.
2026-07-05 09:22:31 +02:00
Julien Calixte
a1f58b7953 docs(firmware): document the vim modal editor 2026-07-05 01:41:34 +02:00
Julien Calixte
0665f2d5fb feat(firmware): add vim text objects and the change operator
Generalise the normal-mode command state machine into d/c operators that
compose with motions (dw, d$, …), doubled forms (dd, cc), and text
objects: iw/aw plus nesting-aware bracket pairs (i(, a{, …) and quotes
(i", i'). ciw/daw/di( and friends now work; pending op/object shows in
the status strip.
2026-07-05 01:41:23 +02:00
Julien Calixte
c88389b623 chore: update package meta data 2026-07-05 01:31:33 +02:00
Julien Calixte
00b57bac55 perf(firmware): window partial refresh to the edited rows
Per keystroke, diff the new frame against the last shown one to find the
changed row band and partial-refresh only those rows instead of all 272.
E-paper update time scales with the gate rows driven, so a single edited
text line refreshes far faster. Windowed in Y only (full width, both
controllers), so the seam/mirroring logic is unchanged. Also drop the
periodic full refresh to every 64 updates — the panel stays visually
clean, so it's now mainly for longevity.
2026-07-05 00:08:14 +02:00
Julien Calixte
17fd663c85 docs(firmware): record Spike 5 partial refresh + typing 2026-07-05 00:00:16 +02:00
Julien Calixte
25665561cd feat(firmware): type on the e-paper panel with partial refresh
Spike 5 — first spike where keyboard input and panel output run
together. usb_kbd changes from a blocking run() into start(): it brings
the USB host stack up on background threads and pushes edge-detected,
US-layout-translated key-downs onto a queue drained via next_key().
main.rs owns the panel, maintains a wrapped/scrolling text buffer, and
partial-refreshes per keystroke batch with a periodic full refresh to
clear ghosting. Logs per-refresh latency.
2026-07-05 00:00:11 +02:00
Julien Calixte
784dcb7666 feat(firmware): add partial refresh to the EPD driver
display_frame_partial writes the new image to bank 0x24, runs GxEPD2's
partial waveform (_Update_Part: 0x3C/0x80, 0x21/0x00,0x10, 0x22/0xFF,
0x20), then syncs bank 0x26 so the next partial has a correct baseline.
Like GxEPD2 for this dual-controller panel, the update covers the full
panel with the partial waveform — no windowing, since the waveform time
dominates. Much faster than a full refresh and without the flashing.
2026-07-05 00:00:02 +02:00
Julien Calixte
9bbcf6d4ed docs(firmware): record Spike 4 USB host keyboard verification 2026-07-04 19:28:59 +02:00
Julien Calixte
8b71e0d9ec feat(firmware): read keycodes from a USB HID boot keyboard
Spike 4. Drive the ESP-IDF USB Host Library directly through the raw
esp-idf-sys bindings (the convenience HID class driver is a managed
component not vendored in mainline, and a boot keyboard doesn't need
it). On attach, src/usb_kbd.rs enumerates the device and dumps its
descriptors, claims the boot-keyboard interface, sends SET_PROTOCOL(boot)
and SET_IDLE(0), then polls the interrupt-IN endpoint and decodes each
8-byte report into modifiers + keycodes logged over UART.

main.rs becomes the Spike 4 harness; the epd module is kept compiled
(allow(dead_code)) so it doesn't bit-rot. Verified on hardware with a
19f5:3255 keyboard: letters, digits, modifiers, and rollover all decode.
2026-07-04 19:28:53 +02:00
Julien Calixte
00a852b8c8 docs(firmware): record Spike 2 EPD verification and build stamping 2026-07-04 18:58:47 +02:00
Julien Calixte
6145d27405 feat(firmware): drive GDEY0579T93 EPD via dual-SSD1683 driver
Add a thin dual-SSD1683 driver (src/epd.rs, ported from GxEPD2's
GxEPD2_579_GDEY0579T93) for the 792x272 e-paper panel: reset/init,
RAM addressing, the split-and-mirror full-frame blit across the
master/slave seam at x=396, and full-refresh waveform. Frame
implements embedded-graphics' DrawTarget.

Replace the Spike 1 blink harness in main.rs with the Spike 2 test:
SPI at 4 MHz over SCK 12 / DIN 11 / CS 7 / DC 6 / RST 5 / BUSY 4,
alternating normal/inverted frames with a seam-straddling circle,
"Typoena", and the build tag. Verified on hardware 2026-07-04.
2026-07-04 18:58:42 +02:00
Julien Calixte
d971f36f10 chore(firmware): stamp builds with UTC time and git hash
Emit BUILD_TIME and BUILD_GIT (git describe --always --dirty) as
rustc env vars so the running firmware can identify itself on serial
and on-panel. A rerun-if-changed on a nonexistent file forces the
script every build, keeping the timestamp fresh. Bring-up lesson:
know which build you're diagnosing.
2026-07-04 18:58:33 +02:00
Julien Calixte
dd63c574f5 docs(firmware): add v1.0 pinout diagram and record verified blink
The bench board is a DevKitC-1 v1.0 (RGB LED on GPIO 48), not the v1.1
layout (GPIO 38). Vendor the official v1.0 pinout diagram under docs/ and
reference it from the README so the pinout is pinned offline, and fold in
the 2026-07-04 on-hardware blink verification note.
2026-07-04 17:30:18 +02:00
Julien Calixte
e91f3be26e feat(firmware): blink on-board WS2812 alongside GPIO 2
The DevKitC-1 has no discrete LED on GPIO 2, so the Spike 1 blink was
invisible without external wiring. Drive the on-board addressable LED
(WS2812 on GPIO 48) each cycle for visible confirmation on the bench.
2026-07-04 16:49:14 +02:00
Julien Calixte
6d573b3b6d chore(firmware): add justfile wrapping common build/flash commands 2026-07-04 16:36:56 +02:00
Julien Calixte
edcae88476 chore(zed): pin rust-analyzer for firmware crate
Zed's bundled rust-analyzer calls `cargo metadata --lockfile-path`,
which is still gated behind `-Z unstable-options` on cargo 1.95.0
(both stable and the esp Xtensa fork). Workspaces fail to load with
the bundled binary.

Point lsp.rust-analyzer.binary.path at the rustup-managed
rust-analyzer (version-locked to cargo 1.95 stable, no unstable
flags). Also set cargo.target = xtensa-esp32s3-espidf with
allTargets=false so RA doesn't try to check the crate for the host
target — esp-idf-sys can't build for macOS.
2026-05-23 14:36:59 +02:00
Julien Calixte
55ba0db0f6 chore(firmware): scaffold Spike 1 Blink crate
Generated from esp-rs/esp-idf-template for the ESP32-S3 std target.
src/main.rs toggles GPIO 2 every 500 ms and logs `blink N` over USB-
serial — the minimum bring-up surface called out in
docs/v0.1-mvp-technical.md (Spike 1: confirm toolchain, flash, and basic
GPIO). edition=2024 with rust-version=1.85.

No editor/render/git/usb/fs modules yet; those land per the spike
methodology when later spikes need them.
2026-05-23 14:36:51 +02:00
Julien Calixte
4bdcdd09ba chore(remanso): add IBM Plex Serif to font families 2026-05-21 18:40:58 +02:00
Julien Calixte
801860fafe docs(roadmap): brand v0.1 boot splash as Typoena 2026-05-21 00:36:36 +02:00
Julien Calixte
43eead0e23 docs(quality-house): drop reMarkable W1 perception 2→1
Latency is the dominant signal for W1 (sub-second response to typing)
and on a typing-focused device the reMarkable 2 + Type Folio's e-ink
delay disqualifies a 2. Updates the TikZ perception array, the table
row + rationale, and the totals narrative (reMarkable 45 → 44, ranking
unchanged).
2026-05-19 18:44:06 +02:00
Julien Calixte
572c83095b docs(quality-house): sync empty chassis to 14x14 after H14 retirement 2026-05-19 14:55:13 +02:00
Julien Calixte
db61a83f06 fix(qfd): correct §4 roof matrix size and glyph convention
Two stale bits in §4's preamble. (a) "15×15 roof matrix" still
referenced H14's pre-retirement column count — corrected to 14×14.
(b) The symbol legend named classical QFD glyphs (◎ ○ × ⊗) but
quality-house.md's roof actually renders ASCII (++ + − −−). Both
listings now lead with the ASCII glyphs that match the source of
truth, with classical equivalents kept in parens.
2026-05-19 14:52:43 +02:00
Julien Calixte
1c6dfec7e6 docs(readme): link GLOSSARY.md from intro and repo layout
GLOSSARY.md was reachable only via docs/qfd.md's §2 preamble.
Surfacing it from README adds two entry points: the intro and
software-stack pointers to docs/qfd.md now follow up with a link
to GLOSSARY.md (the ontology layers used across the docs), and
the repo-layout block lists GLOSSARY.md alongside CONTEXT.md so
the two glossaries' division of labour — device vocab vs
methodology vocab — is visible at a glance.
2026-05-19 14:51:29 +02:00
Julien Calixte
6dff2315c8 fix(quality-house): correct H10-H15 roof coord after H14 retirement
The H10-H15 mild conflict node still pointed at C-10-15 (H15's
pre-retirement column). H14's removal renumbered H15 to column 14,
so the roof coordinate becomes C-10-14. Missed in the earlier
sweep — comment line already says "H10-H15" so the intent was
unchanged, only the cell coord was stale.
2026-05-19 14:51:17 +02:00
Julien Calixte
b85bb27a9b docs(qfd): introduce Functions layer and GLOSSARY.md ontology
The doc previously conflated functions (transformations the device
performs) with characteristics (measurable attributes). Surfacing
Functions as their own ontology layer makes HOW names — which pack
a function reference plus an attribute — readable without function
definitions staying implicit.

- new GLOSSARY.md at root: 5-layer ontology stack (WHAT / Function /
  Characteristic / Metric+Unit / Target), peer to CONTEXT.md
  (device-specific vocabulary)
- qfd.md §2 opens with a Functions inventory (Type, Save, Publish,
  Recover, Boot, Provision); Render and Reconnect noted as
  sub-functions; Provision flagged as build-time-only in v0.1
- H1 "Keypress → glyph latency" → "Type latency (keypress → glyph)"
- H4 "Cold boot → cursor ready" → "Boot latency (cold)"
  (the arrow transformation moves to the Functions inventory; the
  parenthetical keeps the residual qualifier)
- cascade through §3 priority list, §6 critical-performance-budget
  rows for H1/H4, §8 inconsistencies, and quality-house.md TikZ
  column labels

Matrix cell strengths held; no Σ recompute.
2026-05-19 14:45:12 +02:00
Julien Calixte
8a223e7837 docs(qfd): retire H14 from HOWs
Module count / public-API surface is a static source-code property,
not a runtime function nor an artifact characteristic like H10 binary
or H15 build time. It was a refactor-leverage proxy for W9 — proxies
of proxies belong in the ADRs and the component matrix, not in the
HoQ. Removed from §2, §5 matrix, §4 conflict list, and the C12
overloaded-list mention; basement Σ total drops 1674 → 1557 so rel%
recomputed in quality-house.md.
2026-05-19 11:46:07 +02:00
Julien Calixte
2aa194bdb9 fix(quality-house): drop tex fences shikiji can't load 2026-05-18 15:26:56 +02:00
Julien Calixte
7e2d6eddc5 docs(quality-house): add empty training chassis 2026-05-18 15:06:27 +02:00
Julien Calixte
aa9f3f60ff 2026-05-17 15:22:05 2026-05-17 15:22:05 +02:00
Julien Calixte
e79101d841 docs(notes): add setup context before the Ctrl-G concern 2026-05-17 13:01:44 +02:00
Julien Calixte
bf36c01502 docs(notes): trim Ctrl-G essay to its core (question + apocalypse)
The post's job is to land the timing question and the apocalypse
reframe — Wi-Fi rationale, optimisation diversions, and generalising
reflections were overexpansion. Cut.
2026-05-17 13:00:31 +02:00
Julien Calixte
b7a0aa7c5c docs: add "Durability before delivery" principle to Publish UX
The user-meaningful moment of a Publish is when the local commit
lands (~0.2 s), not when the push completes (~5–10 s). New principle
in CONTEXT.md, instantiated in v0.1 product doc with staged status
transitions and a corrected on-demand Wi-Fi status example.
2026-05-17 12:54:09 +02:00
Julien Calixte
011f79f134 docs(notes): add Ctrl-G perceived-latency essay
Long-form rationale for the "durability before delivery" framing —
why a 10-second network operation in response to a single keystroke
doesn't have to feel slow. Establishes docs/notes/ as the home for
shareable design rationale (not authoritative spec).
2026-05-17 12:54:04 +02:00
Julien Calixte
d5f22c697c docs(v0.1-tech): switch Wi-Fi to on-demand model, off by default
Always-on station mode burns ~410 mAh/day on the radio alone; on-demand
drops that to ~25 mAh/day at 10 Publishes/day. Radio comes up on Ctrl-G
with a 10 s association timeout, holds for a ~90 s grace window after
each Publish, then tears down. SNTP cached up to 24 h to avoid
re-querying every Publish.

Also removes stale SoftAP provisioning bullets that contradicted the
"v0.1 has no provisioning module" stance later in the same doc.
2026-05-17 12:38:47 +02:00
Julien Calixte
cbdd6aa197 docs: lock device to one linear branch via Publish-is-sync principle
The user's mental model of Publish is a Google Doc backed by git, not a
curated commit log. Branches fall out of scope under that framing; the
device tracks one stream of work on whichever branch the remote was
cloned on, and never switches. Drops :Gbranch from v0.7 to match.
2026-05-17 12:38:36 +02:00
Julien Calixte
ffcd49588a style: apply oxfmt to docs (table padding, italic style) 2026-05-17 01:30:36 +02:00
Julien Calixte
1e1e59e716 docs(qfd): add W14 portability requirement
Captures "I can carry the device and write away from a desk" as a
distinct WHAT from W11 (multi-day battery), weight 8. Recomputed
basement Σ (1546→1674); H8 climbs #6→#3 in the §3 priority list as
its voter base widens to include W14, and H12 enters the top six at
#4. §6's "(b) narrow voter base" override for H8 is retired and a new
§7 ADR-008 vs W11+W14 unresolved-conflict bullet records that wall
power in v0.1 now disappoints two WHATs, not one.
2026-05-17 01:29:53 +02:00
Julien Calixte
b0169690c4 docs(quality-house): drop reMarkable W1 to 2 after firsthand test
reMarkable 2 with Type Folio tested less responsive than Freewrite Smart
Typewriter (Sailfish). With Smart at 3, reMarkable drops one notch to 2.
Total: reMarkable 42 → 41, now tied with Smart at 41.
2026-05-16 14:38:01 +02:00
Julien Calixte
059da87695 docs(quality-house): extend Sailfish rescore to Smart Typewriter
Sailfish ships on Smart Typewriter Gen 3 as well as Traveler, so the
same firmware-driven bumps apply: W1 2→3 (Smart still trails Traveler
by one notch on panel size), W5 3→4, W9 1→2. Smart total 38 → 41.
2026-05-16 14:27:59 +02:00
Julien Calixte
e152237477 docs: rename project to Typoena
Project gets a proper name. Replaces "Ours" / "Our product" placeholders
in the QFD perception zone and the working title "typewriter" in
README/CONTEXT headers and the npm name. "Typewriter" the category
noun (the writing-machine concept) stays unchanged — Typoena is the
brand, typewriter is the category. SoftAP SSID typewriter-setup and the
repo directory are deliberately left as-is.
2026-05-16 14:21:32 +02:00
Julien Calixte
52845849c1 docs(quality-house): note Freewrite Sailfish firmware and rescore W1/W5/W9
The Sailfish firmware (2025-11-19) rewrote the Freewrite Traveler OS in
Rust, cut keystroke latency 40–100 %, and trimmed power draw -30 %
typing / -50 % idle. Three rows are bumped: W1 3→4, W5 3→4, W9 1→2.
Freewrite now ties reMarkable at 42; Pomera still #2 at 45.
2026-05-16 14:17:52 +02:00
Julien Calixte
9573c08bad fix(quality-house): shrink Freewrite Smart marker so Traveler shows through 2026-05-16 12:53:29 +02:00
Julien Calixte
5e476a9651 docs(quality-house): add Freewrite Smart Typewriter to perception zone 2026-05-16 11:21:29 +02:00
Julien Calixte
8b161cc808 fix(quality-house): raise header height so HOW labels clear the roof 2026-05-16 01:27:02 +02:00
Julien Calixte
07bb0edcba fix(quality-house): compute WHAT-label width via pgfmath
text width={\qfdWhatW - 0.2}cm doesn't parse — the braces don't
evaluate the arithmetic, so TikZ sees "4.6 - 0.2cm" which isn't a
valid dimension. Pre-compute the narrower width with
\pgfmathsetmacro and reference the resulting macro instead.
2026-05-16 01:20:03 +02:00
Julien Calixte
3a4bd3db18 fix(quality-house): keep WHAT labels inside their column
Text box anchored at qfdLeftEdge + 0.1 with width qfdWhatW overflowed
0.1 cm past the cell's right edge into the Weight column, clipping
trailing words like "the", "lag,", "hob-". Shrink the box by 0.2 cm
so it has 0.1 cm clearance on both sides.
2026-05-16 01:05:17 +02:00