Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 9 additions & 1 deletion openspec/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,15 @@
| 42 | `42-editor-mesh-repair` | 41 | v1.13.0. Диагностика и ремонт STL, QEM децимация (meshoptimizer) с фиксацией вершин, сглаживание MLS с сохранением рёбер >30°, BVH raycasting (three-mesh-bvh), карта толщины стенок, кисть выделения граней, Lay on Face, измерения |
| 43 | `43-editor-cut-split` | 41, 42 | v1.14.0. Plane Cut (меш и твердотельный), Split на стол с соединителями (шипы, штифты, магниты, ласточкин хвост), мастер отверстий (Hole tool: винты, втулки, магниты), нарезка винтовой резьбы (Thread tool: метрическая/дюймовая) и текст на грани |
| 44 | `44-editor-face-tools` | 41, 42 | v1.15.0. Топологическое именование (FaceFingerprint, EdgeFingerprint), выбор граней/рёбер (CAD box select: window/crossing), контекстные плашки в 3D (HUD Context Chips), Push/Pull, точные 3D Fillet/Chamfer рёбер, эскиз на грани с проекцией рёбер |
| 45 | `45-editor-project-default` | 43, 44 | v2.0.0 (major: `/` ведёт в редактор, выбор генераторов переезжает на `/generators`). Файл проекта `.pkit` (ZIP: scene.json + сетки + эскизы + 3D-пины/заметки, защита ZipSlip), кольцевой буфер автосохранения, редактор — вход по умолчанию, генераторы как вставляемые объекты (Send to Editor / Edit in generator) |
| 44a | `44a-storybook` | 44 | v1.15.1. Storybook 8 для библиотеки компонентов: `src/ui/`, токены `theme.css`, декораторы i18n (EN/RU) и единиц (мм/дюйм), smoke-тест |
| 44b | `44b-editor-viewport-navigation` | 44 | v1.16.0. Адаптивная сетка FreeCAD 5×5 (3D и эскиз), синхронизация кривой зума эскиза с OrbitControls, разделение Shift+Drag (панорамирование) и рамки выделения |
| 44c | `44c-editor-sketch-input-face` | 44b | v1.17.0. Поля HUD ввода координат для окружностей (центр X, Y, диаметр/радиус) и точек, бесшовный пайплайн «эскиз на грани ➔ выдавливание (Join/Cut)» |
| 44d | `44d-editor-layout-workbenches` | 44a, 44c | v1.18.0. Единый компактный хедер редактора, разделение верстаков Model / Sketch, симметричные сайдбары 280px с ручкой изменения ширины |
| 44e | `44e-editor-context-menu` | 44c, 44d | v1.19.0. Универсальное контекстное меню (ПКМ) во вьюпорте (объекты, пустое поле, грани, ребра) и на холсте эскиза |
| 44f | `44f-editor-op-preview` | 44d | v1.20.0. Полупрозрачный фантомный предпросмотр операций (Extrude, Revolve, Cut, Push/Pull) прямо во вьюпорте в процессе настройки |
| 44g | `44g-editor-split-panel` | 44d, 44f | v1.20.1. Перенос «Разрезать по столу» из модального окна в боковую панель инструмента с 3D-плоскостями разреза и предпросмотром стола |
| 44h | `44h-editor-mesh-repair-wizard` | 44a, 44d | v1.21.0. Инспекция и ремонт STL по референсу MeshDoc: визуализация дефектных ребер на модели, отчет До/После с дельтами, расчет веса филамента |
| 45 | `45-editor-project-default` | 44h | v2.0.0 (major: `/` ведёт в редактор, выбор генераторов переезжает на `/generators`). Файл проекта `.pkit` (ZIP: scene.json + сетки + эскизы + 3D-пины/заметки, защита ZipSlip), кольцевой буфер автосохранения, редактор — вход по умолчанию, генераторы как вставляемые объекты (Send to Editor / Edit in generator) |
| 46 | `46-editor-step-cad` | 45 | v2.1.0. Обмен данными CAD: экспорт тел в точный формат STEP (AP203/214/242) для CAD и слайсеров (Bambu/Prusa/Orca), импорт STEP-файлов в дерево операций, валидация замкнутости и сшивка |
| 47 | `47-editor-sweep-loft` | 44, 46 | v2.2.0. Кинематические операции твердотельного моделирования: Sweep (протягивание профиля по траектории), Loft (переход между произвольными сечениями) и Draft (литейный уклон граней) |

Expand Down
2 changes: 2 additions & 0 deletions openspec/changes/44a-storybook/.openspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-11-08
31 changes: 31 additions & 0 deletions openspec/changes/44a-storybook/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Design: Component Catalog (Storybook)

