@holoscript/core 1.0.0-alpha.2 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/package.json +2 -2
  2. package/src/HoloScript2DParser.js +227 -0
  3. package/src/HoloScript2DParser.ts +5 -0
  4. package/src/HoloScriptCodeParser.js +1102 -0
  5. package/src/HoloScriptCodeParser.ts +145 -20
  6. package/src/HoloScriptDebugger.js +458 -0
  7. package/src/HoloScriptParser.js +338 -0
  8. package/src/HoloScriptPlusParser.js +371 -0
  9. package/src/HoloScriptPlusParser.ts +543 -0
  10. package/src/HoloScriptRuntime.js +1399 -0
  11. package/src/HoloScriptRuntime.test.js +351 -0
  12. package/src/HoloScriptRuntime.ts +17 -3
  13. package/src/HoloScriptTypeChecker.js +356 -0
  14. package/src/__tests__/GraphicsServices.test.js +357 -0
  15. package/src/__tests__/GraphicsServices.test.ts +427 -0
  16. package/src/__tests__/HoloScriptPlusParser.test.js +317 -0
  17. package/src/__tests__/HoloScriptPlusParser.test.ts +392 -0
  18. package/src/__tests__/integration.test.js +336 -0
  19. package/src/__tests__/performance.bench.js +218 -0
  20. package/src/__tests__/type-checker.test.js +60 -0
  21. package/src/__tests__/type-checker.test.ts +73 -0
  22. package/src/index.js +217 -0
  23. package/src/index.ts +158 -18
  24. package/src/interop/Interoperability.js +413 -0
  25. package/src/interop/Interoperability.ts +494 -0
  26. package/src/logger.js +42 -0
  27. package/src/parser/EnhancedParser.js +205 -0
  28. package/src/parser/EnhancedParser.ts +251 -0
  29. package/src/parser/HoloScriptPlusParser.js +928 -0
  30. package/src/parser/HoloScriptPlusParser.ts +1089 -0
  31. package/src/runtime/HoloScriptPlusRuntime.js +674 -0
  32. package/src/runtime/HoloScriptPlusRuntime.ts +861 -0
  33. package/src/runtime/PerformanceTelemetry.js +323 -0
  34. package/src/runtime/PerformanceTelemetry.ts +467 -0
  35. package/src/runtime/RuntimeOptimization.js +361 -0
  36. package/src/runtime/RuntimeOptimization.ts +416 -0
  37. package/src/services/HololandGraphicsPipelineService.js +506 -0
  38. package/src/services/HololandGraphicsPipelineService.ts +662 -0
  39. package/src/services/PlatformPerformanceOptimizer.js +356 -0
  40. package/src/services/PlatformPerformanceOptimizer.ts +503 -0
  41. package/src/state/ReactiveState.js +427 -0
  42. package/src/state/ReactiveState.ts +572 -0
  43. package/src/tools/DeveloperExperience.js +376 -0
  44. package/src/tools/DeveloperExperience.ts +438 -0
  45. package/src/traits/AIDriverTrait.js +322 -0
  46. package/src/traits/AIDriverTrait.test.js +329 -0
  47. package/src/traits/AIDriverTrait.test.ts +357 -0
  48. package/src/traits/AIDriverTrait.ts +474 -0
  49. package/src/traits/LightingTrait.js +313 -0
  50. package/src/traits/LightingTrait.test.js +410 -0
  51. package/src/traits/LightingTrait.test.ts +462 -0
  52. package/src/traits/LightingTrait.ts +505 -0
  53. package/src/traits/MaterialTrait.js +194 -0
  54. package/src/traits/MaterialTrait.test.js +286 -0
  55. package/src/traits/MaterialTrait.test.ts +329 -0
  56. package/src/traits/MaterialTrait.ts +324 -0
  57. package/src/traits/RenderingTrait.js +356 -0
  58. package/src/traits/RenderingTrait.test.js +363 -0
  59. package/src/traits/RenderingTrait.test.ts +427 -0
  60. package/src/traits/RenderingTrait.ts +555 -0
  61. package/src/traits/VRTraitSystem.js +740 -0
  62. package/src/traits/VRTraitSystem.ts +1040 -0
  63. package/src/traits/VoiceInputTrait.js +284 -0
  64. package/src/traits/VoiceInputTrait.test.js +226 -0
  65. package/src/traits/VoiceInputTrait.test.ts +252 -0
  66. package/src/traits/VoiceInputTrait.ts +401 -0
  67. package/src/types/AdvancedTypeSystem.js +226 -0
  68. package/src/types/AdvancedTypeSystem.ts +494 -0
  69. package/src/types/HoloScriptPlus.d.ts +853 -0
  70. package/src/types.js +6 -0
  71. package/src/types.ts +96 -1
  72. package/tsconfig.json +1 -1
  73. package/tsup.config.d.ts +2 -0
  74. package/tsup.config.js +18 -0
