chili3d Agent Skills & AI Rules

GitHub

A browser-based 3D CAD application for online model design and editing

4,522 stars TypeScript TypeScript 1 file ยท ~2,178 tokens #3d#browser-based#cad#geometry#occ#occt#opencascade#three
RAW Rules
24 Discovered Rules โ€ข ~6,415 Estimated Tokens
Quick:
Loading skill content...

AI Agent Protocol & Instructions

AGENTS.md root-instruction ~2,013 tokens
Raw
# Chili3D coding guidelines

## Build & Test

```bash
npm run dev            # Rspack dev server โ†’ localhost:8080
npm run build          # Production build (Rspack + SWC)
npm run test           # All tests (Rstest + Happy-DOM); npm run testc = with coverage
npm run check          # Biome lint + auto-fix (run before commits)
npm run format         # Biome + clang-format across all files
npm run build:wasm     # C++ โ†’ WebAssembly (CMake + Emscripten); setup:wasm = one-time deps

npx rstest packages/core/test/result.test.ts   # single file
npx rstest -t "should handle error case"       # filter by name
```

## Monorepo Structure

Browser-based parametric 3D CAD: OCCT C++ kernel compiled to WebAssembly, rendered with Three.js. npm workspace under `packages/`:

```
web โ”€โ”€> builder โ”€โ”€> app โ”€โ”€> core
                  โ”€โ”€> i18n / three / wasm โ”€โ”€> core
                  โ”€โ”€> ui โ”€โ”€> core + element
                  โ”€โ”€> parametric โ”€โ”€> core
```

- **`core`** โ€” Everything abstract: shape interfaces, math, document model, reactive data (`Observable`, `Binding`, `PubSub`), `Result<T,E>`, undo, commands, serialization, plugins, services, UI abstractions
- **`parametric`** โ€” Parametric feature-list bodies (Onshape-style) plus the 2D sketch module (`src/sketch/`, wrapping the garlic constraint solver). A body stores no shapes โ€” only an ordered feature list replayed through `registerFeature` handlers, so any upstream edit re-evaluates the chain; the bulk of the module is stable identity for sub-shapes across rebuilds (kernel history โ†’ tracked ids โ†’ stored `EdgeRef`/`ProfileRef`) and the timeline rules for which shape a reference resolves against.
- **`wasm`** โ€” Concrete `ShapeFactory` โ†’ OCCT via Emscripten; exports `initWasm()`
- **`three`** โ€” Three.js viewport, camera controller, visuals, highlighter, gizmo, mesh export
- **`element`** โ€” Custom reactive DOM elements (radio groups, expanders, data converters)
- **`ui`** โ€” App chrome: main window, ribbon, property panels, project tree, dialogs, toast, status bar
- **`app`** โ€” `Application`, body nodes (`bodys/`), command implementations, `CommandService`, `HotkeyService`
- **`builder`** โ€” `AppBuilder` fluent chain (`.useIndexedDB().useWasmOcc().useParametric().useThree().useUI().build()`), default ribbon layout; `mergeRibbonProfiles` merges module contributions (`SketchRibbonProfiles` from `@chili3d/parametric`, `ParametricRibbonProfiles`) into `DefaultRibbon`
- **`i18n`** / **`storage`** / **`web`** โ€” Locale data (en, zh-cn, pt-br) / IndexedDB persistence / entry point (loading screen, `?plugin=`/`?url=`/`?model=` params)

Import via workspace names (`import { ... } from "@chili3d/core"`); one root `tsconfig.json` covers all packages.

## C++ WASM (`cpp/`)

OCCT v8.0.0 โ†’ `chili-wasm.wasm` via Emscripten. `cpp/src/`: `factory.cpp` (shape creation; the tracked ops report per-output history twice โ€” single-valued `faceMap`/`edgeMap` keeping the first ancestor, plus flat (out, in) `faceAncestors`/`edgeAncestors` pairs keeping every derivation so boolean-merged faces record all their inputs), `shape.cpp` (topology traversal), `converter.cpp` (STEP/IGES/BREP/STL), `mesher.cpp` (B-rep โ†’ mesh), `geometry.cpp` (curve/surface queries). The Release build sets `-sDISABLE_EXCEPTION_CATCHING=1`, so any OCCT raise aborts the whole module and C++ try/catch is ineffective โ€” the query files (`shape.cpp`/`mesher.cpp`/`geometry.cpp`) guard degenerate and null-geometry paths preventively (`IsGeometric`/`IsNull`/`IsDone` prechecks; `Edge::curve` reports degenerate edges through a JS-level throw, which still works with catching disabled), and the tracked sweep ops report cap faces through a separate `capFaces` channel on the tracked result (`LastShape()` of the sweep; empty when it coincides with `FirstShape()`, e.g. a 360ยฐ revolve). Output: `packages/wasm/lib/chili-wasm.{wasm,js,d.ts}`. C++ style: WebKit (clang-format); license LGPL-3.0 (TS is AGPL-3.0).

