Compare commits

...

2 Commits

Author SHA1 Message Date
Julien Calixte
6af959f92d feat(case): cut an FPC ribbon relief into the bracket frame
Gap in the left frame member aligned with the body's FPC clearance so
the flex folds back through the bracket plane into the cavity instead
of being pinched. Refresh renders and the bracket alt-text.
2026-07-11 09:27:25 +02:00
Julien Calixte
757dd492b9 docs: trim AI writing tells from READMEs and docs prose
Drop magic adverbs (silently, arguably), a stakes-inflation flourish,
and the bold-first Snippets bullets; de-duplicate the "usable artifact,
not a checkpoint" line shared by the README and roadmap.
2026-07-11 09:19:58 +02:00
13 changed files with 36 additions and 29 deletions

View File

@@ -91,9 +91,9 @@ around, not against:
## Roadmap
Frequent releases. Each version is a usable artifact, not a checkpoint.
Per-version scope, current `[x]`/`[~]` marks, and the Macroplan source live in
[`docs/roadmap.md`](docs/roadmap.md).
Releases are frequent, and every version is a usable artifact rather than a
checkpoint. Per-version scope, current `[x]`/`[~]` marks, and the Macroplan
source live in [`docs/roadmap.md`](docs/roadmap.md).
| Version | Theme | One-liner |
| ------------------------------------------------------- | ------------ | -------------------------------------------- |

View File

@@ -17,7 +17,7 @@ Sitting with that, here's the concern I couldn't shake:
The reframing question: **what is the user actually waiting for?** For `Ctrl-S`, the moment that matters is "my work is saved" — and the SD card completes the write in 50200 ms. Save = safe. Same instant.
For `Ctrl-G`, the equivalent moment isn't "push complete." It's "commit landed locally" — which happens at ~0.2 seconds, well before the push even starts. From that moment on, your work is preserved across power loss, SD removal, the apocalypse — everything except remote delivery. The remaining 510 seconds is _transport of an already-safe thing_.
For `Ctrl-G`, the equivalent moment isn't "push complete." It's "commit landed locally" — which happens at ~0.2 seconds, well before the push even starts. From that moment on, your work is preserved across power loss and SD removal — everything except remote delivery. The remaining 510 seconds is _transport of an already-safe thing_.
Surface that moment in the side panel at ~0.2 seconds (`✓ committed abc1234 · pushing…`) and the perceived latency of `Ctrl-G` collapses from 10 seconds to roughly 200 milliseconds. The gap with `Ctrl-S` disappears.

View File

@@ -51,7 +51,7 @@ runs **SD-only** (see "EPD bus lock" below).
against marginal signal integrity.
3. Verified the card on the Mac: `Windows_FAT_32 TYPOENA`, 33.6 GB partition on
a 133 GB card, **healthy and readable**. Rules out a dead card / wrong FS.
4. Read the esp-idf SD init source: the CMD8 handler *silently tolerates* the
4. Read the esp-idf SD init source: the CMD8 handler *tolerates* the
same `ESP_ERR_NOT_SUPPORTED` (treats it as "not a v2 card"), while CMD59's
does not. So the failure might be a persistent bad response, not a CMD59
one-off — needed the raw R1 bytes to tell.

View File

@@ -80,7 +80,7 @@ Implementation notes that carry into the real module:
## What it does *not* prove — the next gate
The risk moved **with** the kill-switch, and arguably got harder. ADR-004 chose
The risk moved **with** the kill-switch and got harder. ADR-004 chose
gix *specifically to avoid* libgit2's C cross-compile to xtensa; falling back to
libgit2 re-introduces exactly that. The open question is now:

View File