## Context
PrintKit is a client-only React 19 + TypeScript app with Tailwind CSS v4, Tabler Icons, and i18next. Its UI design is documented across static HTML artboards in `design/artboards/`. As the editor workspace expands with complex panels, floating toolbars, and contextual dialogs, testing components in isolation becomes necessary to prevent regressions and accelerate UI iteration.

## Goals
- Add Storybook 8 with `@storybook/react-vite` sharing the root `vite.config.ts` plugins and CSS.
- Provide global decorators for i18n (`en`/`ru`) and `UnitProvider` (`mm`/`in`).
- Include stories for all `src/ui/` primitives and core editor shell components with mock data.
- Ensure automated verification via portable stories in Vitest so stories never rot.

## Non-Goals
- Visual snapshot regression services (Chromatic, Percy).
- Three.js WebGL viewport story (Viewport is heavy and requires WebGL context; container mocks are used instead).

## Decisions

### Decision 1: Storybook 8 with `@storybook/react-vite`
We use `@storybook/react-vite` configured in `.storybook/main.ts`. It resolves root path aliases and loads `src/app/theme.css` inside `.storybook/preview.ts`. `__APP_VERSION__` is defined to match `vite.config.ts`.

### Decision 2: Global Decorators for i18n and Units
In `.storybook/preview.ts`, we declare global toolbar items:
1. `locale`: choices `en` and `ru`. A decorator calls `i18n.changeLanguage(locale)` before rendering.
2. `unit`: choices `mm` and `in`. A decorator wraps stories in `<UnitProvider initialUnit={unit}>`.
Stories use the standard dark background `#0e1013` (PrintKit background token).

### Decision 3: Portable Stories Smoke Testing with Vitest
Rather than relying solely on manual browser inspection, we add `src/stories.test.ts` which uses `@storybook/react` portable stories (`composeStories`) to mount every exported story in a jsdom test. Any syntax break, missing translation key crash, or undefined prop will fail `npm test`.

## Risks & Mitigations
- **Tailwind v4 in Storybook:** Tailwind v4 uses `@theme` directives directly in CSS. We import `src/app/theme.css` in `.storybook/preview.ts` so all custom color tokens (`--color-surface-1`, `--color-accent`, etc.) are available.
30 changes: 30 additions & 0 deletions openspec/changes/44a-storybook/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Proposal

## Why

PrintKit's UI component library (`src/ui/`) and modular editor controls have grown across 44 changes without an isolated visual catalog. Developers currently verify UI states, dark theme tokens, and bilingual labels (EN/RU) by navigating live modes or checking static HTML artboards. Adding Storybook allows isolated component development, interactive state inspection (disabled, error, stepper, units), and automated rendering verification without running the full WASM/WebGL canvas.

## What Changes

- **Storybook 8 Integration:** Configure Storybook (`@storybook/react-vite`) inside `.storybook/` integrated with Vite 6/7, Tailwind CSS v4 (`src/app/theme.css`), and the build-time define `__APP_VERSION__`.
- **Global Decorators:** Provide an i18next language switcher (EN / RU) in the Storybook toolbar, a `UnitProvider` toggle (mm / inch), and dark workspace backgrounds matching PrintKit's theme tokens.
- **UI Component Stories:** Add co-located `*.stories.tsx` stories for all foundational controls in `src/ui/` (`Button`, `Toggle`, `SegmentedControl`, `NumberField`, `LengthField`, `Section`, `ConfirmDialog`, `Banner`, `ContextMenu`).
- **Editor Shell Stories:** Add stories with mocked data for key Editor panels and widgets (`Toolbar`, `SketchToolbar`, `Outliner`, `Properties`, `ViewCube`, `MeasurementsBar`). WebGL Viewport is mocked with placeholder boundaries.
- **Automated Smoke Testing:** Add a Vitest test (`stories.test.ts`) using Storybook portable stories (`composeStories`) to assert that every story renders without throwing or logging console errors.
- **NPM Scripts:** Add `npm run storybook` for local development and `npm run build-storybook` for static export into git-ignored `storybook-static/`.

## Capabilities

### New Capabilities
- `component-catalog`: Storybook configuration, global theme/i18n/unit decorators, component story definitions, and smoke test suite for the UI library.

### Modified Capabilities

## Impact

