Skip to content

Commit 35eb9c4

Browse files
committed
v2.13.0 — Per-account container-weight calibration: the bundled catalogue carries manufacturer empty-weights, and a user who actually weighs their spool can now correct the figure from a dedicated modal (container shown large, a guided "how to measure" equation that adapts to the container type — a Masterspool keeps its cardboard core, other types do not — a catalogue-vs-yours comparison that follows the field as you type, and a choice of whether the spools already using that container adopt the new value, twin-mirrored and only written where the weight actually differs). Stored in a new owner-only users/{uid}/containerOverrides/{containerId} doc and applied over the bundled JSON at read time via containerFind(), the single accessor every consumer already routes through — the shipped catalogue is never modified and no migration was run. The fully-digital tier is now DISPLAYED as "TigerData" (was "TigerCloud") across the badge, stat tile, encode title, quick-filter, 9 locales, docs and the browsable What's New history — while the stored protocol value, the filter comparison and the backend byProtocol key deliberately stay "TigerCloud", since renaming them would silently orphan the tier for every existing spool. The three tier badges were rebuilt as one family reading white → silver → gold, all clearing WCAG AA (TigerTag was a grey pill on a grey card, effectively invisible; TigerTag+ moved off the app's action orange). New npm run docs:check validator fails the commit when a doc restates a number the code owns and drifts — llms.txt had reached v1.8.2 / 12k lines / 5 brands against a real 2.12.0 / 28.5k / 6. New assets-src/ holds full-resolution masters outside the build (brand/ folded into it). Fixes: custom links were never stored (the write skipped the product identity and the optimistic update, so the link vanished on save); the custom-colour pencil turned invisible on a pale swatch; stepper − / + buttons did not fill their control.
1 parent 01a76a2 commit 35eb9c4

40 files changed

Lines changed: 1731 additions & 260 deletions

‎.githooks/pre-commit‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@ if git diff --cached --name-only | grep -qE '^(renderer/(inventory\.js|CODEMAP\.
5959
node scripts/check-codemap.mjs
6060
fi
6161

62+
# ── Documentation drift ───────────────────────────────────────────────
63+
# Some docs restate numbers that live in the code (version, renderer line
64+
# count, printer-brand count, i18n key count) and quietly rot — llms.txt,
65+
# which agents read first, once claimed v1.8.2 / 12k lines / 5 brands while
66+
# the app was at v2.12.0 / 28.5k / 6. Also flags doc references to paths
67+
# that no longer exist. Only derivable facts are checked, never prose.
68+
# Runs whenever a doc or one of the files it describes is staged.
69+
if git diff --cached --name-only | grep -qE '^(llms\.txt|README\.md|FEATURES\.md|CLAUDE\.md|AGENT\.md|package\.json|renderer/(inventory\.js|locales/en\.json)|renderer/(css|printers)/)'; then
70+
node scripts/check-docs-drift.mjs
71+
fi
72+
6273
# Add more checks here. Examples:
6374
# • lint
6475
# • formatter

