campedersen commited on
Commit
2b3c4a6
·
verified ·
1 Parent(s): 2dd47f7

Initial deploy - SVG rendering with WASM kernel

Browse files
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ node_modules/
Dockerfile ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:20-slim
2
+
3
+ # Create non-root user for HuggingFace Spaces
4
+ RUN useradd -m -u 1000 user
5
+ USER user
6
+ ENV HOME=/home/user PATH=/home/user/.local/bin:$PATH
7
+
8
+ WORKDIR /home/user/app
9
+
10
+ # Copy application files directly - no npm install needed
11
+ COPY --chown=user kernel-wasm ./kernel-wasm
12
+ COPY --chown=user server.mjs ./
13
+
14
+ EXPOSE 7860
15
+
16
+ CMD ["node", "server.mjs"]
17
+
README.md CHANGED
@@ -1,10 +1,51 @@
1
  ---
2
- title: Vcad Render
3
- emoji: 👀
4
- colorFrom: indigo
5
- colorTo: pink
6
  sdk: docker
 
7
  pinned: false
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: vcad Render API
3
+ emoji: 🔧
4
+ colorFrom: green
5
+ colorTo: blue
6
  sdk: docker
7
+ app_port: 7860
8
  pinned: false
9
  ---
10
 
11
+ # vcad Render API
12
+
13
+ HTTP API that renders [Compact IR](https://campedersen.com/cad0) to PNG images using the vcad kernel.
14
+
15
+ ## Endpoints
16
+
17
+ ### POST /render
18
+
19
+ Renders Compact IR to a PNG image.
20
+
21
+ **Request:**
22
+ ```json
23
+ {
24
+ "ir": "C 50 30 10\nY 5 20\nT 1 25 15 0\nD 0 2"
25
+ }
26
+ ```
27
+
28
+ **Response:** PNG image (image/png)
29
+
30
+ ### GET /health
31
+
32
+ Health check endpoint.
33
+
34
+ **Response:**
35
+ ```json
36
+ {"status": "ok"}
37
+ ```
38
+
39
+ ## Compact IR Syntax
40
+
41
+ - `C w h d` - Box (cuboid)
42
+ - `Y r h` - Cylinder
43
+ - `S r` - Sphere
44
+ - `T idx x y z` - Translate node at index
45
+ - `U a b` - Union of nodes a and b
46
+ - `D a b` - Difference (a minus b)
47
+
48
+ ## Related
49
+
50
+ - [cad0 model](https://huggingface.co/campedersen/cad0) - Text to Compact IR
51
+ - [vcad](https://vcad.io) - Full CAD app
kernel-wasm/package.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "@vcad/kernel-wasm",
3
+ "type": "module",
4
+ "description": "WASM bindings for the vcad B-rep kernel",
5
+ "version": "0.8.0",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/ecto/vcad"
10
+ },
11
+ "files": [
12
+ "vcad_kernel_wasm_bg.wasm",
13
+ "vcad_kernel_wasm.js",
14
+ "vcad_kernel_wasm.d.ts"
15
+ ],
16
+ "main": "vcad_kernel_wasm.js",
17
+ "types": "vcad_kernel_wasm.d.ts",
18
+ "sideEffects": [
19
+ "./snippets/*"
20
+ ]
21
+ }
kernel-wasm/vcad_kernel_wasm.d.ts ADDED
@@ -0,0 +1,656 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * Stub PhysicsSim when physics feature is not enabled.
6
+ */
7
+ export class PhysicsSim {
8
+ free(): void;
9
+ [Symbol.dispose](): void;
10
+ /**
11
+ * Returns an error when physics feature is not enabled.
12
+ */
13
+ constructor(_doc_json: string, _end_effector_ids: string[], _dt?: number | null, _substeps?: number | null);
14
+ }
15
+
16
+ /**
17
+ * Stub RayTracer when raytrace feature is not enabled.
18
+ */
19
+ export class RayTracer {
20
+ private constructor();
21
+ free(): void;
22
+ [Symbol.dispose](): void;
23
+ /**
24
+ * Returns an error when raytrace feature is not enabled.
25
+ */
26
+ static create(): RayTracer;
27
+ }
28
+
29
+ /**
30
+ * A 3D solid geometry object.
31
+ *
32
+ * Create solids from primitives, combine with boolean operations,
33
+ * transform, and extract triangle meshes for rendering.
34
+ */
35
+ export class Solid {
36
+ private constructor();
37
+ free(): void;
38
+ [Symbol.dispose](): void;
39
+ /**
40
+ * Get the bounding box as [minX, minY, minZ, maxX, maxY, maxZ].
41
+ */
42
+ boundingBox(): Float64Array;
43
+ /**
44
+ * Check if the solid can be exported to STEP format.
45
+ *
46
+ * Returns `true` if the solid has B-rep data available for STEP export.
47
+ * Returns `false` for mesh-only or empty solids.
48
+ */
49
+ canExportStep(): boolean;
50
+ /**
51
+ * Get the center of mass as [x, y, z].
52
+ */
53
+ centerOfMass(): Float64Array;
54
+ /**
55
+ * Chamfer all edges of the solid by the given distance.
56
+ */
57
+ chamfer(distance: number): Solid;
58
+ /**
59
+ * Create a circular pattern of the solid around an axis.
60
+ *
61
+ * # Arguments
62
+ *
63
+ * * `axis_origin_x/y/z` - A point on the rotation axis
64
+ * * `axis_dir_x/y/z` - Direction of the rotation axis
65
+ * * `count` - Number of copies (including original)
66
+ * * `angle_deg` - Total angle span in degrees
67
+ */
68
+ circularPattern(axis_origin_x: number, axis_origin_y: number, axis_origin_z: number, axis_dir_x: number, axis_dir_y: number, axis_dir_z: number, count: number, angle_deg: number): Solid;
69
+ /**
70
+ * Create a cone/frustum along Z axis.
71
+ */
72
+ static cone(radius_bottom: number, radius_top: number, height: number, segments?: number | null): Solid;
73
+ /**
74
+ * Create a box with corner at origin and dimensions (sx, sy, sz).
75
+ */
76
+ static cube(sx: number, sy: number, sz: number): Solid;
77
+ /**
78
+ * Create a cylinder along Z axis with given radius and height.
79
+ */
80
+ static cylinder(radius: number, height: number, segments?: number | null): Solid;
81
+ /**
82
+ * Boolean difference (self − other).
83
+ */
84
+ difference(other: Solid): Solid;
85
+ /**
86
+ * Create an empty solid.
87
+ */
88
+ static empty(): Solid;
89
+ /**
90
+ * Create a solid by extruding a 2D sketch profile.
91
+ *
92
+ * Takes a sketch profile and extrusion direction as JS objects.
93
+ */
94
+ static extrude(profile_js: any, direction: Float64Array): Solid;
95
+ /**
96
+ * Fillet all edges of the solid with the given radius.
97
+ */
98
+ fillet(radius: number): Solid;
99
+ /**
100
+ * Get the triangle mesh representation.
101
+ *
102
+ * Returns a JS object with `positions` (Float32Array) and `indices` (Uint32Array).
103
+ */
104
+ getMesh(segments?: number | null): any;
105
+ /**
106
+ * Generate a horizontal section view at a given Z height.
107
+ *
108
+ * Convenience method that creates a horizontal section plane.
109
+ */
110
+ horizontalSection(z: number, hatch_spacing?: number | null, hatch_angle?: number | null, segments?: number | null): any;
111
+ /**
112
+ * Boolean intersection (self ∩ other).
113
+ */
114
+ intersection(other: Solid): Solid;
115
+ /**
116
+ * Check if the solid is empty (has no geometry).
117
+ */
118
+ isEmpty(): boolean;
119
+ /**
120
+ * Create a linear pattern of the solid along a direction.
121
+ *
122
+ * # Arguments
123
+ *
124
+ * * `dir_x`, `dir_y`, `dir_z` - Direction vector
125
+ * * `count` - Number of copies (including original)
126
+ * * `spacing` - Distance between copies
127
+ */
128
+ linearPattern(dir_x: number, dir_y: number, dir_z: number, count: number, spacing: number): Solid;
129
+ /**
130
+ * Create a solid by lofting between multiple profiles.
131
+ *
132
+ * Takes an array of sketch profiles (minimum 2).
133
+ */
134
+ static loft(profiles_js: any, closed?: boolean | null): Solid;
135
+ /**
136
+ * Get the number of triangles in the tessellated mesh.
137
+ */
138
+ numTriangles(): number;
139
+ /**
140
+ * Project the solid to a 2D view for technical drawing.
141
+ *
142
+ * # Arguments
143
+ * * `view_direction` - View direction: "front", "back", "top", "bottom", "left", "right", or "isometric"
144
+ * * `segments` - Number of segments for tessellation (optional, default 32)
145
+ *
146
+ * # Returns
147
+ * A JS object containing the projected view with edges and bounds.
148
+ */
149
+ projectView(view_direction: string, segments?: number | null): any;
150
+ /**
151
+ * Create a solid by revolving a 2D sketch profile around an axis.
152
+ *
153
+ * Takes a sketch profile, axis origin, axis direction, and angle in degrees.
154
+ */
155
+ static revolve(profile_js: any, axis_origin: Float64Array, axis_dir: Float64Array, angle_deg: number): Solid;
156
+ /**
157
+ * Rotate the solid by angles in degrees around X, Y, Z axes.
158
+ */
159
+ rotate(x_deg: number, y_deg: number, z_deg: number): Solid;
160
+ /**
161
+ * Scale the solid by (x, y, z).
162
+ */
163
+ scale(x: number, y: number, z: number): Solid;
164
+ /**
165
+ * Generate a section view by cutting the solid with a plane.
166
+ *
167
+ * # Arguments
168
+ * * `plane_json` - JSON string with plane definition: `{"origin": [x,y,z], "normal": [x,y,z], "up": [x,y,z]}`
169
+ * * `hatch_json` - Optional JSON string with hatch pattern: `{"spacing": f64, "angle": f64}`
170
+ * * `segments` - Number of segments for tessellation (optional, default 32)
171
+ *
172
+ * # Returns
173
+ * A JS object containing the section view with curves, hatch lines, and bounds.
174
+ */
175
+ sectionView(plane_json: string, hatch_json?: string | null, segments?: number | null): any;
176
+ /**
177
+ * Shell (hollow) the solid by offsetting all faces inward.
178
+ */
179
+ shell(thickness: number): Solid;
180
+ /**
181
+ * Create a sphere centered at origin with given radius.
182
+ */
183
+ static sphere(radius: number, segments?: number | null): Solid;
184
+ /**
185
+ * Compute the surface area of the solid.
186
+ */
187
+ surfaceArea(): number;
188
+ /**
189
+ * Create a solid by sweeping a profile along a helix path.
190
+ *
191
+ * Takes a sketch profile and helix parameters.
192
+ */
193
+ static sweepHelix(profile_js: any, radius: number, pitch: number, height: number, turns: number, twist_angle?: number | null, scale_start?: number | null, scale_end?: number | null, path_segments?: number | null, arc_segments?: number | null, orientation?: number | null): Solid;
194
+ /**
195
+ * Create a solid by sweeping a profile along a line path.
196
+ *
197
+ * Takes a sketch profile and path endpoints.
198
+ */
199
+ static sweepLine(profile_js: any, start: Float64Array, end: Float64Array, twist_angle?: number | null, scale_start?: number | null, scale_end?: number | null, orientation?: number | null): Solid;
200
+ /**
201
+ * Export the solid to STEP format.
202
+ *
203
+ * # Returns
204
+ * A byte buffer containing the STEP file data.
205
+ *
206
+ * # Errors
207
+ * Returns an error if the solid has no B-rep data (e.g., mesh-only after certain operations).
208
+ */
209
+ toStepBuffer(): Uint8Array;
210
+ /**
211
+ * Translate the solid by (x, y, z).
212
+ */
213
+ translate(x: number, y: number, z: number): Solid;
214
+ /**
215
+ * Boolean union (self ∪ other).
216
+ */
217
+ union(other: Solid): Solid;
218
+ /**
219
+ * Compute the volume of the solid.
220
+ */
221
+ volume(): number;
222
+ }
223
+
224
+ /**
225
+ * Annotation layer for dimension annotations.
226
+ *
227
+ * This class provides methods for creating and rendering dimension annotations
228
+ * on 2D projected views.
229
+ */
230
+ export class WasmAnnotationLayer {
231
+ free(): void;
232
+ [Symbol.dispose](): void;
233
+ /**
234
+ * Add an aligned dimension between two points.
235
+ *
236
+ * The dimension line is parallel to the line connecting the two points.
237
+ *
238
+ * # Arguments
239
+ * * `x1`, `y1` - First point coordinates
240
+ * * `x2`, `y2` - Second point coordinates
241
+ * * `offset` - Distance from points to dimension line
242
+ */
243
+ addAlignedDimension(x1: number, y1: number, x2: number, y2: number, offset: number): void;
244
+ /**
245
+ * Add an angular dimension between three points.
246
+ *
247
+ * The angle is measured at the vertex (middle point).
248
+ *
249
+ * # Arguments
250
+ * * `x1`, `y1` - First point on one leg
251
+ * * `vx`, `vy` - Vertex point (angle measured here)
252
+ * * `x2`, `y2` - Second point on other leg
253
+ * * `arc_radius` - Radius of the arc showing the angle
254
+ */
255
+ addAngleDimension(x1: number, y1: number, vx: number, vy: number, x2: number, y2: number, arc_radius: number): void;
256
+ /**
257
+ * Add a diameter dimension for a circle.
258
+ *
259
+ * # Arguments
260
+ * * `cx`, `cy` - Center of the circle
261
+ * * `radius` - Radius of the circle
262
+ * * `leader_angle` - Angle in radians for the leader line direction
263
+ */
264
+ addDiameterDimension(cx: number, cy: number, radius: number, leader_angle: number): void;
265
+ /**
266
+ * Add a horizontal dimension between two points.
267
+ *
268
+ * # Arguments
269
+ * * `x1`, `y1` - First point coordinates
270
+ * * `x2`, `y2` - Second point coordinates
271
+ * * `offset` - Distance from points to dimension line (positive = above)
272
+ */
273
+ addHorizontalDimension(x1: number, y1: number, x2: number, y2: number, offset: number): void;
274
+ /**
275
+ * Add a radius dimension for a circle.
276
+ *
277
+ * # Arguments
278
+ * * `cx`, `cy` - Center of the circle
279
+ * * `radius` - Radius of the circle
280
+ * * `leader_angle` - Angle in radians for the leader line direction
281
+ */
282
+ addRadiusDimension(cx: number, cy: number, radius: number, leader_angle: number): void;
283
+ /**
284
+ * Add a vertical dimension between two points.
285
+ *
286
+ * # Arguments
287
+ * * `x1`, `y1` - First point coordinates
288
+ * * `x2`, `y2` - Second point coordinates
289
+ * * `offset` - Distance from points to dimension line (positive = right)
290
+ */
291
+ addVerticalDimension(x1: number, y1: number, x2: number, y2: number, offset: number): void;
292
+ /**
293
+ * Get the number of annotations in the layer.
294
+ */
295
+ annotationCount(): number;
296
+ /**
297
+ * Clear all annotations from the layer.
298
+ */
299
+ clear(): void;
300
+ /**
301
+ * Check if the layer has any annotations.
302
+ */
303
+ isEmpty(): boolean;
304
+ /**
305
+ * Create a new empty annotation layer.
306
+ */
307
+ constructor();
308
+ /**
309
+ * Render all dimensions and return as JSON.
310
+ *
311
+ * Returns an array of rendered dimensions, each containing:
312
+ * - `lines`: Array of line segments [[x1, y1], [x2, y2]]
313
+ * - `arcs`: Array of arc definitions
314
+ * - `arrows`: Array of arrow definitions
315
+ * - `texts`: Array of text labels
316
+ *
317
+ * # Arguments
318
+ * * `view_json` - Optional JSON string of a ProjectedView for geometry resolution
319
+ */
320
+ renderAll(view_json?: string | null): any;
321
+ }
322
+
323
+ /**
324
+ * Compute creased normals (CPU fallback when GPU feature is disabled).
325
+ */
326
+ export function computeCreasedNormalsGpu(_positions: Float32Array, _indices: Uint32Array, _crease_angle: number): Promise<Float32Array>;
327
+
328
+ /**
329
+ * Create a detail view from a projected view.
330
+ *
331
+ * A detail view is a magnified region of a parent view, useful for showing
332
+ * fine features that would be too small in the main view.
333
+ *
334
+ * # Arguments
335
+ * * `parent_json` - JSON string of the parent ProjectedView
336
+ * * `center_x` - X coordinate of the region center
337
+ * * `center_y` - Y coordinate of the region center
338
+ * * `scale` - Magnification factor (e.g., 2.0 = 2x)
339
+ * * `width` - Width of the region to capture
340
+ * * `height` - Height of the region to capture
341
+ * * `label` - Label for the detail view (e.g., "A")
342
+ *
343
+ * # Returns
344
+ * A JS object containing the detail view with edges and bounds.
345
+ */
346
+ export function createDetailView(parent_json: string, center_x: number, center_y: number, scale: number, width: number, height: number, label: string): any;
347
+
348
+ /**
349
+ * Decimate a mesh (CPU fallback when GPU feature is disabled).
350
+ */
351
+ export function decimateMeshGpu(_positions: Float32Array, _indices: Uint32Array, _target_ratio: number): Promise<any>;
352
+
353
+ /**
354
+ * Evaluate compact IR and return a Solid for rendering.
355
+ *
356
+ * This is a convenience function that parses compact IR and evaluates
357
+ * the geometry in a single step.
358
+ *
359
+ * # Arguments
360
+ * * `compact_ir` - The compact IR text to evaluate
361
+ *
362
+ * # Returns
363
+ * A Solid object that can be rendered or queried.
364
+ */
365
+ export function evaluateCompactIR(compact_ir: string): Solid;
366
+
367
+ /**
368
+ * Export a projected view to DXF format.
369
+ *
370
+ * Returns the DXF content as bytes.
371
+ *
372
+ * # Arguments
373
+ * * `view_json` - JSON string of a ProjectedView
374
+ *
375
+ * # Returns
376
+ * A byte array containing the DXF file content.
377
+ */
378
+ export function exportProjectedViewToDxf(view_json: string): Uint8Array;
379
+
380
+ /**
381
+ * Import solids from STEP file bytes.
382
+ *
383
+ * Returns a JS array of mesh data for each imported body.
384
+ * Each mesh contains `positions` (Float32Array) and `indices` (Uint32Array).
385
+ *
386
+ * # Arguments
387
+ * * `data` - Raw STEP file contents as bytes
388
+ *
389
+ * # Returns
390
+ * A JS array of mesh objects for rendering the imported geometry.
391
+ */
392
+ export function importStepBuffer(data: Uint8Array): any;
393
+
394
+ /**
395
+ * Initialize the WASM module (sets up panic hook for better error messages).
396
+ */
397
+ export function init(): void;
398
+
399
+ /**
400
+ * Initialize the GPU context (stub when GPU feature is disabled).
401
+ */
402
+ export function initGpu(): Promise<boolean>;
403
+
404
+ /**
405
+ * Check if GPU processing is available.
406
+ */
407
+ export function isGpuAvailable(): boolean;
408
+
409
+ /**
410
+ * Check if physics simulation is available.
411
+ */
412
+ export function isPhysicsAvailable(): boolean;
413
+
414
+ /**
415
+ * Chamfer all edges of a solid by the given distance.
416
+ *
417
+ * This is a standalone wrapper for lazy loading via wasmosis.
418
+ */
419
+ export function op_chamfer(solid: Solid, distance: number): Solid;
420
+
421
+ /**
422
+ * Create a circular pattern of a solid around an axis.
423
+ *
424
+ * This is a standalone wrapper for lazy loading via wasmosis.
425
+ */
426
+ export function op_circular_pattern(solid: Solid, axis_origin_x: number, axis_origin_y: number, axis_origin_z: number, axis_dir_x: number, axis_dir_y: number, axis_dir_z: number, count: number, angle_deg: number): Solid;
427
+
428
+ /**
429
+ * Fillet all edges of a solid with the given radius.
430
+ *
431
+ * This is a standalone wrapper for lazy loading via wasmosis.
432
+ */
433
+ export function op_fillet(solid: Solid, radius: number): Solid;
434
+
435
+ /**
436
+ * Create a linear pattern of a solid along a direction.
437
+ *
438
+ * This is a standalone wrapper for lazy loading via wasmosis.
439
+ */
440
+ export function op_linear_pattern(solid: Solid, dir_x: number, dir_y: number, dir_z: number, count: number, spacing: number): Solid;
441
+
442
+ /**
443
+ * Create a solid by lofting between multiple profiles.
444
+ *
445
+ * This is a standalone wrapper for lazy loading via wasmosis.
446
+ */
447
+ export function op_loft(profiles_js: any, closed?: boolean | null): Solid;
448
+
449
+ /**
450
+ * Create a solid by revolving a 2D sketch profile around an axis.
451
+ *
452
+ * This is a standalone wrapper for lazy loading via wasmosis.
453
+ */
454
+ export function op_revolve(profile_js: any, axis_origin: Float64Array, axis_dir: Float64Array, angle_deg: number): Solid;
455
+
456
+ /**
457
+ * Shell (hollow) a solid by offsetting all faces inward.
458
+ *
459
+ * This is a standalone wrapper for lazy loading via wasmosis.
460
+ */
461
+ export function op_shell(solid: Solid, thickness: number): Solid;
462
+
463
+ /**
464
+ * Create a solid by sweeping a profile along a helix path.
465
+ *
466
+ * This is a standalone wrapper for lazy loading via wasmosis.
467
+ */
468
+ export function op_sweep_helix(profile_js: any, radius: number, pitch: number, height: number, turns: number, twist_angle?: number | null, scale_start?: number | null, scale_end?: number | null, path_segments?: number | null, arc_segments?: number | null, orientation?: number | null): Solid;
469
+
470
+ /**
471
+ * Create a solid by sweeping a profile along a line path.
472
+ *
473
+ * This is a standalone wrapper for lazy loading via wasmosis.
474
+ */
475
+ export function op_sweep_line(profile_js: any, start: Float64Array, end: Float64Array, twist_angle?: number | null, scale_start?: number | null, scale_end?: number | null, orientation?: number | null): Solid;
476
+
477
+ /**
478
+ * Parse compact IR text format into a vcad IR Document (JSON).
479
+ *
480
+ * The compact IR format is a token-efficient text representation designed
481
+ * for ML model training and inference. See `vcad_ir::compact` for format details.
482
+ *
483
+ * # Arguments
484
+ * * `compact_ir` - The compact IR text to parse
485
+ *
486
+ * # Returns
487
+ * A JSON string representing the parsed vcad IR Document.
488
+ *
489
+ * # Example
490
+ * ```javascript
491
+ * const ir = "C 50 30 5\nY 5 10\nT 1 25 15 0\nD 0 2";
492
+ * const doc = parseCompactIR(ir);
493
+ * console.log(doc); // JSON document
494
+ * ```
495
+ */
496
+ export function parseCompactIR(compact_ir: string): string;
497
+
498
+ /**
499
+ * Process geometry (CPU fallback when GPU feature is disabled).
500
+ */
501
+ export function processGeometryGpu(_positions: Float32Array, _indices: Uint32Array, _crease_angle: number, _generate_lod: boolean): Promise<any>;
502
+
503
+ /**
504
+ * Project a triangle mesh to a 2D view.
505
+ *
506
+ * # Arguments
507
+ * * `mesh_js` - Mesh data as JS object with `positions` (Float32Array) and `indices` (Uint32Array)
508
+ * * `view_direction` - View direction: "front", "back", "top", "bottom", "left", "right", or "isometric"
509
+ *
510
+ * # Returns
511
+ * A JS object containing the projected view with edges and bounds.
512
+ */
513
+ export function projectMesh(mesh_js: any, view_direction: string): any;
514
+
515
+ /**
516
+ * Generate a section view from a triangle mesh.
517
+ *
518
+ * # Arguments
519
+ * * `mesh_js` - Mesh data as JS object with `positions` (Float32Array) and `indices` (Uint32Array)
520
+ * * `plane_json` - JSON string with plane definition: `{"origin": [x,y,z], "normal": [x,y,z], "up": [x,y,z]}`
521
+ * * `hatch_json` - Optional JSON string with hatch pattern: `{"spacing": f64, "angle": f64}`
522
+ *
523
+ * # Returns
524
+ * A JS object containing the section view with curves, hatch lines, and bounds.
525
+ */
526
+ export function sectionMesh(mesh_js: any, plane_json: string, hatch_json?: string | null): any;
527
+
528
+ /**
529
+ * Convert a vcad IR Document (JSON) to compact IR text format.
530
+ *
531
+ * # Arguments
532
+ * * `doc_json` - JSON string representing a vcad IR Document
533
+ *
534
+ * # Returns
535
+ * The compact IR text representation.
536
+ *
537
+ * # Example
538
+ * ```javascript
539
+ * const compact = toCompactIR(docJson);
540
+ * console.log(compact); // "C 50 30 5\nY 5 10\n..."
541
+ * ```
542
+ */
543
+ export function toCompactIR(doc_json: string): string;
544
+
545
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
546
+
547
+ export interface InitOutput {
548
+ readonly memory: WebAssembly.Memory;
549
+ readonly __wbg_physicssim_free: (a: number, b: number) => void;
550
+ readonly __wbg_raytracer_free: (a: number, b: number) => void;
551
+ readonly __wbg_solid_free: (a: number, b: number) => void;
552
+ readonly __wbg_wasmannotationlayer_free: (a: number, b: number) => void;
553
+ readonly computeCreasedNormalsGpu: (a: number, b: number, c: number, d: number, e: number) => any;
554
+ readonly createDetailView: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => [number, number, number];
555
+ readonly decimateMeshGpu: (a: number, b: number, c: number, d: number, e: number) => any;
556
+ readonly evaluateCompactIR: (a: number, b: number) => [number, number, number];
557
+ readonly exportProjectedViewToDxf: (a: number, b: number) => [number, number, number, number];
558
+ readonly importStepBuffer: (a: number, b: number) => [number, number, number];
559
+ readonly initGpu: () => any;
560
+ readonly isGpuAvailable: () => number;
561
+ readonly op_chamfer: (a: number, b: number) => number;
562
+ readonly op_circular_pattern: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => number;
563
+ readonly op_fillet: (a: number, b: number) => number;
564
+ readonly op_linear_pattern: (a: number, b: number, c: number, d: number, e: number, f: number) => number;
565
+ readonly op_loft: (a: any, b: number) => [number, number, number];
566
+ readonly op_revolve: (a: any, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
567
+ readonly op_shell: (a: number, b: number) => number;
568
+ readonly op_sweep_helix: (a: any, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number) => [number, number, number];
569
+ readonly op_sweep_line: (a: any, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number) => [number, number, number];
570
+ readonly parseCompactIR: (a: number, b: number) => [number, number, number, number];
571
+ readonly physicssim_new: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
572
+ readonly processGeometryGpu: (a: number, b: number, c: number, d: number, e: number, f: number) => any;
573
+ readonly projectMesh: (a: any, b: number, c: number) => any;
574
+ readonly raytracer_create: () => [number, number, number];
575
+ readonly sectionMesh: (a: any, b: number, c: number, d: number, e: number) => any;
576
+ readonly solid_boundingBox: (a: number) => [number, number];
577
+ readonly solid_canExportStep: (a: number) => number;
578
+ readonly solid_centerOfMass: (a: number) => [number, number];
579
+ readonly solid_cone: (a: number, b: number, c: number, d: number) => number;
580
+ readonly solid_cube: (a: number, b: number, c: number) => number;
581
+ readonly solid_cylinder: (a: number, b: number, c: number) => number;
582
+ readonly solid_difference: (a: number, b: number) => number;
583
+ readonly solid_empty: () => number;
584
+ readonly solid_extrude: (a: any, b: number, c: number) => [number, number, number];
585
+ readonly solid_getMesh: (a: number, b: number) => any;
586
+ readonly solid_horizontalSection: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => any;
587
+ readonly solid_intersection: (a: number, b: number) => number;
588
+ readonly solid_isEmpty: (a: number) => number;
589
+ readonly solid_loft: (a: any, b: number) => [number, number, number];
590
+ readonly solid_numTriangles: (a: number) => number;
591
+ readonly solid_projectView: (a: number, b: number, c: number, d: number) => any;
592
+ readonly solid_rotate: (a: number, b: number, c: number, d: number) => number;
593
+ readonly solid_scale: (a: number, b: number, c: number, d: number) => number;
594
+ readonly solid_sectionView: (a: number, b: number, c: number, d: number, e: number, f: number) => any;
595
+ readonly solid_sphere: (a: number, b: number) => number;
596
+ readonly solid_surfaceArea: (a: number) => number;
597
+ readonly solid_sweepHelix: (a: any, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number) => [number, number, number];
598
+ readonly solid_sweepLine: (a: any, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number) => [number, number, number];
599
+ readonly solid_toStepBuffer: (a: number) => [number, number, number, number];
600
+ readonly solid_translate: (a: number, b: number, c: number, d: number) => number;
601
+ readonly solid_union: (a: number, b: number) => number;
602
+ readonly solid_volume: (a: number) => number;
603
+ readonly toCompactIR: (a: number, b: number) => [number, number, number, number];
604
+ readonly wasmannotationlayer_addAlignedDimension: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
605
+ readonly wasmannotationlayer_addAngleDimension: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
606
+ readonly wasmannotationlayer_addDiameterDimension: (a: number, b: number, c: number, d: number, e: number) => void;
607
+ readonly wasmannotationlayer_addHorizontalDimension: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
608
+ readonly wasmannotationlayer_addRadiusDimension: (a: number, b: number, c: number, d: number, e: number) => void;
609
+ readonly wasmannotationlayer_addVerticalDimension: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
610
+ readonly wasmannotationlayer_annotationCount: (a: number) => number;
611
+ readonly wasmannotationlayer_clear: (a: number) => void;
612
+ readonly wasmannotationlayer_isEmpty: (a: number) => number;
613
+ readonly wasmannotationlayer_new: () => number;
614
+ readonly wasmannotationlayer_renderAll: (a: number, b: number, c: number) => any;
615
+ readonly solid_linearPattern: (a: number, b: number, c: number, d: number, e: number, f: number) => number;
616
+ readonly init: () => void;
617
+ readonly solid_revolve: (a: any, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
618
+ readonly isPhysicsAvailable: () => number;
619
+ readonly solid_chamfer: (a: number, b: number) => number;
620
+ readonly solid_fillet: (a: number, b: number) => number;
621
+ readonly solid_shell: (a: number, b: number) => number;
622
+ readonly solid_circularPattern: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => number;
623
+ readonly wasm_bindgen__closure__destroy__ha1c57de1520edab9: (a: number, b: number) => void;
624
+ readonly wasm_bindgen__convert__closures_____invoke__h90946713c829438a: (a: number, b: number, c: any, d: any) => void;
625
+ readonly wasm_bindgen__convert__closures_____invoke__h4889c924fd29fd81: (a: number, b: number, c: any) => void;
626
+ readonly __wbindgen_malloc: (a: number, b: number) => number;
627
+ readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
628
+ readonly __wbindgen_exn_store: (a: number) => void;
629
+ readonly __externref_table_alloc: () => number;
630
+ readonly __wbindgen_externrefs: WebAssembly.Table;
631
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
632
+ readonly __externref_table_dealloc: (a: number) => void;
633
+ readonly __wbindgen_start: () => void;
634
+ }
635
+
636
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
637
+
638
+ /**
639
+ * Instantiates the given `module`, which can either be bytes or
640
+ * a precompiled `WebAssembly.Module`.
641
+ *
642
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
643
+ *
644
+ * @returns {InitOutput}
645
+ */
646
+ export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
647
+
648
+ /**
649
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
650
+ * for everything else, calls `WebAssembly.instantiate` directly.
651
+ *
652
+ * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
653
+ *
654
+ * @returns {Promise<InitOutput>}
655
+ */
656
+ export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
kernel-wasm/vcad_kernel_wasm.js ADDED
@@ -0,0 +1,1915 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* @ts-self-types="./vcad_kernel_wasm.d.ts" */
2
+
3
+ /**
4
+ * Stub PhysicsSim when physics feature is not enabled.
5
+ */
6
+ export class PhysicsSim {
7
+ __destroy_into_raw() {
8
+ const ptr = this.__wbg_ptr;
9
+ this.__wbg_ptr = 0;
10
+ PhysicsSimFinalization.unregister(this);
11
+ return ptr;
12
+ }
13
+ free() {
14
+ const ptr = this.__destroy_into_raw();
15
+ wasm.__wbg_physicssim_free(ptr, 0);
16
+ }
17
+ /**
18
+ * Returns an error when physics feature is not enabled.
19
+ * @param {string} _doc_json
20
+ * @param {string[]} _end_effector_ids
21
+ * @param {number | null} [_dt]
22
+ * @param {number | null} [_substeps]
23
+ */
24
+ constructor(_doc_json, _end_effector_ids, _dt, _substeps) {
25
+ const ptr0 = passStringToWasm0(_doc_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
26
+ const len0 = WASM_VECTOR_LEN;
27
+ const ptr1 = passArrayJsValueToWasm0(_end_effector_ids, wasm.__wbindgen_malloc);
28
+ const len1 = WASM_VECTOR_LEN;
29
+ const ret = wasm.physicssim_new(ptr0, len0, ptr1, len1, isLikeNone(_dt) ? 0x100000001 : Math.fround(_dt), isLikeNone(_substeps) ? 0x100000001 : (_substeps) >>> 0);
30
+ if (ret[2]) {
31
+ throw takeFromExternrefTable0(ret[1]);
32
+ }
33
+ this.__wbg_ptr = ret[0] >>> 0;
34
+ PhysicsSimFinalization.register(this, this.__wbg_ptr, this);
35
+ return this;
36
+ }
37
+ }
38
+ if (Symbol.dispose) PhysicsSim.prototype[Symbol.dispose] = PhysicsSim.prototype.free;
39
+
40
+ /**
41
+ * Stub RayTracer when raytrace feature is not enabled.
42
+ */
43
+ export class RayTracer {
44
+ static __wrap(ptr) {
45
+ ptr = ptr >>> 0;
46
+ const obj = Object.create(RayTracer.prototype);
47
+ obj.__wbg_ptr = ptr;
48
+ RayTracerFinalization.register(obj, obj.__wbg_ptr, obj);
49
+ return obj;
50
+ }
51
+ __destroy_into_raw() {
52
+ const ptr = this.__wbg_ptr;
53
+ this.__wbg_ptr = 0;
54
+ RayTracerFinalization.unregister(this);
55
+ return ptr;
56
+ }
57
+ free() {
58
+ const ptr = this.__destroy_into_raw();
59
+ wasm.__wbg_raytracer_free(ptr, 0);
60
+ }
61
+ /**
62
+ * Returns an error when raytrace feature is not enabled.
63
+ * @returns {RayTracer}
64
+ */
65
+ static create() {
66
+ const ret = wasm.raytracer_create();
67
+ if (ret[2]) {
68
+ throw takeFromExternrefTable0(ret[1]);
69
+ }
70
+ return RayTracer.__wrap(ret[0]);
71
+ }
72
+ }
73
+ if (Symbol.dispose) RayTracer.prototype[Symbol.dispose] = RayTracer.prototype.free;
74
+
75
+ /**
76
+ * A 3D solid geometry object.
77
+ *
78
+ * Create solids from primitives, combine with boolean operations,
79
+ * transform, and extract triangle meshes for rendering.
80
+ */
81
+ export class Solid {
82
+ static __wrap(ptr) {
83
+ ptr = ptr >>> 0;
84
+ const obj = Object.create(Solid.prototype);
85
+ obj.__wbg_ptr = ptr;
86
+ SolidFinalization.register(obj, obj.__wbg_ptr, obj);
87
+ return obj;
88
+ }
89
+ __destroy_into_raw() {
90
+ const ptr = this.__wbg_ptr;
91
+ this.__wbg_ptr = 0;
92
+ SolidFinalization.unregister(this);
93
+ return ptr;
94
+ }
95
+ free() {
96
+ const ptr = this.__destroy_into_raw();
97
+ wasm.__wbg_solid_free(ptr, 0);
98
+ }
99
+ /**
100
+ * Get the bounding box as [minX, minY, minZ, maxX, maxY, maxZ].
101
+ * @returns {Float64Array}
102
+ */
103
+ boundingBox() {
104
+ const ret = wasm.solid_boundingBox(this.__wbg_ptr);
105
+ var v1 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
106
+ wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
107
+ return v1;
108
+ }
109
+ /**
110
+ * Check if the solid can be exported to STEP format.
111
+ *
112
+ * Returns `true` if the solid has B-rep data available for STEP export.
113
+ * Returns `false` for mesh-only or empty solids.
114
+ * @returns {boolean}
115
+ */
116
+ canExportStep() {
117
+ const ret = wasm.solid_canExportStep(this.__wbg_ptr);
118
+ return ret !== 0;
119
+ }
120
+ /**
121
+ * Get the center of mass as [x, y, z].
122
+ * @returns {Float64Array}
123
+ */
124
+ centerOfMass() {
125
+ const ret = wasm.solid_centerOfMass(this.__wbg_ptr);
126
+ var v1 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
127
+ wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
128
+ return v1;
129
+ }
130
+ /**
131
+ * Chamfer all edges of the solid by the given distance.
132
+ * @param {number} distance
133
+ * @returns {Solid}
134
+ */
135
+ chamfer(distance) {
136
+ const ret = wasm.op_chamfer(this.__wbg_ptr, distance);
137
+ return Solid.__wrap(ret);
138
+ }
139
+ /**
140
+ * Create a circular pattern of the solid around an axis.
141
+ *
142
+ * # Arguments
143
+ *
144
+ * * `axis_origin_x/y/z` - A point on the rotation axis
145
+ * * `axis_dir_x/y/z` - Direction of the rotation axis
146
+ * * `count` - Number of copies (including original)
147
+ * * `angle_deg` - Total angle span in degrees
148
+ * @param {number} axis_origin_x
149
+ * @param {number} axis_origin_y
150
+ * @param {number} axis_origin_z
151
+ * @param {number} axis_dir_x
152
+ * @param {number} axis_dir_y
153
+ * @param {number} axis_dir_z
154
+ * @param {number} count
155
+ * @param {number} angle_deg
156
+ * @returns {Solid}
157
+ */
158
+ circularPattern(axis_origin_x, axis_origin_y, axis_origin_z, axis_dir_x, axis_dir_y, axis_dir_z, count, angle_deg) {
159
+ const ret = wasm.op_circular_pattern(this.__wbg_ptr, axis_origin_x, axis_origin_y, axis_origin_z, axis_dir_x, axis_dir_y, axis_dir_z, count, angle_deg);
160
+ return Solid.__wrap(ret);
161
+ }
162
+ /**
163
+ * Create a cone/frustum along Z axis.
164
+ * @param {number} radius_bottom
165
+ * @param {number} radius_top
166
+ * @param {number} height
167
+ * @param {number | null} [segments]
168
+ * @returns {Solid}
169
+ */
170
+ static cone(radius_bottom, radius_top, height, segments) {
171
+ const ret = wasm.solid_cone(radius_bottom, radius_top, height, isLikeNone(segments) ? 0x100000001 : (segments) >>> 0);
172
+ return Solid.__wrap(ret);
173
+ }
174
+ /**
175
+ * Create a box with corner at origin and dimensions (sx, sy, sz).
176
+ * @param {number} sx
177
+ * @param {number} sy
178
+ * @param {number} sz
179
+ * @returns {Solid}
180
+ */
181
+ static cube(sx, sy, sz) {
182
+ const ret = wasm.solid_cube(sx, sy, sz);
183
+ return Solid.__wrap(ret);
184
+ }
185
+ /**
186
+ * Create a cylinder along Z axis with given radius and height.
187
+ * @param {number} radius
188
+ * @param {number} height
189
+ * @param {number | null} [segments]
190
+ * @returns {Solid}
191
+ */
192
+ static cylinder(radius, height, segments) {
193
+ const ret = wasm.solid_cylinder(radius, height, isLikeNone(segments) ? 0x100000001 : (segments) >>> 0);
194
+ return Solid.__wrap(ret);
195
+ }
196
+ /**
197
+ * Boolean difference (self − other).
198
+ * @param {Solid} other
199
+ * @returns {Solid}
200
+ */
201
+ difference(other) {
202
+ _assertClass(other, Solid);
203
+ const ret = wasm.solid_difference(this.__wbg_ptr, other.__wbg_ptr);
204
+ return Solid.__wrap(ret);
205
+ }
206
+ /**
207
+ * Create an empty solid.
208
+ * @returns {Solid}
209
+ */
210
+ static empty() {
211
+ const ret = wasm.solid_empty();
212
+ return Solid.__wrap(ret);
213
+ }
214
+ /**
215
+ * Create a solid by extruding a 2D sketch profile.
216
+ *
217
+ * Takes a sketch profile and extrusion direction as JS objects.
218
+ * @param {any} profile_js
219
+ * @param {Float64Array} direction
220
+ * @returns {Solid}
221
+ */
222
+ static extrude(profile_js, direction) {
223
+ const ptr0 = passArrayF64ToWasm0(direction, wasm.__wbindgen_malloc);
224
+ const len0 = WASM_VECTOR_LEN;
225
+ const ret = wasm.solid_extrude(profile_js, ptr0, len0);
226
+ if (ret[2]) {
227
+ throw takeFromExternrefTable0(ret[1]);
228
+ }
229
+ return Solid.__wrap(ret[0]);
230
+ }
231
+ /**
232
+ * Fillet all edges of the solid with the given radius.
233
+ * @param {number} radius
234
+ * @returns {Solid}
235
+ */
236
+ fillet(radius) {
237
+ const ret = wasm.op_fillet(this.__wbg_ptr, radius);
238
+ return Solid.__wrap(ret);
239
+ }
240
+ /**
241
+ * Get the triangle mesh representation.
242
+ *
243
+ * Returns a JS object with `positions` (Float32Array) and `indices` (Uint32Array).
244
+ * @param {number | null} [segments]
245
+ * @returns {any}
246
+ */
247
+ getMesh(segments) {
248
+ const ret = wasm.solid_getMesh(this.__wbg_ptr, isLikeNone(segments) ? 0x100000001 : (segments) >>> 0);
249
+ return ret;
250
+ }
251
+ /**
252
+ * Generate a horizontal section view at a given Z height.
253
+ *
254
+ * Convenience method that creates a horizontal section plane.
255
+ * @param {number} z
256
+ * @param {number | null} [hatch_spacing]
257
+ * @param {number | null} [hatch_angle]
258
+ * @param {number | null} [segments]
259
+ * @returns {any}
260
+ */
261
+ horizontalSection(z, hatch_spacing, hatch_angle, segments) {
262
+ const ret = wasm.solid_horizontalSection(this.__wbg_ptr, z, !isLikeNone(hatch_spacing), isLikeNone(hatch_spacing) ? 0 : hatch_spacing, !isLikeNone(hatch_angle), isLikeNone(hatch_angle) ? 0 : hatch_angle, isLikeNone(segments) ? 0x100000001 : (segments) >>> 0);
263
+ return ret;
264
+ }
265
+ /**
266
+ * Boolean intersection (self ∩ other).
267
+ * @param {Solid} other
268
+ * @returns {Solid}
269
+ */
270
+ intersection(other) {
271
+ _assertClass(other, Solid);
272
+ const ret = wasm.solid_intersection(this.__wbg_ptr, other.__wbg_ptr);
273
+ return Solid.__wrap(ret);
274
+ }
275
+ /**
276
+ * Check if the solid is empty (has no geometry).
277
+ * @returns {boolean}
278
+ */
279
+ isEmpty() {
280
+ const ret = wasm.solid_isEmpty(this.__wbg_ptr);
281
+ return ret !== 0;
282
+ }
283
+ /**
284
+ * Create a linear pattern of the solid along a direction.
285
+ *
286
+ * # Arguments
287
+ *
288
+ * * `dir_x`, `dir_y`, `dir_z` - Direction vector
289
+ * * `count` - Number of copies (including original)
290
+ * * `spacing` - Distance between copies
291
+ * @param {number} dir_x
292
+ * @param {number} dir_y
293
+ * @param {number} dir_z
294
+ * @param {number} count
295
+ * @param {number} spacing
296
+ * @returns {Solid}
297
+ */
298
+ linearPattern(dir_x, dir_y, dir_z, count, spacing) {
299
+ const ret = wasm.op_linear_pattern(this.__wbg_ptr, dir_x, dir_y, dir_z, count, spacing);
300
+ return Solid.__wrap(ret);
301
+ }
302
+ /**
303
+ * Create a solid by lofting between multiple profiles.
304
+ *
305
+ * Takes an array of sketch profiles (minimum 2).
306
+ * @param {any} profiles_js
307
+ * @param {boolean | null} [closed]
308
+ * @returns {Solid}
309
+ */
310
+ static loft(profiles_js, closed) {
311
+ const ret = wasm.solid_loft(profiles_js, isLikeNone(closed) ? 0xFFFFFF : closed ? 1 : 0);
312
+ if (ret[2]) {
313
+ throw takeFromExternrefTable0(ret[1]);
314
+ }
315
+ return Solid.__wrap(ret[0]);
316
+ }
317
+ /**
318
+ * Get the number of triangles in the tessellated mesh.
319
+ * @returns {number}
320
+ */
321
+ numTriangles() {
322
+ const ret = wasm.solid_numTriangles(this.__wbg_ptr);
323
+ return ret >>> 0;
324
+ }
325
+ /**
326
+ * Project the solid to a 2D view for technical drawing.
327
+ *
328
+ * # Arguments
329
+ * * `view_direction` - View direction: "front", "back", "top", "bottom", "left", "right", or "isometric"
330
+ * * `segments` - Number of segments for tessellation (optional, default 32)
331
+ *
332
+ * # Returns
333
+ * A JS object containing the projected view with edges and bounds.
334
+ * @param {string} view_direction
335
+ * @param {number | null} [segments]
336
+ * @returns {any}
337
+ */
338
+ projectView(view_direction, segments) {
339
+ const ptr0 = passStringToWasm0(view_direction, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
340
+ const len0 = WASM_VECTOR_LEN;
341
+ const ret = wasm.solid_projectView(this.__wbg_ptr, ptr0, len0, isLikeNone(segments) ? 0x100000001 : (segments) >>> 0);
342
+ return ret;
343
+ }
344
+ /**
345
+ * Create a solid by revolving a 2D sketch profile around an axis.
346
+ *
347
+ * Takes a sketch profile, axis origin, axis direction, and angle in degrees.
348
+ * @param {any} profile_js
349
+ * @param {Float64Array} axis_origin
350
+ * @param {Float64Array} axis_dir
351
+ * @param {number} angle_deg
352
+ * @returns {Solid}
353
+ */
354
+ static revolve(profile_js, axis_origin, axis_dir, angle_deg) {
355
+ const ptr0 = passArrayF64ToWasm0(axis_origin, wasm.__wbindgen_malloc);
356
+ const len0 = WASM_VECTOR_LEN;
357
+ const ptr1 = passArrayF64ToWasm0(axis_dir, wasm.__wbindgen_malloc);
358
+ const len1 = WASM_VECTOR_LEN;
359
+ const ret = wasm.solid_revolve(profile_js, ptr0, len0, ptr1, len1, angle_deg);
360
+ if (ret[2]) {
361
+ throw takeFromExternrefTable0(ret[1]);
362
+ }
363
+ return Solid.__wrap(ret[0]);
364
+ }
365
+ /**
366
+ * Rotate the solid by angles in degrees around X, Y, Z axes.
367
+ * @param {number} x_deg
368
+ * @param {number} y_deg
369
+ * @param {number} z_deg
370
+ * @returns {Solid}
371
+ */
372
+ rotate(x_deg, y_deg, z_deg) {
373
+ const ret = wasm.solid_rotate(this.__wbg_ptr, x_deg, y_deg, z_deg);
374
+ return Solid.__wrap(ret);
375
+ }
376
+ /**
377
+ * Scale the solid by (x, y, z).
378
+ * @param {number} x
379
+ * @param {number} y
380
+ * @param {number} z
381
+ * @returns {Solid}
382
+ */
383
+ scale(x, y, z) {
384
+ const ret = wasm.solid_scale(this.__wbg_ptr, x, y, z);
385
+ return Solid.__wrap(ret);
386
+ }
387
+ /**
388
+ * Generate a section view by cutting the solid with a plane.
389
+ *
390
+ * # Arguments
391
+ * * `plane_json` - JSON string with plane definition: `{"origin": [x,y,z], "normal": [x,y,z], "up": [x,y,z]}`
392
+ * * `hatch_json` - Optional JSON string with hatch pattern: `{"spacing": f64, "angle": f64}`
393
+ * * `segments` - Number of segments for tessellation (optional, default 32)
394
+ *
395
+ * # Returns
396
+ * A JS object containing the section view with curves, hatch lines, and bounds.
397
+ * @param {string} plane_json
398
+ * @param {string | null} [hatch_json]
399
+ * @param {number | null} [segments]
400
+ * @returns {any}
401
+ */
402
+ sectionView(plane_json, hatch_json, segments) {
403
+ const ptr0 = passStringToWasm0(plane_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
404
+ const len0 = WASM_VECTOR_LEN;
405
+ var ptr1 = isLikeNone(hatch_json) ? 0 : passStringToWasm0(hatch_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
406
+ var len1 = WASM_VECTOR_LEN;
407
+ const ret = wasm.solid_sectionView(this.__wbg_ptr, ptr0, len0, ptr1, len1, isLikeNone(segments) ? 0x100000001 : (segments) >>> 0);
408
+ return ret;
409
+ }
410
+ /**
411
+ * Shell (hollow) the solid by offsetting all faces inward.
412
+ * @param {number} thickness
413
+ * @returns {Solid}
414
+ */
415
+ shell(thickness) {
416
+ const ret = wasm.op_shell(this.__wbg_ptr, thickness);
417
+ return Solid.__wrap(ret);
418
+ }
419
+ /**
420
+ * Create a sphere centered at origin with given radius.
421
+ * @param {number} radius
422
+ * @param {number | null} [segments]
423
+ * @returns {Solid}
424
+ */
425
+ static sphere(radius, segments) {
426
+ const ret = wasm.solid_sphere(radius, isLikeNone(segments) ? 0x100000001 : (segments) >>> 0);
427
+ return Solid.__wrap(ret);
428
+ }
429
+ /**
430
+ * Compute the surface area of the solid.
431
+ * @returns {number}
432
+ */
433
+ surfaceArea() {
434
+ const ret = wasm.solid_surfaceArea(this.__wbg_ptr);
435
+ return ret;
436
+ }
437
+ /**
438
+ * Create a solid by sweeping a profile along a helix path.
439
+ *
440
+ * Takes a sketch profile and helix parameters.
441
+ * @param {any} profile_js
442
+ * @param {number} radius
443
+ * @param {number} pitch
444
+ * @param {number} height
445
+ * @param {number} turns
446
+ * @param {number | null} [twist_angle]
447
+ * @param {number | null} [scale_start]
448
+ * @param {number | null} [scale_end]
449
+ * @param {number | null} [path_segments]
450
+ * @param {number | null} [arc_segments]
451
+ * @param {number | null} [orientation]
452
+ * @returns {Solid}
453
+ */
454
+ static sweepHelix(profile_js, radius, pitch, height, turns, twist_angle, scale_start, scale_end, path_segments, arc_segments, orientation) {
455
+ const ret = wasm.solid_sweepHelix(profile_js, radius, pitch, height, turns, !isLikeNone(twist_angle), isLikeNone(twist_angle) ? 0 : twist_angle, !isLikeNone(scale_start), isLikeNone(scale_start) ? 0 : scale_start, !isLikeNone(scale_end), isLikeNone(scale_end) ? 0 : scale_end, isLikeNone(path_segments) ? 0x100000001 : (path_segments) >>> 0, isLikeNone(arc_segments) ? 0x100000001 : (arc_segments) >>> 0, !isLikeNone(orientation), isLikeNone(orientation) ? 0 : orientation);
456
+ if (ret[2]) {
457
+ throw takeFromExternrefTable0(ret[1]);
458
+ }
459
+ return Solid.__wrap(ret[0]);
460
+ }
461
+ /**
462
+ * Create a solid by sweeping a profile along a line path.
463
+ *
464
+ * Takes a sketch profile and path endpoints.
465
+ * @param {any} profile_js
466
+ * @param {Float64Array} start
467
+ * @param {Float64Array} end
468
+ * @param {number | null} [twist_angle]
469
+ * @param {number | null} [scale_start]
470
+ * @param {number | null} [scale_end]
471
+ * @param {number | null} [orientation]
472
+ * @returns {Solid}
473
+ */
474
+ static sweepLine(profile_js, start, end, twist_angle, scale_start, scale_end, orientation) {
475
+ const ptr0 = passArrayF64ToWasm0(start, wasm.__wbindgen_malloc);
476
+ const len0 = WASM_VECTOR_LEN;
477
+ const ptr1 = passArrayF64ToWasm0(end, wasm.__wbindgen_malloc);
478
+ const len1 = WASM_VECTOR_LEN;
479
+ const ret = wasm.solid_sweepLine(profile_js, ptr0, len0, ptr1, len1, !isLikeNone(twist_angle), isLikeNone(twist_angle) ? 0 : twist_angle, !isLikeNone(scale_start), isLikeNone(scale_start) ? 0 : scale_start, !isLikeNone(scale_end), isLikeNone(scale_end) ? 0 : scale_end, !isLikeNone(orientation), isLikeNone(orientation) ? 0 : orientation);
480
+ if (ret[2]) {
481
+ throw takeFromExternrefTable0(ret[1]);
482
+ }
483
+ return Solid.__wrap(ret[0]);
484
+ }
485
+ /**
486
+ * Export the solid to STEP format.
487
+ *
488
+ * # Returns
489
+ * A byte buffer containing the STEP file data.
490
+ *
491
+ * # Errors
492
+ * Returns an error if the solid has no B-rep data (e.g., mesh-only after certain operations).
493
+ * @returns {Uint8Array}
494
+ */
495
+ toStepBuffer() {
496
+ const ret = wasm.solid_toStepBuffer(this.__wbg_ptr);
497
+ if (ret[3]) {
498
+ throw takeFromExternrefTable0(ret[2]);
499
+ }
500
+ var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
501
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
502
+ return v1;
503
+ }
504
+ /**
505
+ * Translate the solid by (x, y, z).
506
+ * @param {number} x
507
+ * @param {number} y
508
+ * @param {number} z
509
+ * @returns {Solid}
510
+ */
511
+ translate(x, y, z) {
512
+ const ret = wasm.solid_translate(this.__wbg_ptr, x, y, z);
513
+ return Solid.__wrap(ret);
514
+ }
515
+ /**
516
+ * Boolean union (self ∪ other).
517
+ * @param {Solid} other
518
+ * @returns {Solid}
519
+ */
520
+ union(other) {
521
+ _assertClass(other, Solid);
522
+ const ret = wasm.solid_union(this.__wbg_ptr, other.__wbg_ptr);
523
+ return Solid.__wrap(ret);
524
+ }
525
+ /**
526
+ * Compute the volume of the solid.
527
+ * @returns {number}
528
+ */
529
+ volume() {
530
+ const ret = wasm.solid_volume(this.__wbg_ptr);
531
+ return ret;
532
+ }
533
+ }
534
+ if (Symbol.dispose) Solid.prototype[Symbol.dispose] = Solid.prototype.free;
535
+
536
+ /**
537
+ * Annotation layer for dimension annotations.
538
+ *
539
+ * This class provides methods for creating and rendering dimension annotations
540
+ * on 2D projected views.
541
+ */
542
+ export class WasmAnnotationLayer {
543
+ __destroy_into_raw() {
544
+ const ptr = this.__wbg_ptr;
545
+ this.__wbg_ptr = 0;
546
+ WasmAnnotationLayerFinalization.unregister(this);
547
+ return ptr;
548
+ }
549
+ free() {
550
+ const ptr = this.__destroy_into_raw();
551
+ wasm.__wbg_wasmannotationlayer_free(ptr, 0);
552
+ }
553
+ /**
554
+ * Add an aligned dimension between two points.
555
+ *
556
+ * The dimension line is parallel to the line connecting the two points.
557
+ *
558
+ * # Arguments
559
+ * * `x1`, `y1` - First point coordinates
560
+ * * `x2`, `y2` - Second point coordinates
561
+ * * `offset` - Distance from points to dimension line
562
+ * @param {number} x1
563
+ * @param {number} y1
564
+ * @param {number} x2
565
+ * @param {number} y2
566
+ * @param {number} offset
567
+ */
568
+ addAlignedDimension(x1, y1, x2, y2, offset) {
569
+ wasm.wasmannotationlayer_addAlignedDimension(this.__wbg_ptr, x1, y1, x2, y2, offset);
570
+ }
571
+ /**
572
+ * Add an angular dimension between three points.
573
+ *
574
+ * The angle is measured at the vertex (middle point).
575
+ *
576
+ * # Arguments
577
+ * * `x1`, `y1` - First point on one leg
578
+ * * `vx`, `vy` - Vertex point (angle measured here)
579
+ * * `x2`, `y2` - Second point on other leg
580
+ * * `arc_radius` - Radius of the arc showing the angle
581
+ * @param {number} x1
582
+ * @param {number} y1
583
+ * @param {number} vx
584
+ * @param {number} vy
585
+ * @param {number} x2
586
+ * @param {number} y2
587
+ * @param {number} arc_radius
588
+ */
589
+ addAngleDimension(x1, y1, vx, vy, x2, y2, arc_radius) {
590
+ wasm.wasmannotationlayer_addAngleDimension(this.__wbg_ptr, x1, y1, vx, vy, x2, y2, arc_radius);
591
+ }
592
+ /**
593
+ * Add a diameter dimension for a circle.
594
+ *
595
+ * # Arguments
596
+ * * `cx`, `cy` - Center of the circle
597
+ * * `radius` - Radius of the circle
598
+ * * `leader_angle` - Angle in radians for the leader line direction
599
+ * @param {number} cx
600
+ * @param {number} cy
601
+ * @param {number} radius
602
+ * @param {number} leader_angle
603
+ */
604
+ addDiameterDimension(cx, cy, radius, leader_angle) {
605
+ wasm.wasmannotationlayer_addDiameterDimension(this.__wbg_ptr, cx, cy, radius, leader_angle);
606
+ }
607
+ /**
608
+ * Add a horizontal dimension between two points.
609
+ *
610
+ * # Arguments
611
+ * * `x1`, `y1` - First point coordinates
612
+ * * `x2`, `y2` - Second point coordinates
613
+ * * `offset` - Distance from points to dimension line (positive = above)
614
+ * @param {number} x1
615
+ * @param {number} y1
616
+ * @param {number} x2
617
+ * @param {number} y2
618
+ * @param {number} offset
619
+ */
620
+ addHorizontalDimension(x1, y1, x2, y2, offset) {
621
+ wasm.wasmannotationlayer_addHorizontalDimension(this.__wbg_ptr, x1, y1, x2, y2, offset);
622
+ }
623
+ /**
624
+ * Add a radius dimension for a circle.
625
+ *
626
+ * # Arguments
627
+ * * `cx`, `cy` - Center of the circle
628
+ * * `radius` - Radius of the circle
629
+ * * `leader_angle` - Angle in radians for the leader line direction
630
+ * @param {number} cx
631
+ * @param {number} cy
632
+ * @param {number} radius
633
+ * @param {number} leader_angle
634
+ */
635
+ addRadiusDimension(cx, cy, radius, leader_angle) {
636
+ wasm.wasmannotationlayer_addRadiusDimension(this.__wbg_ptr, cx, cy, radius, leader_angle);
637
+ }
638
+ /**
639
+ * Add a vertical dimension between two points.
640
+ *
641
+ * # Arguments
642
+ * * `x1`, `y1` - First point coordinates
643
+ * * `x2`, `y2` - Second point coordinates
644
+ * * `offset` - Distance from points to dimension line (positive = right)
645
+ * @param {number} x1
646
+ * @param {number} y1
647
+ * @param {number} x2
648
+ * @param {number} y2
649
+ * @param {number} offset
650
+ */
651
+ addVerticalDimension(x1, y1, x2, y2, offset) {
652
+ wasm.wasmannotationlayer_addVerticalDimension(this.__wbg_ptr, x1, y1, x2, y2, offset);
653
+ }
654
+ /**
655
+ * Get the number of annotations in the layer.
656
+ * @returns {number}
657
+ */
658
+ annotationCount() {
659
+ const ret = wasm.wasmannotationlayer_annotationCount(this.__wbg_ptr);
660
+ return ret >>> 0;
661
+ }
662
+ /**
663
+ * Clear all annotations from the layer.
664
+ */
665
+ clear() {
666
+ wasm.wasmannotationlayer_clear(this.__wbg_ptr);
667
+ }
668
+ /**
669
+ * Check if the layer has any annotations.
670
+ * @returns {boolean}
671
+ */
672
+ isEmpty() {
673
+ const ret = wasm.wasmannotationlayer_isEmpty(this.__wbg_ptr);
674
+ return ret !== 0;
675
+ }
676
+ /**
677
+ * Create a new empty annotation layer.
678
+ */
679
+ constructor() {
680
+ const ret = wasm.wasmannotationlayer_new();
681
+ this.__wbg_ptr = ret >>> 0;
682
+ WasmAnnotationLayerFinalization.register(this, this.__wbg_ptr, this);
683
+ return this;
684
+ }
685
+ /**
686
+ * Render all dimensions and return as JSON.
687
+ *
688
+ * Returns an array of rendered dimensions, each containing:
689
+ * - `lines`: Array of line segments [[x1, y1], [x2, y2]]
690
+ * - `arcs`: Array of arc definitions
691
+ * - `arrows`: Array of arrow definitions
692
+ * - `texts`: Array of text labels
693
+ *
694
+ * # Arguments
695
+ * * `view_json` - Optional JSON string of a ProjectedView for geometry resolution
696
+ * @param {string | null} [view_json]
697
+ * @returns {any}
698
+ */
699
+ renderAll(view_json) {
700
+ var ptr0 = isLikeNone(view_json) ? 0 : passStringToWasm0(view_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
701
+ var len0 = WASM_VECTOR_LEN;
702
+ const ret = wasm.wasmannotationlayer_renderAll(this.__wbg_ptr, ptr0, len0);
703
+ return ret;
704
+ }
705
+ }
706
+ if (Symbol.dispose) WasmAnnotationLayer.prototype[Symbol.dispose] = WasmAnnotationLayer.prototype.free;
707
+
708
+ /**
709
+ * Compute creased normals (CPU fallback when GPU feature is disabled).
710
+ * @param {Float32Array} _positions
711
+ * @param {Uint32Array} _indices
712
+ * @param {number} _crease_angle
713
+ * @returns {Promise<Float32Array>}
714
+ */
715
+ export function computeCreasedNormalsGpu(_positions, _indices, _crease_angle) {
716
+ const ptr0 = passArrayF32ToWasm0(_positions, wasm.__wbindgen_malloc);
717
+ const len0 = WASM_VECTOR_LEN;
718
+ const ptr1 = passArray32ToWasm0(_indices, wasm.__wbindgen_malloc);
719
+ const len1 = WASM_VECTOR_LEN;
720
+ const ret = wasm.computeCreasedNormalsGpu(ptr0, len0, ptr1, len1, _crease_angle);
721
+ return ret;
722
+ }
723
+
724
+ /**
725
+ * Create a detail view from a projected view.
726
+ *
727
+ * A detail view is a magnified region of a parent view, useful for showing
728
+ * fine features that would be too small in the main view.
729
+ *
730
+ * # Arguments
731
+ * * `parent_json` - JSON string of the parent ProjectedView
732
+ * * `center_x` - X coordinate of the region center
733
+ * * `center_y` - Y coordinate of the region center
734
+ * * `scale` - Magnification factor (e.g., 2.0 = 2x)
735
+ * * `width` - Width of the region to capture
736
+ * * `height` - Height of the region to capture
737
+ * * `label` - Label for the detail view (e.g., "A")
738
+ *
739
+ * # Returns
740
+ * A JS object containing the detail view with edges and bounds.
741
+ * @param {string} parent_json
742
+ * @param {number} center_x
743
+ * @param {number} center_y
744
+ * @param {number} scale
745
+ * @param {number} width
746
+ * @param {number} height
747
+ * @param {string} label
748
+ * @returns {any}
749
+ */
750
+ export function createDetailView(parent_json, center_x, center_y, scale, width, height, label) {
751
+ const ptr0 = passStringToWasm0(parent_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
752
+ const len0 = WASM_VECTOR_LEN;
753
+ const ptr1 = passStringToWasm0(label, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
754
+ const len1 = WASM_VECTOR_LEN;
755
+ const ret = wasm.createDetailView(ptr0, len0, center_x, center_y, scale, width, height, ptr1, len1);
756
+ if (ret[2]) {
757
+ throw takeFromExternrefTable0(ret[1]);
758
+ }
759
+ return takeFromExternrefTable0(ret[0]);
760
+ }
761
+
762
+ /**
763
+ * Decimate a mesh (CPU fallback when GPU feature is disabled).
764
+ * @param {Float32Array} _positions
765
+ * @param {Uint32Array} _indices
766
+ * @param {number} _target_ratio
767
+ * @returns {Promise<any>}
768
+ */
769
+ export function decimateMeshGpu(_positions, _indices, _target_ratio) {
770
+ const ptr0 = passArrayF32ToWasm0(_positions, wasm.__wbindgen_malloc);
771
+ const len0 = WASM_VECTOR_LEN;
772
+ const ptr1 = passArray32ToWasm0(_indices, wasm.__wbindgen_malloc);
773
+ const len1 = WASM_VECTOR_LEN;
774
+ const ret = wasm.decimateMeshGpu(ptr0, len0, ptr1, len1, _target_ratio);
775
+ return ret;
776
+ }
777
+
778
+ /**
779
+ * Evaluate compact IR and return a Solid for rendering.
780
+ *
781
+ * This is a convenience function that parses compact IR and evaluates
782
+ * the geometry in a single step.
783
+ *
784
+ * # Arguments
785
+ * * `compact_ir` - The compact IR text to evaluate
786
+ *
787
+ * # Returns
788
+ * A Solid object that can be rendered or queried.
789
+ * @param {string} compact_ir
790
+ * @returns {Solid}
791
+ */
792
+ export function evaluateCompactIR(compact_ir) {
793
+ const ptr0 = passStringToWasm0(compact_ir, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
794
+ const len0 = WASM_VECTOR_LEN;
795
+ const ret = wasm.evaluateCompactIR(ptr0, len0);
796
+ if (ret[2]) {
797
+ throw takeFromExternrefTable0(ret[1]);
798
+ }
799
+ return Solid.__wrap(ret[0]);
800
+ }
801
+
802
+ /**
803
+ * Export a projected view to DXF format.
804
+ *
805
+ * Returns the DXF content as bytes.
806
+ *
807
+ * # Arguments
808
+ * * `view_json` - JSON string of a ProjectedView
809
+ *
810
+ * # Returns
811
+ * A byte array containing the DXF file content.
812
+ * @param {string} view_json
813
+ * @returns {Uint8Array}
814
+ */
815
+ export function exportProjectedViewToDxf(view_json) {
816
+ const ptr0 = passStringToWasm0(view_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
817
+ const len0 = WASM_VECTOR_LEN;
818
+ const ret = wasm.exportProjectedViewToDxf(ptr0, len0);
819
+ if (ret[3]) {
820
+ throw takeFromExternrefTable0(ret[2]);
821
+ }
822
+ var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
823
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
824
+ return v2;
825
+ }
826
+
827
+ /**
828
+ * Import solids from STEP file bytes.
829
+ *
830
+ * Returns a JS array of mesh data for each imported body.
831
+ * Each mesh contains `positions` (Float32Array) and `indices` (Uint32Array).
832
+ *
833
+ * # Arguments
834
+ * * `data` - Raw STEP file contents as bytes
835
+ *
836
+ * # Returns
837
+ * A JS array of mesh objects for rendering the imported geometry.
838
+ * @param {Uint8Array} data
839
+ * @returns {any}
840
+ */
841
+ export function importStepBuffer(data) {
842
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
843
+ const len0 = WASM_VECTOR_LEN;
844
+ const ret = wasm.importStepBuffer(ptr0, len0);
845
+ if (ret[2]) {
846
+ throw takeFromExternrefTable0(ret[1]);
847
+ }
848
+ return takeFromExternrefTable0(ret[0]);
849
+ }
850
+
851
+ /**
852
+ * Initialize the WASM module (sets up panic hook for better error messages).
853
+ */
854
+ export function init() {
855
+ wasm.init();
856
+ }
857
+
858
+ /**
859
+ * Initialize the GPU context (stub when GPU feature is disabled).
860
+ * @returns {Promise<boolean>}
861
+ */
862
+ export function initGpu() {
863
+ const ret = wasm.initGpu();
864
+ return ret;
865
+ }
866
+
867
+ /**
868
+ * Check if GPU processing is available.
869
+ * @returns {boolean}
870
+ */
871
+ export function isGpuAvailable() {
872
+ const ret = wasm.isGpuAvailable();
873
+ return ret !== 0;
874
+ }
875
+
876
+ /**
877
+ * Check if physics simulation is available.
878
+ * @returns {boolean}
879
+ */
880
+ export function isPhysicsAvailable() {
881
+ const ret = wasm.isGpuAvailable();
882
+ return ret !== 0;
883
+ }
884
+
885
+ /**
886
+ * Chamfer all edges of a solid by the given distance.
887
+ *
888
+ * This is a standalone wrapper for lazy loading via wasmosis.
889
+ * @param {Solid} solid
890
+ * @param {number} distance
891
+ * @returns {Solid}
892
+ */
893
+ export function op_chamfer(solid, distance) {
894
+ _assertClass(solid, Solid);
895
+ const ret = wasm.op_chamfer(solid.__wbg_ptr, distance);
896
+ return Solid.__wrap(ret);
897
+ }
898
+
899
+ /**
900
+ * Create a circular pattern of a solid around an axis.
901
+ *
902
+ * This is a standalone wrapper for lazy loading via wasmosis.
903
+ * @param {Solid} solid
904
+ * @param {number} axis_origin_x
905
+ * @param {number} axis_origin_y
906
+ * @param {number} axis_origin_z
907
+ * @param {number} axis_dir_x
908
+ * @param {number} axis_dir_y
909
+ * @param {number} axis_dir_z
910
+ * @param {number} count
911
+ * @param {number} angle_deg
912
+ * @returns {Solid}
913
+ */
914
+ export function op_circular_pattern(solid, axis_origin_x, axis_origin_y, axis_origin_z, axis_dir_x, axis_dir_y, axis_dir_z, count, angle_deg) {
915
+ _assertClass(solid, Solid);
916
+ const ret = wasm.op_circular_pattern(solid.__wbg_ptr, axis_origin_x, axis_origin_y, axis_origin_z, axis_dir_x, axis_dir_y, axis_dir_z, count, angle_deg);
917
+ return Solid.__wrap(ret);
918
+ }
919
+
920
+ /**
921
+ * Fillet all edges of a solid with the given radius.
922
+ *
923
+ * This is a standalone wrapper for lazy loading via wasmosis.
924
+ * @param {Solid} solid
925
+ * @param {number} radius
926
+ * @returns {Solid}
927
+ */
928
+ export function op_fillet(solid, radius) {
929
+ _assertClass(solid, Solid);
930
+ const ret = wasm.op_fillet(solid.__wbg_ptr, radius);
931
+ return Solid.__wrap(ret);
932
+ }
933
+
934
+ /**
935
+ * Create a linear pattern of a solid along a direction.
936
+ *
937
+ * This is a standalone wrapper for lazy loading via wasmosis.
938
+ * @param {Solid} solid
939
+ * @param {number} dir_x
940
+ * @param {number} dir_y
941
+ * @param {number} dir_z
942
+ * @param {number} count
943
+ * @param {number} spacing
944
+ * @returns {Solid}
945
+ */
946
+ export function op_linear_pattern(solid, dir_x, dir_y, dir_z, count, spacing) {
947
+ _assertClass(solid, Solid);
948
+ const ret = wasm.op_linear_pattern(solid.__wbg_ptr, dir_x, dir_y, dir_z, count, spacing);
949
+ return Solid.__wrap(ret);
950
+ }
951
+
952
+ /**
953
+ * Create a solid by lofting between multiple profiles.
954
+ *
955
+ * This is a standalone wrapper for lazy loading via wasmosis.
956
+ * @param {any} profiles_js
957
+ * @param {boolean | null} [closed]
958
+ * @returns {Solid}
959
+ */
960
+ export function op_loft(profiles_js, closed) {
961
+ const ret = wasm.op_loft(profiles_js, isLikeNone(closed) ? 0xFFFFFF : closed ? 1 : 0);
962
+ if (ret[2]) {
963
+ throw takeFromExternrefTable0(ret[1]);
964
+ }
965
+ return Solid.__wrap(ret[0]);
966
+ }
967
+
968
+ /**
969
+ * Create a solid by revolving a 2D sketch profile around an axis.
970
+ *
971
+ * This is a standalone wrapper for lazy loading via wasmosis.
972
+ * @param {any} profile_js
973
+ * @param {Float64Array} axis_origin
974
+ * @param {Float64Array} axis_dir
975
+ * @param {number} angle_deg
976
+ * @returns {Solid}
977
+ */
978
+ export function op_revolve(profile_js, axis_origin, axis_dir, angle_deg) {
979
+ const ptr0 = passArrayF64ToWasm0(axis_origin, wasm.__wbindgen_malloc);
980
+ const len0 = WASM_VECTOR_LEN;
981
+ const ptr1 = passArrayF64ToWasm0(axis_dir, wasm.__wbindgen_malloc);
982
+ const len1 = WASM_VECTOR_LEN;
983
+ const ret = wasm.op_revolve(profile_js, ptr0, len0, ptr1, len1, angle_deg);
984
+ if (ret[2]) {
985
+ throw takeFromExternrefTable0(ret[1]);
986
+ }
987
+ return Solid.__wrap(ret[0]);
988
+ }
989
+
990
+ /**
991
+ * Shell (hollow) a solid by offsetting all faces inward.
992
+ *
993
+ * This is a standalone wrapper for lazy loading via wasmosis.
994
+ * @param {Solid} solid
995
+ * @param {number} thickness
996
+ * @returns {Solid}
997
+ */
998
+ export function op_shell(solid, thickness) {
999
+ _assertClass(solid, Solid);
1000
+ const ret = wasm.op_shell(solid.__wbg_ptr, thickness);
1001
+ return Solid.__wrap(ret);
1002
+ }
1003
+
1004
+ /**
1005
+ * Create a solid by sweeping a profile along a helix path.
1006
+ *
1007
+ * This is a standalone wrapper for lazy loading via wasmosis.
1008
+ * @param {any} profile_js
1009
+ * @param {number} radius
1010
+ * @param {number} pitch
1011
+ * @param {number} height
1012
+ * @param {number} turns
1013
+ * @param {number | null} [twist_angle]
1014
+ * @param {number | null} [scale_start]
1015
+ * @param {number | null} [scale_end]
1016
+ * @param {number | null} [path_segments]
1017
+ * @param {number | null} [arc_segments]
1018
+ * @param {number | null} [orientation]
1019
+ * @returns {Solid}
1020
+ */
1021
+ export function op_sweep_helix(profile_js, radius, pitch, height, turns, twist_angle, scale_start, scale_end, path_segments, arc_segments, orientation) {
1022
+ const ret = wasm.op_sweep_helix(profile_js, radius, pitch, height, turns, !isLikeNone(twist_angle), isLikeNone(twist_angle) ? 0 : twist_angle, !isLikeNone(scale_start), isLikeNone(scale_start) ? 0 : scale_start, !isLikeNone(scale_end), isLikeNone(scale_end) ? 0 : scale_end, isLikeNone(path_segments) ? 0x100000001 : (path_segments) >>> 0, isLikeNone(arc_segments) ? 0x100000001 : (arc_segments) >>> 0, !isLikeNone(orientation), isLikeNone(orientation) ? 0 : orientation);
1023
+ if (ret[2]) {
1024
+ throw takeFromExternrefTable0(ret[1]);
1025
+ }
1026
+ return Solid.__wrap(ret[0]);
1027
+ }
1028
+
1029
+ /**
1030
+ * Create a solid by sweeping a profile along a line path.
1031
+ *
1032
+ * This is a standalone wrapper for lazy loading via wasmosis.
1033
+ * @param {any} profile_js
1034
+ * @param {Float64Array} start
1035
+ * @param {Float64Array} end
1036
+ * @param {number | null} [twist_angle]
1037
+ * @param {number | null} [scale_start]
1038
+ * @param {number | null} [scale_end]
1039
+ * @param {number | null} [orientation]
1040
+ * @returns {Solid}
1041
+ */
1042
+ export function op_sweep_line(profile_js, start, end, twist_angle, scale_start, scale_end, orientation) {
1043
+ const ptr0 = passArrayF64ToWasm0(start, wasm.__wbindgen_malloc);
1044
+ const len0 = WASM_VECTOR_LEN;
1045
+ const ptr1 = passArrayF64ToWasm0(end, wasm.__wbindgen_malloc);
1046
+ const len1 = WASM_VECTOR_LEN;
1047
+ const ret = wasm.op_sweep_line(profile_js, ptr0, len0, ptr1, len1, !isLikeNone(twist_angle), isLikeNone(twist_angle) ? 0 : twist_angle, !isLikeNone(scale_start), isLikeNone(scale_start) ? 0 : scale_start, !isLikeNone(scale_end), isLikeNone(scale_end) ? 0 : scale_end, !isLikeNone(orientation), isLikeNone(orientation) ? 0 : orientation);
1048
+ if (ret[2]) {
1049
+ throw takeFromExternrefTable0(ret[1]);
1050
+ }
1051
+ return Solid.__wrap(ret[0]);
1052
+ }
1053
+
1054
+ /**
1055
+ * Parse compact IR text format into a vcad IR Document (JSON).
1056
+ *
1057
+ * The compact IR format is a token-efficient text representation designed
1058
+ * for ML model training and inference. See `vcad_ir::compact` for format details.
1059
+ *
1060
+ * # Arguments
1061
+ * * `compact_ir` - The compact IR text to parse
1062
+ *
1063
+ * # Returns
1064
+ * A JSON string representing the parsed vcad IR Document.
1065
+ *
1066
+ * # Example
1067
+ * ```javascript
1068
+ * const ir = "C 50 30 5\nY 5 10\nT 1 25 15 0\nD 0 2";
1069
+ * const doc = parseCompactIR(ir);
1070
+ * console.log(doc); // JSON document
1071
+ * ```
1072
+ * @param {string} compact_ir
1073
+ * @returns {string}
1074
+ */
1075
+ export function parseCompactIR(compact_ir) {
1076
+ let deferred3_0;
1077
+ let deferred3_1;
1078
+ try {
1079
+ const ptr0 = passStringToWasm0(compact_ir, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1080
+ const len0 = WASM_VECTOR_LEN;
1081
+ const ret = wasm.parseCompactIR(ptr0, len0);
1082
+ var ptr2 = ret[0];
1083
+ var len2 = ret[1];
1084
+ if (ret[3]) {
1085
+ ptr2 = 0; len2 = 0;
1086
+ throw takeFromExternrefTable0(ret[2]);
1087
+ }
1088
+ deferred3_0 = ptr2;
1089
+ deferred3_1 = len2;
1090
+ return getStringFromWasm0(ptr2, len2);
1091
+ } finally {
1092
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
1093
+ }
1094
+ }
1095
+
1096
+ /**
1097
+ * Process geometry (CPU fallback when GPU feature is disabled).
1098
+ * @param {Float32Array} _positions
1099
+ * @param {Uint32Array} _indices
1100
+ * @param {number} _crease_angle
1101
+ * @param {boolean} _generate_lod
1102
+ * @returns {Promise<any>}
1103
+ */
1104
+ export function processGeometryGpu(_positions, _indices, _crease_angle, _generate_lod) {
1105
+ const ptr0 = passArrayF32ToWasm0(_positions, wasm.__wbindgen_malloc);
1106
+ const len0 = WASM_VECTOR_LEN;
1107
+ const ptr1 = passArray32ToWasm0(_indices, wasm.__wbindgen_malloc);
1108
+ const len1 = WASM_VECTOR_LEN;
1109
+ const ret = wasm.processGeometryGpu(ptr0, len0, ptr1, len1, _crease_angle, _generate_lod);
1110
+ return ret;
1111
+ }
1112
+
1113
+ /**
1114
+ * Project a triangle mesh to a 2D view.
1115
+ *
1116
+ * # Arguments
1117
+ * * `mesh_js` - Mesh data as JS object with `positions` (Float32Array) and `indices` (Uint32Array)
1118
+ * * `view_direction` - View direction: "front", "back", "top", "bottom", "left", "right", or "isometric"
1119
+ *
1120
+ * # Returns
1121
+ * A JS object containing the projected view with edges and bounds.
1122
+ * @param {any} mesh_js
1123
+ * @param {string} view_direction
1124
+ * @returns {any}
1125
+ */
1126
+ export function projectMesh(mesh_js, view_direction) {
1127
+ const ptr0 = passStringToWasm0(view_direction, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1128
+ const len0 = WASM_VECTOR_LEN;
1129
+ const ret = wasm.projectMesh(mesh_js, ptr0, len0);
1130
+ return ret;
1131
+ }
1132
+
1133
+ /**
1134
+ * Generate a section view from a triangle mesh.
1135
+ *
1136
+ * # Arguments
1137
+ * * `mesh_js` - Mesh data as JS object with `positions` (Float32Array) and `indices` (Uint32Array)
1138
+ * * `plane_json` - JSON string with plane definition: `{"origin": [x,y,z], "normal": [x,y,z], "up": [x,y,z]}`
1139
+ * * `hatch_json` - Optional JSON string with hatch pattern: `{"spacing": f64, "angle": f64}`
1140
+ *
1141
+ * # Returns
1142
+ * A JS object containing the section view with curves, hatch lines, and bounds.
1143
+ * @param {any} mesh_js
1144
+ * @param {string} plane_json
1145
+ * @param {string | null} [hatch_json]
1146
+ * @returns {any}
1147
+ */
1148
+ export function sectionMesh(mesh_js, plane_json, hatch_json) {
1149
+ const ptr0 = passStringToWasm0(plane_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1150
+ const len0 = WASM_VECTOR_LEN;
1151
+ var ptr1 = isLikeNone(hatch_json) ? 0 : passStringToWasm0(hatch_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1152
+ var len1 = WASM_VECTOR_LEN;
1153
+ const ret = wasm.sectionMesh(mesh_js, ptr0, len0, ptr1, len1);
1154
+ return ret;
1155
+ }
1156
+
1157
+ /**
1158
+ * Convert a vcad IR Document (JSON) to compact IR text format.
1159
+ *
1160
+ * # Arguments
1161
+ * * `doc_json` - JSON string representing a vcad IR Document
1162
+ *
1163
+ * # Returns
1164
+ * The compact IR text representation.
1165
+ *
1166
+ * # Example
1167
+ * ```javascript
1168
+ * const compact = toCompactIR(docJson);
1169
+ * console.log(compact); // "C 50 30 5\nY 5 10\n..."
1170
+ * ```
1171
+ * @param {string} doc_json
1172
+ * @returns {string}
1173
+ */
1174
+ export function toCompactIR(doc_json) {
1175
+ let deferred3_0;
1176
+ let deferred3_1;
1177
+ try {
1178
+ const ptr0 = passStringToWasm0(doc_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1179
+ const len0 = WASM_VECTOR_LEN;
1180
+ const ret = wasm.toCompactIR(ptr0, len0);
1181
+ var ptr2 = ret[0];
1182
+ var len2 = ret[1];
1183
+ if (ret[3]) {
1184
+ ptr2 = 0; len2 = 0;
1185
+ throw takeFromExternrefTable0(ret[2]);
1186
+ }
1187
+ deferred3_0 = ptr2;
1188
+ deferred3_1 = len2;
1189
+ return getStringFromWasm0(ptr2, len2);
1190
+ } finally {
1191
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
1192
+ }
1193
+ }
1194
+
1195
+ function __wbg_get_imports() {
1196
+ const import0 = {
1197
+ __proto__: null,
1198
+ __wbg_Error_8c4e43fe74559d73: function(arg0, arg1) {
1199
+ const ret = Error(getStringFromWasm0(arg0, arg1));
1200
+ return ret;
1201
+ },
1202
+ __wbg_Number_04624de7d0e8332d: function(arg0) {
1203
+ const ret = Number(arg0);
1204
+ return ret;
1205
+ },
1206
+ __wbg_String_8f0eb39a4a4c2f66: function(arg0, arg1) {
1207
+ const ret = String(arg1);
1208
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1209
+ const len1 = WASM_VECTOR_LEN;
1210
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
1211
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
1212
+ },
1213
+ __wbg___wbindgen_bigint_get_as_i64_8fcf4ce7f1ca72a2: function(arg0, arg1) {
1214
+ const v = arg1;
1215
+ const ret = typeof(v) === 'bigint' ? v : undefined;
1216
+ getDataViewMemory0().setBigInt64(arg0 + 8 * 1, isLikeNone(ret) ? BigInt(0) : ret, true);
1217
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
1218
+ },
1219
+ __wbg___wbindgen_boolean_get_bbbb1c18aa2f5e25: function(arg0) {
1220
+ const v = arg0;
1221
+ const ret = typeof(v) === 'boolean' ? v : undefined;
1222
+ return isLikeNone(ret) ? 0xFFFFFF : ret ? 1 : 0;
1223
+ },
1224
+ __wbg___wbindgen_debug_string_0bc8482c6e3508ae: function(arg0, arg1) {
1225
+ const ret = debugString(arg1);
1226
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1227
+ const len1 = WASM_VECTOR_LEN;
1228
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
1229
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
1230
+ },
1231
+ __wbg___wbindgen_in_47fa6863be6f2f25: function(arg0, arg1) {
1232
+ const ret = arg0 in arg1;
1233
+ return ret;
1234
+ },
1235
+ __wbg___wbindgen_is_bigint_31b12575b56f32fc: function(arg0) {
1236
+ const ret = typeof(arg0) === 'bigint';
1237
+ return ret;
1238
+ },
1239
+ __wbg___wbindgen_is_function_0095a73b8b156f76: function(arg0) {
1240
+ const ret = typeof(arg0) === 'function';
1241
+ return ret;
1242
+ },
1243
+ __wbg___wbindgen_is_object_5ae8e5880f2c1fbd: function(arg0) {
1244
+ const val = arg0;
1245
+ const ret = typeof(val) === 'object' && val !== null;
1246
+ return ret;
1247
+ },
1248
+ __wbg___wbindgen_is_undefined_9e4d92534c42d778: function(arg0) {
1249
+ const ret = arg0 === undefined;
1250
+ return ret;
1251
+ },
1252
+ __wbg___wbindgen_jsval_eq_11888390b0186270: function(arg0, arg1) {
1253
+ const ret = arg0 === arg1;
1254
+ return ret;
1255
+ },
1256
+ __wbg___wbindgen_jsval_loose_eq_9dd77d8cd6671811: function(arg0, arg1) {
1257
+ const ret = arg0 == arg1;
1258
+ return ret;
1259
+ },
1260
+ __wbg___wbindgen_number_get_8ff4255516ccad3e: function(arg0, arg1) {
1261
+ const obj = arg1;
1262
+ const ret = typeof(obj) === 'number' ? obj : undefined;
1263
+ getDataViewMemory0().setFloat64(arg0 + 8 * 1, isLikeNone(ret) ? 0 : ret, true);
1264
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
1265
+ },
1266
+ __wbg___wbindgen_string_get_72fb696202c56729: function(arg0, arg1) {
1267
+ const obj = arg1;
1268
+ const ret = typeof(obj) === 'string' ? obj : undefined;
1269
+ var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1270
+ var len1 = WASM_VECTOR_LEN;
1271
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
1272
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
1273
+ },
1274
+ __wbg___wbindgen_throw_be289d5034ed271b: function(arg0, arg1) {
1275
+ throw new Error(getStringFromWasm0(arg0, arg1));
1276
+ },
1277
+ __wbg__wbg_cb_unref_d9b87ff7982e3b21: function(arg0) {
1278
+ arg0._wbg_cb_unref();
1279
+ },
1280
+ __wbg_call_389efe28435a9388: function() { return handleError(function (arg0, arg1) {
1281
+ const ret = arg0.call(arg1);
1282
+ return ret;
1283
+ }, arguments); },
1284
+ __wbg_call_4708e0c13bdc8e95: function() { return handleError(function (arg0, arg1, arg2) {
1285
+ const ret = arg0.call(arg1, arg2);
1286
+ return ret;
1287
+ }, arguments); },
1288
+ __wbg_done_57b39ecd9addfe81: function(arg0) {
1289
+ const ret = arg0.done;
1290
+ return ret;
1291
+ },
1292
+ __wbg_entries_58c7934c745daac7: function(arg0) {
1293
+ const ret = Object.entries(arg0);
1294
+ return ret;
1295
+ },
1296
+ __wbg_error_7534b8e9a36f1ab4: function(arg0, arg1) {
1297
+ let deferred0_0;
1298
+ let deferred0_1;
1299
+ try {
1300
+ deferred0_0 = arg0;
1301
+ deferred0_1 = arg1;
1302
+ console.error(getStringFromWasm0(arg0, arg1));
1303
+ } finally {
1304
+ wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
1305
+ }
1306
+ },
1307
+ __wbg_error_9a7fe3f932034cde: function(arg0) {
1308
+ console.error(arg0);
1309
+ },
1310
+ __wbg_get_9b94d73e6221f75c: function(arg0, arg1) {
1311
+ const ret = arg0[arg1 >>> 0];
1312
+ return ret;
1313
+ },
1314
+ __wbg_get_b3ed3ad4be2bc8ac: function() { return handleError(function (arg0, arg1) {
1315
+ const ret = Reflect.get(arg0, arg1);
1316
+ return ret;
1317
+ }, arguments); },
1318
+ __wbg_get_with_ref_key_1dc361bd10053bfe: function(arg0, arg1) {
1319
+ const ret = arg0[arg1];
1320
+ return ret;
1321
+ },
1322
+ __wbg_instanceof_ArrayBuffer_c367199e2fa2aa04: function(arg0) {
1323
+ let result;
1324
+ try {
1325
+ result = arg0 instanceof ArrayBuffer;
1326
+ } catch (_) {
1327
+ result = false;
1328
+ }
1329
+ const ret = result;
1330
+ return ret;
1331
+ },
1332
+ __wbg_instanceof_Map_53af74335dec57f4: function(arg0) {
1333
+ let result;
1334
+ try {
1335
+ result = arg0 instanceof Map;
1336
+ } catch (_) {
1337
+ result = false;
1338
+ }
1339
+ const ret = result;
1340
+ return ret;
1341
+ },
1342
+ __wbg_instanceof_Uint8Array_9b9075935c74707c: function(arg0) {
1343
+ let result;
1344
+ try {
1345
+ result = arg0 instanceof Uint8Array;
1346
+ } catch (_) {
1347
+ result = false;
1348
+ }
1349
+ const ret = result;
1350
+ return ret;
1351
+ },
1352
+ __wbg_isArray_d314bb98fcf08331: function(arg0) {
1353
+ const ret = Array.isArray(arg0);
1354
+ return ret;
1355
+ },
1356
+ __wbg_isSafeInteger_bfbc7332a9768d2a: function(arg0) {
1357
+ const ret = Number.isSafeInteger(arg0);
1358
+ return ret;
1359
+ },
1360
+ __wbg_iterator_6ff6560ca1568e55: function() {
1361
+ const ret = Symbol.iterator;
1362
+ return ret;
1363
+ },
1364
+ __wbg_length_32ed9a279acd054c: function(arg0) {
1365
+ const ret = arg0.length;
1366
+ return ret;
1367
+ },
1368
+ __wbg_length_35a7bace40f36eac: function(arg0) {
1369
+ const ret = arg0.length;
1370
+ return ret;
1371
+ },
1372
+ __wbg_log_6b5ca2e6124b2808: function(arg0) {
1373
+ console.log(arg0);
1374
+ },
1375
+ __wbg_new_361308b2356cecd0: function() {
1376
+ const ret = new Object();
1377
+ return ret;
1378
+ },
1379
+ __wbg_new_3eb36ae241fe6f44: function() {
1380
+ const ret = new Array();
1381
+ return ret;
1382
+ },
1383
+ __wbg_new_8a6f238a6ece86ea: function() {
1384
+ const ret = new Error();
1385
+ return ret;
1386
+ },
1387
+ __wbg_new_b5d9e2fb389fef91: function(arg0, arg1) {
1388
+ try {
1389
+ var state0 = {a: arg0, b: arg1};
1390
+ var cb0 = (arg0, arg1) => {
1391
+ const a = state0.a;
1392
+ state0.a = 0;
1393
+ try {
1394
+ return wasm_bindgen__convert__closures_____invoke__h90946713c829438a(a, state0.b, arg0, arg1);
1395
+ } finally {
1396
+ state0.a = a;
1397
+ }
1398
+ };
1399
+ const ret = new Promise(cb0);
1400
+ return ret;
1401
+ } finally {
1402
+ state0.a = state0.b = 0;
1403
+ }
1404
+ },
1405
+ __wbg_new_dd2b680c8bf6ae29: function(arg0) {
1406
+ const ret = new Uint8Array(arg0);
1407
+ return ret;
1408
+ },
1409
+ __wbg_new_no_args_1c7c842f08d00ebb: function(arg0, arg1) {
1410
+ const ret = new Function(getStringFromWasm0(arg0, arg1));
1411
+ return ret;
1412
+ },
1413
+ __wbg_next_3482f54c49e8af19: function() { return handleError(function (arg0) {
1414
+ const ret = arg0.next();
1415
+ return ret;
1416
+ }, arguments); },
1417
+ __wbg_next_418f80d8f5303233: function(arg0) {
1418
+ const ret = arg0.next;
1419
+ return ret;
1420
+ },
1421
+ __wbg_prototypesetcall_bdcdcc5842e4d77d: function(arg0, arg1, arg2) {
1422
+ Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
1423
+ },
1424
+ __wbg_queueMicrotask_0aa0a927f78f5d98: function(arg0) {
1425
+ const ret = arg0.queueMicrotask;
1426
+ return ret;
1427
+ },
1428
+ __wbg_queueMicrotask_5bb536982f78a56f: function(arg0) {
1429
+ queueMicrotask(arg0);
1430
+ },
1431
+ __wbg_resolve_002c4b7d9d8f6b64: function(arg0) {
1432
+ const ret = Promise.resolve(arg0);
1433
+ return ret;
1434
+ },
1435
+ __wbg_set_3f1d0b984ed272ed: function(arg0, arg1, arg2) {
1436
+ arg0[arg1] = arg2;
1437
+ },
1438
+ __wbg_set_f43e577aea94465b: function(arg0, arg1, arg2) {
1439
+ arg0[arg1 >>> 0] = arg2;
1440
+ },
1441
+ __wbg_stack_0ed75d68575b0f3c: function(arg0, arg1) {
1442
+ const ret = arg1.stack;
1443
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1444
+ const len1 = WASM_VECTOR_LEN;
1445
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
1446
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
1447
+ },
1448
+ __wbg_static_accessor_GLOBAL_12837167ad935116: function() {
1449
+ const ret = typeof global === 'undefined' ? null : global;
1450
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
1451
+ },
1452
+ __wbg_static_accessor_GLOBAL_THIS_e628e89ab3b1c95f: function() {
1453
+ const ret = typeof globalThis === 'undefined' ? null : globalThis;
1454
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
1455
+ },
1456
+ __wbg_static_accessor_SELF_a621d3dfbb60d0ce: function() {
1457
+ const ret = typeof self === 'undefined' ? null : self;
1458
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
1459
+ },
1460
+ __wbg_static_accessor_WINDOW_f8727f0cf888e0bd: function() {
1461
+ const ret = typeof window === 'undefined' ? null : window;
1462
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
1463
+ },
1464
+ __wbg_then_b9e7b3b5f1a9e1b5: function(arg0, arg1) {
1465
+ const ret = arg0.then(arg1);
1466
+ return ret;
1467
+ },
1468
+ __wbg_value_0546255b415e96c1: function(arg0) {
1469
+ const ret = arg0.value;
1470
+ return ret;
1471
+ },
1472
+ __wbindgen_cast_0000000000000001: function(arg0, arg1) {
1473
+ // Cast intrinsic for `Closure(Closure { dtor_idx: 177, function: Function { arguments: [Externref], shim_idx: 178, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
1474
+ const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__ha1c57de1520edab9, wasm_bindgen__convert__closures_____invoke__h4889c924fd29fd81);
1475
+ return ret;
1476
+ },
1477
+ __wbindgen_cast_0000000000000002: function(arg0) {
1478
+ // Cast intrinsic for `F64 -> Externref`.
1479
+ const ret = arg0;
1480
+ return ret;
1481
+ },
1482
+ __wbindgen_cast_0000000000000003: function(arg0) {
1483
+ // Cast intrinsic for `I64 -> Externref`.
1484
+ const ret = arg0;
1485
+ return ret;
1486
+ },
1487
+ __wbindgen_cast_0000000000000004: function(arg0, arg1) {
1488
+ // Cast intrinsic for `Ref(String) -> Externref`.
1489
+ const ret = getStringFromWasm0(arg0, arg1);
1490
+ return ret;
1491
+ },
1492
+ __wbindgen_cast_0000000000000005: function(arg0) {
1493
+ // Cast intrinsic for `U64 -> Externref`.
1494
+ const ret = BigInt.asUintN(64, arg0);
1495
+ return ret;
1496
+ },
1497
+ __wbindgen_init_externref_table: function() {
1498
+ const table = wasm.__wbindgen_externrefs;
1499
+ const offset = table.grow(4);
1500
+ table.set(0, undefined);
1501
+ table.set(offset + 0, undefined);
1502
+ table.set(offset + 1, null);
1503
+ table.set(offset + 2, true);
1504
+ table.set(offset + 3, false);
1505
+ },
1506
+ };
1507
+ return {
1508
+ __proto__: null,
1509
+ "./vcad_kernel_wasm_bg.js": import0,
1510
+ };
1511
+ }
1512
+
1513
+ function wasm_bindgen__convert__closures_____invoke__h4889c924fd29fd81(arg0, arg1, arg2) {
1514
+ wasm.wasm_bindgen__convert__closures_____invoke__h4889c924fd29fd81(arg0, arg1, arg2);
1515
+ }
1516
+
1517
+ function wasm_bindgen__convert__closures_____invoke__h90946713c829438a(arg0, arg1, arg2, arg3) {
1518
+ wasm.wasm_bindgen__convert__closures_____invoke__h90946713c829438a(arg0, arg1, arg2, arg3);
1519
+ }
1520
+
1521
+ const PhysicsSimFinalization = (typeof FinalizationRegistry === 'undefined')
1522
+ ? { register: () => {}, unregister: () => {} }
1523
+ : new FinalizationRegistry(ptr => wasm.__wbg_physicssim_free(ptr >>> 0, 1));
1524
+ const RayTracerFinalization = (typeof FinalizationRegistry === 'undefined')
1525
+ ? { register: () => {}, unregister: () => {} }
1526
+ : new FinalizationRegistry(ptr => wasm.__wbg_raytracer_free(ptr >>> 0, 1));
1527
+ const SolidFinalization = (typeof FinalizationRegistry === 'undefined')
1528
+ ? { register: () => {}, unregister: () => {} }
1529
+ : new FinalizationRegistry(ptr => wasm.__wbg_solid_free(ptr >>> 0, 1));
1530
+ const WasmAnnotationLayerFinalization = (typeof FinalizationRegistry === 'undefined')
1531
+ ? { register: () => {}, unregister: () => {} }
1532
+ : new FinalizationRegistry(ptr => wasm.__wbg_wasmannotationlayer_free(ptr >>> 0, 1));
1533
+
1534
+ function addToExternrefTable0(obj) {
1535
+ const idx = wasm.__externref_table_alloc();
1536
+ wasm.__wbindgen_externrefs.set(idx, obj);
1537
+ return idx;
1538
+ }
1539
+
1540
+ function _assertClass(instance, klass) {
1541
+ if (!(instance instanceof klass)) {
1542
+ throw new Error(`expected instance of ${klass.name}`);
1543
+ }
1544
+ }
1545
+
1546
+ const CLOSURE_DTORS = (typeof FinalizationRegistry === 'undefined')
1547
+ ? { register: () => {}, unregister: () => {} }
1548
+ : new FinalizationRegistry(state => state.dtor(state.a, state.b));
1549
+
1550
+ function debugString(val) {
1551
+ // primitive types
1552
+ const type = typeof val;
1553
+ if (type == 'number' || type == 'boolean' || val == null) {
1554
+ return `${val}`;
1555
+ }
1556
+ if (type == 'string') {
1557
+ return `"${val}"`;
1558
+ }
1559
+ if (type == 'symbol') {
1560
+ const description = val.description;
1561
+ if (description == null) {
1562
+ return 'Symbol';
1563
+ } else {
1564
+ return `Symbol(${description})`;
1565
+ }
1566
+ }
1567
+ if (type == 'function') {
1568
+ const name = val.name;
1569
+ if (typeof name == 'string' && name.length > 0) {
1570
+ return `Function(${name})`;
1571
+ } else {
1572
+ return 'Function';
1573
+ }
1574
+ }
1575
+ // objects
1576
+ if (Array.isArray(val)) {
1577
+ const length = val.length;
1578
+ let debug = '[';
1579
+ if (length > 0) {
1580
+ debug += debugString(val[0]);
1581
+ }
1582
+ for(let i = 1; i < length; i++) {
1583
+ debug += ', ' + debugString(val[i]);
1584
+ }
1585
+ debug += ']';
1586
+ return debug;
1587
+ }
1588
+ // Test for built-in
1589
+ const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
1590
+ let className;
1591
+ if (builtInMatches && builtInMatches.length > 1) {
1592
+ className = builtInMatches[1];
1593
+ } else {
1594
+ // Failed to match the standard '[object ClassName]'
1595
+ return toString.call(val);
1596
+ }
1597
+ if (className == 'Object') {
1598
+ // we're a user defined class or Object
1599
+ // JSON.stringify avoids problems with cycles, and is generally much
1600
+ // easier than looping through ownProperties of `val`.
1601
+ try {
1602
+ return 'Object(' + JSON.stringify(val) + ')';
1603
+ } catch (_) {
1604
+ return 'Object';
1605
+ }
1606
+ }
1607
+ // errors
1608
+ if (val instanceof Error) {
1609
+ return `${val.name}: ${val.message}\n${val.stack}`;
1610
+ }
1611
+ // TODO we could test for more things here, like `Set`s and `Map`s.
1612
+ return className;
1613
+ }
1614
+
1615
+ function getArrayF64FromWasm0(ptr, len) {
1616
+ ptr = ptr >>> 0;
1617
+ return getFloat64ArrayMemory0().subarray(ptr / 8, ptr / 8 + len);
1618
+ }
1619
+
1620
+ function getArrayU8FromWasm0(ptr, len) {
1621
+ ptr = ptr >>> 0;
1622
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
1623
+ }
1624
+
1625
+ let cachedDataViewMemory0 = null;
1626
+ function getDataViewMemory0() {
1627
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
1628
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
1629
+ }
1630
+ return cachedDataViewMemory0;
1631
+ }
1632
+
1633
+ let cachedFloat32ArrayMemory0 = null;
1634
+ function getFloat32ArrayMemory0() {
1635
+ if (cachedFloat32ArrayMemory0 === null || cachedFloat32ArrayMemory0.byteLength === 0) {
1636
+ cachedFloat32ArrayMemory0 = new Float32Array(wasm.memory.buffer);
1637
+ }
1638
+ return cachedFloat32ArrayMemory0;
1639
+ }
1640
+
1641
+ let cachedFloat64ArrayMemory0 = null;
1642
+ function getFloat64ArrayMemory0() {
1643
+ if (cachedFloat64ArrayMemory0 === null || cachedFloat64ArrayMemory0.byteLength === 0) {
1644
+ cachedFloat64ArrayMemory0 = new Float64Array(wasm.memory.buffer);
1645
+ }
1646
+ return cachedFloat64ArrayMemory0;
1647
+ }
1648
+
1649
+ function getStringFromWasm0(ptr, len) {
1650
+ ptr = ptr >>> 0;
1651
+ return decodeText(ptr, len);
1652
+ }
1653
+
1654
+ let cachedUint32ArrayMemory0 = null;
1655
+ function getUint32ArrayMemory0() {
1656
+ if (cachedUint32ArrayMemory0 === null || cachedUint32ArrayMemory0.byteLength === 0) {
1657
+ cachedUint32ArrayMemory0 = new Uint32Array(wasm.memory.buffer);
1658
+ }
1659
+ return cachedUint32ArrayMemory0;
1660
+ }
1661
+
1662
+ let cachedUint8ArrayMemory0 = null;
1663
+ function getUint8ArrayMemory0() {
1664
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
1665
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
1666
+ }
1667
+ return cachedUint8ArrayMemory0;
1668
+ }
1669
+
1670
+ function handleError(f, args) {
1671
+ try {
1672
+ return f.apply(this, args);
1673
+ } catch (e) {
1674
+ const idx = addToExternrefTable0(e);
1675
+ wasm.__wbindgen_exn_store(idx);
1676
+ }
1677
+ }
1678
+
1679
+ function isLikeNone(x) {
1680
+ return x === undefined || x === null;
1681
+ }
1682
+
1683
+ function makeMutClosure(arg0, arg1, dtor, f) {
1684
+ const state = { a: arg0, b: arg1, cnt: 1, dtor };
1685
+ const real = (...args) => {
1686
+
1687
+ // First up with a closure we increment the internal reference
1688
+ // count. This ensures that the Rust closure environment won't
1689
+ // be deallocated while we're invoking it.
1690
+ state.cnt++;
1691
+ const a = state.a;
1692
+ state.a = 0;
1693
+ try {
1694
+ return f(a, state.b, ...args);
1695
+ } finally {
1696
+ state.a = a;
1697
+ real._wbg_cb_unref();
1698
+ }
1699
+ };
1700
+ real._wbg_cb_unref = () => {
1701
+ if (--state.cnt === 0) {
1702
+ state.dtor(state.a, state.b);
1703
+ state.a = 0;
1704
+ CLOSURE_DTORS.unregister(state);
1705
+ }
1706
+ };
1707
+ CLOSURE_DTORS.register(real, state, state);
1708
+ return real;
1709
+ }
1710
+
1711
+ function passArray32ToWasm0(arg, malloc) {
1712
+ const ptr = malloc(arg.length * 4, 4) >>> 0;
1713
+ getUint32ArrayMemory0().set(arg, ptr / 4);
1714
+ WASM_VECTOR_LEN = arg.length;
1715
+ return ptr;
1716
+ }
1717
+
1718
+ function passArray8ToWasm0(arg, malloc) {
1719
+ const ptr = malloc(arg.length * 1, 1) >>> 0;
1720
+ getUint8ArrayMemory0().set(arg, ptr / 1);
1721
+ WASM_VECTOR_LEN = arg.length;
1722
+ return ptr;
1723
+ }
1724
+
1725
+ function passArrayF32ToWasm0(arg, malloc) {
1726
+ const ptr = malloc(arg.length * 4, 4) >>> 0;
1727
+ getFloat32ArrayMemory0().set(arg, ptr / 4);
1728
+ WASM_VECTOR_LEN = arg.length;
1729
+ return ptr;
1730
+ }
1731
+
1732
+ function passArrayF64ToWasm0(arg, malloc) {
1733
+ const ptr = malloc(arg.length * 8, 8) >>> 0;
1734
+ getFloat64ArrayMemory0().set(arg, ptr / 8);
1735
+ WASM_VECTOR_LEN = arg.length;
1736
+ return ptr;
1737
+ }
1738
+
1739
+ function passArrayJsValueToWasm0(array, malloc) {
1740
+ const ptr = malloc(array.length * 4, 4) >>> 0;
1741
+ for (let i = 0; i < array.length; i++) {
1742
+ const add = addToExternrefTable0(array[i]);
1743
+ getDataViewMemory0().setUint32(ptr + 4 * i, add, true);
1744
+ }
1745
+ WASM_VECTOR_LEN = array.length;
1746
+ return ptr;
1747
+ }
1748
+
1749
+ function passStringToWasm0(arg, malloc, realloc) {
1750
+ if (realloc === undefined) {
1751
+ const buf = cachedTextEncoder.encode(arg);
1752
+ const ptr = malloc(buf.length, 1) >>> 0;
1753
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
1754
+ WASM_VECTOR_LEN = buf.length;
1755
+ return ptr;
1756
+ }
1757
+
1758
+ let len = arg.length;
1759
+ let ptr = malloc(len, 1) >>> 0;
1760
+
1761
+ const mem = getUint8ArrayMemory0();
1762
+
1763
+ let offset = 0;
1764
+
1765
+ for (; offset < len; offset++) {
1766
+ const code = arg.charCodeAt(offset);
1767
+ if (code > 0x7F) break;
1768
+ mem[ptr + offset] = code;
1769
+ }
1770
+ if (offset !== len) {
1771
+ if (offset !== 0) {
1772
+ arg = arg.slice(offset);
1773
+ }
1774
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
1775
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
1776
+ const ret = cachedTextEncoder.encodeInto(arg, view);
1777
+
1778
+ offset += ret.written;
1779
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
1780
+ }
1781
+
1782
+ WASM_VECTOR_LEN = offset;
1783
+ return ptr;
1784
+ }
1785
+
1786
+ function takeFromExternrefTable0(idx) {
1787
+ const value = wasm.__wbindgen_externrefs.get(idx);
1788
+ wasm.__externref_table_dealloc(idx);
1789
+ return value;
1790
+ }
1791
+
1792
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
1793
+ cachedTextDecoder.decode();
1794
+ const MAX_SAFARI_DECODE_BYTES = 2146435072;
1795
+ let numBytesDecoded = 0;
1796
+ function decodeText(ptr, len) {
1797
+ numBytesDecoded += len;
1798
+ if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
1799
+ cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
1800
+ cachedTextDecoder.decode();
1801
+ numBytesDecoded = len;
1802
+ }
1803
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
1804
+ }
1805
+
1806
+ const cachedTextEncoder = new TextEncoder();
1807
+
1808
+ if (!('encodeInto' in cachedTextEncoder)) {
1809
+ cachedTextEncoder.encodeInto = function (arg, view) {
1810
+ const buf = cachedTextEncoder.encode(arg);
1811
+ view.set(buf);
1812
+ return {
1813
+ read: arg.length,
1814
+ written: buf.length
1815
+ };
1816
+ };
1817
+ }
1818
+
1819
+ let WASM_VECTOR_LEN = 0;
1820
+
1821
+ let wasmModule, wasm;
1822
+ function __wbg_finalize_init(instance, module) {
1823
+ wasm = instance.exports;
1824
+ wasmModule = module;
1825
+ cachedDataViewMemory0 = null;
1826
+ cachedFloat32ArrayMemory0 = null;
1827
+ cachedFloat64ArrayMemory0 = null;
1828
+ cachedUint32ArrayMemory0 = null;
1829
+ cachedUint8ArrayMemory0 = null;
1830
+ wasm.__wbindgen_start();
1831
+ return wasm;
1832
+ }
1833
+
1834
+ async function __wbg_load(module, imports) {
1835
+ if (typeof Response === 'function' && module instanceof Response) {
1836
+ if (typeof WebAssembly.instantiateStreaming === 'function') {
1837
+ try {
1838
+ return await WebAssembly.instantiateStreaming(module, imports);
1839
+ } catch (e) {
1840
+ const validResponse = module.ok && expectedResponseType(module.type);
1841
+
1842
+ if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
1843
+ console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
1844
+
1845
+ } else { throw e; }
1846
+ }
1847
+ }
1848
+
1849
+ const bytes = await module.arrayBuffer();
1850
+ return await WebAssembly.instantiate(bytes, imports);
1851
+ } else {
1852
+ const instance = await WebAssembly.instantiate(module, imports);
1853
+
1854
+ if (instance instanceof WebAssembly.Instance) {
1855
+ return { instance, module };
1856
+ } else {
1857
+ return instance;
1858
+ }
1859
+ }
1860
+
1861
+ function expectedResponseType(type) {
1862
+ switch (type) {
1863
+ case 'basic': case 'cors': case 'default': return true;
1864
+ }
1865
+ return false;
1866
+ }
1867
+ }
1868
+
1869
+ function initSync(module) {
1870
+ if (wasm !== undefined) return wasm;
1871
+
1872
+
1873
+ if (module !== undefined) {
1874
+ if (Object.getPrototypeOf(module) === Object.prototype) {
1875
+ ({module} = module)
1876
+ } else {
1877
+ console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
1878
+ }
1879
+ }
1880
+
1881
+ const imports = __wbg_get_imports();
1882
+ if (!(module instanceof WebAssembly.Module)) {
1883
+ module = new WebAssembly.Module(module);
1884
+ }
1885
+ const instance = new WebAssembly.Instance(module, imports);
1886
+ return __wbg_finalize_init(instance, module);
1887
+ }
1888
+
1889
+ async function __wbg_init(module_or_path) {
1890
+ if (wasm !== undefined) return wasm;
1891
+
1892
+
1893
+ if (module_or_path !== undefined) {
1894
+ if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
1895
+ ({module_or_path} = module_or_path)
1896
+ } else {
1897
+ console.warn('using deprecated parameters for the initialization function; pass a single object instead')
1898
+ }
1899
+ }
1900
+
1901
+ if (module_or_path === undefined) {
1902
+ module_or_path = new URL('vcad_kernel_wasm_bg.wasm', import.meta.url);
1903
+ }
1904
+ const imports = __wbg_get_imports();
1905
+
1906
+ if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
1907
+ module_or_path = fetch(module_or_path);
1908
+ }
1909
+
1910
+ const { instance, module } = await __wbg_load(await module_or_path, imports);
1911
+
1912
+ return __wbg_finalize_init(instance, module);
1913
+ }
1914
+
1915
+ export { initSync, __wbg_init as default };
kernel-wasm/vcad_kernel_wasm_bg.wasm ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0c2a2873e8d01b12a6e17c5a09e1bed2785ec8b847117e442055cf0f9c196efd
3
+ size 1417044
kernel-wasm/vcad_kernel_wasm_bg.wasm.d.ts ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ export const memory: WebAssembly.Memory;
4
+ export const __wbg_physicssim_free: (a: number, b: number) => void;
5
+ export const __wbg_raytracer_free: (a: number, b: number) => void;
6
+ export const __wbg_solid_free: (a: number, b: number) => void;
7
+ export const __wbg_wasmannotationlayer_free: (a: number, b: number) => void;
8
+ export const computeCreasedNormalsGpu: (a: number, b: number, c: number, d: number, e: number) => any;
9
+ export const createDetailView: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => [number, number, number];
10
+ export const decimateMeshGpu: (a: number, b: number, c: number, d: number, e: number) => any;
11
+ export const evaluateCompactIR: (a: number, b: number) => [number, number, number];
12
+ export const exportProjectedViewToDxf: (a: number, b: number) => [number, number, number, number];
13
+ export const importStepBuffer: (a: number, b: number) => [number, number, number];
14
+ export const initGpu: () => any;
15
+ export const isGpuAvailable: () => number;
16
+ export const op_chamfer: (a: number, b: number) => number;
17
+ export const op_circular_pattern: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => number;
18
+ export const op_fillet: (a: number, b: number) => number;
19
+ export const op_linear_pattern: (a: number, b: number, c: number, d: number, e: number, f: number) => number;
20
+ export const op_loft: (a: any, b: number) => [number, number, number];
21
+ export const op_revolve: (a: any, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
22
+ export const op_shell: (a: number, b: number) => number;
23
+ export const op_sweep_helix: (a: any, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number) => [number, number, number];
24
+ export const op_sweep_line: (a: any, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number) => [number, number, number];
25
+ export const parseCompactIR: (a: number, b: number) => [number, number, number, number];
26
+ export const physicssim_new: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
27
+ export const processGeometryGpu: (a: number, b: number, c: number, d: number, e: number, f: number) => any;
28
+ export const projectMesh: (a: any, b: number, c: number) => any;
29
+ export const raytracer_create: () => [number, number, number];
30
+ export const sectionMesh: (a: any, b: number, c: number, d: number, e: number) => any;
31
+ export const solid_boundingBox: (a: number) => [number, number];
32
+ export const solid_canExportStep: (a: number) => number;
33
+ export const solid_centerOfMass: (a: number) => [number, number];
34
+ export const solid_cone: (a: number, b: number, c: number, d: number) => number;
35
+ export const solid_cube: (a: number, b: number, c: number) => number;
36
+ export const solid_cylinder: (a: number, b: number, c: number) => number;
37
+ export const solid_difference: (a: number, b: number) => number;
38
+ export const solid_empty: () => number;
39
+ export const solid_extrude: (a: any, b: number, c: number) => [number, number, number];
40
+ export const solid_getMesh: (a: number, b: number) => any;
41
+ export const solid_horizontalSection: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => any;
42
+ export const solid_intersection: (a: number, b: number) => number;
43
+ export const solid_isEmpty: (a: number) => number;
44
+ export const solid_loft: (a: any, b: number) => [number, number, number];
45
+ export const solid_numTriangles: (a: number) => number;
46
+ export const solid_projectView: (a: number, b: number, c: number, d: number) => any;
47
+ export const solid_rotate: (a: number, b: number, c: number, d: number) => number;
48
+ export const solid_scale: (a: number, b: number, c: number, d: number) => number;
49
+ export const solid_sectionView: (a: number, b: number, c: number, d: number, e: number, f: number) => any;
50
+ export const solid_sphere: (a: number, b: number) => number;
51
+ export const solid_surfaceArea: (a: number) => number;
52
+ export const solid_sweepHelix: (a: any, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number) => [number, number, number];
53
+ export const solid_sweepLine: (a: any, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number) => [number, number, number];
54
+ export const solid_toStepBuffer: (a: number) => [number, number, number, number];
55
+ export const solid_translate: (a: number, b: number, c: number, d: number) => number;
56
+ export const solid_union: (a: number, b: number) => number;
57
+ export const solid_volume: (a: number) => number;
58
+ export const toCompactIR: (a: number, b: number) => [number, number, number, number];
59
+ export const wasmannotationlayer_addAlignedDimension: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
60
+ export const wasmannotationlayer_addAngleDimension: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
61
+ export const wasmannotationlayer_addDiameterDimension: (a: number, b: number, c: number, d: number, e: number) => void;
62
+ export const wasmannotationlayer_addHorizontalDimension: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
63
+ export const wasmannotationlayer_addRadiusDimension: (a: number, b: number, c: number, d: number, e: number) => void;
64
+ export const wasmannotationlayer_addVerticalDimension: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
65
+ export const wasmannotationlayer_annotationCount: (a: number) => number;
66
+ export const wasmannotationlayer_clear: (a: number) => void;
67
+ export const wasmannotationlayer_isEmpty: (a: number) => number;
68
+ export const wasmannotationlayer_new: () => number;
69
+ export const wasmannotationlayer_renderAll: (a: number, b: number, c: number) => any;
70
+ export const solid_linearPattern: (a: number, b: number, c: number, d: number, e: number, f: number) => number;
71
+ export const init: () => void;
72
+ export const solid_revolve: (a: any, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
73
+ export const isPhysicsAvailable: () => number;
74
+ export const solid_chamfer: (a: number, b: number) => number;
75
+ export const solid_fillet: (a: number, b: number) => number;
76
+ export const solid_shell: (a: number, b: number) => number;
77
+ export const solid_circularPattern: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => number;
78
+ export const wasm_bindgen__closure__destroy__ha1c57de1520edab9: (a: number, b: number) => void;
79
+ export const wasm_bindgen__convert__closures_____invoke__h90946713c829438a: (a: number, b: number, c: any, d: any) => void;
80
+ export const wasm_bindgen__convert__closures_____invoke__h4889c924fd29fd81: (a: number, b: number, c: any) => void;
81
+ export const __wbindgen_malloc: (a: number, b: number) => number;
82
+ export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
83
+ export const __wbindgen_exn_store: (a: number) => void;
84
+ export const __externref_table_alloc: () => number;
85
+ export const __wbindgen_externrefs: WebAssembly.Table;
86
+ export const __wbindgen_free: (a: number, b: number, c: number) => void;
87
+ export const __externref_table_dealloc: (a: number) => void;
88
+ export const __wbindgen_start: () => void;
server.mjs ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Render API - HTTP server that renders Compact IR to SVG
4
+ * POST /render with body: { ir: "<compact ir>" }
5
+ * Returns: SVG image
6
+ */
7
+
8
+ import { createServer } from 'node:http';
9
+ import * as fs from 'node:fs';
10
+ import * as path from 'node:path';
11
+ import { fileURLToPath } from 'node:url';
12
+
13
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
+ const PORT = process.env.PORT || 7860;
15
+
16
+ // Load WASM kernel
17
+ let kernel = null;
18
+
19
+ async function loadKernel() {
20
+ if (kernel) return kernel;
21
+
22
+ const wasmModule = await import('./kernel-wasm/vcad_kernel_wasm.js');
23
+
24
+ const possiblePaths = [
25
+ path.join(__dirname, 'node_modules', '@vcad', 'kernel-wasm', 'vcad_kernel_wasm_bg.wasm'),
26
+ path.join(__dirname, 'kernel-wasm', 'vcad_kernel_wasm_bg.wasm'),
27
+ ];
28
+
29
+ let wasmBuffer = null;
30
+ for (const wasmPath of possiblePaths) {
31
+ if (fs.existsSync(wasmPath)) {
32
+ wasmBuffer = fs.readFileSync(wasmPath);
33
+ console.log(`WASM loaded from: ${wasmPath}`);
34
+ break;
35
+ }
36
+ }
37
+
38
+ if (!wasmBuffer) {
39
+ throw new Error('Could not find WASM file');
40
+ }
41
+
42
+ wasmModule.initSync({ module: wasmBuffer });
43
+ kernel = wasmModule;
44
+ console.log('WASM kernel initialized');
45
+ return kernel;
46
+ }
47
+
48
+ // 3D to 2D projection
49
+ function project(x, y, z, angle = 45, elevation = 25) {
50
+ const radAngle = (angle * Math.PI) / 180;
51
+ const radElev = (elevation * Math.PI) / 180;
52
+
53
+ const x1 = x * Math.cos(radAngle) - z * Math.sin(radAngle);
54
+ const z1 = x * Math.sin(radAngle) + z * Math.cos(radAngle);
55
+ const y1 = y * Math.cos(radElev) - z1 * Math.sin(radElev);
56
+ const z2 = y * Math.sin(radElev) + z1 * Math.cos(radElev);
57
+
58
+ return { x: x1, y: y1, z: z2 };
59
+ }
60
+
61
+ // Render mesh to SVG
62
+ function renderMeshToSVG(mesh, width = 600, height = 600) {
63
+ const { positions, indices } = mesh;
64
+
65
+ if (!positions || positions.length === 0) {
66
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}"><rect fill="#1a1a1a" width="100%" height="100%"/><text x="50%" y="50%" fill="white" text-anchor="middle">Empty mesh</text></svg>`;
67
+ }
68
+
69
+ // Find bounding box
70
+ let minX = Infinity, maxX = -Infinity;
71
+ let minY = Infinity, maxY = -Infinity;
72
+
73
+ for (let i = 0; i < positions.length; i += 3) {
74
+ const p = project(positions[i], positions[i + 1], positions[i + 2]);
75
+ minX = Math.min(minX, p.x);
76
+ maxX = Math.max(maxX, p.x);
77
+ minY = Math.min(minY, p.y);
78
+ maxY = Math.max(maxY, p.y);
79
+ }
80
+
81
+ // Scale to fit
82
+ const rangeX = maxX - minX || 1;
83
+ const rangeY = maxY - minY || 1;
84
+ const scale = Math.min((width - 100) / rangeX, (height - 100) / rangeY);
85
+ const offsetX = width / 2 - ((minX + maxX) / 2) * scale;
86
+ const offsetY = height / 2 + ((minY + maxY) / 2) * scale;
87
+
88
+ // Collect triangles with depth
89
+ const triangles = [];
90
+ for (let i = 0; i < indices.length; i += 3) {
91
+ const i0 = indices[i], i1 = indices[i + 1], i2 = indices[i + 2];
92
+
93
+ const v0 = project(positions[i0 * 3], positions[i0 * 3 + 1], positions[i0 * 3 + 2]);
94
+ const v1 = project(positions[i1 * 3], positions[i1 * 3 + 1], positions[i1 * 3 + 2]);
95
+ const v2 = project(positions[i2 * 3], positions[i2 * 3 + 1], positions[i2 * 3 + 2]);
96
+
97
+ // Calculate normal for lighting
98
+ const nx = (v1.y - v0.y) * (v2.z - v0.z) - (v1.z - v0.z) * (v2.y - v0.y);
99
+ const ny = (v1.z - v0.z) * (v2.x - v0.x) - (v1.x - v0.x) * (v2.z - v0.z);
100
+ const nz = (v1.x - v0.x) * (v2.y - v0.y) - (v1.y - v0.y) * (v2.x - v0.x);
101
+ const len = Math.sqrt(nx * nx + ny * ny + nz * nz) || 1;
102
+
103
+ // Simple lighting
104
+ const light = Math.max(0.3, (nx / len * 0.3 + ny / len * 0.5 + nz / len * 0.8));
105
+ const avgZ = (v0.z + v1.z + v2.z) / 3;
106
+
107
+ triangles.push({
108
+ points: [
109
+ { x: v0.x * scale + offsetX, y: -v0.y * scale + offsetY },
110
+ { x: v1.x * scale + offsetX, y: -v1.y * scale + offsetY },
111
+ { x: v2.x * scale + offsetX, y: -v2.y * scale + offsetY },
112
+ ],
113
+ z: avgZ,
114
+ light,
115
+ });
116
+ }
117
+
118
+ // Sort by depth (painter's algorithm)
119
+ triangles.sort((a, b) => a.z - b.z);
120
+
121
+ // Build SVG
122
+ let svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">\n`;
123
+ svg += `<rect fill="#1a1a1a" width="100%" height="100%"/>\n`;
124
+ svg += `<g stroke="rgba(255,255,255,0.3)" stroke-width="0.5">\n`;
125
+
126
+ for (const tri of triangles) {
127
+ const g = Math.floor(200 * tri.light);
128
+ const b = Math.floor(220 * tri.light);
129
+ const r = Math.floor(g * 0.4);
130
+ const fill = `rgb(${r},${g},${Math.floor(b * 0.5)})`;
131
+
132
+ const pts = tri.points.map(p => `${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(' ');
133
+ svg += `<polygon points="${pts}" fill="${fill}"/>\n`;
134
+ }
135
+
136
+ svg += `</g>\n</svg>`;
137
+ return svg;
138
+ }
139
+
140
+ async function renderIR(compactIR) {
141
+ const k = await loadKernel();
142
+
143
+ const solid = k.evaluateCompactIR(compactIR);
144
+
145
+ if (solid.isEmpty()) {
146
+ throw new Error('Solid is empty');
147
+ }
148
+
149
+ const mesh = solid.getMesh(32);
150
+ return renderMeshToSVG(mesh);
151
+ }
152
+
153
+ // HTTP server
154
+ const server = createServer(async (req, res) => {
155
+ // CORS headers
156
+ res.setHeader('Access-Control-Allow-Origin', '*');
157
+ res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
158
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
159
+
160
+ if (req.method === 'OPTIONS') {
161
+ res.writeHead(204);
162
+ res.end();
163
+ return;
164
+ }
165
+
166
+ if (req.method === 'GET' && req.url === '/health') {
167
+ res.writeHead(200, { 'Content-Type': 'application/json' });
168
+ res.end(JSON.stringify({ status: 'ok' }));
169
+ return;
170
+ }
171
+
172
+ if (req.method === 'GET' && req.url === '/') {
173
+ res.writeHead(200, { 'Content-Type': 'text/html' });
174
+ res.end(`<!DOCTYPE html>
175
+ <html>
176
+ <head><title>vcad Render API</title></head>
177
+ <body style="background:#1a1a1a;color:white;font-family:sans-serif;padding:2rem">
178
+ <h1>vcad Render API</h1>
179
+ <p>POST /render with {"ir": "C 50 30 10"} to render Compact IR to SVG</p>
180
+ <p><a href="/health" style="color:#4ade80">/health</a> - Health check</p>
181
+ </body>
182
+ </html>`);
183
+ return;
184
+ }
185
+
186
+ if (req.method === 'POST' && req.url === '/render') {
187
+ let body = '';
188
+ req.on('data', chunk => { body += chunk; });
189
+ req.on('end', async () => {
190
+ try {
191
+ const { ir } = JSON.parse(body);
192
+ if (!ir) {
193
+ res.writeHead(400, { 'Content-Type': 'application/json' });
194
+ res.end(JSON.stringify({ error: 'Missing ir field' }));
195
+ return;
196
+ }
197
+
198
+ const svg = await renderIR(ir);
199
+ res.writeHead(200, { 'Content-Type': 'image/svg+xml' });
200
+ res.end(svg);
201
+ } catch (err) {
202
+ console.error('Render error:', err.message);
203
+ res.writeHead(500, { 'Content-Type': 'application/json' });
204
+ res.end(JSON.stringify({ error: err.message }));
205
+ }
206
+ });
207
+ return;
208
+ }
209
+
210
+ res.writeHead(404, { 'Content-Type': 'application/json' });
211
+ res.end(JSON.stringify({ error: 'Not found' }));
212
+ });
213
+
214
+ // Start server
215
+ await loadKernel();
216
+ server.listen(PORT, () => {
217
+ console.log(`Render API listening on port ${PORT}`);
218
+ });