- Affects developer tooling and adds devDependencies (`@storybook/react-vite`, `@storybook/react`, etc.).
- Adds `.storybook/main.ts`, `.storybook/preview.ts`, and `*.stories.tsx` files across `src/ui/` and `src/features/editor/`.
- No breaking changes or runtime bundle impact on the production web application.
- Target version: 1.15.1 (patch: developer tooling and component catalog without modifying production geometry or storage schema).
- Out of scope: Visual regression testing services (Chromatic/Percy), deployment of Storybook to public subdomains.
- Depends on: `44-editor-face-tools`.
46 changes: 46 additions & 0 deletions openspec/changes/44a-storybook/specs/component-catalog/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Spec Delta

## Purpose
Defines the component catalog infrastructure, decorators, story coverage, and rendering smoke verification for PrintKit UI components.

## ADDED Requirements

### Requirement: Component Catalog Environment
The development environment SHALL provide an isolated Storybook workspace running under Vite with Tailwind CSS v4 tokens, allowing interactive inspection of UI controls without loading the 3D geometry engine or WebGL viewport.

#### Scenario: Launching catalog
- **WHEN** the developer executes `npm run storybook`
- **THEN** the Storybook server starts and loads stories with PrintKit dark theme CSS applied

#### Scenario: Static catalog build
- **WHEN** the developer executes `npm run build-storybook`
- **THEN** static HTML and assets are generated into `storybook-static/` without TypeScript or bundler errors

### Requirement: Catalog Decorators
Storybook SHALL provide global toolbar controls to toggle the interface language between English and Russian, switch display units between millimetres and inches, and apply PrintKit dark theme backgrounds.

#### Scenario: Switching language
- **WHEN** the user switches the language toolbar item between EN and RU
- **THEN** all displayed story labels and tooltips update to the selected language using i18next

#### Scenario: Switching display units
- **WHEN** the user switches the unit toolbar item between mm and in
- **THEN** length fields dynamically recalculate and display values in the active unit while preserving stored millimeters

### Requirement: Foundation UI Stories
The component catalog SHALL provide stories for all reusable controls in `src/ui/` covering default, focused, disabled, error, and interactive states.

#### Scenario: LengthField story
- **WHEN** inspecting the `LengthField` story
- **THEN** stepper buttons (+/−), keyboard increment, and unit label are displayed and fully interactive

#### Scenario: Section story
- **WHEN** inspecting the `Section` story
- **THEN** collapsed state, modified orange summary highlight, and reset actions are demonstrated

### Requirement: Automated Story Smoke Verification
The test suite SHALL include an automated smoke test asserting that every declared component story mounts successfully in jsdom without runtime exceptions.

#### Scenario: Story test execution
- **WHEN** `npm test` runs
- **THEN** all stories are evaluated through portable stories and pass with zero unhandled errors
33 changes: 33 additions & 0 deletions openspec/changes/44a-storybook/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Tasks

## 1. Setup and Tooling

- [ ] 1.1 Install Storybook dependencies (`@storybook/react-vite`, `@storybook/react`, etc.) and configure `.storybook/main.ts` with Vite config resolution and `__APP_VERSION__` definition. Verification: `npx storybook --version`.
- [ ] 1.2 Configure `.storybook/preview.ts` with global CSS (`src/app/theme.css`), i18n decorator with EN/RU toolbar switcher, and `UnitProvider` decorator with mm/in switcher. Verification: Storybook preview loads dark theme tokens.
- [ ] 1.3 Add scripts `storybook` and `build-storybook` to `package.json`, and add `storybook-static/` to `.gitignore`. Verification: `npm run build-storybook` succeeds.

## 2. Foundation UI Stories (`src/ui/`)

- [ ] 2.1 Add stories for basic input controls: `Button.stories.tsx`, `Toggle.stories.tsx`, `SegmentedControl.stories.tsx`. Built from `design/artboards/Components.dc.html`. Verification: Stories render in Storybook with all variants.
- [ ] 2.2 Add stories for numeric and measurement controls: `NumberField.stories.tsx`, `LengthField.stories.tsx` (stepper ±, min/max limits, mm and inches). Verification: Interactivity check in Storybook.
- [ ] 2.3 Add stories for layout and container controls: `Section.stories.tsx` (default, modified highlight, reset), `Banner.stories.tsx`, `ConfirmDialog.stories.tsx`. Verification: Visual check in Storybook.

## 3. Editor Shell Component Stories