‎CHANGELOG.md‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,40 @@ Versions follow [Semantic Versioning](https://semver.org/).
55

66
---
77

8+
## v2.13.0 — 2026-07-19
9+
10+
### Added
11+
12+
- **Per-account container-weight calibration.** The bundled catalogue (`data/container_spool/spools_filament.json`) carries manufacturer empty-weights; a user who actually weighs their spool can now correct the figure. A pencil sits to the LEFT of the weight in the "Choose a container" side-card (discreet until the row is hovered) and opens a dedicated **calibration modal** (`#cwModalOverlay`): the container shown large (photo + brand/type), the value as a grouped `[− value +]` stepper with the unit inside, a "How to measure" strip, an amber strip naming how many spools inherit the weight, a catalogue-vs-yours comparison whose right-hand figure follows the field as you type, and a save-mode choice.
13+
- Stored in a NEW **`users/{uid}/containerOverrides/{containerId}`** doc (`{ containerWeight, updatedAt }`; owner-only rule added to `firestore.rules` and deployed) and applied over the bundled JSON **at read time — the JSON is never modified**.
14+
- Resolution happens in `containerFind()`, the single accessor every consumer already routes through, so the corrected weight reaches the picker, the detail panel and future spool writes at once.
15+
- Each spool stores a *snapshot* of the weight it was given, so a correction does not reach existing spools on its own. The **"When saving"** choice ("Update all N spools with this value" — the default — or "Keep current spool values") is offered before committing rather than as a second screen; the alignment runs after the dialog closes and is twin-mirrored so both chips of one physical spool stay in agreement. It only writes to spools whose weight actually differs, so leaving it on when nothing changed costs nothing. Shown/hidden **once on open** rather than live against the typed value: a live gate resized the modal mid-typing.
16+
- The **"How to measure" strip** reads as an equation — the container's photo **+** the cardboard core **=** the scale. The middle term and its joint drop out for containers with no core (`type` ≠ Masterspool), the remaining joint flips `+` → `=` and the last step renumbers, so the equation stays true. Operators are plain white discs sitting as flex items *between* the cards; `margin: calc(-1 * (var(--op-size) + var(--how-gap)) / 2)` gives a disc a net flow width of exactly `-gap`, so the cards keep their spacing while the disc centres on the gap's midpoint (0.0000 px offset). New assets `oem_carton_core.png` and `oem_kitchen_scale.png`, cropped on an **alpha threshold of ~24, not 1** — a render's diffuse shadow carries a couple of alpha units across most of the canvas, so a threshold-1 trim framed a 1017×590 subject in a 1492×1023 box.
17+
- Picker rows became `div[role=button]` (a `<button>` cannot legally contain the edit `<button>`), with Enter/Space selection restored — `renderer/inventory.js`, `renderer/inventory.html`, `renderer/css/60-modals.css`, `renderer/css/70-detail-misc.css`, backend `firestore.rules`. i18n: 23 new keys × 9 locales.
18+
- **`npm run docs:check`** — a validator for the documentation facts that restate the code, wired into the pre-commit hook beside `i18n:check` and `codemap:check`. Several docs repeat numbers the code owns (version, renderer line count, printer-brand count, i18n key count, folder paths) and rot silently: `llms.txt`, the file an agent reads first, had reached **v1.8.2 / ~12 000 lines / 5 brands** against a real v2.12.0 / 28 500 / 6, with Anycubic missing from its protocol table entirely. It compares each stated fact to its source of truth (with tolerances where the number moves constantly), flags doc references to paths that no longer exist, skips templates and globs, and never reviews prose — `scripts/check-docs-drift.mjs`, `.githooks/pre-commit`, `package.json`, `CLAUDE.md`.
19+
- **`assets-src/`** — one versioned home for every full-resolution image that must never be bundled (`build.files` is an allowlist and does not list it), mirroring each asset's path under `assets/`. Optimising an asset in place destroys its original; this gives it somewhere to live first, so a later re-export starts from the master rather than an already-compressed file. **`brand/` was folded into it** and removed: both existed for the same reason, and the "does the app load it?" distinction was not worth a second folder — `assets-src/README.md`.
20+
- **`.circle-center`** — a utility for content optically centred in a round badge (`renderer/css/00-base.css`). `flex + align-items:center` drifts on numerals: it centres the *line box*, whose height includes ascender and descender, and a digit has no descender; an inherited line-height worsens it and monospace faces worst of all. The utility uses `place-items:center` on a grid, `line-height:1`, `tabular-nums` so a counter never widens between 1 and 11, and a `.06em` nudge for the half-descender digits never use.
21+
22+
### Changed
23+
24+
- **The fully-digital tier is now displayed as "TigerData"** (was "TigerCloud") — a **display-only** rebrand covering the spool badge, the header stat tile, the encode-flow title, the protocol quick-filter, `statCloud` / `productCloudCreated` in all 9 locales, README / `FEATURES.md` / `ROADMAP.md`, and the browsable What's New history (29 strings across 8 past versions — that modal is live UI, not an archive).
25+
- **The stored value stays `TigerCloud` wherever it is data**: the Firestore `protocol` field written by `normalizeRow` and `syncSpoolMirrors`, the stat tile's `filter: "TigerCloud"`, every filter comparison, and the backend's `byProtocol` map key. Renaming any of those would silently orphan the tier for every existing spool of every user; `docs/firestore-schema.md` now carries an explicit warning beside the field.
26+
- `populateOneQuickFilter` gained an optional `labelOf` projection so an option's **value** stays the stored string while its visible text changes.
27+
- Frozen records keep the original wording (`CHANGELOG.md`, `data/release-notes/*`, `DEVLOG.md`). Tiger Hub was updated in the same pass (separate repo); the backend repo is untouched and no data migration was run.
28+
- **The three tier badges reworked — order, geometry and colour.** Tiles now follow the capability ladder, **TigerData → TigerTag → TigerTag+**. The three share one capsule (18 px, fully rounded, 1 px hairline border, 10 px/650 type) and one construction borrowed from the wishlist buy button (`.lv-buy`): a top-lit vertical gradient, a matching border, dark type. Only the metal changes — white → silver → gold. `.tag-diy` was `--surface-2` on `--muted`, a grey pill on a grey card and effectively invisible; `.tag-plus` moved off orange, which frees the app's ACTION colour (a tier badge wearing the same orange as every button competed with every call to action); `.tag-cloud` dropped a purple picked years ago only to "differ from orange". All three clear **WCAG AA**. An earlier faux-metal pass (five-stop gradient + text-shadow) was abandoned: it simulated a material in an otherwise flat UI and read as dull beige at 10 px.
29+
- **The "Stock value" tile states whether it is excl. or incl. tax.** The figure already followed the account's HT/TTC preference but never named it, and the two readings differ by the VAT rate. Reuses the existing `reorderHT` / `reorderTTC` wording. It must sit on the tile's `label` (rendered as HTML) and not on `mini`, which is piped into a `data-mini` attribute — that attribute is now escaped so markup there can no longer break the card.
30+
- **The inventory's "Protocol" filter is labelled "Type"** in all 9 locales (`filterShortProtocol` plus the hardcoded HTML fallback). The key name is unchanged — it still filters the `protocol` field.
31+
- **No dimming scrim behind the "Add product" side-card**, matching the rack editor. Both are editors acting on the inventory behind them, not blocking dialogs. The overlay stays in the DOM and keeps its `pointer-events`, so click-outside still closes.
32+
- **Ecosystem cross-links + `llms.txt` refresh.** README now points TigerPOD at its own repository in both the ecosystem table and its section; `llms.txt` was corrected on every drifted fact and gained an **Ecosystem repositories** table plus `FEATURES.md` / `CODEMAP-main.md` in its docs list.
33+
34+
### Fixed
35+
36+
- **Custom links were not stored at all.** Attaching a link is the only entry point that can fire on a product with no `users/{uid}/products/{keyHash}` doc yet — every other `_writeProductField` caller acts on an already-created product. It created a doc carrying just `{updatedAt, attachments}` with **no `key` / `label` / `cloudSeed` identity**, and its optimistic local update is guarded by `if (rec)`, so with no record in `state.products` nothing was applied and the immediate re-render read back an empty product: the link vanished on save. Both attachment writes now go through `_writeProduct(r, …)`, which seeds the identity from the row, and that writer's optimistic patch covers `attachments` and creates the local record when missing. Not a rules problem — `products` has no field whitelist.
37+
- **The custom-colour swatch's pencil vanished on a white or pale colour** in the Add-product picker. The icon was hardcoded white with a double drop-shadow halo trying to keep it legible on any background — a workaround that failed on light colours and read as a smudge on the rest. It now flips black/white against the swatch via `readableTextOn()`, the same relative-luminance helper the avatars use; the halo is gone.
38+
- **Stepper − / + buttons did not fill their control.** The global `button { height: 40px }` is more than a default here: neither `.cw-step` nor `.rec-step` set a height, so both sat top-aligned inside a taller wrapper with a hover fill stopping short of the edges — visible on the calibration stepper and latent on the rack side-card's. Both now use `height: auto` + `align-self: stretch`.
39+
40+
---
41+
842
## v2.12.0 — 2026-07-18
943

1044
### Added

‎CLAUDE.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,33 @@ Behaviour:
488488
- Re-parses every file after write — aborts the entire run if any output isn't valid JSON.
489489
- Source: `scripts/i18n-add.mjs`.
490490
491+
### Docs that restate the code — kept honest by `npm run docs:check`
492+
493+
Several docs repeat numbers that actually live in the code: the version, the
494+
renderer's line count, how many printer brands ship, how many i18n keys exist,
495+
paths to folders. Nothing breaks when they drift, so nobody notices — `llms.txt`
496+
(the file an AI agent reads FIRST to understand this repo) once claimed **v1.8.2 /
497+
~12 000 lines / 5 brands** while the app was at **v2.12.0 / 28 500 lines / 6
498+
brands**, with Anycubic missing from its protocol table entirely.
499+
500+
`scripts/check-docs-drift.mjs` compares each stated fact against its source of
501+
truth and fails the commit on a mismatch. The **pre-commit hook runs it** whenever
502+
a doc — or a file it describes — is staged. Run it by hand with `npm run docs:check`.
503+
504+
| Checked | Source of truth | Tolerance |
505+
|---|---|---|
506+
| `llms.txt` "Current version" | `package.json` | current, or the patch it was bumped from |
507+
| `llms.txt` "~N lines" | `renderer/inventory.js` | 15 % |
508+
| `llms.txt` CSS file count | `renderer/css/*.css` | exact |
509+
| `llms.txt` brand count **+ protocol table rows** | `renderer/printers/*/index.js` | exact |
510+
| `llms.txt` "N keys × 9 locales" | `renderer/locales/en.json` | 2 % |
511+
| `FEATURES.md` "current as of vX.Y.Z" | `package.json` | current, or previous patch |
512+
| Paths in README / llms.txt / CLAUDE.md / AGENT.md | the filesystem | must exist (templates + globs skipped) |
513+
514+
It only checks facts it can derive — it never reviews prose. When a check fires,
515+
fix the doc rather than bypassing: the numbers are read by humans **and** agents.
516+
Add a new check here whenever a doc starts restating something the code owns.
517+
491518
### Consistency check (auto-run on every commit)
492519
A pre-commit hook runs `npm run i18n:check` automatically — the commit is blocked if the 9 locale files drift apart. Activated by the `prepare` npm script which sets `core.hooksPath=.githooks/`. To run manually:
493520

‎FEATURES.md‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Tiger Studio Manager — Feature Catalogue
22

3-
Tiger Studio Manager is the Electron desktop companion to the TigerTag ecosystem: a filament-inventory manager built around RFID/NFC-tagged spools ("TigerTag" chips), a fully-digital "TigerCloud" tier, live 3D-printer integration across six brands, physical storage/rack management, a Firebase-backed social layer (friends, shareable wishlists, public profiles), and companion hardware (TD1S color sensor, TigerScale, TigerPOD dual-reader stand). This document catalogues every **shipped** feature, grouped by domain, current as of **v2.12.0**. Per-version release detail lives in `CHANGELOG.md`; forward-looking / in-progress work lives in `ROADMAP.md`.
3+
Tiger Studio Manager is the Electron desktop companion to the TigerTag ecosystem: a filament-inventory manager built around RFID/NFC-tagged spools ("TigerTag" chips), a fully-digital "TigerData" tier, live 3D-printer integration across six brands, physical storage/rack management, a Firebase-backed social layer (friends, shareable wishlists, public profiles), and companion hardware (TD1S color sensor, TigerScale, TigerPOD dual-reader stand). This document catalogues every **shipped** feature, grouped by domain, current as of **v2.13.0**. Per-version release detail lives in `CHANGELOG.md`; forward-looking / in-progress work lives in `ROADMAP.md`.
44

55
---
66

@@ -15,16 +15,17 @@ Tiger Studio Manager is the Electron desktop companion to the TigerTag ecosystem
1515
- TD1S color/TD sensor integration in the detail panel — scan color and TD separately or together (v1.3+; unified color+TD modal v1.8.0).
1616
- Spool toolbox (detail panel) — scan color, scan TD (with a hold-to-confirm "Clear TD" split button, v1.4.13), link/unlink twin, remove from rack, delete (v1.4.8).
1717
- Every toolbox action gained an ⓘ hover explainer (v1.10.29).
18-
- **Duplicate ×N** — mint 1–50 copies of a TigerCloud/TigerTag spool in one write, hold-to-confirm (v1.8.3).
18+
- **Duplicate ×N** — mint 1–50 copies of a TigerData/TigerTag spool in one write, hold-to-confirm (v1.8.3).
1919
- **Erase / Recycle to NFC / Restore TigerTag+** — reinitialise, wipe, or restore a physical chip's backed-up signature (v1.10.29).
2020
- **Guided chip update** — step-by-step panel with per-reader UID-match check before the write proceeds (v2.0.0).
2121
- Add Product side panel — Brand/Material picker bottom-sheets, mobile-style HSV color picker (preset grid + custom SV rectangle + hue slider), advanced Type/Diameter/Aspect/temps/TD/unit fields, integer clamping, live RFID-data debug preview (v1.4.11 → v1.4.12; reorganised with always-visible core fields + app-styled dropdowns v2.5.0).
2222
- Multi-colour picker — Mono / Dual / Tri / Rainbow selector with a live-updating color circle (v1.4.14).
23-
- Custom product image via external URL for DIY & TigerCloud spools (TigerTag+ stays catalogue-locked) (v1.4.13).
23+
- Custom product image via external URL for DIY & TigerData spools (TigerTag+ stays catalogue-locked) (v1.4.13).
2424
- TD1S button in the header auto-fills color + TD on scan (v1.4.13).
25-
- **TigerCloud** — fully-digital spools with no physical chip (`CLOUD_<id>`), atomically promoted to a real hex UID (with all fields, twin pointers, rack assignment and friend ACLs carried over) the moment a chip is programmed; dedicated purple tier badge and stat tile (v1.4.12; stat tile v1.4.13).
25+
- Per-account **container-weight calibration** — correct a container's empty weight against your own scale, with a guided "how to measure" step (a Masterspool keeps its cardboard core, other types do not), a catalogue-vs-yours comparison, and a choice of whether the spools already using that container adopt the new value. Stored in `users/{uid}/containerOverrides/{containerId}` and applied over the bundled catalogue at read time — the shipped JSON is never modified (v2.13.0).
26+
- **TigerData** — fully-digital spools with no physical chip (`CLOUD_<id>`), atomically promoted to a real hex UID (with all fields, twin pointers, rack assignment and friend ACLs carried over) the moment a chip is programmed; dedicated purple tier badge and stat tile (v1.4.12; stat tile v1.4.13).
2627
- **Chip history & backup** — private list of every physical chip ever programmed, with the repairable TigerTag+ signature backed up on first read; a green "Backed up" shield badge marks protected spools (v1.10.28, badge v1.10.29). Product ID shown as a clickable catalogue link (v1.10.29).
27-
- Grouping of identical spools — table view first (v1.10.15), then grid view + a dedicated group side panel with a live speedometer gauge of combined remaining weight (v1.10.18); grouping includes TigerCloud spools (v1.10.16) and distinguishes different colours/aspects within the same brand+material (v1.10.31).
28+
- Grouping of identical spools — table view first (v1.10.15), then grid view + a dedicated group side panel with a live speedometer gauge of combined remaining weight (v1.10.18); grouping includes TigerData spools (v1.10.16) and distinguishes different colours/aspects within the same brand+material (v1.10.31).
2829
- Multi-select mode (grid + table) — tick spools or printers and delete together with a hold-to-confirm, header master checkbox to select all visible (v2.0.0; header checkbox v2.1.0).
2930
- Bulk **Tags** editing across a selection (v2.1.0), bulk **Price** editing (v2.2.0, spools v2.2.0 too), bulk ★ Favorite / ❤ Love toggles (v2.3.0), multi-select inside a friend's inventory scoped to ★/❤ only (v2.3.0).
3031
- **Tags** — free-form spool labels with autocomplete, an "All tags" filter, and search-bar integration; twin-mirrored (v1.10.28; type-to-filter/create-on-the-fly rework v1.10.31).
@@ -111,7 +112,7 @@ Tiger Studio Manager is the Electron desktop companion to the TigerTag ecosystem
111112
## Favorites & product identities
112113

113114
- Per-user `products` collection — one record per product identity (buy link, tax-free price, minimum stock, note, tags, SKU/EAN, ❤/★ flags, display snapshot, sanitised `cloudSeed`) shared by every matching spool and surviving spool deletion (v2.1.0).
114-
- Product-info side card — buy link, price, min stock, note, tags, SKU/EAN, ❤/★, and a "Create a TigerTag Cloud" action, fully auto-saving (v2.1.0).
115+
- Product-info side card — buy link, price, min stock, note, tags, SKU/EAN, ❤/★, and a "+ Material" action minting a chipless TigerData spool of this exact filament, fully auto-saving (v2.1.0; action renamed v2.2.0).
115116
- Info (ⓘ) button on a product opens its reorder panel (price / buy-link / min-stock) alongside the product card (v2.10.0; present and left-aligned on all three product side-cards, and toggling, v2.12.0).
116117
- Product web-link attachments — datasheets, tutorials or videos attached to a product identity and shared by every spool of it, tier-capped free 1 / plus 2 / premium 5 and enforced server-side (v2.12.0).
117118
- Favorites view — Grid, Table and "To order" modes, sortable table (v2.1.0; sortable v2.2.0).

0 commit comments

Comments
 (0)