@@ -0,0 +1,474 @@
1
+ /**
2
+ * @holoscript/core AI-Driven NPC Trait
3
+ *
4
+ * Enables intelligent NPC behaviors using behavior trees and goal planning
5
+ * Integrates with Infinity Assistant service for agent-based decision making
6
+ */
7
+
8
+ export type BehaviorState = 'idle' | 'moving' | 'acting' | 'talking' | 'reacting';
9
+ export type DecisionMode = 'reactive' | 'goal-driven' | 'learning' | 'hybrid';
10
+
11
+ /**
12
+ * Behavior tree node
13
+ */
14
+ export interface BehaviorNode {
15
+ id: string;
16
+ type: 'sequence' | 'selector' | 'parallel' | 'action' | 'condition';
17
+ children?: BehaviorNode[];
18
+ action?: (context: NPCContext) => Promise<boolean>;
19
+ condition?: (context: NPCContext) => boolean;
20
+ metadata?: Record<string, unknown>;
21
+ }
22
+
23
+ /**
24
+ * NPC Context for behavior execution
25
+ */
26
+ export interface NPCContext {
27
+ npcId: string;
28
+ position: [number, number, number];
29
+ rotation: [number, number, number];
30
+ targetId?: string;
31
+ targetPosition?: [number, number, number];
32
+ memory: Map<string, unknown>;
33
+ state: BehaviorState;
34
+ energy: number; // 0-1
35
+ mood: number; // -1 to 1 (negative = sad, positive = happy)
36
+ perception: {
37
+ nearbyEntities: string[];
38
+ visibleEntities: string[];
39
+ hearableVoice?: string;
40
+ };
41
+ dialogue?: {
42
+ lastSaid?: string;
43
+ lastHeard?: string;
44
+ conversationHistory: Array<{ speaker: string; text: string }>;
45
+ };
46
+ }
47
+
48
+ /**
49
+ * Goal for GOAP-style planning
50
+ */
51
+ export interface NPCGoal {
52
+ id: string;
53
+ name: string;
54
+ priority: number; // 0-1
55
+ preconditions: Map<string, unknown>;
56
+ effects: Map<string, unknown>;
57
+ cost: number;
58
+ timeoutMs?: number;
59
+ }
60
+
61
+ /**
62
+ * AI-Driven NPC configuration
63
+ */
64
+ export interface AIDriverConfig {
65
+ /** NPC identifier */
66
+ npcId: string;
67
+
68
+ /** Decision making mode */
69
+ decisionMode: DecisionMode;
70
+
71
+ /** Base behavior tree */
72
+ behaviorTree?: BehaviorNode;
73
+
74
+ /** Available goals */
75
+ goals?: NPCGoal[];
76
+
77
+ /** Personality traits */
78
+ personality?: {
79
+ sociability: number; // 0-1
80
+ aggression: number; // 0-1
81
+ curiosity: number; // 0-1
82
+ loyalty: number; // 0-1
83
+ };
84
+
85
+ /** Response to stimuli */
86
+ stimuliThresholds?: {
87
+ hearing: number; // perception distance
88
+ sight: number; // vision distance
89
+ touch: number; // collision distance
90
+ };
91
+
92
+ /** Learning config */
93
+ enableLearning?: boolean;
94
+ learningRate?: number;
95
+
96
+ /** Infinity Assistant integration */
97
+ agentId?: string;
98
+ }
99
+
100
+ /**
101
+ * Behavior tree runner
102
+ */
103
+ export class BehaviorTreeRunner {
104
+ private rootNode: BehaviorNode;
105
+
106
+ constructor(rootNode: BehaviorNode) {
107
+ this.rootNode = rootNode;
108
+ }
109
+
110
+ async tick(context: NPCContext): Promise<boolean> {
111
+ return this.executeNode(this.rootNode, context);
112
+ }
113
+
114
+ private async executeNode(
115
+ node: BehaviorNode,
116
+ context: NPCContext
117
+ ): Promise<boolean> {
118
+ if (node.type === 'action') {
119
+ if (node.action) {
120
+ try {
121
+ return await node.action(context);
122
+ } catch (error) {
123
+ console.error(`Action failed: ${node.id}`, error);
124
+ return false;
125
+ }
126
+ }
127
+ return true;
128
+ }
129
+
130
+ if (node.type === 'condition') {
131
+ return node.condition ? node.condition(context) : true;
132
+ }
133
+
134
+ if (node.type === 'sequence') {
135
+ for (const child of node.children || []) {
136
+ const result = await this.executeNode(child, context);
137
+ if (!result) return false;
138
+ }
139
+ return true;
140
+ }
141
+
142
+ if (node.type === 'selector') {
143
+ for (const child of node.children || []) {
144
+ const result = await this.executeNode(child, context);
145
+ if (result) return true;
146
+ }
147
+ return false;
148
+ }
149
+
150
+ if (node.type === 'parallel') {
151
+ const results = await Promise.all(
152
+ (node.children || []).map((child) => this.executeNode(child, context))
153
+ );
154
+ return results.every((r) => r);
155
+ }
156
+
157
+ return true;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Goal-Oriented Action Planning (GOAP)
163
+ */
164
+ export class GOAPPlanner {
165
+ private goals: NPCGoal[];
166
+
167
+ constructor(goals: NPCGoal[]) {
168
+ this.goals = goals.sort((a, b) => b.priority - a.priority);
169
+ }
170
+
171
+ /**
172
+ * Plan a sequence of actions to reach goal
173
+ */
174
+ planGoal(currentState: Map<string, unknown>, _goal: NPCGoal): NPCGoal[] {
175
+ // Simple greedy planner: select highest-priority achievable goal
176
+ for (const g of this.goals) {
177
+ if (this.canAchieve(currentState, g)) {
178
+ return [g];
179
+ }
180
+ }
181
+ return [];
182
+ }
183
+
184
+ private canAchieve(
185
+ currentState: Map<string, unknown>,
186
+ goal: NPCGoal
187
+ ): boolean {
188
+ for (const [key, value] of goal.preconditions) {
189
+ if (currentState.get(key) !== value) {
190
+ return false;
191
+ }
192
+ }
193
+ return true;
194
+ }
195
+ }
196
+
197
+ /**
198
+ * AIDriverTrait - Enables intelligent NPC behaviors
199
+ */
200
+ export class AIDriverTrait {
201
+ private config: AIDriverConfig;
202
+ private context: NPCContext;
203
+ private behaviorRunner: BehaviorTreeRunner | null = null;
204
+ private goapPlanner: GOAPPlanner | null = null;
205
+ private updateInterval: ReturnType<typeof setInterval> | null = null;
206
+ private learningModel: Map<string, number> = new Map();
207
+
208
+ constructor(config: AIDriverConfig) {
209
+ const defaults = {
210
+ decisionMode: 'hybrid' as const,
211
+ personality: {
212
+ sociability: 0.5,
213
+ aggression: 0.3,
214
+ curiosity: 0.6,
215
+ loyalty: 0.7,
216
+ },
217
+ stimuliThresholds: {
218
+ hearing: 50,
219
+ sight: 100,
220
+ touch: 5,
221
+ },
222
+ enableLearning: true,
223
+ learningRate: 0.1,
224
+ };
225
+ this.config = { ...defaults, ...config };
226
+
227
+ this.context = {
228
+ npcId: config.npcId,
229
+ position: [0, 0, 0],
230
+ rotation: [0, 0, 0],
231
+ memory: new Map(),
232
+ state: 'idle',
233
+ energy: 1.0,
234
+ mood: 0,
235
+ perception: {
236
+ nearbyEntities: [],
237
+ visibleEntities: [],
238
+ },
239
+ };
240
+
241
+ if (config.behaviorTree) {
242
+ this.behaviorRunner = new BehaviorTreeRunner(config.behaviorTree);
243
+ }
244
+
245
+ if (config.goals && config.goals.length > 0) {
246
+ this.goapPlanner = new GOAPPlanner(config.goals);
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Start NPC AI loop
252
+ */
253
+ public startAI(): void {
254
+ if (this.updateInterval) return;
255
+
256
+ this.updateInterval = setInterval(() => {
257
+ this.tick();
258
+ }, 100); // 10 Hz update rate
259
+ }
260
+
261
+ /**
262
+ * Stop NPC AI loop
263
+ */
264
+ public stopAI(): void {
265
+ if (this.updateInterval) {
266
+ clearInterval(this.updateInterval);
267
+ this.updateInterval = null;
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Main AI tick
273
+ */
274
+ private async tick(): Promise<void> {
275
+ // Update energy (decreases over time)
276
+ this.context.energy = Math.max(0, this.context.energy - 0.001);
277
+
278
+ // Stress/mood changes
279
+ if (this.context.perception.visibleEntities.length > 0) {
280
+ this.context.mood += 0.1 * (Math.random() - 0.5);
281
+ }
282
+
283
+ // Execute appropriate decision mode
284
+ switch (this.config.decisionMode) {
285
+ case 'reactive':
286
+ await this.reactiveDecision();
287
+ break;
288
+ case 'goal-driven':
289
+ await this.goalDrivenDecision();
290
+ break;
291
+ case 'learning':
292
+ await this.learningDecision();
293
+ break;
294
+ case 'hybrid':
295
+ await this.hybridDecision();
296
+ break;
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Reactive decision: immediate response to stimuli
302
+ */
303
+ private async reactiveDecision(): Promise<void> {
304
+ if (this.behaviorRunner) {
305
+ await this.behaviorRunner.tick(this.context);
306
+ }
307
+ }
308
+
309
+ /**
310
+ * Goal-driven decision: plan towards objectives
311
+ */
312
+ private async goalDrivenDecision(): Promise<void> {
313
+ if (!this.goapPlanner) return;
314
+
315
+ const worldState = this.buildWorldState();
316
+ // Select highest priority goal
317
+ const plan = this.goapPlanner.planGoal(
318
+ worldState,
319
+ this.config.goals?.[0] || { id: 'idle', name: 'Idle', priority: 0, preconditions: new Map(), effects: new Map(), cost: 0 }
320
+ );
321
+
322
+ if (plan.length > 0) {
323
+ // Execute plan
324
+ this.context.state = 'moving';
325
+ }
326
+ }
327
+
328
+ /**
329
+ * Learning decision: adapt behavior from experience
330
+ */
331
+ private async learningDecision(): Promise<void> {
332
+ // Composite reactive + learning
333
+ await this.reactiveDecision();
334
+
335
+ // Learn from interactions
336
+ if (this.config.enableLearning) {
337
+ this.updateLearningModel();
338
+ }
339
+ }
340
+
341
+ /**
342
+ * Hybrid decision: combination of reactive and goal-driven
343
+ */
344
+ private async hybridDecision(): Promise<void> {
345
+ // Execute behavior tree (reactive)
346
+ if (this.behaviorRunner) {
347
+ const treeResult = await this.behaviorRunner.tick(this.context);
348
+
349
+ // If no immediate action, pursue goals
350
+ if (!treeResult && this.goapPlanner) {
351
+ await this.goalDrivenDecision();
352
+ }
353
+ }
354
+ }
355
+
356
+ /**
357
+ * Build world state for planning
358
+ */
359
+ private buildWorldState(): Map<string, unknown> {
360
+ const state = new Map<string, unknown>();
361
+ state.set('position', this.context.position);
362
+ state.set('energy', this.context.energy);
363
+ state.set('mood', this.context.mood);
364
+ state.set('nearbyEntities', this.context.perception.nearbyEntities.length);
365
+ return state;
366
+ }
367
+
368
+ /**
369
+ * Update learning model from interactions
370
+ */
371
+ private updateLearningModel(): void {
372
+ // Simple Q-learning-like update
373
+ const currentReward = this.calculateReward();
374
+ const learningRate = this.config.learningRate || 0.1;
375
+
376
+ // Update learned value estimates
377
+ const stateKey = `state_${this.context.state}`;
378
+ const currentValue = this.learningModel.get(stateKey) || 0;
379
+ const newValue = currentValue + learningRate * (currentReward - currentValue);
380
+ this.learningModel.set(stateKey, newValue);
381
+ }
382
+
383
+ /**
384
+ * Calculate immediate reward
385
+ */
386
+ private calculateReward(): number {
387
+ let reward = 0;
388
+
389
+ // Reward based on energy maintenance
390
+ if (this.context.energy > 0.5) reward += 1;
391
+
392
+ // Reward based on social interaction (if sociable)
393
+ if (
394
+ this.config.personality?.sociability || 0 > 0.5 &&
395
+ this.context.perception.nearbyEntities.length > 0
396
+ ) {
397
+ reward += 1;
398
+ }
399
+
400
+ // Reward based on goal progress
401
+ if (this.context.state !== 'idle') reward += 0.5;
402
+
403
+ return reward;
404
+ }
405
+
406
+ /**
407
+ * Set NPC position
408
+ */
409
+ public setPosition(position: [number, number, number]): void {
410
+ this.context.position = position;
411
+ }
412
+
413
+ /**
414
+ * Update perception (nearby entities, visible targets)
415
+ */
416
+ public updatePerception(
417
+ nearbyEntities: string[],
418
+ visibleEntities: string[]
419
+ ): void {
420
+ this.context.perception.nearbyEntities = nearbyEntities;
421
+ this.context.perception.visibleEntities = visibleEntities;
422
+ }
423
+
424
+ /**
425
+ * Add dialogue to conversation history
426
+ */
427
+ public speak(text: string): void {
428
+ if (!this.context.dialogue) {
429
+ this.context.dialogue = { conversationHistory: [] };
430
+ }
431
+ this.context.dialogue.lastSaid = text;
432
+ this.context.dialogue.conversationHistory.push({
433
+ speaker: this.config.npcId,
434
+ text,
435
+ });
436
+ }
437
+
438
+ /**
439
+ * Receive dialogue from another entity
440
+ */
441
+ public hear(speaker: string, text: string): void {
442
+ if (!this.context.dialogue) {
443
+ this.context.dialogue = { conversationHistory: [] };
444
+ }
445
+ this.context.dialogue.lastHeard = text;
446
+ this.context.dialogue.conversationHistory.push({
447
+ speaker,
448
+ text,
449
+ });
450
+ }
451
+
452
+ /**
453
+ * Get current NPC context
454
+ */
455
+ public getContext(): Readonly<NPCContext> {
456
+ return { ...this.context };
457
+ }
458
+
459
+ /**
460
+ * Dispose and cleanup
461
+ */
462
+ public dispose(): void {
463
+ this.stopAI();
464
+ this.context.memory.clear();
465
+ this.learningModel.clear();
466
+ }
467
+ }
468
+
469
+ /**
470
+ * HoloScript+ @ai_driven trait factory
471
+ */
472
+ export function createAIDriverTrait(config: AIDriverConfig): AIDriverTrait {
473
+ return new AIDriverTrait(config);
474
+ }