- [ ] 3.1 Add stories for editor navigation: `Toolbar.stories.tsx`, `SketchToolbar.stories.tsx`, `ViewCube.stories.tsx` with mocked callbacks and DoF states. No artboard exists; built from `ui/` components. Verification: Visual check in Storybook.
- [ ] 3.2 Add stories for editor sidebars: `Outliner.stories.tsx` (object hierarchy, lock/visible, health icons) and `Properties.stories.tsx` (transforms, primitive params, mesh health). Verification: Visual check in Storybook.
- [ ] 3.3 Add stories for contextual panels: `ConstraintPanel.stories.tsx`, `FeatureDialog.stories.tsx`, `CutPanel.stories.tsx`. Verification: Visual check in Storybook.

## 4. Automated Testing and Conventions

- [ ] 4.1 Create `src/stories.test.ts` using portable stories (`composeStories`) to mount every story in Vitest (jsdom) and assert no console errors or exceptions. Verification: `npm test` passes.
- [ ] 4.2 Document Storybook convention in `AGENTS.md` (all new `src/ui/` components must ship with co-located `*.stories.tsx`). Verification: file check.

## 5. Version

- [ ] 5.1 Bump `package.json` to 1.15.1 and add `1.15.1 — 44a-storybook` to `CHANGELOG.md`. Test: `npx vitest run src/site.test.ts`.

## 6. Verification

- [ ] 6.1 Run `npm test` and `npm run build` to confirm clean test and TypeScript build.
- [ ] 6.2 Run `npm run build-storybook` to confirm clean static build generation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-11-08
48 changes: 48 additions & 0 deletions openspec/changes/44b-editor-viewport-navigation/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Design: Viewport Navigation and Adaptive 5×5 Grid

## Context
CAD applications like FreeCAD and Fusion 360 provide intuitive navigation where zooming continuously reveals finer decimal and 5×5 grid divisions, panning is seamless with standard modifier combinations (`Shift + Drag`), and zoom scaling remains consistent between 3D model space and 2D sketch mode. In PrintKit, fixed shader parameters and unnormalized wheel events created jarring jumps and gesture conflicts.

## Goals
- Compute hierarchical 5×5 grid intervals based on camera distance and FOV in both perspective and orthographic modes.
- Unify 3D ground grid and sketch plane grid shaders with major line emphasis every 5 minor lines.
- Implement delta-normalized cursor-anchored zoom matching Three.js `OrbitControls.dolly`.
- Route mouse events cleanly to separate camera panning (`Shift + Drag`) from box selection.

## Non-Goals
- Changing default camera rotation axis from Z-up.
- Fully customizable navigation keybinding profiles.

## Decisions

### Decision 1: Pure Grid Level Calculator (`gridLevels.ts`)
We calculate the screen scale `mmPerPx` at the plane target:
`mmPerPx = (2 * distance * Math.tan((fov * Math.PI) / 360)) / viewportHeight` in perspective, or `orthoHeight / viewportHeight` in ortho.
Levels scale by powers of 5 and 10: `..., 0.08, 0.4, 2, 10, 50, 250, 1250, ...`.
Given `mmPerPx`, we determine:
- `minorSpacing`: finest interval with screen spacing $\ge 12\text{ px}$.
- `majorSpacing`: $5 \times \text{minorSpacing}$.
- `subdivisionFade`: a $0..1$ alpha blending factor for the incoming sub-grid.

### Decision 2: Shared Grid Shader
Instead of creating dozens of line meshes in `buildSketchGrid`, both the ground grid and sketch plane use a custom GLSL shader plane that evaluates coordinates in the plane's local coordinate frame:
`line(coord, minorSpacing)` and `line(coord, majorSpacing)`.
Major lines render with higher opacity and thickness. In sketch mode, X and Y axes retain red and green overlays.

### Decision 3: OrbitControls-Aligned Zoom in Sketch
In `Viewport.tsx`:
```ts
const deltaY = e.deltaMode === 1 ? e.deltaY * 20 : e.deltaMode === 2 ? e.deltaY * 100 : e.deltaY
const zoomFactor = Math.pow(0.95, -deltaY * 0.002)
```
This guarantees identical trackpad pinch and mouse wheel sensitivity across 3D and 2D views.

### Decision 4: Gesture Dispatch Matrix
A pure function `classifyGesture(event, state)` determines action:
- `button === 0 && e.shiftKey && moved > 5`: `pan`
- `button === 0 && !e.shiftKey && moved > 5 && tool === 'select'`: `boxSelect`
- `button === 0 && !e.shiftKey && moved > 5 && isDrawingTool`: `drawDrag`
- `button === 0 && moved <= 5`: `clickSelect`

## Risks & Mitigations
- **Shader precision at sub-millimetre scales:** High-resolution grids ($0.08\text{ mm}$) can experience floating point moiré at large distances. The shader uses distance-based fadeout (`uFade`) to cull distant sub-grids.
Loading
Loading