@zcomponent/core 2.0.0-alpha.4 → 2.0.0-alpha.5

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 (2) hide show
  1. package/package.json +2 -1
  2. package/prompt.md +611 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zcomponent/core",
3
- "version": "2.0.0-alpha.4",
3
+ "version": "2.0.0-alpha.5",
4
4
  "description": "The core component model and built-in functionality for Mattercraft.",
5
5
  "author": "Zappar Limited",
6
6
  "license": "Proprietary",
@@ -39,6 +39,7 @@
39
39
  "files": [
40
40
  "index.js",
41
41
  "index.d.ts",
42
+ "prompt.md",
42
43
  "lib/**/*",
43
44
  "css/**/*",
44
45
  "assets/**/*"
package/prompt.md ADDED
@@ -0,0 +1,611 @@
1
+ # Scripting
2
+
3
+ ## Component and Behavior Registration
4
+
5
+ Components and behaviors are registered using class decorators that provide metadata to the Mattercraft editor:
6
+
7
+ ```typescript
8
+ @zComponent({
9
+ icon: 'music_note',
10
+ group: 'Media',
11
+ tags: ['core/audio'],
12
+ })
13
+ export class Audio extends Component<undefined, AudioConstructorProps> {
14
+ // Component implementation
15
+ }
16
+ ```
17
+
18
+ ```typescript
19
+ @zBehavior({
20
+ icon: 'volume_up',
21
+ group: BehaviorGroups.Actions,
22
+ runAtDesignTime: true,
23
+ })
24
+ export class PlaySound extends ActionBehavior<PlaySoundProps> {
25
+ // Behavior implementation
26
+ }
27
+ ```
28
+
29
+ **Registration Options:**
30
+
31
+ - `icon`: Material Design icon name for the component/behavior
32
+ - `group`: Category grouping in the Mattercraft UI
33
+ - `tags`: Array of tags for search and categorization
34
+ - `parents`: Array of parent tags or glob patterns that limit where the entity can be created
35
+ - `runAtDesignTime`: (Behaviors only) Whether to execute in the editor
36
+
37
+ ## Property Configuration with Decorators
38
+
39
+ ### @zUI() - UI Customization and Actions
40
+
41
+ Public properties are visible in the Mattercraft UI by default. Use `@zUI()` to customize how a property is presented, or to expose an event or method as a UI action:
42
+
43
+ ```typescript
44
+ public volume = 1;
45
+
46
+ @zUI({ group: 'Audio', priority: 20, type: 'proportion' })
47
+ public gain = 0.8;
48
+
49
+ @zUI()
50
+ public play() {
51
+ // Play implementation
52
+ }
53
+ ```
54
+
55
+ **Configuration Options:**
56
+
57
+ - `group`: Groups properties under a header in the UI
58
+ - `priority`: Determines display order (higher values appear first)
59
+ - `type`: Specifies the UI widget type
60
+ - `values`: Constrains values to specific types (see Values section)
61
+
62
+ ### @zObserve() - Change Handling
63
+
64
+ The `@zObserve()` decorator creates change handlers for properties:
65
+
66
+ ```typescript
67
+ @zUI({ group: 'Audio' })
68
+ @zObserve((value, instance) => {
69
+ instance._updateVolume();
70
+ })
71
+ public volume = 1;
72
+ ```
73
+
74
+ **Observer patterns:**
75
+
76
+ Simple observers:
77
+
78
+ ```typescript
79
+ @zObserve((v, instance: Audio) => {
80
+ instance._updateVolume();
81
+ })
82
+ public muted = false;
83
+ ```
84
+
85
+ Context-aware observers:
86
+
87
+ ```typescript
88
+ @zObserve((v, instance) =>
89
+ instance.contextManager.get(AudioContextContext).setVolumeForLayer(instance.constructorProps?.layer, v)
90
+ )
91
+ public volume = 1;
92
+ ```
93
+
94
+ ### @zIgnore() - Serialization and UI Control
95
+
96
+ Excludes a public property from serialization and the Mattercraft UI. Use it for internal state that should not be user-editable:
97
+
98
+ ```typescript
99
+ @zIgnore()
100
+ public element: HTMLElement;
101
+ ```
102
+
103
+ ### @zLoad() - Async Loading
104
+
105
+ Marks methods as loadable processes that should complete before the experience starts:
106
+
107
+ ```typescript
108
+ @zLoad()
109
+ private async _load() {
110
+ const response = await fetch(this.constructorProps?.source);
111
+ this.data = await response.arrayBuffer();
112
+ }
113
+ ```
114
+
115
+ ### @zRegister() - Event Registration
116
+
117
+ Registers methods to listen to events:
118
+
119
+ ```typescript
120
+ const someEvent = new Event<[number]>();
121
+
122
+ @zRegister(someEvent)
123
+ private _handleChange(value: number) {
124
+ // Handle event
125
+ }
126
+ ```
127
+
128
+ The first argument can be an `Event` instance, an event property on this entity (for example, `@zRegister('onStateChange')`), or a context class followed by one of its event property names.
129
+
130
+ The string form resolves a property on the decorated entity itself. It does not resolve a behavior's attached component through `this.instance`. For an event on `this.instance` or another component selected at runtime, use `this.register(component.onEvent, handler)`; use the same managed-listener form for `Observable` values.
131
+
132
+ ## Lifecycle Decorators
133
+
134
+ ### @zOnStart() - Auto-Start Methods
135
+
136
+ Calls methods when the experience starts:
137
+
138
+ ```typescript
139
+ @zOnStart()
140
+ private _initializeAudio() {
141
+ // Initialize audio when experience starts
142
+ }
143
+ ```
144
+
145
+ ### @zOnConstructed() - Auto-Construction Methods
146
+
147
+ Calls methods when construction completes:
148
+
149
+ ```typescript
150
+ @zOnConstructed()
151
+ private _setupInitialState() {
152
+ // Setup after construction
153
+ }
154
+ ```
155
+
156
+ ### @zOnLaunch() - Auto-Launch Methods
157
+
158
+ Calls methods when the experience launches:
159
+
160
+ ```typescript
161
+ @zOnLaunch()
162
+ private _requestPermissions() {
163
+ // Request permissions when user launches
164
+ }
165
+ ```
166
+
167
+ ## Environment Condition Decorators
168
+
169
+ ### @zOnlyRuntime() - Runtime-Only Methods
170
+
171
+ Methods only execute during runtime (not in editor):
172
+
173
+ ```typescript
174
+ @zOnlyRuntime()
175
+ public startGame() {
176
+ // Only runs for end users
177
+ }
178
+ ```
179
+
180
+ ### @zOnlyDesignTime() - Design-Time-Only Methods
181
+
182
+ Methods only execute in the Mattercraft editor:
183
+
184
+ ```typescript
185
+ @zOnlyDesignTime()
186
+ public previewEffect() {
187
+ // Only runs in editor
188
+ }
189
+ ```
190
+
191
+ ### @zOnlyEditTime() - Edit-Time-Only Methods
192
+
193
+ Methods only execute during edit time:
194
+
195
+ ```typescript
196
+ @zOnlyEditTime()
197
+ public validateSettings() {
198
+ // Only runs during editing
199
+ }
200
+ ```
201
+
202
+ ### @zOnlyProduction() - Production-Only Methods
203
+
204
+ Methods only execute in production builds:
205
+
206
+ ```typescript
207
+ @zOnlyProduction()
208
+ public enableAnalytics() {
209
+ // Only runs in production
210
+ }
211
+ ```
212
+
213
+ ### @zOnlyDevelopment() - Development-Only Methods
214
+
215
+ Methods only execute in development builds:
216
+
217
+ ```typescript
218
+ @zOnlyDevelopment()
219
+ public enableDebugMode() {
220
+ // Only runs in development
221
+ }
222
+ ```
223
+
224
+ ## Rendering Event Decorators
225
+
226
+ ### @zOnBeforeRender() - Before Render Methods
227
+
228
+ Registers methods for before render events:
229
+
230
+ ```typescript
231
+ @zOnBeforeRender()
232
+ private _updateAnimation(deltaTime: number) {
233
+ // Called every frame before rendering
234
+ }
235
+ ```
236
+
237
+ ### @zOnAfterRender() - After Render Methods
238
+
239
+ Registers methods for after render events:
240
+
241
+ ```typescript
242
+ @zOnAfterRender()
243
+ private _updateUI(deltaTime: number) {
244
+ // Called every frame after rendering
245
+ }
246
+ ```
247
+
248
+ ## Analytics Decorators
249
+
250
+ ### @zLogEvent() - Analytics Logging
251
+
252
+ Logs analytics events when methods are called:
253
+
254
+ ```typescript
255
+ @zLogEvent('button_clicked')
256
+ public handleButtonClick() {
257
+ // Analytics event logged
258
+ }
259
+ ```
260
+
261
+ ## UI Type System
262
+
263
+ ### Built-in UI Types
264
+
265
+ The `type` option in `@zUI()` configures the UI widget:
266
+
267
+ **Numeric inputs:**
268
+
269
+ - `proportion`: 0-1 range with slider input
270
+ - `time-seconds`, `time-milliseconds`: Time inputs with unit conversion
271
+ - `angle-radians`, `angle-degrees`: Angle inputs with unit conversion
272
+
273
+ **Color inputs:**
274
+
275
+ - `color-hex`: Hex color picker (`#FF0000`)
276
+ - `color-norm-rgb`, `color-norm-rgba`: Normalized RGB/RGBA arrays (0-1)
277
+ - `color-unnorm-rgb`, `color-unnorm-rgba`: Unnormalized RGB/RGBA arrays (0-255)
278
+
279
+ **Text inputs:**
280
+
281
+ - `text-multiline`: Textarea for multiline text
282
+
283
+ **Function types:**
284
+
285
+ - `function-emit-component-prop-event`: Event emission function
286
+
287
+ ### Value Constraints
288
+
289
+ The `values` option constrains property values:
290
+
291
+ ```typescript
292
+ @zUI({ values: 'layerclipids' })
293
+ public state?: string;
294
+
295
+ @zUI({ values: 'streamids' })
296
+ public stream?: string;
297
+
298
+ @zUI({ values: 'easings' })
299
+ public easing: Easing = 'linear';
300
+ ```
301
+
302
+ **Available value types:**
303
+
304
+ - `layerclipids`: Timeline/state IDs in the scene
305
+ - `layerids`: Layer IDs in the scene
306
+ - `streamids`: Available stream IDs
307
+ - `easings`: Animation easing functions
308
+ - `nodeids`: Scene node IDs
309
+ - `nodelabels`: Scene node labels
310
+ - `animations`: Animation names in the file-in-context
311
+ - `morphtargets`: Morph target names in the file-in-context
312
+ - `events`: Component events annotated with @zUI
313
+
314
+ ## Constructor Props and Type System
315
+
316
+ Constructor props use TypeScript types to configure the UI. Import specialized types from `@zcomponent/core`:
317
+
318
+ ```typescript
319
+ import { Range, Angle, ProjectFile, Color, Time, Proportion, MultilineText } from '@zcomponent/core';
320
+
321
+ export interface MyComponentProps {
322
+ // File selection with glob patterns
323
+ model: ProjectFile<'*.glb'>;
324
+ texture: ProjectFile<'*.{png,jpg}'>;
325
+
326
+ // Numeric ranges with bounds
327
+ opacity: Range<0, 1>;
328
+ volume: Range<0, 100>;
329
+
330
+ // Angular values with units
331
+ rotation: Angle<'degrees'>;
332
+ phase: Angle<'radians'>;
333
+
334
+ // Color values with format
335
+ background: Color<'hex'>;
336
+ tint: Color<'norm-rgb'>;
337
+ overlay: Color<'rgba'>;
338
+
339
+ // Time values with units
340
+ duration: Time<'seconds'>;
341
+ delay: Time<'milliseconds'>;
342
+
343
+ // Proportional values (0-1)
344
+ progress: Proportion;
345
+
346
+ // Text inputs
347
+ description: MultilineText;
348
+
349
+ // Basic types
350
+ title: string;
351
+ count: number;
352
+ enabled: boolean;
353
+ }
354
+ ```
355
+
356
+ **Available Types:**
357
+
358
+ - `Range<MIN, MAX>`: Numeric range with bounds
359
+ - `Angle<'radians' | 'degrees'>`: Angular measurement
360
+ - `ProjectFile<GLOB>`: File path with glob constraint
361
+ - `Color<FORMAT, SPACE>`: Color value with format/space
362
+ - `Time<'seconds' | 'milliseconds' | 'hertz'>`: Time duration
363
+ - `Proportion`: 0-1 range value
364
+ - `MultilineText`: Multiline text content
365
+ - `Url`: URL string
366
+ - `EmailAddress`: Email with validation
367
+
368
+ ## Events
369
+
370
+ Events are type-safe and exposed to the UI with `@zUI()`:
371
+
372
+ ```typescript
373
+ @zUI()
374
+ public readonly onEnded = new Event<[Audio]>();
375
+
376
+ @zUI()
377
+ public readonly onSave = new Event();
378
+ ```
379
+
380
+ Emit events with arguments:
381
+
382
+ ```typescript
383
+ this.onEnded.emit(this);
384
+ ```
385
+
386
+ Register event handlers:
387
+
388
+ ```typescript
389
+ this.register(otherComponent.onEnded, audio => {
390
+ // Handle audio end event
391
+ });
392
+ ```
393
+
394
+ ## Methods as UI Actions
395
+
396
+ Methods can be exposed as actions in the UI:
397
+
398
+ ```typescript
399
+ @zUI()
400
+ public play(opts?: PlayOptions) {
401
+ // Play implementation
402
+ }
403
+
404
+ @zUI()
405
+ public preview() {
406
+ this.perform();
407
+ }
408
+
409
+ @zUI({ type: 'time-milliseconds' })
410
+ public seek(t: number) {
411
+ // Seek implementation
412
+ }
413
+ ```
414
+
415
+ ## Property Groups
416
+
417
+ Group related properties using group objects or strings:
418
+
419
+ ```typescript
420
+ const audioGroup: ZPropGroup = {
421
+ name: 'Audio',
422
+ priority: 20,
423
+ };
424
+
425
+ @zUI({ group: audioGroup })
426
+ public muted = false;
427
+
428
+ @zUI({ group: 'Settings', priority: 10 })
429
+ public autoplay = true;
430
+ ```
431
+
432
+ ## Complete Example
433
+
434
+ ```typescript
435
+ @zComponent({ icon: 'music_note', group: 'Media' })
436
+ export class Audio extends Component<undefined, AudioConstructorProps> {
437
+ @zUI()
438
+ public readonly onEnded = new Event<[Audio]>();
439
+
440
+ @zUI({ group: 'Audio', priority: 20 })
441
+ @zObserve((v, instance: Audio) => {
442
+ instance._updateVolume();
443
+ })
444
+ public muted = false;
445
+
446
+ @zUI({ group: 'Audio', priority: 20, type: 'proportion' })
447
+ @zObserve((v, instance: Audio) => {
448
+ instance._updateVolume();
449
+ })
450
+ public volume = 1;
451
+
452
+ @zUI()
453
+ public play() {
454
+ // Play implementation
455
+ }
456
+
457
+ @zUI({ type: 'time-milliseconds' })
458
+ public seek(t: number) {
459
+ // Seek implementation
460
+ }
461
+
462
+ private _updateVolume() {
463
+ // Volume update logic
464
+ }
465
+ }
466
+ ```
467
+
468
+ ## Contexts
469
+
470
+ Contexts centralize state across components. Access contexts through the contextManager:
471
+
472
+ ```typescript
473
+ import { CanvasContext } from '@zcomponent/core';
474
+
475
+ const canvasContext = this.contextManager.get(CanvasContext);
476
+ canvasContext.canvas; // HTMLCanvasElement
477
+ ```
478
+
479
+ ## Hooks and Utilities
480
+
481
+ ### Canvas and Rendering Hooks
482
+
483
+ - `useCanvas(mgr: ContextManager)`: Returns the HTMLCanvasElement
484
+ - `useOverlay(mgr: ContextManager)`: Returns an Observable<HTMLDivElement>
485
+ - `useCanvasSize(mgr: ContextManager)`: Returns canvas size observable
486
+ - `useOnBeforeRender(mgr: ContextManager)`: Frame event before 3D render
487
+ - `useOnAfterRender(mgr: ContextManager)`: Frame event after 3D render
488
+ - `useCanvasToDataURL(mgr: ContextManager)`: Canvas to data URL function
489
+ - `useCanvasToArrayBuffer(mgr: ContextManager)`: Canvas to array buffer function
490
+
491
+ ### Lifecycle Hooks
492
+
493
+ - `useIsLoaded(mgr: ContextManager)`: Observable indicating if experience is loaded
494
+ - `useIsStarted(mgr: ContextManager)`: Observable indicating if experience is started
495
+ - `useIsConstructed(mgr: ContextManager)`: Observable indicating if experience is constructed
496
+ - `useIsLaunched(mgr: ContextManager)`: Observable indicating if experience is launched
497
+ - `useLoadPercent(mgr: ContextManager)`: Observable with loading progress percentage
498
+
499
+ ### Audio Context Hooks
500
+
501
+ - `useAudioContext(ctx: ContextManager)`: Returns WebAudio AudioContext
502
+
503
+ ### Analytics Hooks
504
+
505
+ - `useAnalyticsOnEvent(mgr: ContextManager)`: Analytics event emission hook
506
+
507
+ ### Cookie Consent Hooks
508
+
509
+ - `useCookieConsentFunctional(mgr: ContextManager)`: Functional cookies consent status
510
+ - `useCookieConsentPerformance(mgr: ContextManager)`: Performance cookies consent status
511
+ - `useCookieConsentMarketing(mgr: ContextManager)`: Marketing cookies consent status
512
+ - `useCookieConsentStatus(mgr: ContextManager)`: Overall cookie consent status
513
+ - `usePerformanceVendors(mgr: ContextManager)`: Registered performance vendors
514
+ - `useMarketingVendors(mgr: ContextManager)`: Registered marketing vendors
515
+ - `useShowCookieSettings(mgr: ContextManager)`: Function to show cookie settings
516
+
517
+ ### Orientation Hooks
518
+
519
+ - `useOnOrientationChange(mgr: ContextManager)`: Device orientation change events
520
+
521
+ ### Snapshot Hooks
522
+
523
+ - `useCanvasImage(ctx: ContextManager)`: Canvas image data URL
524
+ - `useShareAPISupported(ctx: ContextManager)`: Whether Share API is supported
525
+ - `useCanShare(ctx: ContextManager)`: Whether canvas can be shared
526
+ - `useCanvasFile(ctx: ContextManager)`: Canvas image as File object
527
+ - `useFileName(ctx: ContextManager)`: File name for snapshots
528
+ - `useText(ctx: ContextManager)`: Share text
529
+ - `useTitle(ctx: ContextManager)`: Share title
530
+ - `useFileType(ctx: ContextManager)`: File type (e.g., 'image/png')
531
+ - `useQuality(ctx: ContextManager)`: Image quality value
532
+
533
+ ### User Event Hooks
534
+
535
+ - `useOnUserEvent(mgr: ContextManager)`: User interaction events
536
+
537
+ ### Environment Utilities
538
+
539
+ - `isDesignTime(ctx: ContextManager)`: Returns true in Mattercraft editor
540
+ - `isEditTime(ctx: ContextManager)`: Returns true during edit time
541
+ - `isDevelopmentBuild(ctx: ContextManager)`: Returns true in development
542
+ - `isProductionBuild(ctx: ContextManager)`: Returns true in production
543
+
544
+ ### Orientation Utilities
545
+
546
+ - `isPortrait(mgr: ContextManager)`: Returns true if device is in portrait
547
+ - `isLandscape(mgr: ContextManager)`: Returns true if device is in landscape
548
+ - `isPortraitSecondary(mgr: ContextManager)`: Returns true if in secondary portrait
549
+ - `isLandscapeSecondary(mgr: ContextManager)`: Returns true if in secondary landscape
550
+
551
+ ### Lifecycle Utilities
552
+
553
+ - `isLoaded(mgr: ContextManager)`: Returns current loaded state
554
+ - `isStarted(mgr: ContextManager)`: Returns current started state
555
+ - `isConstructed(mgr: ContextManager)`: Returns current constructed state
556
+ - `isLaunched(mgr: ContextManager)`: Returns current launched state
557
+
558
+ ## Lifecycle
559
+
560
+ Use lifecycle decorators on methods. Keep constructors for synchronous field initialization rather than lifecycle registration:
561
+
562
+ ```typescript
563
+ import { zLoad, zOnConstructed, zOnLaunch, zOnStart } from '@zcomponent/core';
564
+
565
+ @zOnConstructed()
566
+ private _afterConstruction() {
567
+ // The full entity tree has been constructed
568
+ }
569
+
570
+ @zOnLaunch()
571
+ private _afterLaunch() {
572
+ // The user has launched the experience
573
+ }
574
+
575
+ @zOnStart()
576
+ private _afterStart() {
577
+ // Start audio, video, or animation
578
+ }
579
+
580
+ @zLoad()
581
+ private async _load() {
582
+ // The loader waits for this promise before completing
583
+ }
584
+ ```
585
+
586
+ ## Accessing ZComponent Nodes and Animation
587
+
588
+ Access the ZComponent instance and its nodes:
589
+
590
+ ```typescript
591
+ import Scene from './Scene.zcomp';
592
+
593
+ const scene = this.getZComponentInstance(Scene);
594
+
595
+ // Access nodes by scriptName
596
+ scene.nodes.DirectionalLight.enabled = false;
597
+
598
+ // Access animation layers and clips
599
+ scene.animation.layers.MyLayer.clips.MyTimeline.play();
600
+ scene.animation.layers.MyLayer.active = null; // Fade out
601
+ ```
602
+
603
+ ## File References
604
+
605
+ Reference files using the URL constructor with import.meta.url:
606
+
607
+ ```typescript
608
+ const fileUrl = new URL('./myfile.png', import.meta.url);
609
+ ```
610
+
611
+ This format ensures Mattercraft's bundler detects and includes the file in the output bundle.