## Key Patterns

- **Interface-driven** โ€” `core` defines interfaces; feature packages implement; `AppBuilder` wires at startup.
- **Result pattern** โ€” Fallible ops return `Result.ok(value)` / `Result.err(error)` (`core/src/foundation/result.ts`); never throw for expected failures.
- **Reactive data** โ€” `Observable` uses `getPrivateValue(key)` / `setPrivateValue(key, value)`; setting emits `emitPropertyChanged`. `ObservableCollection` powers property editor and project tree.
- **Serialization** โ€” `@serializable()` on classes, `@serialize()` on fields โ†’ `{ __cla$$__: "ClassName", ...props }`.
- **Body nodes** โ€” `app/src/bodys/`; extend `ParameterShapeNode`, implement `generateShape(): Result<IShape>`, `setPropertyEmitShapeChanged()` triggers re-evaluation.
- **Commands** โ€” `ICommand.execute(application): Promise<void>`; `CancelableCommand` adds `cancel()`, `AsyncController`, dispose stack.
- **Undo/redo** โ€” `Transaction` records snapshots, `History` keeps the stack; commands create transactions automatically.
- **Plugins** โ€” Loaded from URLs or `?plugin=`; manager in `core/src/plugin/` + `app/src/pluginManager.ts`; examples in `plugins/`.
- **Global singleton** โ€” `getCurrentApplication()` (from `core`) instead of DI threading.
- **MCP server** โ€” a separate package (`chili3d-mcp`, moved out of this repo): its `live_*` tools drive the user's open browser tab, and headless tools (`run_cad_program`, `render_preview`, โ€ฆ) are a server-side scratchpad. Units: millimetres; angles: degrees.

## Testing

- Rstest (not Jest/Vitest) + Happy-DOM; root `rstest.config.ts`, globals enabled (`describe`, `test`, `expect`); tests in `packages/*/test/`; legacy decorators enabled.
- Reuse shared mocks from `@chili3d/core/test-utils` (`TestDocument`, `createMockDocument`, `createMockApplication`, `createMockVisual`, ...) instead of per-package copies; package-specific facades (e.g. `packages/ui/test/_helpers/`) extend them. `initializeI18n()` runs automatically via rstest `setupFiles` โ€” never call it in test files.
- Assertions must execute: none hidden in event callbacks (unless the callback is also asserted to fire), no tautologies (`x === true || x === false`), no `if (x) expect(...)` โ€” assert the precondition, then the behavior; `await` every promise whose `.then` asserts.
- Assert behavior, not absence of crashes: bare `not.toThrow()` / `toBeDefined()` is a smell; `querySelector` results need `not.toBeNull()`.
- Restore global monkeypatches (`PubSub.default.pub`, `globalThis.fetch`, ...) in `finally`/`afterEach`, or use `rs.stubGlobal` + `rs.unstubAllGlobals()`.
- Type `rs.fn` mocks with the real signature (`rs.fn((_edges: IEdge[]) => ...)`) so `mock.calls` typechecks; use `test.each` for near-identical repeated cases.

## Code Style

- Biome: 4-space indent, 110-col width, double quotes, semicolons always
- `I`-prefixed behavioral interfaces โ€” plain data-carrier shapes stay unprefixed (`...Data`, `...Ref`, `...Options`, e.g. `SketchData`, `EdgeRef`); `camelCase` functions/variables/files; `PascalCase` classes; `UPPER_SNAKE_CASE` constants
- CSS Modules (`*.module.css`); type-only imports (`import type { IFoo }`)
- Every TS file starts with the AGPL-3.0 header:

```ts
// Part of the Chili3d Project, under the AGPL-3.0 License.
// See LICENSE file in the project root for full license information.
```

## Git

Commits: `<emoji> <type>(<scope>): <description>` โ€” โœจ `feat` ยท ๐Ÿ› `fix` ยท โ™ป๏ธ `refactor` ยท โœ… `test` ยท ๐Ÿ“ `docs` ยท ๐Ÿ’„ `style` ยท ๐Ÿ”ง `chore`. Scope = package name. Active branch: `dev` โ†’ PR to `main`.