@@ -245,28 +245,27 @@ engine remain (snippets are net-new scope, added 2026-07-08).
(Zed-inspired, but no completion popup: e-ink's ~630 ms refresh rules out
a live filtering menu, and it fights the distraction-free premise). Shape,
mirroring the existing `list_marker` insert-transform:
- [ ] **Trigger:** Tab in Insert mode. If the word immediately before the
caret matches a snippet prefix, expand it; otherwise insert spaces as
today (`expand_snippet(word) -> Option<(body, stops)>`, alongside
- [ ] Tab in Insert mode triggers expansion: if the word immediately before
the caret matches a snippet prefix, expand it; otherwise insert spaces
as today (`expand_snippet(word) -> Option<(body, stops)>`, alongside
`list_marker`).
- [ ] **Body syntax:** literal text + numbered empty tab stops `$1 … $n` and a
final `$0`. **No placeholder text** (`${1:label}`) — the editor has no
selection/overtype model, so a placeholder would just be text to delete.
**No dynamic/computed values** (e.g. no `date` — there's no RTC; the
wall clock is valid only after Wi-Fi+SNTP, so it'd stamp 1970 on a cold
boot).
- [ ] **Tab-stop session:** after expansion the caret lands on `$1`; Tab
advances to the next stop, **forward only** (no Shift-Tab). Stored stop
offsets shift with edits at the caret (all pending stops are always
after it). Session auto-aborts on Esc, a mode change, or a motion that
leaves the stops.
- [ ] **Indicator:** on a typing pause (same throttle as the insert cursor /
word-count refresh — the panel never repaints per keystroke), if the
word before the caret is a snippet prefix, the **side panel** shows the
hint (the target expansion). Quiet while typing; hint appears on pause.
- [ ] **Source:** snippet table hard-coded in the binary to start; a
git-syncable file on SD (`/sd/repo/.snippets`) is a later option,
deferred while SD is still blocked.
- [ ] A snippet body is literal text plus numbered empty tab stops `$1 … $n`
and a final `$0`. There is no placeholder text (`${1:label}`) — the
editor has no selection/overtype model, so a placeholder would just be
text to delete. There are no dynamic or computed values either (e.g. no
`date` — there's no RTC; the wall clock is valid only after Wi-Fi+SNTP,
so it'd stamp 1970 on a cold boot).
- [ ] After expansion the caret lands on `$1`; Tab advances to the next stop,
forward only (no Shift-Tab). Stored stop offsets shift with edits at the
caret (all pending stops are always after it). The session auto-aborts
on Esc, a mode change, or a motion that leaves the stops.
- [ ] On a typing pause (same throttle as the insert cursor / word-count
refresh — the panel never repaints per keystroke), if the word before
the caret is a snippet prefix, the side panel shows the hint (the target
expansion). Quiet while typing; the hint appears on pause.
- [ ] The snippet table is hard-coded in the binary to start; a git-syncable
file on SD (`/sd/repo/.snippets`) is a later option, deferred while SD
is still blocked.
- [ ] Starter set: link `[$1]($2)$0`, image `![$1]($2)$0`, fenced code block,
etc.

View File

@@ -101,7 +101,7 @@ foam+bracket; the bracket is what stops it dropping _into_ the cavity
![Midline section: glass clamped between the front lip and the rear foam + bracket; the internal FPC clearance is hidden below the left bezel, standoffs on the cavity floor](renders/section.png)
![The screwed bracket — four corner holes, window clears the active area](renders/bracket.png)
![The screwed bracket — four corner holes, window clears the active area, and a gap in the left edge lets the FPC fold back into the cavity](renders/bracket.png)
### Boards (the baseplate is the chassis)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -232,7 +232,15 @@ module bracket() {
ow = P_w + 18; oh = P_h + 18;
difference() {
linear_extrude(bracket_t)
difference() { rrect(ow, oh, 4); rrect(A_ap_w+2, A_ap_h+2, 2); }
difference() {
rrect(ow, oh, 4);
rrect(A_ap_w+2, A_ap_h+2, 2);
// ribbon (FPC) relief: a gap in the LEFT frame member, lined up
// with the body's FPC clearance so the flex can fold back through
// the bracket plane into the cavity instead of being pinched
translate([-(ow + A_ap_w+2)/4, 0])
square([(ow - (A_ap_w+2))/2 + 4, fpc_w], center=true);
}
for (bx=[-(P_w/2+5), P_w/2+5], by=[-(P_h/2+5), P_h/2+5])
translate([bx, by, -1]) cylinder(h=bracket_t+2, r=1.45); // M2 clear
}