partforge 0.67.4 → 0.69.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/types/index.d.ts CHANGED
@@ -88,6 +88,7 @@ export interface MountElements {
88
88
  theme?: HTMLElement | null;
89
89
  cutaway?: HTMLElement | null;
90
90
  measure?: HTMLElement | null;
91
+ annotate?: HTMLElement | null;
91
92
  railToggle?: HTMLElement | null;
92
93
  };
93
94
  }
@@ -110,6 +111,19 @@ export interface MountOptions {
110
111
  onDownload?: (file: DownloadPayload) => void;
111
112
  /** The active view (tab) name — emitted once on mount, then on every change. */
112
113
  onViewChange?: (view: string) => void;
114
+ /**
115
+ * Receive user annotations (freehand ink over the frozen view). Supplying
116
+ * this reveals the `#annotate` viewbar button; omitting it hides the button
117
+ * entirely.
118
+ */
119
+ onAnnotationSend?: (payload: AnnotationPayload) => void;
120
+ /**
121
+ * Who owns annotation mode's Send affordance. `"viewbar"` (the default) puts
122
+ * Send beside Undo/Clear in the actions row. `"host"` drops it and leaves
123
+ * Undo/Clear: the host draws its own send control — e.g. a composer pairing
124
+ * the sketch with a typed message — and calls `runtime.annotate.send()`.
125
+ */
126
+ annotateSend?: "viewbar" | "host";
113
127
  /** @deprecated alias for `elements.viewer`. */
114
128
  container?: HTMLElement | null;
115
129
  /** @deprecated alias for `elements.controls`. */
@@ -156,6 +170,66 @@ export interface MeasureRuntime {
156
170
  pinCount(): number;
157
171
  }
158
172
 
173
+ /** One freehand stroke: points normalized 0..1 in viewport space; width as a
174
+ * fraction of the viewport's short edge. */
175
+ export interface AnnotationStroke {
176
+ points: [number, number][];
177
+ width: number;
178
+ }
179
+
180
+ /** A raycast sample grounding a stroke in the model. `t` anchors sit at the
181
+ * stroke's start/mid/end by arc length; `kind: "centroid"` anchors sit at the
182
+ * enclosed-region centroid of a closed stroke. `hit` is null when the sample
183
+ * ray missed all geometry — a deliberate signal, not an error. */
184
+ export interface AnnotationAnchor {
185
+ stroke: number;
186
+ t?: number;
187
+ kind?: "centroid";
188
+ screen: [number, number];
189
+ hit: { subPart: string; pointLocal: [number, number, number] } | null;
190
+ }
191
+
192
+ /** A camera pose. `world` replays exactly against the annotated build; `parts`
193
+ * is the same pose in the shared CAD frame (survives per-view recentring when
194
+ * the model is rebuilt), or null when no meshes were live. */
195
+ export interface AnnotationCamera {
196
+ world: { pos: number[]; target: number[]; up: number[]; fov: number };
197
+ parts: { pos: number[]; target: number[]; up: number[]; fov: number } | null;
198
+ }
199
+
200
+ /** What onAnnotationSend receives. The drawing and the 3D render are separate
201
+ * images over the same framing, so a host can composite them now and
202
+ * re-render the model from the same camera against later updates. */
203
+ export interface AnnotationPayload {
204
+ version: 1;
205
+ strokes: AnnotationStroke[];
206
+ anchors: AnnotationAnchor[];
207
+ /** Two base64 data URLs. On a large hi-DPI stage the drawing PNG alone can
208
+ * run several MB of base64 — hosts should not assume this payload is small. */
209
+ images: { drawing: string; model: string };
210
+ camera: AnnotationCamera;
211
+ viewport: { width: number; height: number; dpr: number };
212
+ context: { view: string; params: Record<string, unknown> };
213
+ }
214
+
215
+ export interface AnnotateRuntime {
216
+ isEnabled(): boolean;
217
+ setEnabled(on: boolean): void;
218
+ /** Drop the most recent stroke. */
219
+ undo(): void;
220
+ clear(): void;
221
+ strokeCount(): number;
222
+ /**
223
+ * Assemble the payload and hand it to `onAnnotationSend`, then exit the mode
224
+ * and discard the ink. Returns false — delivering nothing and keeping the ink
225
+ * — when the mode is off, the canvas is empty, or the render failed.
226
+ */
227
+ send(): boolean;
228
+ /** Every stroke, undo and clear. Returns an unsubscribe. */
229
+ onInkChange(cb: () => void): () => void;
230
+ onModeChange(cb: () => void): () => void;
231
+ }
232
+
159
233
  /** Where playback is: idle, swinging the camera to an intro cue, playing, or paused. */
160
234
  export type AnimationStatus = "idle" | "intro" | "playing" | "paused";
161
235
 
@@ -269,6 +343,8 @@ export interface PartRuntime {
269
343
  animation: AnimationRuntime | null;
270
344
  /** Measurement mode's runtime-controls API — mode on/off, unit, and pin state; dimensioned captures come from `captureCurrent()` while enabled. Always present (a no-op stand-in outside `makeHandle` tests). */
271
345
  measure: MeasureRuntime;
346
+ /** Annotation mode's runtime-controls API — mode on/off, ink state, and send. Always present; a no-op stand-in when `onAnnotationSend` was not supplied. */
347
+ annotate: AnnotateRuntime;
272
348
  }
273
349
 
274
350
  /** Mount a full parametric-part app from a `PartDefinition`. */
package/types/kernel.d.ts CHANGED
@@ -498,4 +498,10 @@ export interface GeometryKernel {
498
498
  resetCacheStats?(): void;
499
499
  /** Free per-job WASM objects (Manifold backend); call after each job. */
500
500
  cleanup?(): void;
501
+ /**
502
+ * Drain the feature-skip warnings recorded since the last drain — one message
503
+ * per fillet/chamfer (or roundAll) the backend skipped instead of failing the
504
+ * build over. Drain per sub-part to attribute each message to its build.
505
+ */
506
+ takeBuildWarnings?(): string[];
501
507
  }