@holoscript/core 2.0.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/{chunk-KWYIVRIH.js → chunk-2XXE34KS.js} +2 -2
  2. package/dist/chunk-2XXE34KS.js.map +1 -0
  3. package/dist/{chunk-EU6CZMGJ.js → chunk-AFFVFO4D.js} +511 -118
  4. package/dist/chunk-AFFVFO4D.js.map +1 -0
  5. package/dist/chunk-DGUM43GV.js +10 -0
  6. package/dist/{chunk-4CV4JOE5.js.map → chunk-DGUM43GV.js.map} +1 -1
  7. package/dist/{chunk-VYIDLUCV.js → chunk-DOY73HDH.js} +4 -4
  8. package/dist/{chunk-VYIDLUCV.js.map → chunk-DOY73HDH.js.map} +1 -1
  9. package/dist/chunk-JEQ2X3Z6.cjs +12 -0
  10. package/dist/{chunk-CZLDE2OZ.cjs.map → chunk-JEQ2X3Z6.cjs.map} +1 -1
  11. package/dist/{chunk-3N67RLQP.cjs → chunk-L6VLNVKP.cjs} +511 -118
  12. package/dist/chunk-L6VLNVKP.cjs.map +1 -0
  13. package/dist/{chunk-VMZN4EVR.cjs → chunk-MFNO57XL.cjs} +2 -2
  14. package/dist/chunk-MFNO57XL.cjs.map +1 -0
  15. package/dist/{chunk-WFI4T3XB.cjs → chunk-R75MREOS.cjs} +6 -6
  16. package/dist/{chunk-WFI4T3XB.cjs.map → chunk-R75MREOS.cjs.map} +1 -1
  17. package/dist/{chunk-4OHVW4XR.cjs → chunk-T57ZL7KR.cjs} +299 -45
  18. package/dist/chunk-T57ZL7KR.cjs.map +1 -0
  19. package/dist/{chunk-MCP6D4LT.js → chunk-U72GEJZT.js} +299 -45
  20. package/dist/chunk-U72GEJZT.js.map +1 -0
  21. package/dist/debugger.cjs +6 -6
  22. package/dist/debugger.d.cts +1 -1
  23. package/dist/debugger.d.ts +1 -1
  24. package/dist/debugger.js +4 -4
  25. package/dist/index.cjs +1896 -1099
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +3145 -1534
  28. package/dist/index.d.ts +3145 -1534
  29. package/dist/index.js +1922 -1133
  30. package/dist/index.js.map +1 -1
  31. package/dist/parser.cjs +3 -3
  32. package/dist/parser.d.cts +34 -1
  33. package/dist/parser.d.ts +34 -1
  34. package/dist/parser.js +2 -2
  35. package/dist/runtime.cjs +3 -3
  36. package/dist/runtime.d.cts +47 -27
  37. package/dist/runtime.d.ts +47 -27
  38. package/dist/runtime.js +2 -2
  39. package/dist/type-checker.cjs +4 -4
  40. package/dist/type-checker.d.cts +3 -3
  41. package/dist/type-checker.d.ts +3 -3
  42. package/dist/type-checker.js +2 -2
  43. package/dist/{types-D6g4ACjP.d.cts → types-4h8cbtF_.d.cts} +80 -13
  44. package/dist/{types-D6g4ACjP.d.ts → types-4h8cbtF_.d.ts} +80 -13
  45. package/package.json +21 -20
  46. package/LICENSE +0 -21
  47. package/dist/chunk-3N67RLQP.cjs.map +0 -1
  48. package/dist/chunk-4CV4JOE5.js +0 -24
  49. package/dist/chunk-4OHVW4XR.cjs.map +0 -1
  50. package/dist/chunk-CZLDE2OZ.cjs +0 -28
  51. package/dist/chunk-EU6CZMGJ.js.map +0 -1
  52. package/dist/chunk-KWYIVRIH.js.map +0 -1
  53. package/dist/chunk-MCP6D4LT.js.map +0 -1
  54. package/dist/chunk-VMZN4EVR.cjs.map +0 -1
package/dist/index.js CHANGED
@@ -1,859 +1,12 @@
1
- export { HoloScriptTypeChecker, createTypeChecker } from './chunk-KWYIVRIH.js';
2
- export { HoloScriptDebugger, createDebugger } from './chunk-VYIDLUCV.js';
3
- import { HoloScriptCodeParser } from './chunk-MCP6D4LT.js';
4
- export { HoloScriptCodeParser } from './chunk-MCP6D4LT.js';
5
- import { HoloScriptRuntime } from './chunk-EU6CZMGJ.js';
6
- export { HoloScriptRuntime } from './chunk-EU6CZMGJ.js';
1
+ export { HoloScriptTypeChecker, createTypeChecker } from './chunk-2XXE34KS.js';
2
+ export { HoloScriptDebugger, createDebugger } from './chunk-DOY73HDH.js';
3
+ import { HoloScriptCodeParser } from './chunk-U72GEJZT.js';
4
+ export { HoloScriptCodeParser } from './chunk-U72GEJZT.js';
5
+ import { HoloScriptRuntime } from './chunk-AFFVFO4D.js';
6
+ export { HoloScriptRuntime } from './chunk-AFFVFO4D.js';
7
7
  import { logger } from './chunk-SATNCODL.js';
8
8
  export { ConsoleLogger, NoOpLogger, enableConsoleLogging, logger, resetLogger, setHoloScriptLogger } from './chunk-SATNCODL.js';
