Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
ca30cc4
plan: 32-photo-trace-ai (optional in-browser AI silhouettes, classic …
Oct 17, 2026
2a8d0a0
poc: browser AI silhouettes (ORT Web) on the owner's photos, findings
Oct 17, 2026
5563aa4
poc: owner's Chrome results (RMBG-1.4 best, BiRefNet fails, WebGPU no…
Oct 17, 2026
baceab2
poc: more permissive candidates (BiRefNet-lite 512, ormbg, MVANet, BEN2)
Oct 17, 2026
97a134c
poc: drop BiRefNet-lite 1024, add ISNet variants, IS-Net, U2Net, InSP…
Oct 17, 2026
faf37d9
plan: 32-photo-trace-ai model manager window, licence classes, PoC ou…
Oct 17, 2026
4498367
poc: round 2 results, drop MVANet/BEN2; plan: per-model backends
Oct 17, 2026
845cb80
Merge remote-tracking branch 'origin/main' into claude/last-visible-c…
Oct 18, 2026
7844bce
poc: BiRefNet-lite 512 results (good on WASM ~9 s, empty on WebGPU); …
Oct 18, 2026
a37ee72
poc: live threshold/smoothing of the soft mask, alpha view; plan: mas…
Oct 18, 2026
a0eb71b
plan: 32-photo-trace-ai permissive licences only (RMBG-1.4 stays a Po…
Oct 18, 2026
49ade92
plan: 32-photo-trace-ai registry task without licence classes
Oct 18, 2026
4ee9a5e
plan: 32-photo-trace-ai user-facing mask controls with per-model defa…
Oct 18, 2026
c1c9426
plan: 33-keychain-ai-silhouette (AI silhouette source for Keychain Im…
Oct 18, 2026
08ef2c0
plan: 34-keychain-photo-relief (depth relief from a photo, v1.5.0); p…
Oct 18, 2026
3f98f48
plan: 34-keychain-photo-relief as a mix of contour, depth and detail …
Oct 21, 2026
bb0bf6e
poc: Keychain pipeline page (stages: crop, silhouette model, depth mo…
Oct 21, 2026
6db0b09
poc: log under the 3D view, layer checkboxes (mask, contour, depth, d…
Oct 21, 2026
619727a
poc: soften relief (per-layer smoothing, depth gamma, slope limit, fi…
Oct 21, 2026
93d4a0d
poc: checkerboard under the silhouette in previews, face/whole-animal…
Oct 21, 2026
973e16a
poc: smooth outline in 3D (subpixel edge from soft mask), higher defa…
Oct 21, 2026
d67d329
poc: line-art samples, open large areas, guided depth, denoise before…
Oct 21, 2026
eddab56
poc: exact outline by marching-squares clipping; plan 34: smooth outl…
Oct 21, 2026
4ab3fe1
poc: outline smoothing in mm (default 0.25 like cutouts); plan 34: re…
Oct 21, 2026
dcd34e0
poc: engrave detail mode, vector outline with corner preservation, dr…
Oct 21, 2026
0aaf5e4
poc: drawing preset engraves inner strokes, whole-animal preset with …
Oct 21, 2026
21fe7b6
poc: cutout PoC as a pipeline with 3D pockets (stages, engines, vecto…
Oct 21, 2026
e10bbe2
poc: smooth AI outline (bicubic upsampling, per-object second pass, r…
Oct 22, 2026
b55ebb7
poc: cutout 3D pockets from the exact polygon (smooth wall normals), …
Oct 22, 2026
c014796
poc: Bezier-fitted pockets for both engines; plan: 35-smooth-outline …
Oct 22, 2026
442d775
poc: Bezier-fitted outline in keychain (analytic wall normals), defau…
Oct 22, 2026
be2861e
plan: model manager as a modal from the Header (sections by kind), no…
Oct 22, 2026
6ecc841
plan: 31a-status-log (shared activity log in the status bar); 32-34 r…
Oct 22, 2026
d322057
plan: 36-site-refresh (card texts and tags, README, Keychain ring car…
Oct 22, 2026
40faf60
plan: 37-resource-monitor (honest CPU/GPU/memory figures for rebuild …
Oct 22, 2026
63341b4
plan: 38-webmcp (tools for browser agents: validated parameter change…
Oct 25, 2026
27b76d8
plan: 38-webmcp creation date
Oct 25, 2026
88b288b
plan: 33/34/35 fill gaps (auto-open large areas, guided depth snappin…
Oct 25, 2026
3c10a74
plan: 36-site-refresh adds product hues for card art and logo (Gridfi…
Oct 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions openspec/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@
| 29 | `29-beta-label` | 22a | Метка beta и дисклеймер; версия 1.0.0 из package.json на фронтенде; правило semver: каждый change поднимает версию (config.yaml, CLAUDE.md, CHANGELOG.md) |
| 30 | `30-rack-front-plate` | 28, 29 | v1.1.0. Передняя панель корпуса: крепление keystone по моделям (гнездо с рампой и защёлкой, обойма за панелью), группы отверстий (колонка, ряд, сетка, зоны вокруг корпуса), «отверстия» вместо «кабельных», окно по умолчанию, ссылки на референсы в README |
| 31 | `31-rack-shelf` | 26, 29 | v1.2.0. Полка: передняя панель с ушами лицом на столе, пол с вентиляцией (щели, можно глухой), боковые стенки с прямым скосом, вентиляция передней панели опционально |
| 31a | `31a-status-log` | 29 | v1.3.0. Общий независимый лог приложения: статус-бар показывает лоадер и текущую строку, по клику открывается панель с полным логом (уровни, источники, фильтры, копирование); лог пишут генерация, импорт, хранилище, фото-диалог, экспорт |
| 32 | `32-photo-trace-ai` | 25a, 29, 31a | v1.4.0. Фото-вырезы: альтернативный нейросетевой движок силуэтов (в браузере, веса по согласию, гибридный точный край), классический остаётся по умолчанию как baseline; сравнение движков |
| 33 | `33-keychain-ai-silhouette` | 32, 11, 29 | v1.5.0. Keychain Image: силуэт по ИИ (удаление фона на браузерной модели), те же ручки порога и сглаживания, один главный объект, результат хранится вместе с картинкой; яркость остаётся по умолчанию |
| 34 | `34-keychain-photo-relief` | 33, 32, 12, 17, 29 | v1.6.0. Keychain Image: рельеф из фото как смесь трёх источников формы (контур, глубина Depth Anything, детали — локальный контраст), кроп области (лицо), силуэт «весь кадр» (плашка), пресеты; результат хранится с картинкой |
| 35 | `35-smooth-outline` | 25a, 34, 29 | v1.7.0. Общий этап контура для вырезов (классика и ИИ) и Keychain: подгонка кубических кривых Безье с минимумом точек, острые углы сохраняются, зазор по кривой; стенки без ряби, детекция не меняется |
| 36 | `36-site-refresh` | 29 | v1.7.1. Актуализация сайта и README: тексты и теги карточек (без «скоро», «snap», «mask»), README по текущему продукту, превью Keychain из PoC-кольца с меньшим зумом, все превью Rack в 1 U, проверка отступов |
| 37 | `37-resource-monitor` | 31a, 32, 29 | v1.8.0. Вкладка «Ресурсы» в панели лога: честные показатели CPU/GPU/памяти для ресурсоёмких случаев (перестроение и отрисовка модели, ИИ на WASM и WebGPU) с пометкой «измерено / оценка / недоступно», отчёт по каждой задаче, режим диагностики (профилирование GPU); без FPS |
| 38 | `38-webmcp` | 31a, 29 | v1.9.0. Инструменты WebMCP для браузерных агентов: чтение и запись параметров активного режима (baseplate, box, rack, keychain shape) с валидацией, сводка модели, экспорт и сброс только с подтверждением пользователя, журнал и отмена действий агента, переключатель; без эффекта, если браузер не поддерживает WebMCP |

```mermaid
gantt
Expand Down
2 changes: 2 additions & 0 deletions openspec/changes/31a-status-log/.openspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-10-22
38 changes: 38 additions & 0 deletions openspec/changes/31a-status-log/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Design

## Context

`MeasurementsBar` (in `features/viewport`) renders X, Y, Z of the model and, on the right, a spinner with "Generating…" when `busy` (from `useModel`, which sets it 200 ms after a request starts) or a check with "Ready". `Workspace` passes `busy` from each mode. There is no shared place to report anything else, and each feature shows its own banner.

## Goals / Non-Goals

**Goals:**
- One log for every part of the app, one place to look at it, the current line always visible.
- A small interface that features can call without knowing about the UI; the UI follows the interface language.

**Non-Goals:**
- Persistence, telemetry, a debugger.

## Decisions

- **Module store, not React state.** `activityLog.ts` is a module-level store (array of entries, a list of jobs, subscribers) read by `useSyncExternalStore`, so workers' clients, hooks and plain functions can write to it without a provider, and logging never re-renders unrelated components. The panel and the bar subscribe to it; tests reset it between cases.
- **Entries carry keys, not sentences.** `{id, time, level, source, key, params, detail?, job?}`; the UI renders `t(key, params)`, so changing the language re-renders old lines. `detail` is raw technical text of an exception (message or short stack) shown inside a collapsed "Details" element on that line, never as UI text. Time is stored as a timestamp and shown as `HH:MM:SS.mmm`.
- **Jobs.** `startJob({source, key, params, cancel?})` returns `{update({key, params, progress}), done(key, params), fail(key, params, detail), cancelled()}`. Updates replace the job's current line (and progress) in place; the log keeps the job's start, the notable milestones (`done`/`fail`/`cancelled` and anything the producer logs explicitly) and does not store every progress tick. A job that runs more than 200 ms drives the status bar loader, which replaces the `busy` prop of `Workspace`.
- **Status bar.** Left: X, Y, Z as now. Right: with a running job, the spinner and the job's current line, plus a Cancel button if the job has one; with none, the latest entry for 4 s, then "Ready" (with the check) when a model exists; counters `⚠ n` and `✕ n` of the entries since the last open or clear. The whole right part is one button (`aria-label` "Open the log"): click or Enter/Space opens the panel. The line is an `aria-live="polite"` region, throttled to one announcement per second so a download does not flood a screen reader. At 390 px the X/Y/Z shorten and the line truncates with an ellipsis; the counters stay.
- **Panel.** `ActivityLogPanel` is rendered once by `AppShell` and opened through a tiny store (`openLog({source?})`), so any component, such as the model manager, can open it filtered to a source. Desktop: a resizable panel above the status bar covering about 40 % of the viewport area; below 768 px a bottom sheet over the parameter drawer. Content: a virtualised-free list (at most 500 lines), time, level icon, source label, text, optional Details; sticky filters (level: all / warnings / errors; source chips with counts); auto-scroll to the newest line that pauses when the user scrolls up and resumes with a "Jump to latest" button; Copy (plain text: app version, language, user agent, then the lines) and Clear with no confirmation (the log is disposable); Esc and a close button, focus returns to the status bar button.
- **Retention.** A ring buffer of 500 entries; the oldest drop first; running jobs are never dropped. Memory only: a reload starts a clean log.
- **Producers in this change.** Only what exists today: (1) model generation in `useModel` and `useKeychainModel` (a `generate` job per rebuild: start, duration and triangle count on done, the validation error key and the warnings of the `ModelResult` as warning lines, a failure as an error with detail); (2) image decoding, mesh and font import (name, size, downscaled, failure); (3) storage: IndexedDB or Cache API unavailable and the memory fallback, as a warning once per session; (4) the photo dialog: sheet found or not (confidence, paper), straightened, silhouettes found (count, sizes), cutouts created; (5) export: format, printer, plates, parts that overflow, file built. The AI changes add `ai` and `model` sources later. A slider move is not logged; only the rebuild it triggers is, and consecutive rebuilds within a debounce window update one job.
- **Keys.** Every message has `log.<source>.<event>` keys in `en.json` and `ru.json`; the existing parity test covers them.
- **Privacy.** Entries never hold pixels, file contents or URLs of user files; names and sizes only; the Copy text states that it stays on the device. No network call is made by the log.
- **Compatibility.** The `busy` prop of `Workspace` and `MeasurementsBar` stays accepted for one change as an override that is ignored when jobs report; the modes switch to jobs in this change and the prop is removed in the same change (a task), since nothing outside the app uses it.

## Risks / Trade-offs

- [Log noise from frequent rebuilds] → jobs coalesce within the debounce window, progress updates are in place, a ring buffer bounds memory.
- [Screen reader flooding] → one polite announcement per second, only the status line is live, not the panel.
- [Duplicate sources of truth for "generating"] → the loader is derived from jobs only; tests check that no mode passes its own busy flag.
- [Technical detail shown in a non-translated language] → only inside "Details"; the line itself is a translated sentence.

## Open Questions

- Whether warnings from validation (`rack.error.*`, `baseplate.error.*`) should also keep their banners (yes for now: the banner is the call to action, the log is the record).
29 changes: 29 additions & 0 deletions openspec/changes/31a-status-log/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Proposal

## Why

The status bar under the 3D view (`MeasurementsBar`) shows the model's X, Y and Z and one indicator, "Generating…" or "Ready". That is all the app says about what it is doing. When a model does not appear, the reason is a banner or nothing; photo processing, image import, storage fallbacks and export have no visible trace; and the planned AI features (`32`–`34`) add long jobs (downloading a model, a run of several passes) that need a visible "what is happening now" and a place to read the whole story afterwards.

Instead of a log hidden in one feature (the model manager), the status bar becomes a general, independent activity log of the whole app: one current line at a glance, and the full log one click away.

## What Changes

- **A shared activity log.** An app-level, memory-only log with levels (info, warning, error), a source (model generation, photo, image, storage, export, AI, app) and a text that follows the interface language. Long work is a *job* with a state, an optional progress and a Cancel; progress updates change the job's line in place instead of adding lines.
- **The status bar shows the activity.** X, Y and Z stay on the left. On the right a loader and the **current line** (the latest line of the running job, otherwise the last message for a few seconds, then "Ready"), with small counters of warnings and errors. Clicking it, or pressing Enter, opens the log.
- **The log panel.** Opens above the status bar (a bottom sheet on a phone): every line with time, level and source, filters by level and by source, Copy (plain text with the app version and language) and Clear, closes with Esc. It is reachable from anywhere that links to it, such as the "AI models" manager, not only from the status bar.
- **Existing work reports to it.** Model generation (start, duration, triangle count, validation errors and warnings with their messages, failures), image and font import, storage fallbacks (IndexedDB or Cache API unavailable), the photo dialog (sheet found, straightened, silhouettes found, cutouts created) and export (file built, plates, parts that do not fit). The AI changes (`32`–`34`) report through the same interface.
- **Not a telemetry.** The log lives in memory of the tab, holds names and sizes but never image data, and is never sent anywhere.

## Capabilities

### New Capabilities
- `activity-log`: the shared activity log, its status bar line and its panel.

### Modified Capabilities

## Impact

- New `src/app/activityLog.ts` (store, `log.info/warn/error`, `startJob`, `useActivityLog` via `useSyncExternalStore`), `features/viewport/StatusBar.tsx` replacing the right part of `MeasurementsBar` (the X/Y/Z part stays), `app/ActivityLogPanel.tsx` rendered by `AppShell`; `useModel`, `useKeychainModel`, `imageStore`, `fontStore`, the photo dialog hook and the export panel emit events; the `busy` prop of `Workspace` is replaced by the job state; strings in en and ru; tests (the store, the line, the panel, producers, key parity, accessibility).
- Out of scope: persistence of the log across reloads, sending it anywhere or any telemetry, logging every slider move or render frame, a profiler, the AI events themselves (added by `32`–`34` through this interface), the Gridfinity or Rack calculations beyond their generation result.
- Version 1.3.0 (minor: a new capability).
- Depends on: `29-beta-label` (the versioning rule); `31-rack-shelf` is already archived.
Loading
Loading