Commit Graph

139 Commits

Author SHA1 Message Date
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
Julien Calixte
9d24f6e89e 2026-05-16 00:41:33 2026-05-16 00:41:33 +02:00
Julien Calixte
1aa1d0e3cf docs(roadmap): clarify hybrid line-number behaviour for v0.2
Spell out the Normal-vs-Insert distinction (relative with current line
absolute / absolute everywhere) so it's clear the gutter behaves like
Neovim's number+relativenumber combo, not flat absolute numbering.
2026-05-16 00:40:07 +02:00
Julien Calixte
3c825d8612 feat(quality-house): connect perception markers with profile lines
Each product now gets a profile line across all WHATs using the same
colour and dash pattern its legend entry already advertises, so the
shape of each competitor's strengths/weaknesses is readable at a glance
instead of having to mentally connect the dots.
2026-05-16 00:39:50 +02:00
Julien Calixte
852b7d8de0 fix(quality-house): give HOW labels and perception title room to breathe
Raise the header zone (qfdHdrH 3.2 → 4.2) so rotated HOW labels stop
crossing into the roof diamond grid, and wrap the perception title onto
two lines via text width so it stays inside its zone instead of bleeding
left over the H14/H15 column labels.
2026-05-16 00:32:35 +02:00
Julien Calixte
c716bdb379 fix: save to local for the mvp 0.1 2026-05-16 00:28:53 +02:00
Julien Calixte
c702ba83d8 docs(qfd,quality-house): make quality-house.md own §3 matrix and §4 roof
Drop the duplicated 13x15 strength matrix and 15x15 roof tables from
qfd.md; the same data already lives in quality-house.md's TikZ source.
qfd.md §3/§4 keep the narrative reading (priority list, conflict list)
and point to quality-house.md for the cells and basement sums. Both
files' regenerate/maintenance notes flipped to reflect the new contract.
2026-05-16 00:23:15 +02:00