9
- import { __export, __esm, __toCommonJS } from './chunk-4CV4JOE5.js';
10
-
11
- // src/traits/MaterialTrait.ts
12
- var MaterialTrait_exports = {};
13
- __export(MaterialTrait_exports, {
14
- MATERIAL_PRESETS: () => MATERIAL_PRESETS,
15
- MaterialTrait: () => MaterialTrait,
16
- createMaterialTrait: () => createMaterialTrait
17
- });
18
- function createMaterialTrait(config) {
19
- return new MaterialTrait(config);
20
- }
21
- var MaterialTrait, MATERIAL_PRESETS;
22
- var init_MaterialTrait = __esm({
23
- "src/traits/MaterialTrait.ts"() {
24
- MaterialTrait = class {
25
- constructor(config) {
26
- this.textureCache = /* @__PURE__ */ new Map();
27
- this.material = {
28
- ...{ type: "pbr" },
29
- ...config
30
- };
31
- }
32
- /**
33
- * Get material properties
34
- */
35
- getMaterial() {
36
- return { ...this.material };
37
- }
38
- /**
39
- * Update material property
40
- */
41
- setProperty(key, value) {
42
- this.material[key] = value;
43
- }
44
- /**
45
- * Get PBR properties
46
- */
47
- getPBRProperties() {
48
- return this.material.pbr;
49
- }
50
- /**
51
- * Update PBR material
52
- */
53
- updatePBR(pbr) {
54
- if (!this.material.pbr) {
55
- this.material.pbr = {
56
- baseColor: { r: 1, g: 1, b: 1 },
57
- metallic: 0,
58
- roughness: 0.5
59
- };
60
- }
61
- this.material.pbr = { ...this.material.pbr, ...pbr };
62
- }
63
- /**
64
- * Add texture map
65
- */
66
- addTexture(texture) {
67
- if (!this.material.textures) {
68
- this.material.textures = [];
69
- }
70
- this.material.textures.push(texture);
71
- }
72
- /**
73
- * Get all textures
74
- */
75
- getTextures() {
76
- return [...this.material.textures || []];
77
- }
78
- /**
79
- * Clear texture cache (for memory optimization)
80
- */
81
- clearTextureCache() {
82
- this.textureCache.clear();
83
- }
84
- /**
85
- * Get shader code if custom
86
- */
87
- getCustomShader() {
88
- return this.material.customShader;
89
- }
90
- /**
91
- * Set custom shader
92
- */
93
- setCustomShader(shader) {
94
- this.material.customShader = shader;
95
- }
96
- /**
97
- * Get optimization hints
98
- */
99
- getOptimization() {
100
- return this.material.optimization;
101
- }
102
- /**
103
- * Enable/disable texture streaming
104
- */
105
- setTextureStreaming(enabled) {
106
- if (!this.material.optimization) {
107
- this.material.optimization = {};
108
- }
109
- this.material.optimization.streamTextures = enabled;
110
- }
111
- /**
112
- * Set texture compression
113
- */
114
- setCompression(compression) {
115
- if (!this.material.optimization) {
116
- this.material.optimization = {};
117
- }
118
- this.material.optimization.compression = compression;
119
- }
120
- /**
121
- * Enable material instancing for performance
122
- */
123
- setInstanced(instanced) {
124
- if (!this.material.optimization) {
125
- this.material.optimization = {};
126
- }
127
- this.material.optimization.instanced = instanced;
128
- }
129
- /**
130
- * Dispose and cleanup
131
- */
132
- dispose() {
133
- this.textureCache.clear();
134
- }
135
- };
136
- MATERIAL_PRESETS = {
137
- /** Shiny metal */
138
- chrome: () => ({
139
- type: "pbr",
140
- pbr: {
141
- baseColor: { r: 0.77, g: 0.77, b: 0.77 },
142
- metallic: 1,
143
- roughness: 0.1
144
- }
145
- }),
146
- /** Rough plastic */
147
- plastic: () => ({
148
- type: "pbr",
149
- pbr: {
150
- baseColor: { r: 1, g: 1, b: 1 },
151
- metallic: 0,
152
- roughness: 0.8
153
- }
154
- }),
155
- /** Wood texture */
156
- wood: () => ({
157
- type: "pbr",
158
- pbr: {
159
- baseColor: { r: 0.6, g: 0.4, b: 0.2 },
160
- metallic: 0,
161
- roughness: 0.4
162
- }
163
- }),
164
- /** Glass */
165
- glass: () => ({
166
- type: "transparent",
167
- blendMode: "blend",
168
- pbr: {
169
- baseColor: { r: 1, g: 1, b: 1, a: 0.3 },
170
- metallic: 0,
171
- roughness: 0,
172
- ior: 1.5,
173
- transmission: 0.9
174
- }
175
- }),
176
- /** Emissive (glowing) */
177
- emissive: () => ({
178
- type: "pbr",
179
- pbr: {
180
- baseColor: { r: 0, g: 1, b: 0 },
181
- metallic: 0,
182
- roughness: 1,
183
- emission: {
184
- color: { r: 0, g: 1, b: 0 },
185
- intensity: 2
186
- }
187
- }
188
- }),
189
- /** Skin material */
190
- skin: () => ({
191
- type: "pbr",
192
- pbr: {
193
- baseColor: { r: 1, g: 0.8, b: 0.7 },
194
- metallic: 0,
195
- roughness: 0.5,
196
- ambientOcclusion: 0.8
197
- }
198
- })
199
- };
200
- }
201
- });
202
-
203
- // src/traits/LightingTrait.ts
204
- var LightingTrait_exports = {};
205
- __export(LightingTrait_exports, {
206
- LIGHTING_PRESETS: () => LIGHTING_PRESETS,
207
- LightingTrait: () => LightingTrait,
208
- createLightingTrait: () => createLightingTrait
209
- });
210
- function createLightingTrait(config) {
211
- return new LightingTrait(config);
212
- }
213
- var LightingTrait, LIGHTING_PRESETS;
214
- var init_LightingTrait = __esm({
215
- "src/traits/LightingTrait.ts"() {
216
- LightingTrait = class {
217
- constructor(config) {
218
- this.lights = /* @__PURE__ */ new Map();
219
- this.lightIdCounter = 0;
220
- this.globalIllumination = {
221
- enabled: true,
222
- intensity: 1,
223
- skyColor: { r: 0.5, g: 0.7, b: 1 },
224
- skyIntensity: 1,
225
- groundColor: { r: 0.4, g: 0.4, b: 0.4 },
226
- groundIntensity: 0.5,
227
- probes: true,
228
- indirectDiffuse: 1,
229
- indirectSpecular: 1,
230
- aoIntensity: 1,
231
- screenSpaceAO: true,
232
- ...config
233
- };
234
- }
235
- /**
236
- * Add a light to the scene
237
- */
238
- addLight(light) {
239
- const id = light.name || `light_${this.lightIdCounter++}`;
240
- this.lights.set(id, light);
241
- return id;
242
- }
243
- /**
244
- * Get light by ID
245
- */
246
- getLight(id) {
247
- return this.lights.get(id);
248
- }
249
- /**
250
- * Get all lights
251
- */
252
- getLights() {
253
- return Array.from(this.lights.values());
254
- }
255
- /**
256
- * Get lights by type
257
- */
258
- getLightsByType(type) {
259
- return Array.from(this.lights.values()).filter((l) => l.type === type);
260
- }
261
- /**
262
- * Update light properties
263
- */
264
- updateLight(id, updates) {
265
- const light = this.lights.get(id);
266
- if (!light) return false;
267
- this.lights.set(id, { ...light, ...updates });
268
- return true;
269
- }
270
- /**
271
- * Remove light
272
- */
273
- removeLight(id) {
274
- return this.lights.delete(id);
275
- }
276
- /**
277
- * Clear all lights
278
- */
279
- clearLights() {
280
- this.lights.clear();
281
- }
282
- /**
283
- * Get global illumination config
284
- */
285
- getGlobalIllumination() {
286
- return { ...this.globalIllumination };
287
- }
288
- /**
289
- * Update global illumination
290
- */
291
- updateGlobalIllumination(updates) {
292
- this.globalIllumination = {
293
- ...this.globalIllumination,
294
- ...updates
295
- };
296
- }
297
- /**
298
- * Enable/disable GI
299
- */
300
- setGIEnabled(enabled) {
301
- this.globalIllumination.enabled = enabled;
302
- }
303
- /**
304
- * Set ambient light colors (skybox mode)
305
- */
306
- setAmbientLight(skyColor, groundColor, intensity = 1) {
307
- this.globalIllumination.skyColor = skyColor;
308
- this.globalIllumination.groundColor = groundColor;
309
- this.globalIllumination.skyIntensity = intensity;
310
- this.globalIllumination.groundIntensity = intensity * 0.5;
311
- }
312
- /**
313
- * Enable/disable screen-space ambient occlusion
314
- */
315
- setScreenSpaceAO(enabled, intensity = 1) {
316
- this.globalIllumination.screenSpaceAO = enabled;
317
- this.globalIllumination.aoIntensity = intensity;
318
- }
319
- /**
320
- * Create directional light (sun)
321
- */
322
- createDirectionalLight(direction, color, intensity = 1, castShadows = true) {
323
- const light = {
324
- type: "directional",
325
- name: `sun_${this.lightIdCounter}`,
326
- direction,
327
- color,
328
- intensity,
329
- shadow: castShadows ? {
330
- type: "soft",
331
- resolution: 2048,
332
- cascades: 4,
333
- softness: 1
334
- } : void 0,
335
- volumetric: true,
336
- priority: 100
337
- };
338
- return this.addLight(light);
339
- }
340
- /**
341
- * Create point light
342
- */
343
- createPointLight(position, color, intensity, range, castShadows = false) {
344
- const light = {
345
- type: "point",
346
- name: `point_${this.lightIdCounter}`,
347
- position,
348
- color,
349
- intensity,
350
- range,
351
- shadow: castShadows ? {
352
- type: "soft",
353
- resolution: 512,
354
- softness: 0.5
355
- } : void 0,
356
- priority: 50
357
- };
358
- return this.addLight(light);
359
- }
360
- /**
361
- * Create spot light
362
- */
363
- createSpotLight(position, direction, color, intensity, range, spotAngle = 45, castShadows = true) {
364
- const light = {
365
- type: "spot",
366
- name: `spot_${this.lightIdCounter}`,
367
- position,
368
- direction,
369
- color,
370
- intensity,
371
- range,
372
- spotAngle,
373
- innerSpotAngle: spotAngle * 0.5,
374
- shadow: castShadows ? {
375
- type: "soft",
376
- resolution: 1024,
377
- softness: 0.8
378
- } : void 0,
379
- priority: 75
380
- };
381
- return this.addLight(light);
382
- }
383
- /**
384
- * Create area light for soft lighting
385
- */
386
- createAreaLight(position, color, intensity, width, height) {
387
- const light = {
388
- type: "area",
389
- name: `area_${this.lightIdCounter}`,
390
- position,
391
- color,
392
- intensity,
393
- range: Math.max(width, height) * 2,
394
- priority: 25
395
- };
396
- return this.addLight(light);
397
- }
398
- /**
399
- * Get shadow-casting lights
400
- */
401
- getShadowCastingLights() {
402
- return Array.from(this.lights.values()).filter((l) => l.shadow && l.shadow.type !== "none");
403
- }
404
- /**
405
- * Get light count by type
406
- */
407
- getLightCount() {
408
- const counts = {
409
- directional: 0,
410
- point: 0,
411
- spot: 0,
412
- area: 0,
413
- probe: 0
414
- };
415
- for (const light of this.lights.values()) {
416
- counts[light.type]++;
417
- }
418
- return counts;
419
- }
420
- /**
421
- * Estimate light impact for performance optimization
422
- */
423
- getPerformanceImpact() {
424
- const totalLights = this.lights.size;
425
- const shadowCasters = this.getShadowCastingLights().length;
426
- let estimatedGPUCost = "low";
427
- if (totalLights > 16 || shadowCasters > 4) {
428
- estimatedGPUCost = "high";
429
- } else if (totalLights > 8 || shadowCasters > 2) {
430
- estimatedGPUCost = "medium";
431
- }
432
- return {
433
- totalLights,
434
- shadowCasters,
435
- estimatedGPUCost
436
- };
437
- }
438
- /**
439
- * Get scene complexity info
440
- */
441
- getSceneInfo() {
442
- const counts = this.getLightCount();
443
- const impact = this.getPerformanceImpact();
444
- return `Lighting: ${counts.directional} dir, ${counts.point} point, ${counts.spot} spot | Shadows: ${impact.shadowCasters} | GPU: ${impact.estimatedGPUCost}`;
445
- }
446
- /**
447
- * Dispose and cleanup
448
- */
449
- dispose() {
450
- this.lights.clear();
451
- }
452
- };
453
- LIGHTING_PRESETS = {
454
- /** Neutral studio lighting */
455
- studio: () => ({
456
- enabled: true,
457
- intensity: 1,
458
- skyColor: { r: 0.5, g: 0.5, b: 0.5 },
459
- skyIntensity: 0.5,
460
- groundColor: { r: 0.3, g: 0.3, b: 0.3 },
461
- groundIntensity: 0.3
462
- }),
463
- /** Bright outdoor lighting */
464
- outdoor: () => ({
465
- enabled: true,
466
- intensity: 1.2,
467
- skyColor: { r: 0.7, g: 0.85, b: 1 },
468
- skyIntensity: 1,
469
- groundColor: { r: 0.4, g: 0.4, b: 0.35 },
470
- groundIntensity: 0.6,
471
- indirectDiffuse: 1.2
472
- }),
473
- /** Dim interior lighting */
474
- interior: () => ({
475
- enabled: true,
476
- intensity: 0.6,
477
- skyColor: { r: 0.3, g: 0.3, b: 0.35 },
478
- skyIntensity: 0.4,
479
- groundColor: { r: 0.2, g: 0.2, b: 0.2 },
480
- groundIntensity: 0.2
481
- }),
482
- /** Night scene */
483
- night: () => ({
484
- enabled: true,
485
- intensity: 0.3,
486
- skyColor: { r: 0.01, g: 0.01, b: 0.02 },
487
- skyIntensity: 0.1,
488
- groundColor: { r: 0.02, g: 0.02, b: 0.02 },
489
- groundIntensity: 0.05,
490
- screenSpaceAO: false
491
- }),
492
- /** Sunset/golden hour */
493
- sunset: () => ({
494
- enabled: true,
495
- intensity: 1.1,
496
- skyColor: { r: 1, g: 0.7, b: 0.3 },
497
- skyIntensity: 1,
498
- groundColor: { r: 0.6, g: 0.4, b: 0.2 },
499
- groundIntensity: 0.8
500
- })
501
- };
502
- }
503
- });
504
-
505
- // src/traits/RenderingTrait.ts
506
- var RenderingTrait_exports = {};
507
- __export(RenderingTrait_exports, {
508
- RenderingTrait: () => RenderingTrait,
509
- createRenderingTrait: () => createRenderingTrait
510
- });
511
- function createRenderingTrait(config) {
512
- return new RenderingTrait(config);
513
- }
514
- var RenderingTrait;
515
- var init_RenderingTrait = __esm({
516
- "src/traits/RenderingTrait.ts"() {
517
- RenderingTrait = class {
518
- constructor(config) {
519
- this.optimization = {
520
- lodStrategy: "automatic",
521
- culling: {
522
- mode: "back",
523
- frustum: true,
524
- occlusion: true
525
- },
526
- batching: {
527
- static: true,
528
- dynamic: true,
529
- instancing: true,
530
- maxInstanceCount: 1e3
531
- },
532
- textures: {
533
- streaming: true,
534
- compression: "auto",
535
- mipmaps: true,
536
- maxResolution: 2048
537
- },
538
- shaders: {
539
- simplifiedShaders: true,
540
- lodBias: 0
541
- },
542
- targetGPUTier: "high",
543
- adaptiveQuality: true,
544
- targetFrameRate: 60,
545
- ...config
546
- };
547
- }
548
- /**
549
- * Get rendering optimization config
550
- */
551
- getOptimization() {
552
- return JSON.parse(JSON.stringify(this.optimization));
553
- }
554
- /**
555
- * Update rendering configuration
556
- */
557
- updateOptimization(updates) {
558
- this.optimization = { ...this.optimization, ...updates };
559
- }
560
- /**
561
- * Setup LOD levels (3 levels is typical)
562
- */
563
- setupLODLevels(strategy = "automatic") {
564
- const levels = [
565
- {
566
- level: 0,
567
- screenRelativeSize: 0.5,
568
- polygonReduction: 1,
569
- textureScale: 1
570
- },
571
- {
572
- level: 1,
573
- screenRelativeSize: 0.25,
574
- polygonReduction: 0.6,
575
- disabledFeatures: ["specular"],
576
- textureScale: 0.5
577
- },
578
- {
579
- level: 2,
580
- screenRelativeSize: 0.1,
581
- polygonReduction: 0.3,
582
- disabledFeatures: ["specular", "normals"],
583
- textureScale: 0.25
584
- }
585
- ];
586
- this.optimization.lodStrategy = strategy;
587
- this.optimization.lodLevels = levels;
588
- }
589
- /**
590
- * Get LOD levels
591
- */
592
- getLODLevels() {
593
- return [...this.optimization.lodLevels || []];
594
- }
595
- /**
596
- * Configure culling
597
- */
598
- setCulling(config) {
599
- const defaultCulling = { mode: "back" };
600
- this.optimization.culling = {
601
- ...defaultCulling,
602
- ...this.optimization.culling,
603
- ...config
604
- };
605
- }
606
- /**
607
- * Enable frustum culling
608
- */
609
- setFrustumCulling(enabled) {
610
- if (!this.optimization.culling) {
611
- this.optimization.culling = { mode: "back" };
612
- }
613
- this.optimization.culling.frustum = enabled;
614
- }
615
- /**
616
- * Enable occlusion culling
617
- */
618
- setOcclusionCulling(enabled, distance) {
619
- if (!this.optimization.culling) {
620
- this.optimization.culling = { mode: "back" };
621
- }
622
- this.optimization.culling.occlusion = enabled;
623
- if (distance) {
624
- this.optimization.culling.occlusionDistance = distance;
625
- }
626
- }
627
- /**
628
- * Configure batching
629
- */
630
- setBatching(config) {
631
- this.optimization.batching = {
632
- ...this.optimization.batching,
633
- ...config
634
- };
635
- }
636
- /**
637
- * Enable GPU instancing
638
- */
639
- setInstancing(enabled, maxInstances) {
640
- if (!this.optimization.batching) {
641
- this.optimization.batching = {};
642
- }
643
- this.optimization.batching.instancing = enabled;
644
- if (maxInstances) {
645
- this.optimization.batching.maxInstanceCount = maxInstances;
646
- }
647
- }
648
- /**
649
- * Configure texture optimization
650
- */
651
- setTextureOptimization(config) {
652
- this.optimization.textures = {
653
- ...this.optimization.textures,
654
- ...config
655
- };
656
- }
657
- /**
658
- * Enable texture streaming
659
- */
660
- setTextureStreaming(enabled, budgetMB) {
661
- if (!this.optimization.textures) {
662
- this.optimization.textures = {};
663
- }
664
- this.optimization.textures.streaming = enabled;
665
- if (budgetMB) {
666
- this.optimization.textures.streamingBudget = budgetMB;
667
- }
668
- }
669
- /**
670
- * Set texture compression
671
- */
672
- setTextureCompression(compression) {
673
- if (!this.optimization.textures) {
674
- this.optimization.textures = {};
675
- }
676
- this.optimization.textures.compression = compression;
677
- }
678
- /**
679
- * Set max texture resolution
680
- */
681
- setMaxTextureResolution(resolution) {
682
- if (!this.optimization.textures) {
683
- this.optimization.textures = {};
684
- }
685
- this.optimization.textures.maxResolution = resolution;
686
- }
687
- /**
688
- * Configure shader optimization
689
- */
690
- setShaderOptimization(config) {
691
- this.optimization.shaders = {
692
- ...this.optimization.shaders,
693
- ...config
694
- };
695
- }
696
- /**
697
- * Set target GPU tier
698
- */
699
- setTargetGPUTier(tier) {
700
- this.optimization.targetGPUTier = tier;
701
- }
702
- /**
703
- * Enable adaptive quality (adjust based on frame rate)
704
- */
705
- setAdaptiveQuality(enabled, targetFrameRate) {
706
- this.optimization.adaptiveQuality = enabled;
707
- if (targetFrameRate) {
708
- this.optimization.targetFrameRate = targetFrameRate;
709
- }
710
- }
711
- /**
712
- * Set fixed timestep for VR/AR
713
- */
714
- setFixedTimestep(timestep) {
715
- this.optimization.fixedTimestep = timestep;
716
- }
717
- /**
718
- * Get rendering preset for quality level
719
- */
720
- getPresetForQuality(quality) {
721
- const presets = {
722
- low: {
723
- targetGPUTier: "low",
724
- lodStrategy: "automatic",
725
- culling: { mode: "back", frustum: true, occlusion: false },
726
- batching: { instancing: true, maxInstanceCount: 500 },
727
- textures: {
728
- compression: "astc",
729
- maxResolution: 512,
730
- streaming: true,
731
- streamingBudget: 128
732
- },
733
- adaptiveQuality: true,
734
- targetFrameRate: 30
735
- },
736
- medium: {
737
- targetGPUTier: "medium",
738
- lodStrategy: "automatic",
739
- culling: { mode: "back", frustum: true, occlusion: true },
740
- batching: { instancing: true, maxInstanceCount: 1e3 },
741
- textures: {
742
- compression: "basis",
743
- maxResolution: 1024,
744
- streaming: true,
745
- streamingBudget: 256
746
- },
747
- adaptiveQuality: true,
748
- targetFrameRate: 60
749
- },
750
- high: {
751
- targetGPUTier: "high",
752
- lodStrategy: "automatic",
753
- culling: { mode: "back", frustum: true, occlusion: true },
754
- batching: { instancing: true, maxInstanceCount: 2e3 },
755
- textures: {
756
- compression: "dxt",
757
- maxResolution: 2048,
758
- streaming: true,
759
- streamingBudget: 512
760
- },
761
- adaptiveQuality: false,
762
- targetFrameRate: 60
763
- },
764
- ultra: {
765
- targetGPUTier: "ultra",
766
- lodStrategy: "manual",
767
- culling: {
768
- mode: "back",
769
- frustum: true,
770
- occlusion: true,
771
- hierarchicalZ: true
772
- },
773
- batching: { instancing: true, maxInstanceCount: 5e3 },
774
- textures: {
775
- compression: "none",
776
- maxResolution: 4096,
777
- virtualTexturing: true,
778
- streaming: true,
779
- streamingBudget: 1024
780
- },
781
- adaptiveQuality: false,
782
- targetFrameRate: 120
783
- }
784
- };
785
- return { ...this.optimization, ...presets[quality] };
786
- }
787
- /**
788
- * Apply quality preset
789
- */
790
- applyQualityPreset(quality) {
791
- const preset = this.getPresetForQuality(quality);
792
- this.optimization = preset;
793
- }
794
- /**
795
- * Estimate GPU memory usage
796
- */
797
- estimateGPUMemory() {
798
- let textureMemory = 0;
799
- let vertexBuffers = 0;
800
- const maxRes = this.optimization.textures?.maxResolution || 2048;
801
- textureMemory = maxRes * maxRes * 4 / (1024 * 1024);
802
- const instanceCount = this.optimization.batching?.maxInstanceCount || 1e3;
803
- const verticesPerMesh = 1e4;
804
- vertexBuffers = verticesPerMesh * 36 * instanceCount / (1024 * 1024) * 0.1;
805
- return {
806
- textureMemory: Math.round(textureMemory),
807
- vertexBuffers: Math.max(1, Math.round(vertexBuffers)),
808
- // At least 1MB
809
- estimatedTotal: Math.round(textureMemory + Math.max(1, vertexBuffers))
810
- };
811
- }
812
- /**
813
- * Get rendering statistics/info
814
- */
815
- getInfo() {
816
- const tier = this.optimization.targetGPUTier;
817
- const lod = this.optimization.lodStrategy;
818
- const culling = this.optimization.culling?.mode;
819
- const instancing = this.optimization.batching?.instancing ? "yes" : "no";
820
- const memory = this.estimateGPUMemory();
821
- return `Rendering: tier=${tier} | LOD=${lod} | culling=${culling} | instancing=${instancing} | memory=${memory.estimatedTotal}MB`;
822
- }
823
- /**
824
- * Optimize for VR/AR (fixed timestep, fast culling)
825
- */
826
- optimizeForVRAR(targetFPS = 90) {
827
- this.optimization.fixedTimestep = 1 / targetFPS;
828
- this.optimization.targetFrameRate = targetFPS;
829
- this.setOcclusionCulling(true, 50);
830
- this.setInstancing(true, 5e3);
831
- this.setAdaptiveQuality(true, targetFPS);
832
- }
833
- /**
834
- * Optimize for mobile (lower resources)
835
- */
836
- optimizeForMobile() {
837
- this.applyQualityPreset("low");
838
- this.setTextureCompression("astc");
839
- this.setInstancing(true, 256);
840
- }
841
- /**
842
- * Optimize for desktop (higher resources)
843
- */
844
- optimizeForDesktop() {
845
- this.applyQualityPreset("ultra");
846
- this.setTextureCompression("none");
847
- this.setInstancing(true, 5e3);
848
- }
849
- /**
850
- * Dispose and cleanup
851
- */
852
- dispose() {
853
- }
854
- };
855
- }
856
- });
9
+ import { __require } from './chunk-DGUM43GV.js';
857
10
 
858
11
  // src/HoloScript2DParser.ts
859
12
  var UI_SECURITY_CONFIG = {
@@ -1090,9 +243,7 @@ var HOLOSCRIPT_SECURITY_CONFIG = {
1090
243
  "__proto__",
1091
244
  "fs",
1092
245
  "child_process",
1093
- "exec",
1094
246
  "spawn",
1095
- "fetch",
1096
247
  "xmlhttprequest"
1097
248
  ],
1098
249
  allowedUIElements: [
@@ -1128,7 +279,7 @@ var HoloScriptParser = class {
1128
279
  });
1129
280
  return [];
1130
281
  }
1131
- const rawTokens = this.tokenizeCommand(command.command.toLowerCase());
282
+ const rawTokens = this.tokenizeCommand(command.command);
1132
283
  const tokens = this.sanitizeTokens(rawTokens);
1133
284
  if (tokens.length === 0) return [];
1134
285
  if (tokens.length > HOLOSCRIPT_SECURITY_CONFIG.maxTokens) {
@@ -1138,7 +289,7 @@ var HoloScriptParser = class {
1138
289
  });
1139
290
  return [];
1140
291
  }
