@gui-chat-plugin/present3d 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2171 @@
1
+ var P = Object.defineProperty;
2
+ var x = (n, e, s) => e in n ? P(n, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : n[e] = s;
3
+ var d = (n, e, s) => x(n, typeof e != "symbol" ? e + "" : e, s);
4
+ import * as l from "three";
5
+ import { Evaluator as M, Brush as B, INTERSECTION as g, SUBTRACTION as C, ADDITION as w } from "three-bvh-csg";
6
+ const U = "present3D", k = {
7
+ type: "function",
8
+ name: U,
9
+ description: "Display interactive 3D visualizations using the full ShapeScript language with expressions, variables, control flow, and functions.",
10
+ parameters: {
11
+ type: "object",
12
+ properties: {
13
+ title: {
14
+ type: "string",
15
+ description: "Title for the 3D visualization"
16
+ },
17
+ script: {
18
+ type: "string",
19
+ description: `ShapeScript code defining the 3D scene. Full language features supported.
20
+
21
+ ## SYNTAX OVERVIEW:
22
+
23
+ ### Expressions & Operators:
24
+ - Arithmetic: +, -, *, /, % with proper precedence
25
+ - Comparison: =, <>, <, <=, >, >=
26
+ - Boolean: and, or, not
27
+ - Parentheses for grouping: (2 + 3) * 4
28
+
29
+ ### Variables:
30
+ define radius 2
31
+ define red (1 0 0)
32
+ sphere { size radius color red }
33
+
34
+ ### Control Flow:
35
+
36
+ For loops with variables:
37
+ for i in 1 to 5 {
38
+ cube { position (i * 2) 0 0 size 1 }
39
+ }
40
+
41
+ For loops with step:
42
+ for i in 0 to 10 step 2 {
43
+ sphere { position 0 i 0 }
44
+ }
45
+
46
+ If/else conditionals:
47
+ define showSphere 1
48
+ if showSphere {
49
+ sphere { size 2 }
50
+ } else {
51
+ cube { size 2 }
52
+ }
53
+
54
+ Switch statements:
55
+ define shape 2
56
+ switch shape {
57
+ case 1
58
+ cube
59
+ case 2
60
+ sphere
61
+ else
62
+ cone
63
+ }
64
+
65
+ ### Built-in Functions:
66
+
67
+ Math: round, floor, ceil, abs, sign, sqrt, pow, min, max
68
+ Trig: sin, cos, tan, asin, acos, atan, atan2 (uses radians)
69
+ Vector: dot, cross, length, normalize, sum
70
+
71
+ IMPORTANT: Function calls require NO space between name and parenthesis:
72
+ - sin(x) ✓ function call
73
+ - sin (x) ✗ NOT a function call (identifier + parenthesized expression)
74
+
75
+ Examples:
76
+ for i in 1 to 8 {
77
+ define angle (i * 0.785) // 45 degrees in radians
78
+ cube { position (cos(angle) * 3) 0 (sin(angle) * 3) }
79
+ }
80
+
81
+ ### Primitives & Properties:
82
+
83
+ Shapes: cube, sphere, cylinder, cone, torus
84
+ Properties: position X Y Z, rotation X Y Z, size X Y Z
85
+ Materials: color R G B (0-1), opacity (0-1)
86
+
87
+ ### CSG Operations:
88
+ union, difference, intersection, xor, stencil
89
+
90
+ Example:
91
+ difference {
92
+ sphere { size 2 color (1 0.5 0) }
93
+ cube { size 1.5 }
94
+ }
95
+
96
+ ### Comments:
97
+ // Single-line comment
98
+ /* Multi-line
99
+ comment */
100
+
101
+ ## COMPLETE EXAMPLES:
102
+
103
+ Linear arrangement with expressions:
104
+ define spacing 1.5
105
+ for i in 1 to 4 {
106
+ cylinder { position ((i - 2.5) * spacing) 0 0 size 0.4 1 }
107
+ }
108
+
109
+ Circular pattern:
110
+ define count 12
111
+ for i in 1 to count {
112
+ define angle ((i / count) * 6.283) // 2 * PI
113
+ cube {
114
+ position (cos(angle) * 3) 0 (sin(angle) * 3)
115
+ color (i / count) 0.5 (1 - i / count)
116
+ size 0.5
117
+ }
118
+ }
119
+
120
+ Conditional geometry:
121
+ define makeHollow 1
122
+ if makeHollow {
123
+ difference {
124
+ sphere { size 2 color (1 0 0) }
125
+ sphere { size 1.7 }
126
+ }
127
+ } else {
128
+ sphere { size 2 color (1 0 0) }
129
+ }
130
+
131
+ Mathematical visualization:
132
+ for x in -5 to 5 {
133
+ for z in -5 to 5 {
134
+ define height (sin(x * 0.5) * cos(z * 0.5) * 2)
135
+ cube {
136
+ position (x * 0.3) height (z * 0.3)
137
+ size 0.25 (abs(height) + 0.1) 0.25
138
+ color (0.5 + height * 0.25) 0.3 (0.5 - height * 0.25)
139
+ }
140
+ }
141
+ }`
142
+ }
143
+ },
144
+ required: ["title", "script"]
145
+ }
146
+ }, O = async (n, e) => {
147
+ const { script: s, title: r } = e;
148
+ if (!s || s.trim() === "")
149
+ throw new Error("ShapeScript code is required but was not provided");
150
+ return {
151
+ message: `Created 3D visualization: ${r}`,
152
+ title: r,
153
+ data: { script: s },
154
+ instructions: "Acknowledge that the 3D visualization has been created and is displayed to the user. They can interact with it by rotating, zooming, and panning the camera."
155
+ };
156
+ }, Y = {
157
+ toolDefinition: k,
158
+ execute: O,
159
+ generatingMessage: "Creating 3D visualization...",
160
+ waitingMessage: "Tell the user that the 3D visualization was created and will be presented shortly.",
161
+ isEnabled: () => !0
162
+ }, H = O, Q = [
163
+ {
164
+ name: "Basic Shapes",
165
+ args: {
166
+ title: "Basic 3D Shapes",
167
+ script: `// Basic shapes demonstration
168
+ cube { position -2 0 0 size 1 color (1 0.3 0.3) }
169
+ sphere { position 0 0 0 size 1 color (0.3 1 0.3) }
170
+ cylinder { position 2 0 0 size 0.5 1 color (0.3 0.3 1) }`
171
+ }
172
+ },
173
+ {
174
+ name: "Circular Pattern",
175
+ args: {
176
+ title: "Circular Pattern",
177
+ script: `// Create a circular pattern of cubes
178
+ define count 12
179
+ for i in 1 to count {
180
+ define angle ((i / count) * 6.283)
181
+ cube {
182
+ position (cos(angle) * 3) 0 (sin(angle) * 3)
183
+ color (i / count) 0.5 (1 - i / count)
184
+ size 0.5
185
+ }
186
+ }`
187
+ }
188
+ },
189
+ {
190
+ name: "CSG Difference",
191
+ args: {
192
+ title: "Hollow Sphere",
193
+ script: `// Create a hollow sphere using CSG difference
194
+ difference {
195
+ sphere { size 2 color (1 0.5 0) }
196
+ sphere { size 1.7 color (1 1 1) }
197
+ cube { position 0 0 2 size 2 }
198
+ }`
199
+ }
200
+ }
201
+ ];
202
+ var t = /* @__PURE__ */ ((n) => (n.CUBE = "CUBE", n.SPHERE = "SPHERE", n.CYLINDER = "CYLINDER", n.CONE = "CONE", n.TORUS = "TORUS", n.CIRCLE = "CIRCLE", n.SQUARE = "SQUARE", n.POLYGON = "POLYGON", n.EXTRUDE = "EXTRUDE", n.LOFT = "LOFT", n.LATHE = "LATHE", n.FILL = "FILL", n.HULL = "HULL", n.GROUP = "GROUP", n.PATH = "PATH", n.POINT = "POINT", n.CURVE = "CURVE", n.DETAIL = "DETAIL", n.BACKGROUND = "BACKGROUND", n.TEXTURE = "TEXTURE", n.UNION = "UNION", n.DIFFERENCE = "DIFFERENCE", n.INTERSECTION = "INTERSECTION", n.XOR = "XOR", n.STENCIL = "STENCIL", n.FOR = "FOR", n.IN = "IN", n.TO = "TO", n.STEP = "STEP", n.IF = "IF", n.ELSE = "ELSE", n.SWITCH = "SWITCH", n.CASE = "CASE", n.DEFINE = "DEFINE", n.OPTION = "OPTION", n.POSITION = "POSITION", n.ROTATION = "ROTATION", n.ORIENTATION = "ORIENTATION", n.SIZE = "SIZE", n.COLOR = "COLOR", n.OPACITY = "OPACITY", n.ROTATE = "ROTATE", n.TRANSLATE = "TRANSLATE", n.SCALE = "SCALE", n.NUMBER = "NUMBER", n.IDENTIFIER = "IDENTIFIER", n.STRING = "STRING", n.PLUS = "PLUS", n.MINUS = "MINUS", n.STAR = "STAR", n.DIVIDE = "DIVIDE", n.PERCENT = "PERCENT", n.LPAREN = "LPAREN", n.RPAREN = "RPAREN", n.LBRACKET = "LBRACKET", n.RBRACKET = "RBRACKET", n.DOT = "DOT", n.EQUALS = "EQUALS", n.NOT_EQUALS = "NOT_EQUALS", n.LESS = "LESS", n.LESS_EQUAL = "LESS_EQUAL", n.GREATER = "GREATER", n.GREATER_EQUAL = "GREATER_EQUAL", n.AND = "AND", n.OR = "OR", n.NOT = "NOT", n.LBRACE = "LBRACE", n.RBRACE = "RBRACE", n.COMMA = "COMMA", n.SLASH = "SLASH", n.NEWLINE = "NEWLINE", n.EOF = "EOF", n.COMMENT = "COMMENT", n))(t || {});
203
+ class R extends Error {
204
+ constructor(e, s, r) {
205
+ super(
206
+ s !== void 0 && r !== void 0 ? `Parse error at line ${s}, column ${r}: ${e}` : `Parse error: ${e}`
207
+ ), this.line = s, this.column = r, this.name = "ParseError";
208
+ }
209
+ }
210
+ class D {
211
+ constructor(e) {
212
+ d(this, "input");
213
+ d(this, "pos", 0);
214
+ d(this, "line", 1);
215
+ d(this, "column", 1);
216
+ this.input = e;
217
+ }
218
+ peek(e = 0) {
219
+ return this.input[this.pos + e] || "";
220
+ }
221
+ advance() {
222
+ const e = this.input[this.pos++];
223
+ return e === `
224
+ ` ? (this.line++, this.column = 1) : this.column++, e;
225
+ }
226
+ skipWhitespace() {
227
+ for (; this.pos < this.input.length; ) {
228
+ const e = this.peek();
229
+ if (e === " " || e === " " || e === "\r")
230
+ this.advance();
231
+ else if (e === "/" && this.peek(1) === "/")
232
+ for (; this.peek() && this.peek() !== `
233
+ `; )
234
+ this.advance();
235
+ else if (e === "/" && this.peek(1) === "*") {
236
+ this.advance(), this.advance();
237
+ let s = 1;
238
+ for (; this.pos < this.input.length && s > 0; )
239
+ this.peek() === "/" && this.peek(1) === "*" ? (s++, this.advance(), this.advance()) : this.peek() === "*" && this.peek(1) === "/" ? (s--, this.advance(), this.advance()) : this.advance();
240
+ } else
241
+ break;
242
+ }
243
+ }
244
+ readNumber() {
245
+ const e = this.line, s = this.column;
246
+ let r = "";
247
+ for (this.peek() === "-" && (r += this.advance()); this.pos < this.input.length; ) {
248
+ const i = this.peek();
249
+ if (i >= "0" && i <= "9" || i === ".")
250
+ r += this.advance();
251
+ else
252
+ break;
253
+ }
254
+ return {
255
+ type: t.NUMBER,
256
+ value: parseFloat(r),
257
+ line: e,
258
+ column: s
259
+ };
260
+ }
261
+ readIdentifier() {
262
+ const e = this.line, s = this.column;
263
+ let r = "";
264
+ for (; this.pos < this.input.length; ) {
265
+ const o = this.peek();
266
+ if (o >= "a" && o <= "z" || o >= "A" && o <= "Z" || o >= "0" && o <= "9" || o === "_")
267
+ r += this.advance();
268
+ else
269
+ break;
270
+ }
271
+ return {
272
+ type: {
273
+ cube: t.CUBE,
274
+ sphere: t.SPHERE,
275
+ cylinder: t.CYLINDER,
276
+ cone: t.CONE,
277
+ torus: t.TORUS,
278
+ circle: t.CIRCLE,
279
+ square: t.SQUARE,
280
+ polygon: t.POLYGON,
281
+ extrude: t.EXTRUDE,
282
+ loft: t.LOFT,
283
+ lathe: t.LATHE,
284
+ fill: t.FILL,
285
+ hull: t.HULL,
286
+ group: t.GROUP,
287
+ path: t.PATH,
288
+ point: t.POINT,
289
+ curve: t.CURVE,
290
+ detail: t.DETAIL,
291
+ background: t.BACKGROUND,
292
+ texture: t.TEXTURE,
293
+ union: t.UNION,
294
+ difference: t.DIFFERENCE,
295
+ intersection: t.INTERSECTION,
296
+ xor: t.XOR,
297
+ stencil: t.STENCIL,
298
+ for: t.FOR,
299
+ in: t.IN,
300
+ to: t.TO,
301
+ step: t.STEP,
302
+ if: t.IF,
303
+ else: t.ELSE,
304
+ switch: t.SWITCH,
305
+ case: t.CASE,
306
+ define: t.DEFINE,
307
+ option: t.OPTION,
308
+ position: t.POSITION,
309
+ rotation: t.ROTATION,
310
+ orientation: t.ORIENTATION,
311
+ size: t.SIZE,
312
+ color: t.COLOR,
313
+ opacity: t.OPACITY,
314
+ rotate: t.ROTATE,
315
+ translate: t.TRANSLATE,
316
+ scale: t.SCALE,
317
+ and: t.AND,
318
+ or: t.OR,
319
+ not: t.NOT
320
+ }[r.toLowerCase()] || t.IDENTIFIER,
321
+ value: r,
322
+ line: e,
323
+ column: s
324
+ };
325
+ }
326
+ readString() {
327
+ const e = this.line, s = this.column;
328
+ let r = "";
329
+ for (this.advance(); this.pos < this.input.length; ) {
330
+ const i = this.peek();
331
+ if (i === '"') {
332
+ this.advance();
333
+ break;
334
+ } else if (i === "\\") {
335
+ this.advance();
336
+ const a = this.peek();
337
+ a === '"' || a === "\\" ? r += this.advance() : a === "n" ? (r += `
338
+ `, this.advance()) : a === "t" ? (r += " ", this.advance()) : (r += a, this.advance());
339
+ } else
340
+ r += this.advance();
341
+ }
342
+ return {
343
+ type: t.STRING,
344
+ value: r,
345
+ line: e,
346
+ column: s
347
+ };
348
+ }
349
+ tokenize() {
350
+ const e = [];
351
+ for (; this.pos < this.input.length; ) {
352
+ const s = this.pos;
353
+ this.skipWhitespace();
354
+ const r = this.pos > s;
355
+ if (this.pos >= this.input.length) break;
356
+ const i = this.peek(), a = this.line, o = this.column;
357
+ if (i >= "0" && i <= "9" || i === "-" && this.peek(1) >= "0" && this.peek(1) <= "9" && (e.length === 0 || e[e.length - 1].type === t.LPAREN || e[e.length - 1].type === t.COMMA || e[e.length - 1].type === t.LBRACE || e[e.length - 1].type === t.LBRACKET || this.isOperator(e[e.length - 1].type))) {
358
+ const c = this.readNumber();
359
+ c.precedingWhitespace = r, e.push(c);
360
+ } else if (i >= "a" && i <= "z" || i >= "A" && i <= "Z") {
361
+ const c = this.readIdentifier();
362
+ c.precedingWhitespace = r, e.push(c);
363
+ } else if (i === '"') {
364
+ const c = this.readString();
365
+ c.precedingWhitespace = r, e.push(c);
366
+ } else if (i === "<" && this.peek(1) === ">")
367
+ this.advance(), this.advance(), e.push({
368
+ type: t.NOT_EQUALS,
369
+ value: "<>",
370
+ line: a,
371
+ column: o,
372
+ precedingWhitespace: r
373
+ });
374
+ else if (i === "<" && this.peek(1) === "=")
375
+ this.advance(), this.advance(), e.push({
376
+ type: t.LESS_EQUAL,
377
+ value: "<=",
378
+ line: a,
379
+ column: o,
380
+ precedingWhitespace: r
381
+ });
382
+ else if (i === ">" && this.peek(1) === "=")
383
+ this.advance(), this.advance(), e.push({
384
+ type: t.GREATER_EQUAL,
385
+ value: ">=",
386
+ line: a,
387
+ column: o,
388
+ precedingWhitespace: r
389
+ });
390
+ else if (i === "+")
391
+ this.advance(), e.push({
392
+ type: t.PLUS,
393
+ value: "+",
394
+ line: a,
395
+ column: o,
396
+ precedingWhitespace: r
397
+ });
398
+ else if (i === "-")
399
+ this.advance(), e.push({
400
+ type: t.MINUS,
401
+ value: "-",
402
+ line: a,
403
+ column: o,
404
+ precedingWhitespace: r
405
+ });
406
+ else if (i === "*")
407
+ this.advance(), e.push({
408
+ type: t.STAR,
409
+ value: "*",
410
+ line: a,
411
+ column: o,
412
+ precedingWhitespace: r
413
+ });
414
+ else if (i === "/")
415
+ this.advance(), e.push({
416
+ type: t.DIVIDE,
417
+ value: "/",
418
+ line: a,
419
+ column: o,
420
+ precedingWhitespace: r
421
+ });
422
+ else if (i === "%")
423
+ this.advance(), e.push({
424
+ type: t.PERCENT,
425
+ value: "%",
426
+ line: a,
427
+ column: o,
428
+ precedingWhitespace: r
429
+ });
430
+ else if (i === "(")
431
+ this.advance(), e.push({
432
+ type: t.LPAREN,
433
+ value: "(",
434
+ line: a,
435
+ column: o,
436
+ precedingWhitespace: r
437
+ });
438
+ else if (i === ")")
439
+ this.advance(), e.push({
440
+ type: t.RPAREN,
441
+ value: ")",
442
+ line: a,
443
+ column: o,
444
+ precedingWhitespace: r
445
+ });
446
+ else if (i === "[")
447
+ this.advance(), e.push({
448
+ type: t.LBRACKET,
449
+ value: "[",
450
+ line: a,
451
+ column: o,
452
+ precedingWhitespace: r
453
+ });
454
+ else if (i === "]")
455
+ this.advance(), e.push({
456
+ type: t.RBRACKET,
457
+ value: "]",
458
+ line: a,
459
+ column: o,
460
+ precedingWhitespace: r
461
+ });
462
+ else if (i === "{")
463
+ this.advance(), e.push({
464
+ type: t.LBRACE,
465
+ value: "{",
466
+ line: a,
467
+ column: o,
468
+ precedingWhitespace: r
469
+ });
470
+ else if (i === "}")
471
+ this.advance(), e.push({
472
+ type: t.RBRACE,
473
+ value: "}",
474
+ line: a,
475
+ column: o,
476
+ precedingWhitespace: r
477
+ });
478
+ else if (i === ",")
479
+ this.advance(), e.push({
480
+ type: t.COMMA,
481
+ value: ",",
482
+ line: a,
483
+ column: o,
484
+ precedingWhitespace: r
485
+ });
486
+ else if (i === ".")
487
+ this.advance(), e.push({
488
+ type: t.DOT,
489
+ value: ".",
490
+ line: a,
491
+ column: o,
492
+ precedingWhitespace: r
493
+ });
494
+ else if (i === "=")
495
+ this.advance(), e.push({
496
+ type: t.EQUALS,
497
+ value: "=",
498
+ line: a,
499
+ column: o,
500
+ precedingWhitespace: r
501
+ });
502
+ else if (i === "<")
503
+ this.advance(), e.push({
504
+ type: t.LESS,
505
+ value: "<",
506
+ line: a,
507
+ column: o,
508
+ precedingWhitespace: r
509
+ });
510
+ else if (i === ">")
511
+ this.advance(), e.push({
512
+ type: t.GREATER,
513
+ value: ">",
514
+ line: a,
515
+ column: o,
516
+ precedingWhitespace: r
517
+ });
518
+ else if (i === `
519
+ `)
520
+ this.advance(), e.push({
521
+ type: t.NEWLINE,
522
+ value: `
523
+ `,
524
+ line: a,
525
+ column: o,
526
+ precedingWhitespace: r
527
+ });
528
+ else
529
+ throw new R(`Unexpected character: '${i}'`, a, o);
530
+ }
531
+ return e.push({
532
+ type: t.EOF,
533
+ value: "",
534
+ line: this.line,
535
+ column: this.column,
536
+ precedingWhitespace: !1
537
+ }), e;
538
+ }
539
+ isOperator(e) {
540
+ return e === t.PLUS || e === t.MINUS || e === t.STAR || e === t.DIVIDE || e === t.PERCENT || e === t.EQUALS || e === t.NOT_EQUALS || e === t.LESS || e === t.LESS_EQUAL || e === t.GREATER || e === t.GREATER_EQUAL || e === t.AND || e === t.OR;
541
+ }
542
+ }
543
+ class F {
544
+ constructor(e) {
545
+ d(this, "tokens");
546
+ d(this, "pos", 0);
547
+ this.tokens = e;
548
+ }
549
+ current() {
550
+ return this.tokens[this.pos];
551
+ }
552
+ peek(e = 1) {
553
+ return this.tokens[this.pos + e] || this.tokens[this.tokens.length - 1];
554
+ }
555
+ advance() {
556
+ return this.tokens[this.pos++];
557
+ }
558
+ expect(e) {
559
+ const s = this.current();
560
+ if (s.type !== e)
561
+ throw new R(
562
+ `Expected ${e} but got ${s.type}`,
563
+ s.line,
564
+ s.column
565
+ );
566
+ return this.advance();
567
+ }
568
+ // Expect an identifier, but allow keywords to be used as identifiers
569
+ expectIdentifier() {
570
+ const e = this.current();
571
+ if (e.type === t.IDENTIFIER)
572
+ return this.advance();
573
+ if (typeof e.value == "string")
574
+ return this.advance();
575
+ throw new R(
576
+ `Expected identifier but got ${e.type}`,
577
+ e.line,
578
+ e.column
579
+ );
580
+ }
581
+ skipNewlines() {
582
+ for (; this.current().type === t.NEWLINE; )
583
+ this.advance();
584
+ }
585
+ // Expression parsing with precedence climbing
586
+ parseExpression(e = 0) {
587
+ let s = this.parsePrimary();
588
+ for (; ; ) {
589
+ const r = this.current(), i = this.getPrecedence(r.type);
590
+ if (i < e) break;
591
+ const a = this.tokenTypeToOperator(r.type);
592
+ if (!a) break;
593
+ this.advance();
594
+ const o = this.parseExpression(i + 1);
595
+ s = {
596
+ type: "binary",
597
+ operator: a,
598
+ left: s,
599
+ right: o
600
+ };
601
+ }
602
+ return s;
603
+ }
604
+ parsePrimary() {
605
+ const e = this.current();
606
+ if (e.type === t.MINUS || e.type === t.NOT)
607
+ return this.advance(), {
608
+ type: "unary",
609
+ operator: e.type === t.MINUS ? "-" : "not",
610
+ operand: this.parsePrimary()
611
+ };
612
+ if (e.type === t.LPAREN) {
613
+ this.advance();
614
+ const s = [];
615
+ if (s.push(this.parseExpression()), this.current().type === t.COMMA)
616
+ for (; this.current().type === t.COMMA && (this.advance(), this.current().type !== t.RPAREN); )
617
+ s.push(this.parseExpression());
618
+ else {
619
+ const r = this.current();
620
+ if ((r.type === t.NUMBER || r.type === t.IDENTIFIER || r.type === t.MINUS || r.type === t.LPAREN) && r.type !== t.RPAREN)
621
+ for (; ; ) {
622
+ const a = this.current();
623
+ if (a.type === t.NUMBER || a.type === t.IDENTIFIER || a.type === t.MINUS || a.type === t.LPAREN)
624
+ s.push(this.parseExpression());
625
+ else
626
+ break;
627
+ }
628
+ }
629
+ return this.expect(t.RPAREN), s.length === 1 ? s[0] : { type: "tuple", elements: s };
630
+ }
631
+ if (e.type === t.NUMBER)
632
+ return this.advance(), {
633
+ type: "number",
634
+ value: e.value
635
+ };
636
+ if (e.type === t.STRING)
637
+ return this.advance(), {
638
+ type: "identifier",
639
+ // Treat strings as special identifiers for now
640
+ name: e.value
641
+ };
642
+ if (e.type === t.IDENTIFIER) {
643
+ const s = e.value;
644
+ if (this.advance(), this.current().type === t.LPAREN && !this.current().precedingWhitespace) {
645
+ this.advance();
646
+ const r = [];
647
+ if (this.current().type !== t.RPAREN)
648
+ for (r.push(this.parseExpression()); this.current().type === t.COMMA && (this.advance(), this.current().type !== t.RPAREN); )
649
+ r.push(this.parseExpression());
650
+ return this.expect(t.RPAREN), {
651
+ type: "call",
652
+ name: s,
653
+ args: r
654
+ };
655
+ }
656
+ return {
657
+ type: "identifier",
658
+ name: s
659
+ };
660
+ }
661
+ if (typeof e.value == "string") {
662
+ const s = e.value;
663
+ return this.advance(), {
664
+ type: "identifier",
665
+ name: s
666
+ };
667
+ }
668
+ throw new R(
669
+ `Unexpected token in expression: ${e.type}`,
670
+ e.line,
671
+ e.column
672
+ );
673
+ }
674
+ getPrecedence(e) {
675
+ switch (e) {
676
+ case t.OR:
677
+ return 1;
678
+ case t.AND:
679
+ return 2;
680
+ case t.EQUALS:
681
+ case t.NOT_EQUALS:
682
+ return 3;
683
+ case t.LESS:
684
+ case t.LESS_EQUAL:
685
+ case t.GREATER:
686
+ case t.GREATER_EQUAL:
687
+ return 4;
688
+ case t.PLUS:
689
+ case t.MINUS:
690
+ return 5;
691
+ case t.STAR:
692
+ case t.DIVIDE:
693
+ case t.PERCENT:
694
+ return 6;
695
+ default:
696
+ return 0;
697
+ }
698
+ }
699
+ tokenTypeToOperator(e) {
700
+ switch (e) {
701
+ case t.PLUS:
702
+ return "+";
703
+ case t.MINUS:
704
+ return "-";
705
+ case t.STAR:
706
+ return "*";
707
+ case t.DIVIDE:
708
+ return "/";
709
+ case t.PERCENT:
710
+ return "%";
711
+ case t.EQUALS:
712
+ return "=";
713
+ case t.NOT_EQUALS:
714
+ return "<>";
715
+ case t.LESS:
716
+ return "<";
717
+ case t.LESS_EQUAL:
718
+ return "<=";
719
+ case t.GREATER:
720
+ return ">";
721
+ case t.GREATER_EQUAL:
722
+ return ">=";
723
+ case t.AND:
724
+ return "and";
725
+ case t.OR:
726
+ return "or";
727
+ default:
728
+ return null;
729
+ }
730
+ }
731
+ // Parse vector or expression
732
+ // Handles both: "x y z" (space-separated) and "(x, y, z)" (tuple)
733
+ parseVectorOrExpression() {
734
+ const e = this.parseExpression(), s = this.current(), r = s.type === t.IDENTIFIER && this.peek().type === t.LBRACE;
735
+ if ((s.type === t.NUMBER || s.type === t.IDENTIFIER || s.type === t.MINUS || s.type === t.LPAREN) && !r && s.type !== t.COMMA) {
736
+ const a = [e];
737
+ for (; ; ) {
738
+ const o = this.current(), c = o.type === t.IDENTIFIER && this.peek().type === t.LBRACE;
739
+ if ((o.type === t.NUMBER || o.type === t.IDENTIFIER || o.type === t.MINUS || o.type === t.LPAREN) && !c)
740
+ a.push(this.parseExpression());
741
+ else
742
+ break;
743
+ }
744
+ if (a.length > 1)
745
+ return { type: "tuple", elements: a };
746
+ }
747
+ return e.type === "tuple", e;
748
+ }
749
+ parseProperties() {
750
+ const e = {};
751
+ for (; this.current().type !== t.RBRACE && this.current().type !== t.EOF; ) {
752
+ switch (this.skipNewlines(), this.current().type) {
753
+ case t.POSITION:
754
+ this.advance(), e.position = this.parseVectorOrExpression();
755
+ break;
756
+ case t.ROTATION:
757
+ this.advance(), e.rotation = this.parseVectorOrExpression();
758
+ break;
759
+ case t.ORIENTATION:
760
+ this.advance(), e.orientation = this.parseVectorOrExpression();
761
+ break;
762
+ case t.SIZE:
763
+ this.advance(), e.size = this.parseVectorOrExpression();
764
+ break;
765
+ case t.COLOR:
766
+ this.advance(), e.color = this.parseVectorOrExpression();
767
+ break;
768
+ case t.OPACITY:
769
+ this.advance(), e.opacity = this.parseExpression();
770
+ break;
771
+ case t.RBRACE:
772
+ return e;
773
+ default:
774
+ return e;
775
+ }
776
+ this.skipNewlines();
777
+ }
778
+ return e;
779
+ }
780
+ parseBlockContents() {
781
+ this.skipNewlines();
782
+ const e = [];
783
+ for (; this.current().type !== t.RBRACE && this.current().type !== t.EOF; ) {
784
+ const s = this.parseNode();
785
+ s && e.push(s), this.skipNewlines();
786
+ }
787
+ return e;
788
+ }
789
+ parseBlock() {
790
+ this.expect(t.LBRACE);
791
+ const e = this.parseBlockContents();
792
+ return this.expect(t.RBRACE), e;
793
+ }
794
+ parseShape(e) {
795
+ this.advance();
796
+ let s = {};
797
+ return this.current().type === t.LBRACE && (this.expect(t.LBRACE), s = this.parseProperties(), this.expect(t.RBRACE)), {
798
+ type: "shape",
799
+ primitive: e,
800
+ properties: s
801
+ };
802
+ }
803
+ parseCSG(e) {
804
+ this.advance();
805
+ const s = this.parseBlock();
806
+ return {
807
+ type: "csg",
808
+ operation: e,
809
+ children: s
810
+ };
811
+ }
812
+ parseForLoop() {
813
+ this.advance();
814
+ let e = "i";
815
+ if (this.current().type === t.IDENTIFIER && (e = this.current().value, this.advance()), this.current().type === t.IN) {
816
+ this.advance();
817
+ const a = this.parseExpression();
818
+ if (this.current().type === t.TO) {
819
+ this.advance();
820
+ const o = this.parseExpression();
821
+ let c;
822
+ this.current().type === t.STEP && (this.advance(), c = this.parseExpression());
823
+ const u = this.parseBlock();
824
+ return {
825
+ type: "for",
826
+ variable: e,
827
+ from: a,
828
+ to: o,
829
+ step: c,
830
+ body: u
831
+ };
832
+ } else {
833
+ const o = this.parseBlock();
834
+ return {
835
+ type: "for",
836
+ variable: e,
837
+ from: { type: "number", value: 0 },
838
+ to: { type: "number", value: 0 },
839
+ iterableValues: a,
840
+ body: o
841
+ };
842
+ }
843
+ }
844
+ let s = { type: "number", value: 1 };
845
+ this.current().type === t.NUMBER && (s = this.parseExpression()), this.expect(t.TO);
846
+ const r = this.parseExpression(), i = this.parseBlock();
847
+ return {
848
+ type: "for",
849
+ variable: e,
850
+ from: s,
851
+ to: r,
852
+ body: i
853
+ };
854
+ }
855
+ parseIf() {
856
+ this.advance();
857
+ const e = this.parseExpression(), s = this.parseBlock();
858
+ let r;
859
+ return this.skipNewlines(), this.current().type === t.ELSE && (this.advance(), this.skipNewlines(), this.current().type === t.IF ? r = [this.parseIf()] : r = this.parseBlock()), {
860
+ type: "if",
861
+ condition: e,
862
+ thenBody: s,
863
+ elseBody: r
864
+ };
865
+ }
866
+ parseSwitch() {
867
+ this.advance();
868
+ const e = this.parseExpression();
869
+ this.expect(t.LBRACE), this.skipNewlines();
870
+ const s = [];
871
+ let r;
872
+ for (; this.current().type !== t.RBRACE && this.current().type !== t.EOF; ) {
873
+ if (this.current().type === t.CASE) {
874
+ this.advance();
875
+ const i = [];
876
+ for (i.push(this.parseExpression()); this.current().type !== t.NEWLINE && this.current().type !== t.LBRACE && this.current().type !== t.EOF; )
877
+ i.push(this.parseExpression());
878
+ this.skipNewlines();
879
+ let a;
880
+ if (this.current().type === t.LBRACE)
881
+ a = this.parseBlock();
882
+ else
883
+ for (a = []; this.current().type !== t.CASE && this.current().type !== t.ELSE && this.current().type !== t.RBRACE && this.current().type !== t.EOF; ) {
884
+ const o = this.parseNode();
885
+ o && a.push(o), this.skipNewlines();
886
+ }
887
+ s.push({ values: i, body: a });
888
+ } else if (this.current().type === t.ELSE)
889
+ if (this.advance(), this.skipNewlines(), this.current().type === t.LBRACE)
890
+ r = this.parseBlock();
891
+ else
892
+ for (r = []; this.current().type !== t.CASE && this.current().type !== t.RBRACE && this.current().type !== t.EOF; ) {
893
+ const i = this.parseNode();
894
+ i && r.push(i), this.skipNewlines();
895
+ }
896
+ else
897
+ this.skipNewlines(), this.current().type !== t.CASE && this.current().type !== t.ELSE && this.current().type !== t.RBRACE && this.advance();
898
+ this.skipNewlines();
899
+ }
900
+ return this.expect(t.RBRACE), {
901
+ type: "switch",
902
+ value: e,
903
+ cases: s,
904
+ defaultCase: r
905
+ };
906
+ }
907
+ parseDefine() {
908
+ this.advance();
909
+ const s = this.expectIdentifier().value;
910
+ if (this.current().type === t.LBRACE) {
911
+ this.advance();
912
+ const i = [], a = [];
913
+ for (; this.current().type !== t.RBRACE && this.current().type !== t.EOF; )
914
+ if (this.current().type === t.OPTION) {
915
+ this.advance();
916
+ const o = this.expectIdentifier().value, c = this.parseVectorOrExpression();
917
+ i.push({
918
+ type: "option",
919
+ name: o,
920
+ defaultValue: c
921
+ });
922
+ } else {
923
+ const o = this.parseNode();
924
+ o && a.push(o);
925
+ }
926
+ return this.expect(t.RBRACE), {
927
+ type: "define",
928
+ name: s,
929
+ options: i,
930
+ body: a
931
+ };
932
+ }
933
+ const r = this.parseVectorOrExpression();
934
+ return {
935
+ type: "define",
936
+ name: s,
937
+ value: r
938
+ };
939
+ }
940
+ parseDetail() {
941
+ return this.advance(), {
942
+ type: "detail",
943
+ value: this.parseExpression()
944
+ };
945
+ }
946
+ parseBackground() {
947
+ return this.advance(), {
948
+ type: "background",
949
+ value: this.parseExpression()
950
+ };
951
+ }
952
+ parseTexture() {
953
+ return this.advance(), {
954
+ type: "texture",
955
+ value: this.parseExpression()
956
+ };
957
+ }
958
+ parseGroup() {
959
+ this.advance(), this.expect(t.LBRACE);
960
+ const e = this.parseBlockContents();
961
+ return this.expect(t.RBRACE), {
962
+ type: "group",
963
+ children: e
964
+ };
965
+ }
966
+ parseBuilder(e) {
967
+ this.advance();
968
+ let s = !1;
969
+ this.current().type === t.PATH && (s = !0, this.advance()), this.expect(t.LBRACE), this.skipNewlines();
970
+ const r = {};
971
+ let i;
972
+ const a = [];
973
+ if (s) {
974
+ const o = [];
975
+ for (; this.current().type !== t.RBRACE && this.current().type !== t.EOF; ) {
976
+ const c = this.current();
977
+ if (c.type === t.POINT) {
978
+ this.advance();
979
+ const u = this.parsePathValue();
980
+ let p = { type: "number", value: 0 };
981
+ (this.current().type === t.NUMBER || this.current().type === t.MINUS || this.current().type === t.IDENTIFIER || this.current().type === t.LPAREN) && (p = this.parsePathValue()), o.push({ type: "point", x: u, y: p });
982
+ } else if (c.type === t.CURVE) {
983
+ this.advance();
984
+ const u = this.parsePathValue(), p = this.parsePathValue();
985
+ let E, f;
986
+ (this.current().type === t.NUMBER || this.current().type === t.MINUS || this.current().type === t.IDENTIFIER || this.current().type === t.LPAREN) && (E = this.parsePathValue(), (this.current().type === t.NUMBER || this.current().type === t.MINUS || this.current().type === t.IDENTIFIER || this.current().type === t.LPAREN) && (f = this.parsePathValue())), o.push({ type: "curve", x: u, y: p, controlX: E, controlY: f });
987
+ } else
988
+ break;
989
+ this.skipNewlines();
990
+ }
991
+ i = {
992
+ type: "path",
993
+ commands: o
994
+ };
995
+ } else
996
+ for (; this.current().type !== t.RBRACE && this.current().type !== t.EOF; ) {
997
+ const o = this.current();
998
+ if (o.type === t.PATH && e === "extrude") {
999
+ i = this.parsePath(), this.skipNewlines();
1000
+ continue;
1001
+ }
1002
+ if (o.type === t.SIZE || o.type === t.COLOR || o.type === t.OPACITY || o.type === t.POSITION || o.type === t.ROTATION || o.type === t.ORIENTATION) {
1003
+ const u = this.parseProperties();
1004
+ Object.assign(r, u), this.skipNewlines();
1005
+ continue;
1006
+ }
1007
+ const c = this.parseNode();
1008
+ c && a.push(c), this.skipNewlines();
1009
+ }
1010
+ return this.expect(t.RBRACE), e === "extrude" ? {
1011
+ type: "extrude",
1012
+ path: i,
1013
+ properties: r,
1014
+ children: a.length > 0 ? a : void 0
1015
+ } : (i && a.unshift(i), {
1016
+ type: e,
1017
+ properties: r,
1018
+ children: a
1019
+ });
1020
+ }
1021
+ parsePathValue() {
1022
+ let e = this.parsePathPrimary();
1023
+ for (; ; ) {
1024
+ const s = this.current();
1025
+ if (s.type === t.STAR || s.type === t.DIVIDE || s.type === t.PERCENT || s.type === t.PLUS || s.type === t.MINUS && !this.isStartOfNewValue()) {
1026
+ const r = this.tokenTypeToOperator(s.type);
1027
+ if (!r) break;
1028
+ this.advance();
1029
+ const i = this.parsePathPrimary();
1030
+ e = {
1031
+ type: "binary",
1032
+ operator: r,
1033
+ left: e,
1034
+ right: i
1035
+ };
1036
+ } else
1037
+ break;
1038
+ }
1039
+ return e;
1040
+ }
1041
+ isStartOfNewValue() {
1042
+ const e = this.current();
1043
+ return e.type !== t.MINUS ? !1 : !!e.precedingWhitespace && (this.peek().type === t.NUMBER || this.peek().type === t.IDENTIFIER || this.peek().type === t.LPAREN);
1044
+ }
1045
+ parsePathPrimary() {
1046
+ const e = this.current();
1047
+ if (e.type === t.LPAREN) {
1048
+ this.advance();
1049
+ const s = this.parseExpression();
1050
+ return this.expect(t.RPAREN), s;
1051
+ }
1052
+ if (e.type === t.MINUS)
1053
+ return this.advance(), {
1054
+ type: "unary",
1055
+ operator: "-",
1056
+ operand: this.parsePathPrimary()
1057
+ };
1058
+ if (e.type === t.NUMBER) {
1059
+ const s = e.value;
1060
+ return this.advance(), {
1061
+ type: "number",
1062
+ value: s
1063
+ };
1064
+ }
1065
+ if (e.type === t.IDENTIFIER) {
1066
+ const s = e.value;
1067
+ if (this.advance(), this.current().type === t.LPAREN && !this.current().precedingWhitespace) {
1068
+ this.advance();
1069
+ const r = [];
1070
+ if (this.current().type !== t.RPAREN)
1071
+ for (r.push(this.parseExpression()); this.current().type === t.COMMA; )
1072
+ this.advance(), r.push(this.parseExpression());
1073
+ return this.expect(t.RPAREN), {
1074
+ type: "call",
1075
+ name: s,
1076
+ args: r
1077
+ };
1078
+ }
1079
+ return {
1080
+ type: "identifier",
1081
+ name: s
1082
+ };
1083
+ }
1084
+ throw new R(
1085
+ `Expected path value, got ${e.type}`,
1086
+ e.line,
1087
+ e.column
1088
+ );
1089
+ }
1090
+ parsePath() {
1091
+ this.advance(), this.expect(t.LBRACE), this.skipNewlines();
1092
+ const e = [];
1093
+ for (; this.current().type !== t.RBRACE && this.current().type !== t.EOF; ) {
1094
+ const s = this.current();
1095
+ switch (s.type) {
1096
+ case t.DEFINE: {
1097
+ this.parseDefine();
1098
+ break;
1099
+ }
1100
+ case t.DETAIL: {
1101
+ this.advance();
1102
+ const r = this.parseExpression();
1103
+ e.push({ type: "detail", value: r });
1104
+ break;
1105
+ }
1106
+ case t.POINT: {
1107
+ this.advance();
1108
+ const r = this.parsePathValue();
1109
+ let i = { type: "number", value: 0 };
1110
+ (this.current().type === t.NUMBER || this.current().type === t.MINUS || this.current().type === t.IDENTIFIER || this.current().type === t.LPAREN) && (i = this.parsePathValue()), e.push({ type: "point", x: r, y: i });
1111
+ break;
1112
+ }
1113
+ case t.CURVE: {
1114
+ this.advance();
1115
+ const r = this.parsePathValue(), i = this.parsePathValue();
1116
+ let a, o;
1117
+ (this.current().type === t.NUMBER || this.current().type === t.MINUS || this.current().type === t.IDENTIFIER || this.current().type === t.LPAREN) && (a = this.parsePathValue(), (this.current().type === t.NUMBER || this.current().type === t.MINUS || this.current().type === t.IDENTIFIER || this.current().type === t.LPAREN) && (o = this.parsePathValue())), e.push({ type: "curve", x: r, y: i, controlX: a, controlY: o });
1118
+ break;
1119
+ }
1120
+ case t.ROTATE: {
1121
+ this.advance();
1122
+ const r = this.parseExpression();
1123
+ e.push({ type: "rotate", angle: r });
1124
+ break;
1125
+ }
1126
+ case t.TRANSLATE: {
1127
+ this.advance();
1128
+ const r = this.parsePathValue(), i = this.parsePathValue();
1129
+ e.push({ type: "translate", x: r, y: i });
1130
+ break;
1131
+ }
1132
+ case t.FOR: {
1133
+ this.advance();
1134
+ let r = "_i";
1135
+ this.current().type === t.IDENTIFIER && this.peek(1).type === t.IN && (r = this.current().value, this.advance(), this.expect(t.IN));
1136
+ const i = this.parseExpression();
1137
+ this.expect(t.TO);
1138
+ const a = this.parseExpression(), o = this.current().type === t.STEP ? (this.advance(), this.parseExpression()) : { type: "number", value: 1 };
1139
+ this.expect(t.LBRACE), this.skipNewlines();
1140
+ const c = [];
1141
+ for (; this.current().type !== t.RBRACE && this.current().type !== t.EOF; ) {
1142
+ const u = this.current();
1143
+ switch (u.type) {
1144
+ case t.POINT: {
1145
+ this.advance();
1146
+ const p = this.parsePathValue();
1147
+ let E = { type: "number", value: 0 };
1148
+ (this.current().type === t.NUMBER || this.current().type === t.MINUS || this.current().type === t.IDENTIFIER || this.current().type === t.LPAREN) && (E = this.parsePathValue()), c.push({ type: "point", x: p, y: E });
1149
+ break;
1150
+ }
1151
+ case t.CURVE: {
1152
+ this.advance();
1153
+ const p = this.parsePathValue(), E = this.parsePathValue();
1154
+ let f, y;
1155
+ (this.current().type === t.NUMBER || this.current().type === t.MINUS || this.current().type === t.IDENTIFIER || this.current().type === t.LPAREN) && (f = this.parsePathValue(), (this.current().type === t.NUMBER || this.current().type === t.MINUS || this.current().type === t.IDENTIFIER || this.current().type === t.LPAREN) && (y = this.parsePathValue())), c.push({ type: "curve", x: p, y: E, controlX: f, controlY: y });
1156
+ break;
1157
+ }
1158
+ case t.ROTATE: {
1159
+ this.advance();
1160
+ const p = this.parseExpression();
1161
+ c.push({ type: "rotate", angle: p });
1162
+ break;
1163
+ }
1164
+ case t.TRANSLATE: {
1165
+ this.advance();
1166
+ const p = this.parsePathValue(), E = this.parsePathValue();
1167
+ c.push({ type: "translate", x: p, y: E });
1168
+ break;
1169
+ }
1170
+ default:
1171
+ throw new R(
1172
+ `Unexpected token in path for loop: ${u.type}`,
1173
+ u.line,
1174
+ u.column
1175
+ );
1176
+ }
1177
+ this.skipNewlines();
1178
+ }
1179
+ this.expect(t.RBRACE), e.push({
1180
+ type: "for",
1181
+ variable: r,
1182
+ from: i,
1183
+ to: a,
1184
+ step: o,
1185
+ commands: c
1186
+ });
1187
+ break;
1188
+ }
1189
+ default:
1190
+ throw new R(
1191
+ `Unexpected token in path: ${s.type}`,
1192
+ s.line,
1193
+ s.column
1194
+ );
1195
+ }
1196
+ this.skipNewlines();
1197
+ }
1198
+ return this.expect(t.RBRACE), {
1199
+ type: "path",
1200
+ commands: e
1201
+ };
1202
+ }
1203
+ parseNode() {
1204
+ this.skipNewlines();
1205
+ const e = this.current(), s = {
1206
+ [t.CUBE]: "cube",
1207
+ [t.SPHERE]: "sphere",
1208
+ [t.CYLINDER]: "cylinder",
1209
+ [t.CONE]: "cone",
1210
+ [t.TORUS]: "torus",
1211
+ [t.CIRCLE]: "circle",
1212
+ [t.SQUARE]: "square",
1213
+ [t.POLYGON]: "polygon"
1214
+ }, r = {
1215
+ [t.UNION]: "union",
1216
+ [t.DIFFERENCE]: "difference",
1217
+ [t.INTERSECTION]: "intersection",
1218
+ [t.XOR]: "xor",
1219
+ [t.STENCIL]: "stencil"
1220
+ }, i = {
1221
+ [t.EXTRUDE]: "extrude",
1222
+ [t.LOFT]: "loft",
1223
+ [t.LATHE]: "lathe",
1224
+ [t.FILL]: "fill",
1225
+ [t.HULL]: "hull"
1226
+ }, a = {
1227
+ [t.COLOR]: "color",
1228
+ [t.ROTATE]: "rotate",
1229
+ [t.TRANSLATE]: "translate",
1230
+ [t.SCALE]: "scale",
1231
+ [t.POSITION]: "translate",
1232
+ // position is an alias for translate
1233
+ [t.ORIENTATION]: "orientation"
1234
+ // orientation sets absolute rotation (not relative like rotate)
1235
+ };
1236
+ if (e.type in s)
1237
+ return this.parseShape(s[e.type]);
1238
+ if (e.type in r)
1239
+ return this.parseCSG(r[e.type]);
1240
+ if (e.type in i)
1241
+ return this.parseBuilder(i[e.type]);
1242
+ if (e.type in a)
1243
+ return this.advance(), {
1244
+ type: a[e.type],
1245
+ value: this.parseVectorOrExpression()
1246
+ };
1247
+ switch (e.type) {
1248
+ case t.FOR:
1249
+ return this.parseForLoop();
1250
+ case t.IF:
1251
+ return this.parseIf();
1252
+ case t.SWITCH:
1253
+ return this.parseSwitch();
1254
+ case t.DEFINE:
1255
+ return this.parseDefine();
1256
+ case t.GROUP:
1257
+ return this.parseGroup();
1258
+ case t.DETAIL:
1259
+ return this.parseDetail();
1260
+ case t.BACKGROUND:
1261
+ return this.parseBackground();
1262
+ case t.TEXTURE:
1263
+ return this.parseTexture();
1264
+ case t.PATH:
1265
+ return this.parsePath();
1266
+ case t.RBRACE:
1267
+ case t.EOF:
1268
+ return null;
1269
+ case t.IDENTIFIER: {
1270
+ const o = e.value;
1271
+ this.advance();
1272
+ const c = {};
1273
+ if (this.current().type === t.LBRACE) {
1274
+ for (this.expect(t.LBRACE), this.skipNewlines(); this.current().type !== t.RBRACE && this.current().type !== t.EOF; ) {
1275
+ if (this.current().type === t.POSITION || this.current().type === t.ROTATION || this.current().type === t.SIZE || this.current().type === t.COLOR || this.current().type === t.OPACITY) {
1276
+ const u = this.parseProperties();
1277
+ Object.assign(c, u);
1278
+ } else if (this.current().type === t.IDENTIFIER) {
1279
+ const u = this.current().value;
1280
+ this.advance();
1281
+ const p = this.parseVectorOrExpression();
1282
+ c[u] = p;
1283
+ } else
1284
+ break;
1285
+ this.skipNewlines();
1286
+ }
1287
+ this.expect(t.RBRACE);
1288
+ }
1289
+ return {
1290
+ type: "customShape",
1291
+ name: o,
1292
+ properties: c
1293
+ };
1294
+ }
1295
+ default:
1296
+ throw new R(
1297
+ `Unexpected token: ${e.type}`,
1298
+ e.line,
1299
+ e.column
1300
+ );
1301
+ }
1302
+ }
1303
+ parse() {
1304
+ const e = [];
1305
+ for (; this.current().type !== t.EOF; ) {
1306
+ const s = this.parseNode();
1307
+ s && e.push(s), this.skipNewlines();
1308
+ }
1309
+ return e;
1310
+ }
1311
+ }
1312
+ function X(n) {
1313
+ try {
1314
+ const r = new D(n).tokenize().filter((a) => a.type !== t.NEWLINE);
1315
+ return new F(r).parse();
1316
+ } catch (e) {
1317
+ throw e instanceof R ? e : new R(
1318
+ e instanceof Error ? e.message : "Unknown parse error"
1319
+ );
1320
+ }
1321
+ }
1322
+ class L {
1323
+ constructor() {
1324
+ d(this, "scopes", []);
1325
+ this.pushScope();
1326
+ }
1327
+ pushScope() {
1328
+ this.scopes.push(/* @__PURE__ */ new Map());
1329
+ }
1330
+ popScope() {
1331
+ this.scopes.length > 1 && this.scopes.pop();
1332
+ }
1333
+ set(e, s) {
1334
+ this.scopes[this.scopes.length - 1].set(e, s);
1335
+ }
1336
+ get(e) {
1337
+ for (let s = this.scopes.length - 1; s >= 0; s--)
1338
+ if (this.scopes[s].has(e))
1339
+ return this.scopes[s].get(e);
1340
+ }
1341
+ has(e) {
1342
+ return this.get(e) !== void 0;
1343
+ }
1344
+ }
1345
+ const T = {
1346
+ // Arithmetic
1347
+ round: (n) => Math.round(h(n)),
1348
+ floor: (n) => Math.floor(h(n)),
1349
+ ceil: (n) => Math.ceil(h(n)),
1350
+ abs: (n) => Math.abs(h(n)),
1351
+ sign: (n) => Math.sign(h(n)),
1352
+ sqrt: (n) => Math.sqrt(h(n)),
1353
+ pow: (n, e) => Math.pow(h(n), h(e)),
1354
+ min: (...n) => Math.min(...n.map(h)),
1355
+ max: (...n) => Math.max(...n.map(h)),
1356
+ // Trigonometric (uses radians)
1357
+ sin: (n) => Math.sin(h(n)),
1358
+ cos: (n) => Math.cos(h(n)),
1359
+ tan: (n) => Math.tan(h(n)),
1360
+ asin: (n) => Math.asin(h(n)),
1361
+ acos: (n) => Math.acos(h(n)),
1362
+ atan: (n) => Math.atan(h(n)),
1363
+ atan2: (n, e) => Math.atan2(h(n), h(e)),
1364
+ // Vector operations
1365
+ dot: (n, e) => {
1366
+ const s = I(n), r = I(e);
1367
+ let i = 0;
1368
+ for (let a = 0; a < Math.min(s.length, r.length); a++)
1369
+ i += h(s[a]) * h(r[a]);
1370
+ return i;
1371
+ },
1372
+ cross: (n, e) => {
1373
+ const s = I(n), r = I(e);
1374
+ if (s.length < 3 || r.length < 3)
1375
+ throw new Error("cross product requires 3D vectors");
1376
+ const i = h(s[0]), a = h(s[1]), o = h(s[2]), c = h(r[0]), u = h(r[1]), p = h(r[2]);
1377
+ return [a * p - o * u, o * c - i * p, i * u - a * c];
1378
+ },
1379
+ length: (n) => {
1380
+ const e = I(n);
1381
+ let s = 0;
1382
+ for (const r of e) {
1383
+ const i = h(r);
1384
+ s += i * i;
1385
+ }
1386
+ return Math.sqrt(s);
1387
+ },
1388
+ normalize: (n) => {
1389
+ const e = I(n), s = T.length(n);
1390
+ return s === 0 ? e : e.map((r) => h(r) / s);
1391
+ },
1392
+ sum: (n) => I(n).reduce((s, r) => s + h(r), 0),
1393
+ // String functions
1394
+ join: (...n) => {
1395
+ const e = n.length > 0 && typeof n[n.length - 1] == "string" ? n.pop() : "";
1396
+ return n.map(String).join(e);
1397
+ },
1398
+ trim: (n) => String(n).trim(),
1399
+ // Random (for procedural generation)
1400
+ rand: () => Math.random()
1401
+ };
1402
+ function h(n) {
1403
+ if (typeof n == "number") return n;
1404
+ if (typeof n == "boolean") return n ? 1 : 0;
1405
+ if (typeof n == "string") {
1406
+ const e = parseFloat(n);
1407
+ if (isNaN(e)) throw new Error(`Cannot convert "${n}" to number`);
1408
+ return e;
1409
+ }
1410
+ if (Array.isArray(n) && n.length > 0)
1411
+ return h(n[0]);
1412
+ throw new Error(`Cannot convert ${typeof n} to number`);
1413
+ }
1414
+ function I(n) {
1415
+ return Array.isArray(n) ? n : [n];
1416
+ }
1417
+ function b(n) {
1418
+ return typeof n == "boolean" ? n : typeof n == "number" ? n !== 0 : typeof n == "string" || Array.isArray(n) ? n.length > 0 : !1;
1419
+ }
1420
+ class V {
1421
+ constructor(e) {
1422
+ d(this, "symbols");
1423
+ this.symbols = e || new L();
1424
+ }
1425
+ getSymbols() {
1426
+ return this.symbols;
1427
+ }
1428
+ evaluate(e) {
1429
+ if (typeof e == "number" || typeof e == "string" || Array.isArray(e))
1430
+ return e;
1431
+ switch (e.type) {
1432
+ case "number":
1433
+ return e.value;
1434
+ case "identifier": {
1435
+ if (e.name === "rnd")
1436
+ return Math.random();
1437
+ const s = this.symbols.get(e.name);
1438
+ if (s === void 0)
1439
+ throw new Error(`Undefined variable: ${e.name}`);
1440
+ return s;
1441
+ }
1442
+ case "binary": {
1443
+ const s = this.evaluate(e.left), r = this.evaluate(e.right);
1444
+ switch (e.operator) {
1445
+ case "+":
1446
+ if (Array.isArray(s) && Array.isArray(r)) {
1447
+ const i = [...s];
1448
+ for (let a = 0; a < i.length && a < r.length; a++)
1449
+ i[a] = h(i[a]) + h(r[a]);
1450
+ return i;
1451
+ }
1452
+ return h(s) + h(r);
1453
+ case "-":
1454
+ if (Array.isArray(s) && Array.isArray(r)) {
1455
+ const i = [...s];
1456
+ for (let a = 0; a < i.length && a < r.length; a++)
1457
+ i[a] = h(i[a]) - h(r[a]);
1458
+ return i;
1459
+ }
1460
+ return h(s) - h(r);
1461
+ case "*":
1462
+ if (Array.isArray(s) && Array.isArray(r)) {
1463
+ const i = Math.min(s.length, r.length), a = [];
1464
+ for (let o = 0; o < i; o++)
1465
+ a.push(h(s[o]) * h(r[o]));
1466
+ return a;
1467
+ }
1468
+ return Array.isArray(s) ? s.map((i) => h(i) * h(r)) : Array.isArray(r) ? r.map((i) => h(s) * h(i)) : h(s) * h(r);
1469
+ case "/":
1470
+ if (Array.isArray(s) && Array.isArray(r)) {
1471
+ const i = Math.min(s.length, r.length), a = [];
1472
+ for (let o = 0; o < i; o++)
1473
+ a.push(h(s[o]) / h(r[o]));
1474
+ return a;
1475
+ }
1476
+ return Array.isArray(s) ? s.map((i) => h(i) / h(r)) : h(s) / h(r);
1477
+ case "%":
1478
+ return h(s) % h(r);
1479
+ case "=":
1480
+ if (Array.isArray(s) && Array.isArray(r)) {
1481
+ if (s.length !== r.length) return !1;
1482
+ for (let i = 0; i < s.length; i++)
1483
+ if (h(s[i]) !== h(r[i])) return !1;
1484
+ return !0;
1485
+ }
1486
+ return s === r;
1487
+ case "<>":
1488
+ if (Array.isArray(s) && Array.isArray(r)) {
1489
+ if (s.length !== r.length) return !0;
1490
+ for (let i = 0; i < s.length; i++)
1491
+ if (h(s[i]) !== h(r[i])) return !0;
1492
+ return !1;
1493
+ }
1494
+ return s !== r;
1495
+ case "<":
1496
+ return h(s) < h(r);
1497
+ case "<=":
1498
+ return h(s) <= h(r);
1499
+ case ">":
1500
+ return h(s) > h(r);
1501
+ case ">=":
1502
+ return h(s) >= h(r);
1503
+ case "and":
1504
+ return b(s) && b(r);
1505
+ case "or":
1506
+ return b(s) || b(r);
1507
+ default:
1508
+ throw new Error(`Unknown binary operator: ${e.operator}`);
1509
+ }
1510
+ }
1511
+ case "unary": {
1512
+ const s = this.evaluate(e.operand);
1513
+ switch (e.operator) {
1514
+ case "-":
1515
+ return Array.isArray(s) ? s.map((r) => -h(r)) : -h(s);
1516
+ case "not":
1517
+ return !b(s);
1518
+ default:
1519
+ throw new Error(`Unknown unary operator: ${e.operator}`);
1520
+ }
1521
+ }
1522
+ case "call": {
1523
+ const s = T[e.name.toLowerCase()];
1524
+ if (!s)
1525
+ throw new Error(`Unknown function: ${e.name}`);
1526
+ const r = e.args.map((i) => this.evaluate(i));
1527
+ return s(...r);
1528
+ }
1529
+ case "tuple":
1530
+ return e.elements.map((s) => this.evaluate(s));
1531
+ case "member":
1532
+ case "subscript":
1533
+ throw new Error(
1534
+ `Member access and subscripting not yet implemented: ${e.type}`
1535
+ );
1536
+ default:
1537
+ throw new Error(
1538
+ `Unknown expression type: ${e.type}`
1539
+ );
1540
+ }
1541
+ }
1542
+ evaluateToNumber(e) {
1543
+ const s = this.evaluate(e);
1544
+ return h(s);
1545
+ }
1546
+ evaluateToBoolean(e) {
1547
+ const s = this.evaluate(e);
1548
+ return b(s);
1549
+ }
1550
+ evaluateToVector3(e) {
1551
+ if (Array.isArray(e) && typeof e[0] == "number")
1552
+ return e;
1553
+ const s = this.evaluate(e);
1554
+ if (Array.isArray(s)) {
1555
+ const i = s.length > 0 ? h(s[0]) : 0, a = s.length > 1 ? h(s[1]) : 0, o = s.length > 2 ? h(s[2]) : 0;
1556
+ return [i, a, o];
1557
+ }
1558
+ const r = h(s);
1559
+ return [r, r, r];
1560
+ }
1561
+ evaluateToColor(e) {
1562
+ if (Array.isArray(e) && typeof e[0] == "number")
1563
+ return e;
1564
+ const s = this.evaluate(e);
1565
+ if (Array.isArray(s)) {
1566
+ const i = s.length > 0 ? h(s[0]) : 0, a = s.length > 1 ? h(s[1]) : 0, o = s.length > 2 ? h(s[2]) : 0;
1567
+ return [i, a, o];
1568
+ }
1569
+ const r = h(s);
1570
+ return [r, r, r];
1571
+ }
1572
+ }
1573
+ class G {
1574
+ constructor(e = {}) {
1575
+ d(this, "options");
1576
+ d(this, "evaluator");
1577
+ d(this, "symbols");
1578
+ d(this, "detailLevel", 32);
1579
+ // Default detail level for curved shapes
1580
+ // Transform state stack for relative transforms
1581
+ d(this, "transformStack", []);
1582
+ this.options = e, this.symbols = new L(), this.evaluator = new V(this.symbols), this.pushTransform();
1583
+ }
1584
+ convert(e) {
1585
+ const s = new l.Group();
1586
+ for (const r of e) {
1587
+ const i = this.convertNode(r);
1588
+ i && s.add(i);
1589
+ }
1590
+ return s;
1591
+ }
1592
+ convertNode(e) {
1593
+ switch (e.type) {
1594
+ case "shape":
1595
+ return this.convertShape(e);
1596
+ case "csg":
1597
+ return this.convertCSG(e);
1598
+ case "block":
1599
+ return this.convertBlock(e);
1600
+ case "for":
1601
+ return this.convertForLoop(e);
1602
+ case "if":
1603
+ return this.convertIf(e);
1604
+ case "switch":
1605
+ return this.convertSwitch(e);
1606
+ case "define":
1607
+ return this.handleDefine(e), null;
1608
+ // Define doesn't create geometry
1609
+ case "extrude":
1610
+ return this.convertExtrude(e);
1611
+ case "loft":
1612
+ return this.convertLoft(e);
1613
+ case "lathe":
1614
+ return this.convertLathe(e);
1615
+ case "fill":
1616
+ return this.convertFill(e);
1617
+ case "hull":
1618
+ return this.convertHull(e);
1619
+ case "group":
1620
+ return this.convertBlock(e);
1621
+ case "detail":
1622
+ return this.handleDetail(e), null;
1623
+ // Detail doesn't create geometry
1624
+ case "color":
1625
+ return this.handleColorCommand(e), null;
1626
+ case "rotate":
1627
+ return this.handleRotateCommand(e), null;
1628
+ case "orientation":
1629
+ return this.handleOrientationCommand(e), null;
1630
+ case "translate":
1631
+ return this.handleTranslateCommand(e), null;
1632
+ case "scale":
1633
+ return this.handleScaleCommand(e), null;
1634
+ case "customShape":
1635
+ return this.convertCustomShape(e);
1636
+ default:
1637
+ return console.warn(`Unknown node type: ${e.type}`), null;
1638
+ }
1639
+ }
1640
+ convertBlock(e) {
1641
+ const s = new l.Group();
1642
+ this.symbols.pushScope(), this.pushTransform();
1643
+ for (const r of e.children) {
1644
+ const i = this.convertNode(r);
1645
+ i && s.add(i);
1646
+ }
1647
+ return this.popTransform(), this.symbols.popScope(), s;
1648
+ }
1649
+ convertShape(e) {
1650
+ const s = this.createGeometry(e), r = this.createMaterial(e), i = new l.Mesh(s, r);
1651
+ return this.applyExplicitTransforms(i, e.properties), this.applyCurrentTransform(i), i;
1652
+ }
1653
+ createGeometry(e) {
1654
+ let s = [1, 1, 1];
1655
+ switch (e.properties.size && (s = this.evaluateVector3(e.properties.size)), s[1] === 0 && s[2] === 0 && s[0] !== 0 && (s = [s[0], s[0], s[0]]), e.primitive) {
1656
+ case "cube":
1657
+ return new l.BoxGeometry(s[0], s[1], s[2]);
1658
+ case "sphere":
1659
+ return new l.SphereGeometry(
1660
+ s[0],
1661
+ this.detailLevel,
1662
+ this.detailLevel
1663
+ );
1664
+ case "cylinder": {
1665
+ const r = e.properties.radiusTop ? this.evaluateNumber(e.properties.radiusTop) : s[0], i = e.properties.radiusBottom ? this.evaluateNumber(e.properties.radiusBottom) : s[0], a = e.properties.height ? this.evaluateNumber(e.properties.height) : s[1];
1666
+ return new l.CylinderGeometry(
1667
+ r,
1668
+ i,
1669
+ a,
1670
+ this.detailLevel
1671
+ );
1672
+ }
1673
+ case "cone": {
1674
+ const r = s[0], i = e.properties.height ? this.evaluateNumber(e.properties.height) : s[1];
1675
+ return new l.ConeGeometry(r, i, this.detailLevel);
1676
+ }
1677
+ case "torus": {
1678
+ const r = e.properties.outerRadius ? this.evaluateNumber(e.properties.outerRadius) : s[0], i = e.properties.innerRadius ? this.evaluateNumber(e.properties.innerRadius) : 0.4;
1679
+ return new l.TorusGeometry(
1680
+ r,
1681
+ i,
1682
+ Math.max(3, Math.floor(this.detailLevel / 2)),
1683
+ this.detailLevel
1684
+ );
1685
+ }
1686
+ case "circle": {
1687
+ const r = s[0] || 1;
1688
+ return new l.CircleGeometry(r, this.detailLevel);
1689
+ }
1690
+ case "square": {
1691
+ const r = s[0] || 1;
1692
+ return new l.PlaneGeometry(r, r);
1693
+ }
1694
+ case "polygon": {
1695
+ const r = s[0] || 1, i = 6;
1696
+ return new l.CircleGeometry(r, i);
1697
+ }
1698
+ default:
1699
+ return console.warn(`Unknown primitive: ${e.primitive}`), new l.BoxGeometry(1, 1, 1);
1700
+ }
1701
+ }
1702
+ createMaterial(e) {
1703
+ const s = e.properties.color ? this.evaluateColor(e.properties.color) : [0.8, 0.8, 0.8], r = new l.Color(s[0], s[1], s[2]), i = e.properties.opacity ? this.evaluateNumber(e.properties.opacity) : 1, a = i < 1;
1704
+ return new l.MeshStandardMaterial({
1705
+ color: r,
1706
+ opacity: i,
1707
+ transparent: a,
1708
+ wireframe: this.options.wireframe ?? !1
1709
+ });
1710
+ }
1711
+ convertCSG(e) {
1712
+ if (e.children.length === 0)
1713
+ return new l.Group();
1714
+ const s = this.currentTransform().matrix.clone();
1715
+ try {
1716
+ const r = new M();
1717
+ this.symbols.pushScope(), this.pushTransform();
1718
+ const i = this.currentTransform();
1719
+ i.matrix.identity(), i.color = void 0;
1720
+ const a = [];
1721
+ for (const u of e.children) {
1722
+ const p = this.convertNode(u);
1723
+ if (p instanceof l.Mesh) {
1724
+ const E = p.clone();
1725
+ E.updateMatrixWorld(!0), a.push(E);
1726
+ } else p instanceof l.Group && p.traverse((E) => {
1727
+ if (E instanceof l.Mesh) {
1728
+ const f = E.clone();
1729
+ f.updateMatrixWorld(!0), a.push(f);
1730
+ }
1731
+ });
1732
+ }
1733
+ if (this.popTransform(), this.symbols.popScope(), a.length === 0)
1734
+ return new l.Group();
1735
+ const o = a.map((u) => {
1736
+ const p = new B(u.geometry, u.material);
1737
+ return p.position.copy(u.position), p.rotation.copy(u.rotation), p.scale.copy(u.scale), p.updateMatrixWorld(!0), p;
1738
+ });
1739
+ let c = o[0];
1740
+ for (let u = 1; u < o.length; u++) {
1741
+ const p = o[u];
1742
+ switch (e.operation) {
1743
+ case "union":
1744
+ c = r.evaluate(c, p, w);
1745
+ break;
1746
+ case "difference":
1747
+ c = r.evaluate(c, p, C);
1748
+ break;
1749
+ case "intersection":
1750
+ c = r.evaluate(c, p, g);
1751
+ break;
1752
+ case "xor": {
1753
+ const E = r.evaluate(
1754
+ c.clone(),
1755
+ p.clone(),
1756
+ C
1757
+ ), f = r.evaluate(
1758
+ p.clone(),
1759
+ c.clone(),
1760
+ C
1761
+ );
1762
+ c = r.evaluate(E, f, w);
1763
+ break;
1764
+ }
1765
+ case "stencil":
1766
+ c = r.evaluate(c, p, g);
1767
+ break;
1768
+ }
1769
+ }
1770
+ return c.material || (c.material = o[0].material), c.applyMatrix4(s), c.updateMatrixWorld(!0), c;
1771
+ } catch {
1772
+ const r = new l.Group();
1773
+ this.symbols.pushScope();
1774
+ for (const i of e.children) {
1775
+ const a = this.convertNode(i);
1776
+ a && r.add(a);
1777
+ }
1778
+ return this.symbols.popScope(), r.applyMatrix4(s), r.updateMatrixWorld(!0), r;
1779
+ }
1780
+ }
1781
+ convertForLoop(e) {
1782
+ const s = new l.Group();
1783
+ if (this.symbols.pushScope(), this.pushTransform(), e.iterableValues) {
1784
+ const r = this.evaluator.evaluate(e.iterableValues), i = Array.isArray(r) ? r : [r];
1785
+ for (let a = 0; a < i.length; a++) {
1786
+ this.symbols.set(e.variable, i[a]);
1787
+ for (const o of e.body) {
1788
+ const c = this.convertNode(o);
1789
+ c && s.add(c);
1790
+ }
1791
+ }
1792
+ } else {
1793
+ const r = this.evaluateNumber(e.from), i = this.evaluateNumber(e.to), a = e.step ? this.evaluateNumber(e.step) : 1, o = [];
1794
+ if (a > 0)
1795
+ for (let c = r; c <= i; c += a)
1796
+ o.push(c);
1797
+ else if (a < 0)
1798
+ for (let c = r; c >= i; c += a)
1799
+ o.push(c);
1800
+ for (let c = 0; c < o.length; c++) {
1801
+ const u = o[c];
1802
+ this.symbols.set(e.variable, u);
1803
+ for (const p of e.body) {
1804
+ const E = this.convertNode(p);
1805
+ E && s.add(E);
1806
+ }
1807
+ }
1808
+ }
1809
+ return this.popTransform(), this.symbols.popScope(), s;
1810
+ }
1811
+ convertIf(e) {
1812
+ const s = new l.Group(), r = this.evaluator.evaluateToBoolean(e.condition);
1813
+ if (this.symbols.pushScope(), this.pushTransform(), r)
1814
+ for (const i of e.thenBody) {
1815
+ const a = this.convertNode(i);
1816
+ a && s.add(a);
1817
+ }
1818
+ else if (e.elseBody)
1819
+ for (const i of e.elseBody) {
1820
+ const a = this.convertNode(i);
1821
+ a && s.add(a);
1822
+ }
1823
+ return this.popTransform(), this.symbols.popScope(), s;
1824
+ }
1825
+ convertSwitch(e) {
1826
+ const s = new l.Group(), r = this.evaluator.evaluate(e.value);
1827
+ this.symbols.pushScope(), this.pushTransform();
1828
+ let i = !1;
1829
+ for (const a of e.cases) {
1830
+ for (const o of a.values) {
1831
+ const c = this.evaluator.evaluate(o);
1832
+ if (this.valuesEqual(r, c)) {
1833
+ for (const u of a.body) {
1834
+ const p = this.convertNode(u);
1835
+ p && s.add(p);
1836
+ }
1837
+ i = !0;
1838
+ break;
1839
+ }
1840
+ }
1841
+ if (i) break;
1842
+ }
1843
+ if (!i && e.defaultCase)
1844
+ for (const a of e.defaultCase) {
1845
+ const o = this.convertNode(a);
1846
+ o && s.add(o);
1847
+ }
1848
+ return this.popTransform(), this.symbols.popScope(), s;
1849
+ }
1850
+ handleDefine(e) {
1851
+ if (e.value !== void 0) {
1852
+ const s = this.evaluator.evaluate(e.value);
1853
+ this.symbols.set(e.name, s);
1854
+ } else (e.body !== void 0 || e.options !== void 0) && this.symbols.set(e.name, e);
1855
+ }
1856
+ convertCustomShape(e) {
1857
+ const s = this.symbols.get(e.name);
1858
+ if (!s || typeof s != "object" || !("type" in s))
1859
+ return console.warn(`Custom shape '${e.name}' not found`), null;
1860
+ const r = s;
1861
+ if (!r.body)
1862
+ return console.warn(`Custom shape '${e.name}' has no body`), null;
1863
+ if (this.symbols.pushScope(), this.pushTransform(), r.options)
1864
+ for (const a of r.options) {
1865
+ const o = this.evaluator.evaluate(a.defaultValue);
1866
+ this.symbols.set(a.name, o);
1867
+ }
1868
+ for (const [a, o] of Object.entries(e.properties)) {
1869
+ const c = this.evaluator.evaluate(o);
1870
+ this.symbols.set(a, c);
1871
+ }
1872
+ const i = new l.Group();
1873
+ for (const a of r.body) {
1874
+ const o = this.convertNode(a);
1875
+ o && i.add(o);
1876
+ }
1877
+ return this.popTransform(), this.symbols.popScope(), i;
1878
+ }
1879
+ pushTransform() {
1880
+ var s;
1881
+ const e = this.currentTransform();
1882
+ this.transformStack.push({
1883
+ matrix: e.matrix.clone(),
1884
+ color: (s = e.color) == null ? void 0 : s.clone()
1885
+ });
1886
+ }
1887
+ popTransform() {
1888
+ this.transformStack.length > 1 && this.transformStack.pop();
1889
+ }
1890
+ currentTransform() {
1891
+ return this.transformStack.length === 0 ? {
1892
+ matrix: new l.Matrix4(),
1893
+ color: void 0
1894
+ } : this.transformStack[this.transformStack.length - 1];
1895
+ }
1896
+ applyCurrentTransform(e) {
1897
+ const s = this.currentTransform();
1898
+ e.applyMatrix4(s.matrix);
1899
+ }
1900
+ applyExplicitTransforms(e, s) {
1901
+ if (s.position) {
1902
+ const r = this.evaluateVector3(s.position);
1903
+ e.position.set(...r);
1904
+ }
1905
+ if (s.rotation) {
1906
+ const r = this.evaluateVector3(s.rotation);
1907
+ e.rotation.set(...r);
1908
+ }
1909
+ if (s.orientation) {
1910
+ const r = this.evaluateVector3(s.orientation);
1911
+ e.rotation.set(...r);
1912
+ }
1913
+ }
1914
+ handleDetail(e) {
1915
+ this.detailLevel = this.evaluateNumber(e.value), this.symbols.set("detail", this.detailLevel);
1916
+ }
1917
+ handleColorCommand(e) {
1918
+ const s = this.evaluateVector3OrColor(e.value);
1919
+ this.currentTransform().color = new l.Color(
1920
+ s[0],
1921
+ s[1],
1922
+ s[2]
1923
+ );
1924
+ }
1925
+ handleRotateCommand(e) {
1926
+ const s = this.evaluateVector3(e.value), r = this.currentTransform(), i = new l.Matrix4(), a = new l.Euler(
1927
+ s[0] * Math.PI * 2,
1928
+ s[1] * Math.PI * 2,
1929
+ s[2] * Math.PI * 2,
1930
+ "XYZ"
1931
+ );
1932
+ i.makeRotationFromEuler(a), r.matrix.multiply(i);
1933
+ }
1934
+ handleOrientationCommand(e) {
1935
+ const s = this.evaluateVector3(e.value), r = this.currentTransform(), i = new l.Vector3(), a = new l.Vector3();
1936
+ r.matrix.decompose(i, new l.Quaternion(), a);
1937
+ const o = new l.Euler(
1938
+ s[0] * Math.PI * 2,
1939
+ s[1] * Math.PI * 2,
1940
+ s[2] * Math.PI * 2,
1941
+ "XYZ"
1942
+ );
1943
+ r.matrix.compose(
1944
+ i,
1945
+ new l.Quaternion().setFromEuler(o),
1946
+ a
1947
+ );
1948
+ }
1949
+ handleTranslateCommand(e) {
1950
+ const s = this.currentTransform(), [r, i, a] = this.evaluateTranslateVector(e.value), o = new l.Matrix4().makeTranslation(r, i, a);
1951
+ s.matrix.multiply(o);
1952
+ }
1953
+ handleScaleCommand(e) {
1954
+ const s = this.evaluateVector3(e.value), r = this.currentTransform(), i = new l.Matrix4().makeScale(
1955
+ s[0],
1956
+ s[1],
1957
+ s[2]
1958
+ );
1959
+ r.matrix.multiply(i);
1960
+ }
1961
+ convertExtrude(e) {
1962
+ const s = e.path ? this.buildPath(e.path) : new l.Shape([new l.Vector2(0, 0)]), i = (e.properties.size ? this.evaluateVector3(e.properties.size) : [1, 1, 1])[2] || 1, a = new l.ExtrudeGeometry(s, {
1963
+ depth: i,
1964
+ bevelEnabled: !1,
1965
+ curveSegments: Math.max(1, Math.floor(this.detailLevel / 4))
1966
+ }), o = this.createMaterial(e), c = new l.Mesh(a, o);
1967
+ return this.applyExplicitTransforms(c, e.properties), this.applyCurrentTransform(c), c;
1968
+ }
1969
+ buildPath(e) {
1970
+ const s = new l.Shape();
1971
+ let r = 0, i = 0, a = 0;
1972
+ const o = (c) => {
1973
+ switch (c.type) {
1974
+ case "point": {
1975
+ const u = this.evaluateNumber(c.x), p = this.evaluateNumber(c.y), E = Math.cos(a), f = Math.sin(a), y = u * E - p * f, v = u * f + p * E;
1976
+ r += y, i += v, s.curves.length === 0 ? s.moveTo(r, i) : s.lineTo(r, i);
1977
+ break;
1978
+ }
1979
+ case "curve": {
1980
+ const u = this.evaluateNumber(c.x), p = this.evaluateNumber(c.y), E = Math.cos(a), f = Math.sin(a), y = u * E - p * f, v = u * f + p * E;
1981
+ if (r += y, i += v, c.controlX !== void 0 && c.controlY !== void 0) {
1982
+ const N = this.evaluateNumber(c.controlX), A = this.evaluateNumber(c.controlY), m = N * E - A * f, S = N * f + A * E;
1983
+ s.quadraticCurveTo(
1984
+ r + m,
1985
+ i + S,
1986
+ r,
1987
+ i
1988
+ );
1989
+ } else
1990
+ s.lineTo(r, i);
1991
+ break;
1992
+ }
1993
+ case "rotate": {
1994
+ const u = this.evaluateNumber(c.angle);
1995
+ a += u * Math.PI * 2;
1996
+ break;
1997
+ }
1998
+ case "translate": {
1999
+ const u = this.evaluateNumber(c.x), p = this.evaluateNumber(c.y);
2000
+ r += u, i += p;
2001
+ break;
2002
+ }
2003
+ case "for": {
2004
+ this.symbols.pushScope();
2005
+ const u = this.evaluateNumber(c.from), p = this.evaluateNumber(c.to), E = c.step ? this.evaluateNumber(c.step) : 1, f = [];
2006
+ if (E > 0)
2007
+ for (let y = u; y <= p; y += E)
2008
+ f.push(y);
2009
+ else if (E < 0)
2010
+ for (let y = u; y >= p; y += E)
2011
+ f.push(y);
2012
+ for (const y of f) {
2013
+ this.symbols.set(c.variable, y);
2014
+ for (const v of c.commands)
2015
+ o(v);
2016
+ }
2017
+ this.symbols.popScope();
2018
+ break;
2019
+ }
2020
+ }
2021
+ };
2022
+ for (const c of e.commands)
2023
+ o(c);
2024
+ return s;
2025
+ }
2026
+ convertLathe(e) {
2027
+ this.symbols.pushScope(), this.pushTransform();
2028
+ let s = null;
2029
+ for (const f of e.children)
2030
+ if (f.type === "path") {
2031
+ s = f;
2032
+ break;
2033
+ }
2034
+ if (!s)
2035
+ return console.warn("Lathe requires a path child"), this.popTransform(), this.symbols.popScope(), new l.Group();
2036
+ const r = [];
2037
+ let i = 0, a = 0, o = 0;
2038
+ const c = (f) => {
2039
+ switch (f.type) {
2040
+ case "point":
2041
+ case "curve": {
2042
+ const y = this.evaluateNumber(f.x), v = this.evaluateNumber(f.y), N = Math.cos(o), A = Math.sin(o), m = y * N - v * A, S = y * A + v * N;
2043
+ i += m, a += S, r.push(new l.Vector2(i, a));
2044
+ break;
2045
+ }
2046
+ case "rotate": {
2047
+ const y = this.evaluateNumber(f.angle);
2048
+ o += y * Math.PI * 2;
2049
+ break;
2050
+ }
2051
+ case "translate": {
2052
+ const y = this.evaluateNumber(f.x), v = this.evaluateNumber(f.y);
2053
+ i += y, a += v;
2054
+ break;
2055
+ }
2056
+ case "for": {
2057
+ this.symbols.pushScope();
2058
+ const y = this.evaluateNumber(f.from), v = this.evaluateNumber(f.to), N = f.step ? this.evaluateNumber(f.step) : 1, A = [];
2059
+ if (N > 0)
2060
+ for (let m = y; m <= v; m += N)
2061
+ A.push(m);
2062
+ else if (N < 0)
2063
+ for (let m = y; m >= v; m += N)
2064
+ A.push(m);
2065
+ for (const m of A) {
2066
+ this.symbols.set(f.variable, m);
2067
+ for (const S of f.commands)
2068
+ c(S);
2069
+ }
2070
+ this.symbols.popScope();
2071
+ break;
2072
+ }
2073
+ }
2074
+ };
2075
+ for (const f of s.commands)
2076
+ c(f);
2077
+ if (r.length < 2)
2078
+ return console.warn("Lathe path must have at least 2 points"), this.popTransform(), this.symbols.popScope(), new l.Group();
2079
+ const u = new l.LatheGeometry(
2080
+ r,
2081
+ this.detailLevel
2082
+ // Number of segments around the axis
2083
+ ), p = this.createMaterial(e), E = new l.Mesh(u, p);
2084
+ return this.applyExplicitTransforms(E, e.properties), this.applyCurrentTransform(E), this.popTransform(), this.symbols.popScope(), E;
2085
+ }
2086
+ convertGroupBuilder(e) {
2087
+ this.symbols.pushScope(), this.pushTransform();
2088
+ const s = new l.Group();
2089
+ for (const r of e.children) {
2090
+ const i = this.convertNode(r);
2091
+ i && s.add(i);
2092
+ }
2093
+ return this.applyExplicitTransforms(s, e.properties), this.applyCurrentTransform(s), this.popTransform(), this.symbols.popScope(), s;
2094
+ }
2095
+ convertLoft(e) {
2096
+ return this.convertGroupBuilder(e);
2097
+ }
2098
+ convertFill(e) {
2099
+ this.symbols.pushScope(), this.pushTransform();
2100
+ let s = null;
2101
+ for (const c of e.children)
2102
+ if (c.type === "path") {
2103
+ s = c;
2104
+ break;
2105
+ }
2106
+ if (!s)
2107
+ return console.warn("Fill requires a path child"), this.popTransform(), this.symbols.popScope(), new l.Group();
2108
+ const r = this.buildPath(s), i = new l.ShapeGeometry(r), a = this.createMaterial(e), o = new l.Mesh(i, a);
2109
+ return this.applyExplicitTransforms(o, e.properties), this.applyCurrentTransform(o), this.popTransform(), this.symbols.popScope(), o;
2110
+ }
2111
+ convertHull(e) {
2112
+ return this.convertGroupBuilder(e);
2113
+ }
2114
+ // Helper methods
2115
+ evaluateNumber(e) {
2116
+ return e === void 0 ? 0 : typeof e == "number" ? e : this.evaluator.evaluateToNumber(e);
2117
+ }
2118
+ evaluateVector3(e) {
2119
+ return e === void 0 ? [0, 0, 0] : Array.isArray(e) && typeof e[0] == "number" ? e : this.evaluator.evaluateToVector3(e);
2120
+ }
2121
+ evaluateTranslateVector(e) {
2122
+ const s = this.evaluator.evaluate(e);
2123
+ if (typeof s == "number")
2124
+ return [s, 0, 0];
2125
+ if (Array.isArray(s)) {
2126
+ const r = s.length > 0 && typeof s[0] == "number" ? s[0] : 0, i = s.length > 1 && typeof s[1] == "number" ? s[1] : 0, a = s.length > 2 && typeof s[2] == "number" ? s[2] : 0;
2127
+ return [r, i, a];
2128
+ }
2129
+ return [0, 0, 0];
2130
+ }
2131
+ evaluateColor(e) {
2132
+ return e === void 0 ? [0.8, 0.8, 0.8] : Array.isArray(e) && typeof e[0] == "number" ? e : this.evaluator.evaluateToColor(e);
2133
+ }
2134
+ evaluateVector3OrColor(e) {
2135
+ const s = this.evaluator.evaluate(e), r = (i) => typeof i == "number" ? i : typeof i == "boolean" ? i ? 1 : 0 : typeof i == "string" ? parseFloat(i) || 0 : Array.isArray(i) && i.length > 0 ? r(i[0]) : 0;
2136
+ if (typeof s == "number")
2137
+ return [s, s, s];
2138
+ if (Array.isArray(s)) {
2139
+ if (s.length === 1)
2140
+ return [r(s[0]), r(s[0]), r(s[0])];
2141
+ if (s.length === 2)
2142
+ return [r(s[0]), r(s[1]), 0];
2143
+ if (s.length >= 3)
2144
+ return [r(s[0]), r(s[1]), r(s[2])];
2145
+ }
2146
+ return [0.8, 0.8, 0.8];
2147
+ }
2148
+ valuesEqual(e, s) {
2149
+ if (typeof e != typeof s) return !1;
2150
+ if (Array.isArray(e) && Array.isArray(s)) {
2151
+ if (e.length !== s.length) return !1;
2152
+ for (let r = 0; r < e.length; r++)
2153
+ if (!this.valuesEqual(e[r], s[r])) return !1;
2154
+ return !0;
2155
+ }
2156
+ return e === s;
2157
+ }
2158
+ }
2159
+ function $(n, e = {}) {
2160
+ return new G(e).convert(n);
2161
+ }
2162
+ export {
2163
+ U as T,
2164
+ k as a,
2165
+ O as b,
2166
+ X as c,
2167
+ $ as d,
2168
+ H as e,
2169
+ Y as p,
2170
+ Q as s
2171
+ };