1141
- const commandType = tokens[0];
292
+ const commandType = tokens[0].toLowerCase();
1142
293
  if ((commandType === "create" || commandType === "add") && tokens.length > 1) {
1143
294
  const elementType = tokens[1];
1144
295
  if (HOLOSCRIPT_SECURITY_CONFIG.allowedUIElements.includes(elementType)) {
@@ -1158,6 +309,21 @@ var HoloScriptParser = class {
1158
309
  return this.parseDebugCommand(tokens.slice(1));
1159
310
  case "visualize":
1160
311
  return this.parseVisualizeCommand(tokens.slice(1));
312
+ case "composition":
313
+ return this.parseComposition(tokens.slice(1));
314
+ case "environment":
315
+ return this.parseEnvironment(tokens.slice(1));
316
+ case "template":
317
+ return this.parseTemplate(tokens.slice(1));
318
+ case "@state":
319
+ return this.parseStateDirective(tokens.slice(1));
320
+ case "every":
321
+ case "on_user_gesture":
322
+ return this.parseGlobalHandler(commandType, tokens.slice(1));
323
+ case "scale":
324
+ return this.parseScale(tokens.slice(1));
325
+ case "focus":
326
+ return this.parseFocus(tokens.slice(1));
1161
327
  default:
1162
328
  return this.parseGenericCommand(tokens);
1163
329
  }
@@ -1196,19 +362,43 @@ var HoloScriptParser = class {
1196
362
  if (tokens.length < 2) return [];
1197
363
  const shape = tokens[0];
1198
364
  const name = tokens[1];
365
+ let res = [];
1199
366
  switch (shape) {
1200
367
  case "orb":
1201
368
  case "sphere":
1202
- return [this.createOrbNode(name, position)];
369
+ res = [this.createOrbNode(name, position)];
370
+ const orbProps = this.parseProperties(tokens.slice(2));
371
+ res[0].properties = orbProps;
372
+ break;
1203
373
  case "function":
1204
- return [this.createFunctionNode(name, tokens.slice(2), position)];
374
+ res = [this.createFunctionNode(name, tokens.slice(2), position)];
375
+ break;
1205
376
  case "gate":
1206
- return [this.createGateNode(name, tokens.slice(2), position)];
377
+ res = [this.createGateNode(name, tokens.slice(2), position)];
378
+ break;
1207
379
  case "stream":
1208
- return [this.createStreamNode(name, tokens.slice(2), position)];
380
+ res = [this.createStreamNode(name, tokens.slice(2), position)];
381
+ break;
382
+ case "server":
383
+ res = [this.createServerNode(tokens.slice(1), position)];
384
+ break;
385
+ case "database":
386
+ res = [this.createDatabaseNode(tokens.slice(1), position)];
387
+ break;
388
+ case "fetch":
389
+ res = [this.createFetchNode(tokens.slice(1), position)];
390
+ break;
1209
391
  default:
1210
- return [this.createGenericNode(shape, name, position)];
392
+ res = [this.createGenericNode(shape, name, position)];
393
+ break;
394
+ }
395
+ if (res.length > 0) {
396
+ const directives = this.extractDirectives(tokens.slice(2));
397
+ if (directives.length > 0) {
398
+ res[0].directives = directives;
399
+ }
1211
400
  }
401
+ return res;
1212
402
  }
1213
403
  parseConnectCommand(tokens) {
1214
404
  if (tokens.length < 3) return [];
@@ -1317,6 +507,61 @@ var HoloScriptParser = class {
1317
507
  }
1318
508
  };
1319
509
  }
510
+ createServerNode(params, position) {
511
+ const portIndex = params.indexOf("port");
512
+ const port = portIndex !== -1 ? parseInt(params[portIndex + 1]) : 3e3;
513
+ const routesIndex = params.indexOf("routes");
514
+ const routes = routesIndex !== -1 ? params[routesIndex + 1].split(",") : [];
515
+ return {
516
+ type: "server",
517
+ port,
518
+ routes,
519
+ position: position || { x: 0, y: 0, z: 0 },
520
+ hologram: {
521
+ shape: "cube",
522
+ color: "#000000",
523
+ // Black box
524
+ size: 2,
525
+ glow: true,
526
+ interactive: false
527
+ }
528
+ };
529
+ }
530
+ createDatabaseNode(params, position) {
531
+ const queryIndex = params.indexOf("query");
532
+ const query = queryIndex !== -1 ? params.slice(queryIndex + 1).join(" ") : "";
533
+ return {
534
+ type: "database",
535
+ query,
536
+ position: position || { x: 0, y: 0, z: 0 },
537
+ hologram: {
538
+ shape: "cylinder",
539
+ color: "#ffd700",
540
+ // Gold
541
+ size: 1.5,
542
+ glow: true,
543
+ interactive: true
544
+ }
545
+ };
546
+ }
547
+ createFetchNode(params, position) {
548
+ const urlIndex = params.indexOf("url");
549
+ const url = urlIndex !== -1 ? params[urlIndex + 1] : "";
550
+ return {
551
+ type: "fetch",
552
+ url,
553
+ method: "GET",
554
+ position: position || { x: 0, y: 0, z: 0 },
555
+ hologram: {
556
+ shape: "orb",
557
+ color: "#00ff00",
558
+ // Green
559
+ size: 0.8,
560
+ glow: true,
561
+ interactive: true
562
+ }
563
+ };
564
+ }
1320
565
  parsePinchGesture(gesture) {
1321
566
  return [{
1322
567
  type: "create",
@@ -1347,7 +592,7 @@ var HoloScriptParser = class {
1347
592
  }];
1348
593
  }
1349
594
  tokenizeCommand(command) {
1350
- return command.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((token) => token.length > 0);
595
+ return command.replace(/[^\w\s.,:/=?&"'*()\[\]@%${}-]/g, " ").split(/\s+/).filter((token) => token.length > 0);
1351
596
  }
1352
597
  sanitizeTokens(tokens) {
1353
598
  return tokens.filter((token) => {
@@ -1389,6 +634,167 @@ var HoloScriptParser = class {
1389
634
  hologram: { shape: "orb", color: "#808080", size: 0.5, glow: false, interactive: true }
1390
635
  }];
1391
636
  }
637
+ parseComposition(tokens) {
638
+ const name = tokens[0] || "unnamed_composition";
639
+ return [{
640
+ type: "composition",
641
+ name,
642
+ children: [],
643
+ position: { x: 0, y: 0, z: 0 }
644
+ }];
645
+ }
646
+ parseEnvironment(tokens) {
647
+ const settings = {};
648
+ if (tokens.includes("fog")) settings.fog = true;
649
+ if (tokens.includes("audio")) settings.audio = tokens[tokens.indexOf("audio") + 1];
650
+ if (tokens.includes("theme")) settings.theme = tokens[tokens.indexOf("theme") + 1];
651
+ return [{
652
+ type: "environment",
653
+ settings
654
+ }];
655
+ }
656
+ parseTemplate(tokens) {
657
+ const name = tokens[0] || "template";
658
+ const parameters = tokens.slice(1).filter((t) => t !== "with" && t !== "params");
659
+ return [{
660
+ type: "template",
661
+ name,
662
+ parameters,
663
+ body: []
664
+ }];
665
+ }
666
+ parseGlobalHandler(type, tokens) {
667
+ return [{
668
+ type: "global_handler",
669
+ handlerType: type === "every" ? "every" : "on_gesture",
670
+ config: { value: tokens[0] },
671
+ action: tokens.slice(1).join(" ")
672
+ }];
673
+ }
674
+ parseScale(tokens) {
675
+ const magnitude = tokens[0] || "standard";
676
+ const multipliers = {
677
+ "galactic": 1e6,
678
+ "macro": 1e3,
679
+ "standard": 1,
680
+ "micro": 1e-3,
681
+ "atomic": 1e-6
682
+ };
683
+ return [{
684
+ type: "scale",
685
+ magnitude,
686
+ multiplier: multipliers[magnitude] || 1,
687
+ body: []
688
+ }];
689
+ }
690
+ parseFocus(tokens) {
691
+ return [{
692
+ type: "focus",
693
+ target: tokens[0] || "origin",
694
+ body: []
695
+ }];
696
+ }
697
+ // ============================================================================
698
+ // HS+ Directive Parsing
699
+ // ============================================================================
700
+ parseStateDirective(tokens) {
701
+ const body = {};
702
+ for (let i = 0; i < tokens.length; i += 2) {
703
+ if (tokens[i] && tokens[i + 1]) {
704
+ const key = tokens[i].replace(":", "");
705
+ const val = this.parseLiteral(tokens[i + 1]);
706
+ body[key] = val;
707
+ }
708
+ }
709
+ return [{
710
+ type: "state-declaration",
711
+ directives: [{ type: "state", body }]
712
+ }];
713
+ }
714
+ extractDirectives(tokens) {
715
+ const directives = [];
716
+ for (let i = 0; i < tokens.length; i++) {
717
+ const token = tokens[i];
718
+ if (token.startsWith("@")) {
719
+ const name = token.slice(1);
720
+ if (this.isTrait(name)) {
721
+ let config = {};
722
+ if (tokens[i + 1] === "{") {
723
+ const closingIndex = this.findClosingBrace(tokens, i + 1);
724
+ if (closingIndex !== -1) {
725
+ config = this.parseProperties(tokens.slice(i + 2, closingIndex));
726
+ i = closingIndex;
727
+ }
728
+ }
729
+ directives.push({
730
+ type: "trait",
731
+ name,
732
+ config
733
+ });
734
+ } else if (this.isLifecycleHook(name)) {
735
+ directives.push({
736
+ type: "lifecycle",
737
+ hook: name,
738
+ body: tokens[i + 1] || ""
739
+ // Assume next token is body for now
740
+ });
741
+ i++;
742
+ }
743
+ }
744
+ }
745
+ return directives;
746
+ }
747
+ isTrait(name) {
748
+ const traits = ["grabbable", "throwable", "pointable", "hoverable", "scalable", "rotatable", "stackable", "snappable", "breakable"];
749
+ return traits.includes(name);
750
+ }
751
+ isLifecycleHook(name) {
752
+ const hooks = ["on_mount", "on_unmount", "on_update", "on_data_update", "on_grab", "on_release", "on_click"];
753
+ return hooks.includes(name);
754
+ }
755
+ parseLiteral(val) {
756
+ if (val === "true") return true;
757
+ if (val === "false") return false;
758
+ if (val === "null") return null;
759
+ if (!isNaN(Number(val))) return Number(val);
760
+ if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
761
+ return val.slice(1, -1);
762
+ }
763
+ return val;
764
+ }
765
+ parseProperties(tokens) {
766
+ const props = {};
767
+ for (let i = 0; i < tokens.length; i++) {
768
+ const token = tokens[i];
769
+ if (token === "{" || token === "}") continue;
770
+ if (token.startsWith("@")) break;
771
+ if (token.endsWith(":")) {
772
+ const key = token.slice(0, -1);
773
+ const val = tokens[i + 1];
774
+ if (val) {
775
+ props[key] = this.parseLiteral(val);
776
+ i++;
777
+ }
778
+ } else if (tokens[i + 1] === ":") {
779
+ const key = token;
780
+ const val = tokens[i + 2];
781
+ if (val) {
782
+ props[key] = this.parseLiteral(val);
783
+ i += 2;
784
+ }
785
+ }
786
+ }
787
+ return props;
788
+ }
789
+ findClosingBrace(tokens, startIndex) {
790
+ let depth = 0;
791
+ for (let i = startIndex; i < tokens.length; i++) {
792
+ if (tokens[i] === "{") depth++;
793
+ else if (tokens[i] === "}") depth--;
794
+ if (depth === 0) return i;
795
+ }
796
+ return -1;
797
+ }
1392
798
  getAST() {
1393
799
  return [...this.ast];
1394
800
  }
@@ -1418,8 +824,9 @@ var HoloScriptParser = class {
1418
824
  }
1419
825
  };
1420
826
 
1421
- // src/parser/HoloScriptPlusParser.ts
827
+ // src/constants.ts
1422
828
  var VR_TRAITS = [
829
+ // Core VR Interaction Traits
1423
830
  "grabbable",
1424
831
  "throwable",
1425
832
  "pointable",
@@ -1428,7 +835,56 @@ var VR_TRAITS = [
1428
835
  "rotatable",
1429
836
  "stackable",
1430
837
  "snappable",
1431
- "breakable"
838
+ "breakable",
839
+ "stretchable",
840
+ "moldable",
841
+ // Humanoid/Avatar Traits
842
+ "skeleton",
843
+ "body",
844
+ "face",
845
+ "expressive",
846
+ "hair",
847
+ "clothing",
848
+ "hands",
849
+ "character_voice",
850
+ "locomotion",
851
+ "poseable",
852
+ "morph",
853
+ // Networking & AI
854
+ "networked",
855
+ "proactive",
856
+ // Media Production Traits
857
+ "recordable",
858
+ "streamable",
859
+ "camera",
860
+ "video",
861
+ // Analytics & Research Traits
862
+ "trackable",
863
+ "survey",
864
+ "abtest",
865
+ "heatmap",
866
+ // Social & Viral Traits
867
+ "shareable",
868
+ "embeddable",
869
+ "qr",
870
+ "collaborative",
871
+ // Effects Traits
872
+ "particle",
873
+ "transition",
874
+ "filter",
875
+ "trail",
876
+ // Audio Traits
877
+ "spatial_audio",
878
+ "voice",
879
+ "reactive_audio",
880
+ // AI & Generative Traits
881
+ "narrator",
882
+ "responsive",
883
+ "procedural",
884
+ "captioned",
885
+ // Timeline & Choreography Traits
886
+ "timeline",
887
+ "choreography"
1432
888
  ];
1433
889
  var LIFECYCLE_HOOKS = [
1434
890
  // Standard lifecycle
@@ -1453,8 +909,152 @@ var LIFECYCLE_HOOKS = [
1453
909
  "on_trigger_hold",
1454
910
  "on_trigger_release",
1455
911
  "on_grip_hold",
1456
- "on_grip_release"
912
+ "on_grip_release",
913
+ // Stretchable/Moldable hooks
914
+ "on_stretch",
915
+ "on_sculpt",
916
+ // Humanoid/Avatar hooks
917
+ "on_pose_change",
918
+ "on_expression_change",
919
+ "on_gesture",
920
+ "on_speak",
921
+ "on_pose_save",
922
+ "on_morph_change",
923
+ // Media Production hooks
924
+ "on_record_start",
925
+ "on_record_stop",
926
+ "on_record_pause",
927
+ "on_stream_start",
928
+ "on_stream_stop",
929
+ "on_viewer_join",
930
+ "on_viewer_leave",
931
+ "on_chat_message",
932
+ "on_camera_switch",
933
+ "on_video_end",
934
+ "on_video_error",
935
+ // Analytics hooks
936
+ "on_track_event",
937
+ "on_survey_start",
938
+ "on_survey_complete",
939
+ "on_survey_skip",
940
+ "on_variant_assigned",
941
+ "on_conversion",
942
+ "on_hotspot_detected",
943
+ // Social hooks
944
+ "on_share",
945
+ "on_share_complete",
946
+ "on_embed",
947
+ "on_scan",
948
+ "on_user_join",
949
+ "on_user_leave",
950
+ "on_draw_stroke",
951
+ "on_object_lock",
952
+ "on_object_unlock",
953
+ // Effects hooks
954
+ "on_particle_spawn",
955
+ "on_particle_death",
956
+ "on_transition_start",
957
+ "on_transition_complete",
958
+ "on_filter_change",
959
+ // Audio hooks
960
+ "on_audio_start",
961
+ "on_audio_end",
962
+ "on_voice_command",
963
+ "on_speech_start",
964
+ "on_speech_end",
965
+ "on_beat",
966
+ "on_frequency_peak",
967
+ // AI hooks
968
+ "on_narration_start",
969
+ "on_narration_end",
970
+ "on_user_question",
971
+ "on_response_ready",
972
+ "on_emotion_change",
973
+ "on_generation_complete",
974
+ // Timeline hooks
975
+ "on_timeline_start",
976
+ "on_timeline_complete",
977
+ "on_keyframe_hit",
978
+ "on_keyframe_add",
979
+ "on_beat_sync",
980
+ "on_move_complete"
981
+ ];
982
+
983
+ // src/HoloScriptValidator.ts
984
+ var _HoloScriptValidator = class _HoloScriptValidator {
985
+ constructor() {
986
+ this.parser = new HoloScriptCodeParser();
987
+ }
988
+ /**
989
+ * Validates source code and returns a list of errors.
990
+ */
991
+ validate(code) {
992
+ const errors = [];
993
+ try {
994
+ this.parser.parse(code);
995
+ } catch (e) {
996
+ errors.push({
997
+ line: e.line || 1,
998
+ // Fallback if parser doesn't provide line
999
+ column: e.column || 1,
1000
+ message: e.message || "Syntax Error",
1001
+ severity: "error"
1002
+ });
1003
+ return errors;
1004
+ }
1005
+ const lines = code.split("\n");
1006
+ lines.forEach((line, index) => {
1007
+ const lineNum = index + 1;
1008
+ const trimmed = line.trim();
1009
+ if (!trimmed || trimmed.startsWith("//")) return;
1010
+ if (trimmed.startsWith("@")) {
1011
+ const match = trimmed.match(/^@(\w+)/);
1012
+ if (match) {
1013
+ const directive = match[1];
1014
+ if (!_HoloScriptValidator.VALID_DIRECTIVES.includes(directive)) {
1015
+ errors.push({
1016
+ line: lineNum,
1017
+ column: line.indexOf("@") + 1,
1018
+ message: `Unknown directive '@${directive}'. Allowed: ${_HoloScriptValidator.VALID_DIRECTIVES.join(", ")}`,
1019
+ severity: "warning"
1020
+ // directives might be custom, so warning for now
1021
+ });
1022
+ }
1023
+ }
1024
+ }
1025
+ if (trimmed.endsWith("{")) {
1026
+ const firstWord = trimmed.split(" ")[0];
1027
+ if (line.match(/^[a-z]+\s+[\w#]+\s*\{$/)) {
1028
+ if (!_HoloScriptValidator.VALID_KEYWORDS.includes(firstWord) && !trimmed.startsWith("trait")) ;
1029
+ }
1030
+ }
1031
+ });
1032
+ return errors;
1033
+ }
1034
+ };
1035
+ // Whitelists
1036
+ _HoloScriptValidator.VALID_DIRECTIVES = [
1037
+ "trait",
1038
+ "state",
1039
+ "on_enter",
1040
+ "on_exit",
1041
+ "on_mount",
1042
+ "on_tick",
1043
+ "on_create",
1044
+ "bot_config",
1045
+ "lifecycle"
1046
+ ];
1047
+ _HoloScriptValidator.VALID_KEYWORDS = [
1048
+ "world",
1049
+ "scene",
1050
+ "prefab",
1051
+ "object",
1052
+ "import",
1053
+ "export"
1457
1054
  ];
1055
+ var HoloScriptValidator = _HoloScriptValidator;
1056
+
1057
+ // src/parser/HoloScriptPlusParser.ts
1458
1058
  var Lexer = class {
1459
1059
  constructor(source) {
1460
1060
  this.pos = 0;
@@ -1848,6 +1448,10 @@ var HoloScriptPlusParser = class {
1848
1448
  this.pos = 0;
1849
1449
  const lexer = new Lexer(source);
1850
1450
  this.tokens = lexer.tokenize();
1451
+ try {
1452
+ __require("fs").writeFileSync("tokens.log", JSON.stringify(this.tokens, null, 2));
1453
+ } catch (e) {
1454
+ }
1851
1455
  const root = this.parseDocument();
1852
1456
  const ast = {
1853
1457
  type: "Program",
@@ -1885,6 +1489,20 @@ var HoloScriptPlusParser = class {
1885
1489
  }
1886
1490
  this.skipNewlines();
1887
1491
  }
1492
+ if (this.check("EOF") && directives.length > 0) {
1493
+ return {
1494
+ type: "fragment",
1495
+ id: "root",
1496
+ properties: {},
1497
+ directives,
1498
+ children: [],
1499
+ traits: /* @__PURE__ */ new Map(),
1500
+ loc: {
1501
+ start: { line: 1, column: 1 },
1502
+ end: { line: this.current().line, column: this.current().column }
1503
+ }
1504
+ };
1505
+ }
1888
1506
  const root = this.parseNode();
1889
1507
  root.directives = [...directives, ...root.directives];
1890
1508
  return root;
@@ -2018,6 +1636,20 @@ var HoloScriptPlusParser = class {
2018
1636
  const body = this.parseControlFlowBody();
2019
1637
  return { type: "for", variable, iterable, body };
2020
1638
  }
1639
+ if (name === "forEach") {
1640
+ this.hasControlFlow = true;
1641
+ const variable = this.expect("IDENTIFIER", "Expected variable name").value;
1642
+ this.expect("IDENTIFIER", 'Expected "in"');
1643
+ const collection = this.parseInlineExpression();
1644
+ const body = this.parseControlFlowBody();
1645
+ return { type: "forEach", variable, collection, body };
1646
+ }
1647
+ if (name === "while") {
1648
+ this.hasControlFlow = true;
1649
+ const condition = this.parseInlineExpression();
1650
+ const body = this.parseControlFlowBody();
1651
+ return { type: "while", condition, body };
1652
+ }
2021
1653
  if (name === "if") {
2022
1654
  this.hasControlFlow = true;
2023
1655
  const condition = this.parseInlineExpression();
@@ -2050,6 +1682,39 @@ var HoloScriptPlusParser = class {
2050
1682
  this.imports.push({ path, alias });
2051
1683
  return { type: "import", path, alias };
2052
1684
  }
1685
+ if (name === "external_api") {
1686
+ const config = this.parseTraitConfig();
1687
+ const url = config.url || "";
1688
+ const method = config.method || "GET";
1689
+ const interval = config.interval || "0s";
1690
+ let body = [];
1691
+ if (this.check("LBRACE")) {
1692
+ body = this.parseControlFlowBody();
1693
+ }
1694
+ return { type: "external_api", url, method, interval, body };
1695
+ }
1696
+ if (name === "generate") {
1697
+ const config = this.parseTraitConfig();
1698
+ const prompt = config.prompt || "";
1699
+ const context = config.context || "";
1700
+ const target = config.target || "children";
1701
+ return { type: "generate", prompt, context, target };
1702
+ }
1703
+ if (name === "npc") {
1704
+ try {
1705
+ __require("fs").appendFileSync("debug_parser.log", `ENTERED NPC BLOCK. Name length: ${name.length}
1706
+ `);
1707
+ } catch (e) {
1708
+ }
1709
+ const npcName = this.expect("STRING", "Expected NPC name").value;
1710
+ const props = this.parsePropsBlock();
1711
+ return { type: "npc", name: npcName, props };
1712
+ }
1713
+ if (name === "dialog") {
1714
+ const dialogName = this.expect("STRING", "Expected dialog name").value;
1715
+ const { props, options } = this.parseDialogBlock();
1716
+ return { type: "dialog", name: dialogName, props, options };
1717
+ }
2053
1718
  if (this.options.strict) {
2054
1719
  this.error(`Unknown directive @${name}`);
2055
1720
  } else {
@@ -2057,34 +1722,89 @@ var HoloScriptPlusParser = class {
2057
1722
  }
2058
1723
  return null;
2059
1724
  }
2060
- parseTraitConfig() {
2061
- const config = {};
2062
- if (this.check("LPAREN")) {
1725
+ parsePropsBlock() {
1726
+ this.skipNewlines();
1727
+ const props = {};
1728
+ if (this.check("LBRACE")) {
2063
1729
  this.advance();
2064
- while (!this.check("RPAREN") && !this.check("EOF")) {
1730
+ this.skipNewlines();
1731
+ while (!this.check("RBRACE") && !this.check("EOF")) {
2065
1732
  const key = this.expect("IDENTIFIER", "Expected property name").value;
2066
1733
  if (this.check("COLON") || this.check("EQUALS")) {
2067
1734
  this.advance();
2068
- config[key] = this.parseValue();
1735
+ props[key] = this.parseValue();
2069
1736
  } else {
2070
- config[key] = true;
1737
+ props[key] = true;
2071
1738
  }
2072
- if (this.check("COMMA")) this.advance();
1739
+ this.skipNewlines();
2073
1740
  }
2074
- this.expect("RPAREN", "Expected )");
1741
+ this.expect("RBRACE", "Expected }");
2075
1742
  }
2076
- return config;
1743
+ return props;
2077
1744
  }
2078
- parseStateBlock() {
2079
- const state = {};
1745
+ parseDialogBlock() {
1746
+ this.skipNewlines();
1747
+ const props = {};
1748
+ const options = [];
2080
1749
  if (this.check("LBRACE")) {
2081
1750
  this.advance();
2082
1751
  this.skipNewlines();
2083
1752
  while (!this.check("RBRACE") && !this.check("EOF")) {
2084
- const key = this.expect("IDENTIFIER", "Expected state variable name").value;
2085
- if (this.check("COLON") || this.check("EQUALS")) {
1753
+ if (this.check("IDENTIFIER") && this.current().value === "option") {
2086
1754
  this.advance();
2087
- state[key] = this.parseValue();
1755
+ const text = this.expect("STRING", "Expected option text").value;
1756
+ this.expect("ARROW", "Expected ->");
1757
+ let target;
1758
+ if (this.check("AT")) {
1759
+ const d = this.parseDirective();
1760
+ target = { type: "directive", value: d };
1761
+ } else {
1762
+ target = this.expect("STRING", "Expected target ID").value;
1763
+ }
1764
+ options.push({ text, target });
1765
+ } else {
1766
+ const key = this.expect("IDENTIFIER", "Expected property name").value;
1767
+ if (this.check("COLON") || this.check("EQUALS")) {
1768
+ this.advance();
1769
+ props[key] = this.parseValue();
1770
+ } else {
1771
+ props[key] = true;
1772
+ }
1773
+ }
1774
+ this.skipNewlines();
1775
+ }
1776
+ this.expect("RBRACE", "Expected }");
1777
+ }
1778
+ return { props, options };
1779
+ }
1780
+ parseTraitConfig() {
1781
+ const config = {};
1782
+ if (this.check("LPAREN")) {
1783
+ this.advance();
1784
+ while (!this.check("RPAREN") && !this.check("EOF")) {
1785
+ const key = this.expect("IDENTIFIER", "Expected property name").value;
1786
+ if (this.check("COLON") || this.check("EQUALS")) {
1787
+ this.advance();
1788
+ config[key] = this.parseValue();
1789
+ } else {
1790
+ config[key] = true;
1791
+ }
1792
+ if (this.check("COMMA")) this.advance();
1793
+ }
1794
+ this.expect("RPAREN", "Expected )");
1795
+ }
1796
+ return config;
1797
+ }
1798
+ parseStateBlock() {
1799
+ const state = {};
1800
+ if (this.check("LBRACE")) {
1801
+ this.advance();
1802
+ this.skipNewlines();
1803
+ while (!this.check("RBRACE") && !this.check("EOF")) {
1804
+ const key = this.expect("IDENTIFIER", "Expected state variable name").value;
1805
+ if (this.check("COLON") || this.check("EQUALS")) {
1806
+ this.advance();
1807
+ state[key] = this.parseValue();
2088
1808
  } else {
2089
1809
  state[key] = null;
2090
1810
  }
@@ -2233,51 +1953,866 @@ var HoloScriptPlusParser = class {
2233
1953
  current() {
2234
1954
  return this.tokens[this.pos] || { type: "EOF", value: "", line: 0, column: 0 };
2235
1955
  }
2236
- check(type) {
2237
- return this.current().type === type;
1956
+ check(type) {
1957
+ return this.current().type === type;
1958
+ }
1959
+ advance() {
1960
+ const token = this.current();
1961
+ if (this.pos < this.tokens.length) {
1962
+ this.pos++;
1963
+ }
1964
+ return token;
1965
+ }
1966
+ expect(type, message) {
1967
+ if (!this.check(type)) {
1968
+ this.error(`${message}. Got ${this.current().type} "${this.current().value}"`);
1969
+ return { type, value: "", line: this.current().line, column: this.current().column };
1970
+ }
1971
+ return this.advance();
1972
+ }
1973
+ skipNewlines() {
1974
+ while (this.check("NEWLINE") || this.check("INDENT") || this.check("DEDENT")) {
1975
+ this.advance();
1976
+ }
1977
+ }
1978
+ error(message) {
1979
+ const token = this.current();
1980
+ this.errors.push({
1981
+ message,
1982
+ line: token.line,
1983
+ column: token.column
1984
+ });
1985
+ }
1986
+ warn(message) {
1987
+ const token = this.current();
1988
+ this.warnings.push({
1989
+ message,
1990
+ line: token.line,
1991
+ column: token.column
1992
+ });
1993
+ }
1994
+ };
1995
+ function createParser(options) {
1996
+ return new HoloScriptPlusParser(options);
1997
+ }
1998
+ function parse(source, options) {
1999
+ const parser = createParser(options);
2000
+ return parser.parse(source);
2001
+ }
2002
+
2003
+ // src/traits/MaterialTrait.ts
2004
+ var MaterialTrait = class {
2005
+ constructor(config) {
2006
+ this.textureCache = /* @__PURE__ */ new Map();
2007
+ this.material = {
2008
+ ...{ type: "pbr" },
2009
+ ...config
2010
+ };
2011
+ }
2012
+ /**
2013
+ * Get material properties
2014
+ */
2015
+ getMaterial() {
2016
+ return { ...this.material };
2017
+ }
2018
+ /**
2019
+ * Update material property
2020
+ */
2021
+ setProperty(key, value) {
2022
+ this.material[key] = value;
2023
+ }
2024
+ /**
2025
+ * Get PBR properties
2026
+ */
2027
+ getPBRProperties() {
2028
+ return this.material.pbr;
2029
+ }
2030
+ /**
2031
+ * Update PBR material
2032
+ */
2033
+ updatePBR(pbr) {
2034
+ if (!this.material.pbr) {
2035
+ this.material.pbr = {
2036
+ baseColor: { r: 1, g: 1, b: 1 },
2037
+ metallic: 0,
2038
+ roughness: 0.5
2039
+ };
2040
+ }
2041
+ this.material.pbr = { ...this.material.pbr, ...pbr };
2042
+ }
2043
+ /**
2044
+ * Add texture map
2045
+ */
2046
+ addTexture(texture) {
2047
+ if (!this.material.textures) {
2048
+ this.material.textures = [];
2049
+ }
2050
+ this.material.textures.push(texture);
2051
+ }
2052
+ /**
2053
+ * Get all textures
2054
+ */
2055
+ getTextures() {
2056
+ return [...this.material.textures || []];
2057
+ }
2058
+ /**
2059
+ * Clear texture cache (for memory optimization)
2060
+ */
2061
+ clearTextureCache() {
2062
+ this.textureCache.clear();
2063
+ }
2064
+ /**
2065
+ * Get shader code if custom
2066
+ */
2067
+ getCustomShader() {
2068
+ return this.material.customShader;
2069
+ }
2070
+ /**
2071
+ * Set custom shader
2072
+ */
2073
+ setCustomShader(shader) {
2074
+ this.material.customShader = shader;
2075
+ }
2076
+ /**
2077
+ * Get optimization hints
2078
+ */
2079
+ getOptimization() {
2080
+ return this.material.optimization;
2081
+ }
2082
+ /**
2083
+ * Enable/disable texture streaming
2084
+ */
2085
+ setTextureStreaming(enabled) {
2086
+ if (!this.material.optimization) {
2087
+ this.material.optimization = {};
2088
+ }
2089
+ this.material.optimization.streamTextures = enabled;
2090
+ }
2091
+ /**
2092
+ * Set texture compression
2093
+ */
2094
+ setCompression(compression) {
2095
+ if (!this.material.optimization) {
2096
+ this.material.optimization = {};
2097
+ }
2098
+ this.material.optimization.compression = compression;
2099
+ }
2100
+ /**
2101
+ * Enable material instancing for performance
2102
+ */
2103
+ setInstanced(instanced) {
2104
+ if (!this.material.optimization) {
2105
+ this.material.optimization = {};
2106
+ }
2107
+ this.material.optimization.instanced = instanced;
2108
+ }
2109
+ /**
2110
+ * Dispose and cleanup
2111
+ */
2112
+ dispose() {
2113
+ this.textureCache.clear();
2114
+ }
2115
+ };
2116
+ function createMaterialTrait(config) {
2117
+ return new MaterialTrait(config);
2118
+ }
2119
+ var MATERIAL_PRESETS = {
2120
+ /** Shiny metal */
2121
+ chrome: () => ({
2122
+ type: "pbr",
2123
+ pbr: {
2124
+ baseColor: { r: 0.77, g: 0.77, b: 0.77 },
2125
+ metallic: 1,
2126
+ roughness: 0.1
2127
+ }
2128
+ }),
2129
+ /** Rough plastic */
2130
+ plastic: () => ({
2131
+ type: "pbr",
2132
+ pbr: {
2133
+ baseColor: { r: 1, g: 1, b: 1 },
2134
+ metallic: 0,
2135
+ roughness: 0.8
2136
+ }
2137
+ }),
2138
+ /** Wood texture */
2139
+ wood: () => ({
2140
+ type: "pbr",
2141
+ pbr: {
2142
+ baseColor: { r: 0.6, g: 0.4, b: 0.2 },
2143
+ metallic: 0,
2144
+ roughness: 0.4
2145
+ }
2146
+ }),
2147
+ /** Glass */
2148
+ glass: () => ({
2149
+ type: "transparent",
2150
+ blendMode: "blend",
2151
+ pbr: {
2152
+ baseColor: { r: 1, g: 1, b: 1, a: 0.3 },
2153
+ metallic: 0,
2154
+ roughness: 0,
2155
+ ior: 1.5,
2156
+ transmission: 0.9
2157
+ }
2158
+ }),
2159
+ /** Emissive (glowing) */
2160
+ emissive: () => ({
2161
+ type: "pbr",
2162
+ pbr: {
2163
+ baseColor: { r: 0, g: 1, b: 0 },
2164
+ metallic: 0,
2165
+ roughness: 1,
2166
+ emission: {
2167
+ color: { r: 0, g: 1, b: 0 },
2168
+ intensity: 2
2169
+ }
2170
+ }
2171
+ }),
2172
+ /** Skin material */
2173
+ skin: () => ({
2174
+ type: "pbr",
2175
+ pbr: {
2176
+ baseColor: { r: 1, g: 0.8, b: 0.7 },
2177
+ metallic: 0,
2178
+ roughness: 0.5,
2179
+ ambientOcclusion: 0.8
2180
+ }
2181
+ })
2182
+ };
2183
+
2184
+ // src/traits/LightingTrait.ts
2185
+ var LightingTrait = class {
2186
+ constructor(config) {
2187
+ this.lights = /* @__PURE__ */ new Map();
2188
+ this.lightIdCounter = 0;
2189
+ this.globalIllumination = {
2190
+ enabled: true,
2191
+ intensity: 1,
2192
+ skyColor: { r: 0.5, g: 0.7, b: 1 },
2193
+ skyIntensity: 1,
2194
+ groundColor: { r: 0.4, g: 0.4, b: 0.4 },
2195
+ groundIntensity: 0.5,
2196
+ probes: true,
2197
+ indirectDiffuse: 1,
2198
+ indirectSpecular: 1,
2199
+ aoIntensity: 1,
2200
+ screenSpaceAO: true,
2201
+ ...config
2202
+ };
2203
+ }
2204
+ /**
2205
+ * Add a light to the scene
2206
+ */
2207
+ addLight(light) {
2208
+ const id = light.name || `light_${this.lightIdCounter++}`;
2209
+ this.lights.set(id, light);
2210
+ return id;
2211
+ }
2212
+ /**
2213
+ * Get light by ID
2214
+ */
2215
+ getLight(id) {
2216
+ return this.lights.get(id);
2217
+ }
2218
+ /**
2219
+ * Get all lights
2220
+ */
2221
+ getLights() {
2222
+ return Array.from(this.lights.values());
2223
+ }
2224
+ /**
2225
+ * Get lights by type
2226
+ */
2227
+ getLightsByType(type) {
2228
+ return Array.from(this.lights.values()).filter((l) => l.type === type);
2229
+ }
2230
+ /**
2231
+ * Update light properties
2232
+ */
2233
+ updateLight(id, updates) {
2234
+ const light = this.lights.get(id);
2235
+ if (!light) return false;
2236
+ this.lights.set(id, { ...light, ...updates });
2237
+ return true;
2238
+ }
2239
+ /**
2240
+ * Remove light
2241
+ */
2242
+ removeLight(id) {
2243
+ return this.lights.delete(id);
2244
+ }
2245
+ /**
2246
+ * Clear all lights
2247
+ */
2248
+ clearLights() {
2249
+ this.lights.clear();
2250
+ }
2251
+ /**
2252
+ * Get global illumination config
2253
+ */
2254
+ getGlobalIllumination() {
2255
+ return { ...this.globalIllumination };
2256
+ }
2257
+ /**
2258
+ * Update global illumination
2259
+ */
2260
+ updateGlobalIllumination(updates) {
2261
+ this.globalIllumination = {
2262
+ ...this.globalIllumination,
2263
+ ...updates
2264
+ };
2265
+ }
2266
+ /**
2267
+ * Enable/disable GI
2268
+ */
2269
+ setGIEnabled(enabled) {
2270
+ this.globalIllumination.enabled = enabled;
2271
+ }
2272
+ /**
2273
+ * Set ambient light colors (skybox mode)
2274
+ */
2275
+ setAmbientLight(skyColor, groundColor, intensity = 1) {
2276
+ this.globalIllumination.skyColor = skyColor;
2277
+ this.globalIllumination.groundColor = groundColor;
2278
+ this.globalIllumination.skyIntensity = intensity;
2279
+ this.globalIllumination.groundIntensity = intensity * 0.5;
2280
+ }
2281
+ /**
2282
+ * Enable/disable screen-space ambient occlusion
2283
+ */
2284
+ setScreenSpaceAO(enabled, intensity = 1) {
2285
+ this.globalIllumination.screenSpaceAO = enabled;
2286
+ this.globalIllumination.aoIntensity = intensity;
2287
+ }
2288
+ /**
2289
+ * Create directional light (sun)
2290
+ */
2291
+ createDirectionalLight(direction, color, intensity = 1, castShadows = true) {
2292
+ const light = {
2293
+ type: "directional",
2294
+ name: `sun_${this.lightIdCounter}`,
2295
+ direction,
2296
+ color,
2297
+ intensity,
2298
+ shadow: castShadows ? {
2299
+ type: "soft",
2300
+ resolution: 2048,
2301
+ cascades: 4,
2302
+ softness: 1
2303
+ } : void 0,
2304
+ volumetric: true,
2305
+ priority: 100
2306
+ };
2307
+ return this.addLight(light);
2308
+ }
2309
+ /**
2310
+ * Create point light
2311
+ */
2312
+ createPointLight(position, color, intensity, range, castShadows = false) {
2313
+ const light = {
2314
+ type: "point",
2315
+ name: `point_${this.lightIdCounter}`,
2316
+ position,
2317
+ color,
2318
+ intensity,
2319
+ range,
2320
+ shadow: castShadows ? {
2321
+ type: "soft",
2322
+ resolution: 512,
2323
+ softness: 0.5
2324
+ } : void 0,
2325
+ priority: 50
2326
+ };
2327
+ return this.addLight(light);
2328
+ }
2329
+ /**
2330
+ * Create spot light
2331
+ */
2332
+ createSpotLight(position, direction, color, intensity, range, spotAngle = 45, castShadows = true) {
2333
+ const light = {
2334
+ type: "spot",
2335
+ name: `spot_${this.lightIdCounter}`,
2336
+ position,
2337
+ direction,
2338
+ color,
2339
+ intensity,
2340
+ range,
2341
+ spotAngle,
2342
+ innerSpotAngle: spotAngle * 0.5,
2343
+ shadow: castShadows ? {
2344
+ type: "soft",
2345
+ resolution: 1024,
2346
+ softness: 0.8
2347
+ } : void 0,
2348
+ priority: 75
2349
+ };
2350
+ return this.addLight(light);
2351
+ }
2352
+ /**
2353
+ * Create area light for soft lighting
2354
+ */
2355
+ createAreaLight(position, color, intensity, width, height) {
2356
+ const light = {
2357
+ type: "area",
2358
+ name: `area_${this.lightIdCounter}`,
2359
+ position,
2360
+ color,
2361
+ intensity,
2362
+ range: Math.max(width, height) * 2,
2363
+ priority: 25
2364
+ };
2365
+ return this.addLight(light);
2366
+ }
2367
+ /**
2368
+ * Get shadow-casting lights
2369
+ */
2370
+ getShadowCastingLights() {
2371
+ return Array.from(this.lights.values()).filter((l) => l.shadow && l.shadow.type !== "none");
2372
+ }
2373
+ /**
2374
+ * Get light count by type
2375
+ */
2376
+ getLightCount() {
2377
+ const counts = {
2378
+ directional: 0,
2379
+ point: 0,
2380
+ spot: 0,
2381
+ area: 0,
2382
+ probe: 0
2383
+ };
2384
+ for (const light of Array.from(this.lights.values())) {
2385
+ counts[light.type]++;
2386
+ }
2387
+ return counts;
2388
+ }
2389
+ /**
2390
+ * Estimate light impact for performance optimization
2391
+ */
2392
+ getPerformanceImpact() {
2393
+ const totalLights = this.lights.size;
2394
+ const shadowCasters = this.getShadowCastingLights().length;
2395
+ let estimatedGPUCost = "low";
2396
+ if (totalLights > 16 || shadowCasters > 4) {
2397
+ estimatedGPUCost = "high";
2398
+ } else if (totalLights > 8 || shadowCasters > 2) {
2399
+ estimatedGPUCost = "medium";
2400
+ }
2401
+ return {
2402
+ totalLights,
2403
+ shadowCasters,
2404
+ estimatedGPUCost
2405
+ };
2406
+ }
2407
+ /**
2408
+ * Get scene complexity info
2409
+ */
2410
+ getSceneInfo() {
2411
+ const counts = this.getLightCount();
2412
+ const impact = this.getPerformanceImpact();
2413
+ return `Lighting: ${counts.directional} dir, ${counts.point} point, ${counts.spot} spot | Shadows: ${impact.shadowCasters} | GPU: ${impact.estimatedGPUCost}`;
2414
+ }
2415
+ /**
2416
+ * Dispose and cleanup
2417
+ */
2418
+ dispose() {
2419
+ this.lights.clear();
2420
+ }
2421
+ };
2422
+ function createLightingTrait(config) {
2423
+ return new LightingTrait(config);
2424
+ }
2425
+ var LIGHTING_PRESETS = {
2426
+ /** Neutral studio lighting */
2427
+ studio: () => ({
2428
+ enabled: true,
2429
+ intensity: 1,
2430
+ skyColor: { r: 0.5, g: 0.5, b: 0.5 },
2431
+ skyIntensity: 0.5,
2432
+ groundColor: { r: 0.3, g: 0.3, b: 0.3 },
2433
+ groundIntensity: 0.3
2434
+ }),
2435
+ /** Bright outdoor lighting */
2436
+ outdoor: () => ({
2437
+ enabled: true,
2438
+ intensity: 1.2,
2439
+ skyColor: { r: 0.7, g: 0.85, b: 1 },
2440
+ skyIntensity: 1,
2441
+ groundColor: { r: 0.4, g: 0.4, b: 0.35 },
2442
+ groundIntensity: 0.6,
2443
+ indirectDiffuse: 1.2
2444
+ }),
2445
+ /** Dim interior lighting */
2446
+ interior: () => ({
2447
+ enabled: true,
2448
+ intensity: 0.6,
2449
+ skyColor: { r: 0.3, g: 0.3, b: 0.35 },
2450
+ skyIntensity: 0.4,
2451
+ groundColor: { r: 0.2, g: 0.2, b: 0.2 },
2452
+ groundIntensity: 0.2
2453
+ }),
2454
+ /** Night scene */
2455
+ night: () => ({
2456
+ enabled: true,
2457
+ intensity: 0.3,
2458
+ skyColor: { r: 0.01, g: 0.01, b: 0.02 },
2459
+ skyIntensity: 0.1,
2460
+ groundColor: { r: 0.02, g: 0.02, b: 0.02 },
2461
+ groundIntensity: 0.05,
2462
+ screenSpaceAO: false
2463
+ }),
2464
+ /** Sunset/golden hour */
2465
+ sunset: () => ({
2466
+ enabled: true,
2467
+ intensity: 1.1,
2468
+ skyColor: { r: 1, g: 0.7, b: 0.3 },
2469
+ skyIntensity: 1,
2470
+ groundColor: { r: 0.6, g: 0.4, b: 0.2 },
2471
+ groundIntensity: 0.8
2472
+ })
2473
+ };
2474
+
2475
+ // src/traits/RenderingTrait.ts
2476
+ var RenderingTrait = class {
2477
+ constructor(config) {
2478
+ this.optimization = {
2479
+ lodStrategy: "automatic",
2480
+ culling: {
2481
+ mode: "back",
2482
+ frustum: true,
2483
+ occlusion: true
2484
+ },
2485
+ batching: {
2486
+ static: true,
2487
+ dynamic: true,
2488
+ instancing: true,
2489
+ maxInstanceCount: 1e3
2490
+ },
2491
+ textures: {
2492
+ streaming: true,
2493
+ compression: "auto",
2494
+ mipmaps: true,
2495
+ maxResolution: 2048
2496
+ },
2497
+ shaders: {
2498
+ simplifiedShaders: true,
2499
+ lodBias: 0
2500
+ },
2501
+ targetGPUTier: "high",
2502
+ adaptiveQuality: true,
2503
+ targetFrameRate: 60,
2504
+ ...config
2505
+ };
2506
+ }
2507
+ /**
2508
+ * Get rendering optimization config
2509
+ */
2510
+ getOptimization() {
2511
+ return JSON.parse(JSON.stringify(this.optimization));
2512
+ }
2513
+ /**
2514
+ * Update rendering configuration
2515
+ */
2516
+ updateOptimization(updates) {
2517
+ this.optimization = { ...this.optimization, ...updates };
2518
+ }
2519
+ /**
2520
+ * Setup LOD levels (3 levels is typical)
2521
+ */
2522
+ setupLODLevels(strategy = "automatic") {
2523
+ const levels = [
2524
+ {
2525
+ level: 0,
2526
+ screenRelativeSize: 0.5,
2527
+ polygonReduction: 1,
2528
+ textureScale: 1
2529
+ },
2530
+ {
2531
+ level: 1,
2532
+ screenRelativeSize: 0.25,
2533
+ polygonReduction: 0.6,
2534
+ disabledFeatures: ["specular"],
2535
+ textureScale: 0.5
2536
+ },
2537
+ {
2538
+ level: 2,
2539
+ screenRelativeSize: 0.1,
2540
+ polygonReduction: 0.3,
2541
+ disabledFeatures: ["specular", "normals"],
2542
+ textureScale: 0.25
2543
+ }
2544
+ ];
2545
+ this.optimization.lodStrategy = strategy;
2546
+ this.optimization.lodLevels = levels;
2547
+ }
2548
+ /**
2549
+ * Get LOD levels
2550
+ */
2551
+ getLODLevels() {
2552
+ return [...this.optimization.lodLevels || []];
2553
+ }
2554
+ /**
2555
+ * Configure culling
2556
+ */
2557
+ setCulling(config) {
2558
+ const defaultCulling = { mode: "back" };
2559
+ this.optimization.culling = {
2560
+ ...defaultCulling,
2561
+ ...this.optimization.culling,
2562
+ ...config
2563
+ };
2564
+ }
2565
+ /**
2566
+ * Enable frustum culling
2567
+ */
2568
+ setFrustumCulling(enabled) {
2569
+ if (!this.optimization.culling) {
2570
+ this.optimization.culling = { mode: "back" };
2571
+ }
2572
+ this.optimization.culling.frustum = enabled;
2573
+ }
2574
+ /**
2575
+ * Enable occlusion culling
2576
+ */
2577
+ setOcclusionCulling(enabled, distance) {
2578
+ if (!this.optimization.culling) {
2579
+ this.optimization.culling = { mode: "back" };
2580
+ }
2581
+ this.optimization.culling.occlusion = enabled;
2582
+ if (distance) {
2583
+ this.optimization.culling.occlusionDistance = distance;
2584
+ }
2585
+ }
2586
+ /**
2587
+ * Configure batching
2588
+ */
2589
+ setBatching(config) {
2590
+ this.optimization.batching = {
2591
+ ...this.optimization.batching,
2592
+ ...config
2593
+ };
2594
+ }
2595
+ /**
2596
+ * Enable GPU instancing
2597
+ */
2598
+ setInstancing(enabled, maxInstances) {
2599
+ if (!this.optimization.batching) {
2600
+ this.optimization.batching = {};
2601
+ }
2602
+ this.optimization.batching.instancing = enabled;
2603
+ if (maxInstances) {
2604
+ this.optimization.batching.maxInstanceCount = maxInstances;
2605
+ }
2606
+ }
2607
+ /**
2608
+ * Configure texture optimization
2609
+ */
2610
+ setTextureOptimization(config) {
2611
+ this.optimization.textures = {
2612
+ ...this.optimization.textures,
2613
+ ...config
2614
+ };
2615
+ }
2616
+ /**
2617
+ * Enable texture streaming
2618
+ */
2619
+ setTextureStreaming(enabled, budgetMB) {
2620
+ if (!this.optimization.textures) {
2621
+ this.optimization.textures = {};
2622
+ }
2623
+ this.optimization.textures.streaming = enabled;
2624
+ if (budgetMB) {
2625
+ this.optimization.textures.streamingBudget = budgetMB;
2626
+ }
2627
+ }
2628
+ /**
2629
+ * Set texture compression
2630
+ */
2631
+ setTextureCompression(compression) {
2632
+ if (!this.optimization.textures) {
2633
+ this.optimization.textures = {};
2634
+ }
2635
+ this.optimization.textures.compression = compression;
2636
+ }
2637
+ /**
2638
+ * Set max texture resolution
2639
+ */
2640
+ setMaxTextureResolution(resolution) {
2641
+ if (!this.optimization.textures) {
2642
+ this.optimization.textures = {};
2643
+ }
2644
+ this.optimization.textures.maxResolution = resolution;
2645
+ }
2646
+ /**
2647
+ * Configure shader optimization
2648
+ */
2649
+ setShaderOptimization(config) {
2650
+ this.optimization.shaders = {
2651
+ ...this.optimization.shaders,
2652
+ ...config
2653
+ };
2654
+ }
2655
+ /**
2656
+ * Set target GPU tier
2657
+ */
2658
+ setTargetGPUTier(tier) {
2659
+ this.optimization.targetGPUTier = tier;
2660
+ }
2661
+ /**
2662
+ * Enable adaptive quality (adjust based on frame rate)
2663
+ */
2664
+ setAdaptiveQuality(enabled, targetFrameRate) {
2665
+ this.optimization.adaptiveQuality = enabled;
2666
+ if (targetFrameRate) {
2667
+ this.optimization.targetFrameRate = targetFrameRate;
2668
+ }
2669
+ }
2670
+ /**
2671
+ * Set fixed timestep for VR/AR
2672
+ */
2673
+ setFixedTimestep(timestep) {
2674
+ this.optimization.fixedTimestep = timestep;
2675
+ }
2676
+ /**
2677
+ * Get rendering preset for quality level
2678
+ */
2679
+ getPresetForQuality(quality) {
2680
+ const presets = {
2681
+ low: {
2682
+ targetGPUTier: "low",
2683
+ lodStrategy: "automatic",
2684
+ culling: { mode: "back", frustum: true, occlusion: false },
2685
+ batching: { instancing: true, maxInstanceCount: 500 },
2686
+ textures: {
2687
+ compression: "astc",
2688
+ maxResolution: 512,
2689
+ streaming: true,
2690
+ streamingBudget: 128
2691
+ },
2692
+ adaptiveQuality: true,
2693
+ targetFrameRate: 30
2694
+ },
2695
+ medium: {
2696
+ targetGPUTier: "medium",
2697
+ lodStrategy: "automatic",
2698
+ culling: { mode: "back", frustum: true, occlusion: true },
2699
+ batching: { instancing: true, maxInstanceCount: 1e3 },
2700
+ textures: {
2701
+ compression: "basis",
2702
+ maxResolution: 1024,
2703
+ streaming: true,
2704
+ streamingBudget: 256
2705
+ },
2706
+ adaptiveQuality: true,
2707
+ targetFrameRate: 60
2708
+ },
2709
+ high: {
2710
+ targetGPUTier: "high",
2711
+ lodStrategy: "automatic",
2712
+ culling: { mode: "back", frustum: true, occlusion: true },
2713
+ batching: { instancing: true, maxInstanceCount: 2e3 },
2714
+ textures: {
2715
+ compression: "dxt",
2716
+ maxResolution: 2048,
2717
+ streaming: true,
2718
+ streamingBudget: 512
2719
+ },
2720
+ adaptiveQuality: false,
2721
+ targetFrameRate: 60
2722
+ },
2723
+ ultra: {
2724
+ targetGPUTier: "ultra",
2725
+ lodStrategy: "manual",
2726
+ culling: {
2727
+ mode: "back",
2728
+ frustum: true,
2729
+ occlusion: true,
2730
+ hierarchicalZ: true
2731
+ },
2732
+ batching: { instancing: true, maxInstanceCount: 5e3 },
2733
+ textures: {
2734
+ compression: "none",
2735
+ maxResolution: 4096,
2736
+ virtualTexturing: true,
2737
+ streaming: true,
2738
+ streamingBudget: 1024
2739
+ },
2740
+ adaptiveQuality: false,
2741
+ targetFrameRate: 120
2742
+ }
2743
+ };
2744
+ return { ...this.optimization, ...presets[quality] };
2745
+ }
2746
+ /**
2747
+ * Apply quality preset
2748
+ */
2749
+ applyQualityPreset(quality) {
2750
+ const preset = this.getPresetForQuality(quality);
2751
+ this.optimization = preset;
2752
+ }
2753
+ /**
2754
+ * Estimate GPU memory usage
2755
+ */
2756
+ estimateGPUMemory() {
2757
+ let textureMemory = 0;
2758
+ let vertexBuffers = 0;
2759
+ const maxRes = this.optimization.textures?.maxResolution || 2048;
2760
+ textureMemory = maxRes * maxRes * 4 / (1024 * 1024);
2761
+ const instanceCount = this.optimization.batching?.maxInstanceCount || 1e3;
2762
+ const verticesPerMesh = 1e4;
2763
+ vertexBuffers = verticesPerMesh * 36 * instanceCount / (1024 * 1024) * 0.1;
2764
+ return {
2765
+ textureMemory: Math.round(textureMemory),
2766
+ vertexBuffers: Math.max(1, Math.round(vertexBuffers)),
2767
+ // At least 1MB
2768
+ estimatedTotal: Math.round(textureMemory + Math.max(1, vertexBuffers))
2769
+ };
2238
2770
  }
2239
- advance() {
2240
- const token = this.current();
2241
- if (this.pos < this.tokens.length) {
2242
- this.pos++;
2243
- }
2244
- return token;
2771
+ /**
2772
+ * Get rendering statistics/info
2773
+ */
2774
+ getInfo() {
2775
+ const tier = this.optimization.targetGPUTier;
2776
+ const lod = this.optimization.lodStrategy;
2777
+ const culling = this.optimization.culling?.mode;
2778
+ const instancing = this.optimization.batching?.instancing ? "yes" : "no";
2779
+ const memory = this.estimateGPUMemory();
2780
+ return `Rendering: tier=${tier} | LOD=${lod} | culling=${culling} | instancing=${instancing} | memory=${memory.estimatedTotal}MB`;
2245
2781
  }
2246
- expect(type, message) {
2247
- if (!this.check(type)) {
2248
- this.error(`${message}. Got ${this.current().type} "${this.current().value}"`);
2249
- return { type, value: "", line: this.current().line, column: this.current().column };
2250
- }
2251
- return this.advance();
2782
+ /**
2783
+ * Optimize for VR/AR (fixed timestep, fast culling)
2784
+ */
2785
+ optimizeForVRAR(targetFPS = 90) {
2786
+ this.optimization.fixedTimestep = 1 / targetFPS;
2787
+ this.optimization.targetFrameRate = targetFPS;
2788
+ this.setOcclusionCulling(true, 50);
2789
+ this.setInstancing(true, 5e3);
2790
+ this.setAdaptiveQuality(true, targetFPS);
2252
2791
  }
2253
- skipNewlines() {
2254
- while (this.check("NEWLINE") || this.check("INDENT") || this.check("DEDENT")) {
2255
- this.advance();
2256
- }
2792
+ /**
2793
+ * Optimize for mobile (lower resources)
2794
+ */
2795
+ optimizeForMobile() {
2796
+ this.applyQualityPreset("low");
2797
+ this.setTextureCompression("astc");
2798
+ this.setInstancing(true, 256);
2257
2799
  }
2258
- error(message) {
2259
- const token = this.current();
2260
- this.errors.push({
2261
- message,
2262
- line: token.line,
2263
- column: token.column
2264
- });
2800
+ /**
2801
+ * Optimize for desktop (higher resources)
2802
+ */
2803
+ optimizeForDesktop() {
2804
+ this.applyQualityPreset("ultra");
2805
+ this.setTextureCompression("none");
2806
+ this.setInstancing(true, 5e3);
2265
2807
  }
2266
- warn(message) {
2267
- const token = this.current();
2268
- this.warnings.push({
2269
- message,
2270
- line: token.line,
2271
- column: token.column
2272
- });
2808
+ /**
2809
+ * Dispose and cleanup
2810
+ */
2811
+ dispose() {
2273
2812
  }
2274
2813
  };
2275
- function createParser(options) {
2276
- return new HoloScriptPlusParser(options);
2277
- }
2278
- function parse(source, options) {
2279
- const parser = createParser(options);
2280
- return parser.parse(source);
2814
+ function createRenderingTrait(config) {
2815
+ return new RenderingTrait(config);
2281
2816
  }
2282
2817
 
2283
2818
  // src/HoloScriptPlusParser.ts
@@ -2531,8 +3066,7 @@ var HoloScriptPlusParser2 = class {
2531
3066
  * Create MaterialTrait from config
2532
3067
  */
2533
3068
  createMaterialTrait(config) {
2534
- const { MaterialTrait: MaterialTrait2 } = (init_MaterialTrait(), __toCommonJS(MaterialTrait_exports));
2535
- const material = new MaterialTrait2({
3069
+ const material = new MaterialTrait({
2536
3070
  type: config.type || "pbr",
2537
3071
  pbr: config.pbr
2538
3072
  });
@@ -2556,13 +3090,13 @@ var HoloScriptPlusParser2 = class {
2556
3090
  * Create LightingTrait from config
2557
3091
  */
2558
3092
  createLightingTrait(config) {
2559
- const { LightingTrait: LightingTrait2, LIGHTING_PRESETS: LIGHTING_PRESETS2 } = (init_LightingTrait(), __toCommonJS(LightingTrait_exports));
2560
3093
  let lighting;
2561
3094
  if (config.preset) {
2562
- const preset = LIGHTING_PRESETS2[config.preset];
2563
- lighting = new LightingTrait2(preset);
3095
+ const presetFactory = LIGHTING_PRESETS[config.preset];
3096
+ const presetConfig = presetFactory ? presetFactory() : void 0;
3097
+ lighting = new LightingTrait(presetConfig);
2564
3098
  } else {
2565
- lighting = new LightingTrait2();
3099
+ lighting = new LightingTrait();
2566
3100
  }
2567
3101
  if (config.globalIllumination) {
2568
3102
  lighting.setGlobalIllumination(config.globalIllumination);
@@ -2578,8 +3112,7 @@ var HoloScriptPlusParser2 = class {
2578
3112
  * Create RenderingTrait from config
2579
3113
  */
2580
3114
  createRenderingTrait(config) {
2581
- const { RenderingTrait: RenderingTrait2 } = (init_RenderingTrait(), __toCommonJS(RenderingTrait_exports));
2582
- const rendering = new RenderingTrait2();
3115
+ const rendering = new RenderingTrait();
2583
3116
  if (config.quality) {
2584
3117
  rendering.applyQualityPreset(config.quality);
2585
3118
  }
@@ -2910,6 +3443,25 @@ var ExpressionEvaluator = class {
2910
3443
  };
2911
3444
  }
2912
3445
  evaluate(expression) {
3446
+ const dangerousPatterns = [
3447
+ /\beval\s*\(/,
3448
+ /\brequire\s*\(/,
3449
+ /\bimport\s*\(/,
3450
+ /\bprocess\s*\./,
3451
+ /\bglobal\s*\./,
3452
+ /\b__dirname\b/,
3453
+ /\b__filename\b/,
3454
+ /\bfs\s*\./,
3455
+ /\bchild_process\s*\./,
3456
+ /\bfs\.writeFileSync/,
3457
+ /\bfs\.readFileSync/
3458
+ ];
3459
+ for (const pattern of dangerousPatterns) {
3460
+ if (pattern.test(expression)) {
3461
+ console.warn(`Security: Blocked suspicious expression: ${expression}`);
3462
+ return void 0;
3463
+ }
3464
+ }
2913
3465
  const contextKeys = Object.keys(this.context);
2914
3466
  const contextValues = Object.values(this.context);
2915
3467
  const builtinKeys = Object.keys(this.builtins);
@@ -2989,7 +3541,8 @@ var grabbableHandler = {
2989
3541
  const distance = Math.sqrt(
2990
3542
  Math.pow(handPos[0] - nodePos2[0], 2) + Math.pow(handPos[1] - nodePos2[1], 2) + Math.pow(handPos[2] - nodePos2[2], 2)
2991
3543
  );
2992
- if (distance > (config.max_grab_distance || 3)) return;
3544
+ const maxDist = (config.max_grab_distance || 3) * context.getScaleMultiplier();
3545
+ if (distance > maxDist) return;
2993
3546
  }
2994
3547
  state.isGrabbed = true;
2995
3548
  state.grabbingHand = event.hand;
@@ -3020,7 +3573,7 @@ var grabbableHandler = {
3020
3573
  ];
3021
3574
  if (node.traits.has("throwable")) {
3022
3575
  const throwConfig = node.traits.get("throwable");
3023
- const multiplier = throwConfig.velocity_multiplier || 1;
3576
+ const multiplier = (throwConfig.velocity_multiplier || 1) * context.getScaleMultiplier();
3024
3577
  context.physics.applyVelocity(node, [
3025
3578
  velocity[0] * multiplier,
3026
3579
  velocity[1] * multiplier,
@@ -3198,6 +3751,21 @@ var scalableHandler = {
3198
3751
  const scaleFactor = currentDistance / state.initialDistance;
3199
3752
  let newScale = state.initialScale * scaleFactor;
3200
3753
  newScale = Math.max(config.min_scale || 0.1, Math.min(config.max_scale || 10, newScale));
3754
+ const scaleMultiplier = context.getScaleMultiplier();
3755
+ const effectiveScale = newScale * scaleMultiplier;
3756
+ if (effectiveScale > 1e6 && scaleMultiplier < 1e6) {
3757
+ context.setScaleContext("galactic");
3758
+ newScale /= 1e6;
3759
+ } else if (effectiveScale > 1e3 && scaleMultiplier < 1e3) {
3760
+ context.setScaleContext("macro");
3761
+ newScale /= 1e3;
3762
+ } else if (effectiveScale < 1e-3 && scaleMultiplier > 1e-3) {
3763
+ context.setScaleContext("micro");
3764
+ newScale *= 1e3;
3765
+ } else if (effectiveScale < 1e-6 && scaleMultiplier > 1e-6) {
3766
+ context.setScaleContext("atomic");
3767
+ newScale *= 1e6;
3768
+ }
3201
3769
  node.properties.scale = newScale;
3202
3770
  context.emit("scale_update", { node, scale: newScale });
3203
3771
  },
@@ -3373,12 +3941,12 @@ var snappableHandler = {
3373
3941
  snap_rotation: false,
3374
3942
  magnetic: false
3375
3943
  },
3376
- onUpdate(node, config, _context, _delta) {
3944
+ onUpdate(node, config, context, _delta) {
3377
3945
  if (!config.snap_points || config.snap_points.length === 0) return;
3378
3946
  if (!config.magnetic) return;
3379
3947
  const nodePos = node.properties.position || [0, 0, 0];
3380
3948
  let closestPoint = null;
3381
- let closestDistance = config.snap_distance || 0.3;
3949
+ let closestDistance = (config.snap_distance || 0.3) * context.getScaleMultiplier();
3382
3950
  for (const snapPoint of config.snap_points) {
3383
3951
  const distance = Math.sqrt(
3384
3952
  Math.pow(nodePos[0] - snapPoint[0], 2) + Math.pow(nodePos[1] - snapPoint[1], 2) + Math.pow(nodePos[2] - snapPoint[2], 2)
@@ -3402,7 +3970,7 @@ var snappableHandler = {
3402
3970
  if (!config.snap_points || config.snap_points.length === 0) return;
3403
3971
  const nodePos = node.properties.position || [0, 0, 0];
3404
3972
  let closestPoint = null;
3405
- let closestDistance = config.snap_distance || 0.3;
3973
+ let closestDistance = (config.snap_distance || 0.3) * context.getScaleMultiplier();
3406
3974
  for (const snapPoint of config.snap_points) {
3407
3975
  const distance = Math.sqrt(
3408
3976
  Math.pow(nodePos[0] - snapPoint[0], 2) + Math.pow(nodePos[1] - snapPoint[1], 2) + Math.pow(nodePos[2] - snapPoint[2], 2)
@@ -3458,202 +4026,138 @@ var breakableHandler = {
3458
4026
  }
3459
4027
  context.emit("break", { node, impactVelocity, collision });
3460
4028
  if (config.respawn) {
3461
- const delay = parseDuration(config.respawn_delay || "5s");
3462
- setTimeout(() => {
3463
- context.emit("respawn", { node });
3464
- }, delay);
3465
- }
3466
- node.properties.__destroyed = true;
3467
- }
3468
- };
3469
- function parseDuration(duration) {
3470
- const match = duration.match(/^(\d+(?:\.\d+)?)(ms|s|m)$/);
3471
- if (!match) return 0;
3472
- const value = parseFloat(match[1]);
3473
- const unit = match[2];
3474
- switch (unit) {
3475
- case "ms":
3476
- return value;
3477
- case "s":
3478
- return value * 1e3;
3479
- case "m":
3480
- return value * 60 * 1e3;
3481
- default:
3482
- return value;
3483
- }
3484
- }
3485
- var VRTraitRegistry = class {
3486
- constructor() {
3487
- this.handlers = /* @__PURE__ */ new Map();
3488
- this.register(grabbableHandler);
3489
- this.register(throwableHandler);
3490
- this.register(pointableHandler);
3491
- this.register(hoverableHandler);
3492
- this.register(scalableHandler);
3493
- this.register(rotatableHandler);
3494
- this.register(stackableHandler);
3495
- this.register(snappableHandler);
3496
- this.register(breakableHandler);
3497
- }
3498
- register(handler) {
3499
- this.handlers.set(handler.name, handler);
3500
- }
3501
- getHandler(name) {
3502
- return this.handlers.get(name);
3503
- }
3504
- attachTrait(node, traitName, config, context) {
3505
- const handler = this.handlers.get(traitName);
3506
- if (!handler) return;
3507
- const mergedConfig = { ...handler.defaultConfig, ...config };
3508
- node.traits.set(traitName, mergedConfig);
3509
- if (handler.onAttach) {
3510
- handler.onAttach(node, mergedConfig, context);
3511
- }
3512
- }
3513
- detachTrait(node, traitName, context) {
3514
- const handler = this.handlers.get(traitName);
3515
- if (!handler) return;
3516
- const config = node.traits.get(traitName);
3517
- if (config && handler.onDetach) {
3518
- handler.onDetach(node, config, context);
3519
- }
3520
- node.traits.delete(traitName);
3521
- }
3522
- updateTrait(node, traitName, context, delta) {
3523
- const handler = this.handlers.get(traitName);
3524
- if (!handler || !handler.onUpdate) return;
3525
- const config = node.traits.get(traitName);
3526
- if (config) {
3527
- handler.onUpdate(node, config, context, delta);
3528
- }
3529
- }
3530
- handleEvent(node, traitName, context, event) {
3531
- const handler = this.handlers.get(traitName);
3532
- if (!handler || !handler.onEvent) return;
3533
- const config = node.traits.get(traitName);
3534
- if (config) {
3535
- handler.onEvent(node, config, context, event);
3536
- }
3537
- }
3538
- updateAllTraits(node, context, delta) {
3539
- for (const traitName of node.traits.keys()) {
3540
- this.updateTrait(node, traitName, context, delta);
3541
- }
3542
- }
3543
- handleEventForAllTraits(node, context, event) {
3544
- for (const traitName of node.traits.keys()) {
3545
- this.handleEvent(node, traitName, context, event);
3546
- }
3547
- }
3548
- };
3549
- var vrTraitRegistry = new VRTraitRegistry();
3550
-
3551
- // src/runtime/HoloScriptPlusRuntime.ts
3552
- function createBuiltins(runtime) {
3553
- return {
3554
- Math,
3555
- range: (start, end, step = 1) => {
3556
- const result = [];
3557
- if (step > 0) {
3558
- for (let i = start; i < end; i += step) {
3559
- result.push(i);
3560
- }
3561
- } else if (step < 0) {
3562
- for (let i = start; i > end; i += step) {
3563
- result.push(i);
3564
- }
3565
- }
3566
- return result;
3567
- },
3568
- interpolate_color: (t, from, to) => {
3569
- const parseHex = (hex) => {
3570
- const clean = hex.replace("#", "");
3571
- return [
3572
- parseInt(clean.substring(0, 2), 16),
3573
- parseInt(clean.substring(2, 4), 16),
3574
- parseInt(clean.substring(4, 6), 16)
3575
- ];
3576
- };
3577
- const toHex = (r, g, b) => {
3578
- const clamp = (v) => Math.max(0, Math.min(255, Math.round(v)));
3579
- return `#${clamp(r).toString(16).padStart(2, "0")}${clamp(g).toString(16).padStart(2, "0")}${clamp(b).toString(16).padStart(2, "0")}`;
3580
- };
3581
- const [r1, g1, b1] = parseHex(from);
3582
- const [r2, g2, b2] = parseHex(to);
3583
- return toHex(
3584
- r1 + (r2 - r1) * t,
3585
- g1 + (g2 - g1) * t,
3586
- b1 + (b2 - b1) * t
3587
- );
3588
- },
3589
- distance_to: (point) => {
3590
- const viewer = runtime.vrContext.headset.position;
3591
- return Math.sqrt(
3592
- Math.pow(point[0] - viewer[0], 2) + Math.pow(point[1] - viewer[1], 2) + Math.pow(point[2] - viewer[2], 2)
3593
- );
3594
- },
3595
- distance_to_viewer: () => {
3596
- return 0;
3597
- },
3598
- hand_position: (handId) => {
3599
- const hand = handId === "left" ? runtime.vrContext.hands.left : runtime.vrContext.hands.right;
3600
- return hand?.position || [0, 0, 0];
3601
- },
3602
- hand_velocity: (handId) => {
3603
- const hand = handId === "left" ? runtime.vrContext.hands.left : runtime.vrContext.hands.right;
3604
- return hand?.velocity || [0, 0, 0];
3605
- },
3606
- dominant_hand: () => {
3607
- return runtime.vrContext.hands.right || runtime.vrContext.hands.left || {
3608
- id: "right",
3609
- position: [0, 0, 0],
3610
- rotation: [0, 0, 0],
3611
- velocity: [0, 0, 0],
3612
- grip: 0,
3613
- trigger: 0
3614
- };
3615
- },
3616
- play_sound: (source, options) => {
3617
- runtime.emit("play_sound", { source, ...options });
3618
- },
3619
- haptic_feedback: (hand, intensity) => {
3620
- const handId = typeof hand === "string" ? hand : hand.id;
3621
- runtime.emit("haptic", { hand: handId, intensity });
3622
- },
3623
- haptic_pulse: (intensity) => {
3624
- runtime.emit("haptic", { hand: "both", intensity });
3625
- },
3626
- apply_velocity: (node, velocity) => {
3627
- runtime.emit("apply_velocity", { node, velocity });
3628
- },
3629
- spawn: (template, position) => {
3630
- return runtime.spawnTemplate(template, position);
3631
- },
3632
- destroy: (node) => {
3633
- runtime.destroyNode(node);
3634
- },
3635
- api_call: async (url, method, body) => {
3636
- const response = await fetch(url, {
3637
- method,
3638
- headers: body ? { "Content-Type": "application/json" } : void 0,
3639
- body: body ? JSON.stringify(body) : void 0
3640
- });
3641
- return response.json();
3642
- },
3643
- open_modal: (modalId) => {
3644
- runtime.emit("open_modal", { id: modalId });
3645
- },
3646
- close_modal: (modalId) => {
3647
- runtime.emit("close_modal", { id: modalId });
3648
- },
3649
- setTimeout: (callback, delay) => {
3650
- return window.setTimeout(callback, delay);
3651
- },
3652
- clearTimeout: (id) => {
3653
- window.clearTimeout(id);
4029
+ const delay = parseDuration(config.respawn_delay || "5s");
4030
+ setTimeout(() => {
4031
+ context.emit("respawn", { node });
4032
+ }, delay);
3654
4033
  }
3655
- };
4034
+ node.properties.__destroyed = true;
4035
+ }
4036
+ };
4037
+ var proactiveHandler = {
4038
+ name: "proactive",
4039
+ defaultConfig: {
4040
+ intelligence_tier: "basic",
4041
+ observation_range: 5,
4042
+ learning_rate: 0.1,
4043
+ auto_suggest: true,
4044
+ context_window: 10
4045
+ },
4046
+ onAttach(node, config, context) {
4047
+ console.log(`[Proactive] Neural bridge attached to ${node.id || node.type}`);
4048
+ context.emit("proactive_init", { nodeId: node.id, tier: config.intelligence_tier });
4049
+ },
4050
+ onUpdate(node, config, context, delta) {
4051
+ if (!config || !config.auto_suggest) return;
4052
+ const vr = context.vr;
4053
+ const pos = node.properties.position;
4054
+ if (!pos || !vr.headset.position) return;
4055
+ const dx = pos[0] - vr.headset.position[0];
4056
+ const dy = pos[1] - vr.headset.position[1];
4057
+ const dz = pos[2] - vr.headset.position[2];
4058
+ const distanceToHead = Math.sqrt(dx * dx + dy * dy + dz * dz);
4059
+ if (distanceToHead < (config.observation_range || 5)) {
4060
+ if (Math.random() < 0.01 * (config.learning_rate || 0.1) * delta) {
4061
+ context.emit("proactive_suggestion", {
4062
+ nodeId: node.id,
4063
+ type: "interaction_hint",
4064
+ suggestion: "Object is observing your proximity. Suggesting engagement."
4065
+ });
4066
+ }
4067
+ }
4068
+ }
4069
+ };
4070
+ function parseDuration(duration) {
4071
+ const match = duration.match(/^(\d+(?:\.\d+)?)(ms|s|m)$/);
4072
+ if (!match) return 0;
4073
+ const value = parseFloat(match[1]);
4074
+ const unit = match[2];
4075
+ switch (unit) {
4076
+ case "ms":
4077
+ return value;
4078
+ case "s":
4079
+ return value * 1e3;
4080
+ case "m":
4081
+ return value * 60 * 1e3;
4082
+ default:
4083
+ return value;
4084
+ }
3656
4085
  }
4086
+ var VRTraitRegistry = class {
4087
+ constructor() {
4088
+ this.handlers = /* @__PURE__ */ new Map();
4089
+ this.register(grabbableHandler);
4090
+ this.register(throwableHandler);
4091
+ this.register(pointableHandler);
4092
+ this.register(hoverableHandler);
4093
+ this.register(scalableHandler);
4094
+ this.register(rotatableHandler);
4095
+ this.register(stackableHandler);
4096
+ this.register(snappableHandler);
4097
+ this.register(breakableHandler);
4098
+ this.register(proactiveHandler);
4099
+ }
4100
+ register(handler) {
4101
+ this.handlers.set(handler.name, handler);
4102
+ }
4103
+ getHandler(name) {
4104
+ return this.handlers.get(name);
4105
+ }
4106
+ attachTrait(node, traitName, config, context) {
4107
+ const handler = this.handlers.get(traitName);
4108
+ if (!handler) return;
4109
+ const mergedConfig = { ...handler.defaultConfig, ...config };
4110
+ node.traits.set(traitName, mergedConfig);
4111
+ if (handler.onAttach) {
4112
+ handler.onAttach(node, mergedConfig, context);
4113
+ }
4114
+ }
4115
+ detachTrait(node, traitName, context) {
4116
+ const handler = this.handlers.get(traitName);
4117
+ if (!handler) return;
4118
+ const config = node.traits.get(traitName);
4119
+ if (config && handler.onDetach) {
4120
+ handler.onDetach(node, config, context);
4121
+ }
4122
+ node.traits.delete(traitName);
4123
+ }
4124
+ updateTrait(node, traitName, context, delta) {
4125
+ const handler = this.handlers.get(traitName);
4126
+ if (!handler || !handler.onUpdate) return;
4127
+ const config = node.traits.get(traitName);
4128
+ if (config) {
4129
+ handler.onUpdate(node, config, context, delta);
4130
+ }
4131
+ }
4132
+ handleEvent(node, traitName, context, event) {
4133
+ const handler = this.handlers.get(traitName);
4134
+ if (!handler || !handler.onEvent) return;
4135
+ const config = node.traits.get(traitName);
4136
+ if (config) {
4137
+ handler.onEvent(node, config, context, event);
4138
+ }
4139
+ }
4140
+ updateAllTraits(node, context, delta) {
4141
+ for (const traitName of node.traits.keys()) {
4142
+ this.updateTrait(node, traitName, context, delta);
4143
+ }
4144
+ }
4145
+ handleEventForAllTraits(node, context, event) {
4146
+ for (const traitName of node.traits.keys()) {
4147
+ this.handleEvent(node, traitName, context, event);
4148
+ }
4149
+ }
4150
+ };
4151
+ var vrTraitRegistry = new VRTraitRegistry();
4152
+
4153
+ // src/runtime/HoloScriptPlusRuntime.ts
4154
+ var StateSync = class {
4155
+ constructor(_options) {
4156
+ }
4157
+ getInterpolatedState(_id) {
4158
+ return null;
4159
+ }
4160
+ };
3657
4161
  var HoloScriptPlusRuntimeImpl = class {
3658
4162
  constructor(ast, options = {}) {
3659
4163
  this.rootInstance = null;
@@ -3662,6 +4166,7 @@ var HoloScriptPlusRuntimeImpl = class {
3662
4166
  this.updateLoopId = null;
3663
4167
  this.lastUpdateTime = 0;
3664
4168
  this.mounted = false;
4169
+ this.scaleMultiplier = 1;
3665
4170
  // VR context
3666
4171
  this.vrContext = {
3667
4172
  hands: {
@@ -3677,12 +4182,15 @@ var HoloScriptPlusRuntimeImpl = class {
3677
4182
  right: null
3678
4183
  }
3679
4184
  };
4185
+ this.generatedNodes = /* @__PURE__ */ new Set();
4186
+ this.apiPollingTimers = /* @__PURE__ */ new Map();
3680
4187
  this.ast = ast;
3681
4188
  this.options = options;
3682
4189
  this.state = createState({});
3683
4190
  this.traitRegistry = vrTraitRegistry;
3684
4191
  this.companions = options.companions || {};
3685
4192
  this.builtins = createBuiltins(this);
4193
+ this.networkSync = new StateSync({ interpolation: true });
3686
4194
  this.evaluator = new ExpressionEvaluator(
3687
4195
  this.state.getSnapshot(),
3688
4196
  this.builtins
@@ -3951,6 +4459,20 @@ var HoloScriptPlusRuntimeImpl = class {
3951
4459
  if (instance.destroyed) return;
3952
4460
  const traitContext = this.createTraitContext(instance);
3953
4461
  this.traitRegistry.updateAllTraits(instance.node, traitContext, delta);
4462
+ if (instance.node.type === "avatar") {
4463
+ this.syncAvatarParts(instance);
4464
+ }
4465
+ if (instance.node.traits.has("networked")) {
4466
+ const interpolated = this.networkSync.getInterpolatedState(instance.node.id || "");
4467
+ if (interpolated) {
4468
+ if (interpolated.position) {
4469
+ instance.node.properties.position = [interpolated.position.x, interpolated.position.y, interpolated.position.z];
4470
+ }
4471
+ if (interpolated.rotation) {
4472
+ instance.node.properties.rotation = [interpolated.rotation.x, interpolated.rotation.y, interpolated.rotation.z];
4473
+ }
4474
+ }
4475
+ }
3954
4476
  if (this.options.renderer && instance.renderedNode) {
3955
4477
  const properties = this.evaluateProperties(instance.node.properties);
3956
4478
  this.options.renderer.updateElement(instance.renderedNode, properties);
@@ -3958,6 +4480,91 @@ var HoloScriptPlusRuntimeImpl = class {
3958
4480
  for (const child of instance.children) {
3959
4481
  this.updateInstance(child, delta);
3960
4482
  }
4483
+ this.updateExternalApis(instance, delta);
4484
+ this.processGenerateDirectives(instance);
4485
+ }
4486
+ syncAvatarParts(instance) {
4487
+ const vrHands = this.vrContext.hands;
4488
+ const vrHead = this.vrContext.headset;
4489
+ if (instance.node.id === "local_player") {
4490
+ instance.node.properties.position = vrHead.position;
4491
+ instance.node.properties.rotation = vrHead.rotation;
4492
+ instance.children.forEach((child) => {
4493
+ if (child.node.id === "left_hand" && vrHands.left) {
4494
+ child.node.properties.position = vrHands.left.position;
4495
+ child.node.properties.rotation = vrHands.left.rotation;
4496
+ } else if (child.node.id === "right_hand" && vrHands.right) {
4497
+ child.node.properties.position = vrHands.right.position;
4498
+ child.node.properties.rotation = vrHands.right.rotation;
4499
+ }
4500
+ });
4501
+ if (instance.node.traits.has("networked")) {
4502
+ this.emit("network_snapshot", {
4503
+ objectId: instance.node.id,
4504
+ position: { x: vrHead.position[0], y: vrHead.position[1], z: vrHead.position[2] },
4505
+ rotation: { x: vrHead.rotation[0], y: vrHead.rotation[1], z: vrHead.rotation[2] },
4506
+ timestamp: Date.now()
4507
+ });
4508
+ }
4509
+ }
4510
+ }
4511
+ processGenerateDirectives(instance) {
4512
+ const generateDirectives = instance.node.directives.filter((d) => d.type === "generate");
4513
+ for (const d of generateDirectives) {
4514
+ const directive = d;
4515
+ const genId = `${instance.node.id || "node"}_${directive.prompt.substring(0, 10)}`;
4516
+ if (this.generatedNodes.has(genId)) continue;
4517
+ console.log(`[Generate] AI Bridge Request: "${directive.prompt}"`);
4518
+ this.emit("generate_request", {
4519
+ id: genId,
4520
+ nodeId: instance.node.id,
4521
+ prompt: directive.prompt,
4522
+ context: directive.context,
4523
+ target: directive.target || "children"
4524
+ });
4525
+ this.generatedNodes.add(genId);
4526
+ }
4527
+ }
4528
+ updateExternalApis(instance, _delta) {
4529
+ const apiDirectives = instance.node.directives.filter((d) => d.type === "external_api");
4530
+ for (const d of apiDirectives) {
4531
+ const directive = d;
4532
+ if (directive.type !== "external_api") continue;
4533
+ const intervalStr = directive.interval || "0s";
4534
+ const intervalMs = this.parseDurationToMs(intervalStr);
4535
+ if (intervalMs <= 0) continue;
4536
+ let lastTime = this.apiPollingTimers.get(instance) || 0;
4537
+ const now = performance.now();
4538
+ if (now - lastTime >= intervalMs) {
4539
+ this.apiPollingTimers.set(instance, now);
4540
+ this.executeExternalApi(instance, directive);
4541
+ }
4542
+ }
4543
+ }
4544
+ async executeExternalApi(instance, directive) {
4545
+ try {
4546
+ const data = await this.builtins.api_call(directive.url, directive.method || "GET");
4547
+ this.state.set("api_data", data);
4548
+ this.updateData(data);
4549
+ } catch (error) {
4550
+ console.error(`External API error for ${directive.url}:`, error);
4551
+ }
4552
+ }
4553
+ parseDurationToMs(duration) {
4554
+ const match = duration.match(/^(\d+)(ms|s|m)$/);
4555
+ if (!match) return 0;
4556
+ const value = parseInt(match[1], 10);
4557
+ const unit = match[2];
4558
+ switch (unit) {
4559
+ case "ms":
4560
+ return value;
4561
+ case "s":
4562
+ return value * 1e3;
4563
+ case "m":
4564
+ return value * 6e4;
4565
+ default:
4566
+ return 0;
4567
+ }
3961
4568
  }
3962
4569
  // ==========================================================================
3963
4570
  // TRAIT CONTEXT
@@ -4007,7 +4614,22 @@ var HoloScriptPlusRuntimeImpl = class {
4007
4614
  },
4008
4615
  emit: this.emit.bind(this),
4009
4616
  getState: () => this.state.getSnapshot(),
4010
- setState: (updates) => this.state.update(updates)
4617
+ setState: (updates) => this.state.update(updates),
4618
+ getScaleMultiplier: () => this.scaleMultiplier,
4619
+ setScaleContext: (magnitude) => {
4620
+ const multipliers = {
4621
+ "galactic": 1e6,
4622
+ "macro": 1e3,
4623
+ "standard": 1,
4624
+ "micro": 1e-3,
4625
+ "atomic": 1e-6
4626
+ };
4627
+ const newMultiplier = multipliers[magnitude] || 1;
4628
+ if (this.scaleMultiplier !== newMultiplier) {
4629
+ this.scaleMultiplier = newMultiplier;
4630
+ this.emit("scale_change", { magnitude, multiplier: newMultiplier });
4631
+ }
4632
+ }
4011
4633
  };
4012
4634
  }
4013
4635
  // ==========================================================================
@@ -4039,6 +4661,54 @@ var HoloScriptPlusRuntimeImpl = class {
4039
4661
  getState() {
4040
4662
  return this.state.getSnapshot();
4041
4663
  }
4664
+ // ==========================================================================
4665
+ // COMPATIBILITY METHODS
4666
+ // ==========================================================================
4667
+ getVariable(name) {
4668
+ return this.state.get(name);
4669
+ }
4670
+ setVariable(name, value) {
4671
+ this.state.set(name, value);
4672
+ }
4673
+ getContext() {
4674
+ const spatialMemory = /* @__PURE__ */ new Map();
4675
+ const hologramState = /* @__PURE__ */ new Map();
4676
+ const traverse = (instance) => {
4677
+ if (instance.node.id) {
4678
+ spatialMemory.set(instance.node.id, instance.node.properties.position || { x: 0, y: 0, z: 0 });
4679
+ hologramState.set(instance.node.id, {
4680
+ shape: instance.node.properties.shape || instance.node.type,
4681
+ color: instance.node.properties.color,
4682
+ size: instance.node.properties.size,
4683
+ glow: instance.node.properties.glow,
4684
+ interactive: instance.node.properties.interactive
4685
+ });
4686
+ }
4687
+ instance.children.forEach(traverse);
4688
+ };
4689
+ if (this.rootInstance) traverse(this.rootInstance);
4690
+ return {
4691
+ spatialMemory,
4692
+ hologramState,
4693
+ state: this.state,
4694
+ builtins: this.builtins,
4695
+ vr: this.vrContext
4696
+ };
4697
+ }
4698
+ reset() {
4699
+ this.unmount();
4700
+ this.state = createState({});
4701
+ this.mounted = false;
4702
+ }
4703
+ updateAnimations() {
4704
+ this.update(1 / 60);
4705
+ }
4706
+ updateParticles(delta) {
4707
+ this.update(delta);
4708
+ }
4709
+ getHologramStates() {
4710
+ return this.getContext().hologramState;
4711
+ }
4042
4712
  setState(updates) {
4043
4713
  this.state.update(updates);
4044
4714
  }
@@ -4054,6 +4724,22 @@ var HoloScriptPlusRuntimeImpl = class {
4054
4724
  });
4055
4725
  }
4056
4726
  }
4727
+ updateEntity(id, properties) {
4728
+ if (!this.rootInstance) return false;
4729
+ let found = false;
4730
+ const traverse = (instance) => {
4731
+ if (instance.node.id === id) {
4732
+ instance.node.properties = { ...instance.node.properties, ...properties };
4733
+ if (this.options.renderer && instance.renderedNode) {
4734
+ this.options.renderer.updateElement(instance.renderedNode, properties);
4735
+ }
4736
+ found = true;
4737
+ }
4738
+ instance.children.forEach(traverse);
4739
+ };
4740
+ traverse(this.rootInstance);
4741
+ return found;
4742
+ }
4057
4743
  on(event, handler) {
4058
4744
  if (!this.eventHandlers.has(event)) {
4059
4745
  this.eventHandlers.set(event, /* @__PURE__ */ new Set());
@@ -4139,6 +4825,114 @@ var HoloScriptPlusRuntimeImpl = class {
4139
4825
  this.destroyInstance(instance);
4140
4826
  }
4141
4827
  };
4828
+ function createBuiltins(runtime) {
4829
+ return {
4830
+ Math,
4831
+ range: (start, end, step = 1) => {
4832
+ const result = [];
4833
+ if (step > 0) {
4834
+ for (let i = start; i < end; i += step) {
4835
+ result.push(i);
4836
+ }
4837
+ } else if (step < 0) {
4838
+ for (let i = start; i > end; i += step) {
4839
+ result.push(i);
4840
+ }
4841
+ }
4842
+ return result;
4843
+ },
4844
+ interpolate_color: (t, from, to) => {
4845
+ const parseHex = (hex) => {
4846
+ const clean = hex.replace("#", "");
4847
+ return [
4848
+ parseInt(clean.substring(0, 2), 16),
4849
+ parseInt(clean.substring(2, 4), 16),
4850
+ parseInt(clean.substring(4, 6), 16)
4851
+ ];
4852
+ };
4853
+ const toHex = (r, g, b) => {
4854
+ const clamp = (v) => Math.max(0, Math.min(255, Math.round(v)));
4855
+ return `#${clamp(r).toString(16).padStart(2, "0")}${clamp(g).toString(16).padStart(2, "0")}${clamp(b).toString(16).padStart(2, "0")}`;
4856
+ };
4857
+ const [r1, g1, b1] = parseHex(from);
4858
+ const [r2, g2, b2] = parseHex(to);
4859
+ return toHex(
4860
+ r1 + (r2 - r1) * t,
4861
+ g1 + (g2 - g1) * t,
4862
+ b1 + (b2 - b1) * t
4863
+ );
4864
+ },
4865
+ distance_to: (point) => {
4866
+ const viewer = runtime.vrContext.headset.position;
4867
+ return Math.sqrt(
4868
+ Math.pow(point[0] - viewer[0], 2) + Math.pow(point[1] - viewer[1], 2) + Math.pow(point[2] - viewer[2], 2)
4869
+ );
4870
+ },
4871
+ distance_to_viewer: () => {
4872
+ return 0;
4873
+ },
4874
+ hand_position: (handId) => {
4875
+ const hand = handId === "left" ? runtime.vrContext.hands.left : runtime.vrContext.hands.right;
4876
+ return hand?.position || [0, 0, 0];
4877
+ },
4878
+ hand_velocity: (handId) => {
4879
+ const hand = handId === "left" ? runtime.vrContext.hands.left : runtime.vrContext.hands.right;
4880
+ return hand?.velocity || [0, 0, 0];
4881
+ },
4882
+ dominant_hand: () => {
4883
+ return runtime.vrContext.hands.right || runtime.vrContext.hands.left || {
4884
+ id: "right",
4885
+ position: [0, 0, 0],
4886
+ rotation: [0, 0, 0],
4887
+ velocity: [0, 0, 0],
4888
+ grip: 0,
4889
+ trigger: 0
4890
+ };
4891
+ },
4892
+ play_sound: (source, options) => {
4893
+ runtime.emit("play_sound", { source, ...options });
4894
+ },
4895
+ haptic_feedback: (hand, intensity) => {
4896
+ const handId = typeof hand === "string" ? hand : hand.id;
4897
+ runtime.emit("haptic", { hand: handId, intensity });
4898
+ },
4899
+ haptic_pulse: (intensity) => {
4900
+ runtime.emit("haptic", { hand: "both", intensity });
4901
+ },
4902
+ apply_velocity: (node, velocity) => {
4903
+ runtime.emit("apply_velocity", { node, velocity });
4904
+ },
4905
+ spawn: (template, position) => {
4906
+ return runtime.spawnTemplate(template, position);
4907
+ },
4908
+ assistant_generate: (prompt, context) => {
4909
+ runtime.emit("assistant_generate", { prompt, context });
4910
+ },
4911
+ destroy: (node) => {
4912
+ runtime.destroyNode(node);
4913
+ },
4914
+ api_call: async (url, method, body) => {
4915
+ const response = await fetch(url, {
4916
+ method,
4917
+ headers: body ? { "Content-Type": "application/json" } : void 0,
4918
+ body: body ? JSON.stringify(body) : void 0
4919
+ });
4920
+ return response.json();
4921
+ },
4922
+ open_modal: (modalId) => {
4923
+ runtime.emit("open_modal", { id: modalId });
4924
+ },
4925
+ close_modal: (modalId) => {
4926
+ runtime.emit("close_modal", { id: modalId });
4927
+ },
4928
+ setTimeout: (callback, delay) => {
4929
+ return window.setTimeout(callback, delay);
4930
+ },
4931
+ clearTimeout: (id) => {
4932
+ window.clearTimeout(id);
4933
+ }
4934
+ };
4935
+ }
4142
4936
 
4143
4937
  // src/traits/VoiceInputTrait.ts
4144
4938
  var VoiceInputTrait = class {
@@ -4681,11 +5475,6 @@ function createAIDriverTrait(config) {
4681
5475
  return new AIDriverTrait(config);
4682
5476
  }
4683
5477
 
4684
- // src/index.ts
4685
- init_MaterialTrait();
4686
- init_LightingTrait();
4687
- init_RenderingTrait();
4688
-
4689
5478
  // src/runtime/PerformanceTelemetry.ts
4690
5479
  var PerformanceTelemetry = class {
4691
5480
  // Export every 10s
@@ -5921,6 +6710,6 @@ function isHoloScriptSupported() {
5921
6710
  return !!(win.window.navigator?.xr || win.window.navigator?.getVRDisplays || win.window.webkitGetUserMedia);
5922
6711
  }
5923
6712
 
5924
- export { AIDriverTrait, BehaviorTreeRunner, GOAPPlanner, HOLOSCRIPT_DEMO_SCRIPTS, HOLOSCRIPT_GESTURES, HOLOSCRIPT_SUPPORTED_PLATFORMS, HOLOSCRIPT_VERSION, HOLOSCRIPT_VOICE_COMMANDS, HoloScript2DParser, HoloScriptParser, HoloScriptPlusParser, HoloScriptPlusRuntimeImpl, HoloScriptPlusParser2 as HoloScriptTraitAnnotationParser, HololandGraphicsPipelineService, LIGHTING_PRESETS, LightingTrait, MATERIAL_PRESETS, MaterialTrait, PerformanceTelemetry, PlatformPerformanceOptimizer, ReactiveState, RenderingTrait, VRTraitRegistry, VoiceInputTrait, bind, computed, createAIDriverTrait, createHoloScriptEnvironment, createLightingTrait, createMaterialTrait, createParser, createRenderingTrait, createState, createVoiceInputTrait, effect, getPerformanceTelemetry, isHoloScriptSupported, parse as parseHoloScriptPlus, reactive };
6713
+ export { AIDriverTrait, BehaviorTreeRunner, GOAPPlanner, HOLOSCRIPT_DEMO_SCRIPTS, HOLOSCRIPT_GESTURES, HOLOSCRIPT_SUPPORTED_PLATFORMS, HOLOSCRIPT_VERSION, HOLOSCRIPT_VOICE_COMMANDS, HoloScript2DParser, HoloScriptParser, HoloScriptPlusParser, HoloScriptPlusRuntimeImpl, HoloScriptPlusParser2 as HoloScriptTraitAnnotationParser, HoloScriptValidator, HololandGraphicsPipelineService, LIFECYCLE_HOOKS, LIGHTING_PRESETS, LightingTrait, MATERIAL_PRESETS, MaterialTrait, PerformanceTelemetry, PlatformPerformanceOptimizer, ReactiveState, RenderingTrait, VRTraitRegistry, VR_TRAITS, VoiceInputTrait, bind, computed, createAIDriverTrait, createHoloScriptEnvironment, createLightingTrait, createMaterialTrait, createParser, createRenderingTrait, createState, createVoiceInputTrait, effect, getPerformanceTelemetry, isHoloScriptSupported, parse as parseHoloScriptPlus, reactive };
5925
6714
  //# sourceMappingURL=index.js.map
5926
6715
  //# sourceMappingURL=index.js.map