@virtualdisplay.io/client 3.1.0 → 3.2.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ## [3.2.1](https://github.com/virtualdisplay-io/client/compare/v3.2.0...v3.2.1) (2025-06-30)
6
+
7
+ ### 🐛 Bug Fixes
8
+
9
+ * prevent .env from being used in production builds ([#48](https://github.com/virtualdisplay-io/client/issues/48)) ([7ab54d0](https://github.com/virtualdisplay-io/client/commit/7ab54d02a9aad94daf5a53899fefa9299f9bf73f))
10
+
11
+ ## [3.2.0](https://github.com/virtualdisplay-io/client/compare/v3.1.0...v3.2.0) (2025-06-27)
12
+
13
+ ### ✨ Features
14
+
15
+ * publish client package to npm registry ([#45](https://github.com/virtualdisplay-io/client/issues/45)) ([825810b](https://github.com/virtualdisplay-io/client/commit/825810b0ca56da8e50f34f2afac9f75a87acbc40))
16
+
17
+ ### 🐛 Bug Fixes
18
+
19
+ * improve GitHub Actions authentication and remove .env.act ([#47](https://github.com/virtualdisplay-io/client/issues/47)) ([3acc86e](https://github.com/virtualdisplay-io/client/commit/3acc86e5c27a26af0b77cc23ddff397eee141de5))
20
+ * use GITHUB_TOKEN for checkout action ([#46](https://github.com/virtualdisplay-io/client/issues/46)) ([f8d60fb](https://github.com/virtualdisplay-io/client/commit/f8d60fba2547950137de10838bcfc874e78d9f33))
21
+
22
+ ### 📝 Documentation
23
+
24
+ * update README version reference to v3.1 ([#44](https://github.com/virtualdisplay-io/client/issues/44)) ([1652c15](https://github.com/virtualdisplay-io/client/commit/1652c157890ca43d1e366b302a37f02465d6450b))
25
+
5
26
  ## [3.1.0](https://github.com/virtualdisplay-io/client/compare/v3.0.0...v3.1.0) (2025-06-25)
6
27
 
7
28
  ### ⚠ BREAKING CHANGES
package/README.md CHANGED
@@ -13,11 +13,11 @@ applications.
13
13
  ## Installation
14
14
 
15
15
  ```bash
16
- npm install @virtualdisplay-io/client
16
+ npm install @virtualdisplay.io/client
17
17
  # or
18
- pnpm add @virtualdisplay-io/client
18
+ pnpm add @virtualdisplay.io/client
19
19
  # or
20
- yarn add @virtualdisplay-io/client
20
+ yarn add @virtualdisplay.io/client
21
21
  ```
22
22
 
23
23
  ## What's new in v3.1
@@ -33,7 +33,7 @@ yarn add @virtualdisplay-io/client
33
33
  ### Simple product (no options)
34
34
 
35
35
  ```typescript
36
- import { VirtualdisplayClient } from '@virtualdisplay-io/client';
36
+ import { VirtualdisplayClient } from '@virtualdisplay.io/client';
37
37
 
38
38
  // That's it! Your 3D model is now displayed
39
39
  const client = new VirtualdisplayClient({
@@ -46,7 +46,7 @@ const client = new VirtualdisplayClient({
46
46
  ### Configurable product (with options)
47
47
 
48
48
  ```typescript
49
- import { VirtualdisplayClient } from '@virtualdisplay-io/client';
49
+ import { VirtualdisplayClient } from '@virtualdisplay.io/client';
50
50
 
51
51
  // Create client instance
52
52
  const client = new VirtualdisplayClient({
@@ -84,14 +84,6 @@ The 3D server hosts the viewer in an iframe, keeping WebGL complexity isolated
84
84
  from your application. The client library handles all communication via
85
85
  postMessage and manages state locally using an attribute mapping system.
86
86
 
87
- ```mermaid
88
- graph LR
89
- A[Your application] -->|API calls| B[VirtualdisplayClient]
90
- B -->|postMessage| C[3D server iframe]
91
- C -->|Events| B
92
- B -->|State updates| A
93
- ```
94
-
95
87
  **Key principles:**
96
88
 
97
89
  - **Iframe architecture**: 3D server loads the viewer independently
@@ -214,55 +206,6 @@ client.setMapping({
214
206
 
215
207
  Here's how the client, mapping system, and 3D server work together:
216
208
 
217
- ```mermaid
218
- sequenceDiagram
219
- participant UI as Your UI
220
- participant Client as VirtualdisplayClient
221
- participant AttrService as AttributeService
222
- participant EventBus as EventBus
223
- participant MsgHandler as MessageHandler
224
- participant Server as 3D server
225
-
226
- Note over Client,Server: 0. Client initialization
227
- UI->>Client: new VirtualdisplayClient(...)
228
- Client->>Client: Create iframe
229
- Client->>MsgHandler: setIframe()
230
- Server->>MsgHandler: STATE message (all nodes)
231
- MsgHandler->>EventBus: emit(STATE_MESSAGE)
232
- EventBus->>AttrService: Update local state
233
-
234
- Note over UI,Server: 1. Configure mapping (setMapping)
235
- UI->>Client: setMapping({attributes: [...]})
236
- Client->>AttrService: loadMapping(config)
237
- AttrService->>AttrService: Validate with AJV
238
- AttrService->>AttrService: Create Attribute objects
239
- AttrService->>AttrService: Generate default mutations<br/>(from isSelected values)
240
- AttrService->>EventBus: emit(MUTATION_MESSAGE)
241
- EventBus->>MsgHandler: Send mutations
242
- MsgHandler->>Server: postMessage(mutations)
243
- Server->>Server: Apply changes
244
- Server->>MsgHandler: STATE message (updated)
245
- MsgHandler->>EventBus: emit(STATE_MESSAGE)
246
- EventBus->>AttrService: Update local state
247
- AttrService->>UI: Trigger onChange callbacks
248
-
249
- Note over UI,Server: 2. User interaction (getAttribute.select)
250
- UI->>Client: getAttribute('Color')
251
- Client->>Client: new AttributeSelector('Color')
252
- UI->>Client: .select('Blue')
253
- Client->>AttrService: selectAttributeValue('Color', 'Blue')
254
- AttrService->>AttrService: Generate mutations<br/>(hide current, show new)
255
- AttrService->>EventBus: emit(MUTATION_MESSAGE)
256
- EventBus->>MsgHandler: Send mutations
257
- MsgHandler->>Server: postMessage(mutations)
258
- Note right of Client: select() returns<br/>immediately
259
- Server->>Server: Apply changes
260
- Server->>MsgHandler: STATE message (updated)
261
- MsgHandler->>EventBus: emit(STATE_MESSAGE)
262
- EventBus->>AttrService: Update local state
263
- AttrService->>UI: Trigger onChange callbacks
264
- ```
265
-
266
209
  **Phase by phase breakdown:**
267
210
 
268
211
  #### Phase 0: Initialization (always happens)
@@ -330,7 +273,7 @@ colorAttribute?.getValues().forEach((value) => {
330
273
  Validate your mapping configuration during development:
331
274
 
332
275
  ```typescript
333
- import { mappingSchema } from '@virtualdisplay-io/client';
276
+ import { mappingSchema } from '@virtualdisplay.io/client';
334
277
  import Ajv from 'ajv';
335
278
 
336
279
  const validate = new Ajv().compile(mappingSchema);
@@ -487,7 +430,7 @@ import {
487
430
  VirtualdisplayClient,
488
431
  VirtualdisplayError,
489
432
  ERROR_CODES,
490
- } from '@virtualdisplay-io/client';
433
+ } from '@virtualdisplay.io/client';
491
434
 
492
435
  try {
493
436
  client.getAttribute('NonExistent').select('Value');
package/README.npm.md ADDED
@@ -0,0 +1,483 @@
1
+ # Virtualdisplay client
2
+
3
+ TypeScript library for embedding interactive 3D product models in web
4
+ applications.
5
+
6
+ **Key features:**
7
+
8
+ - Simple attribute-based API for product configurators
9
+ - Fire-and-forget messaging with automatic state synchronization
10
+ - Zero external dependencies (all bundled)
11
+ - Works with any frontend framework or vanilla JavaScript
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @virtualdisplay.io/client
17
+ # or
18
+ pnpm add @virtualdisplay.io/client
19
+ # or
20
+ yarn add @virtualdisplay.io/client
21
+ ```
22
+
23
+ ## What's new in v3.1
24
+
25
+ - Simplified message handling with unified event system
26
+ - JSON Schema validation using AJV
27
+ - Cleaner, more maintainable codebase
28
+ - Improved TypeScript types
29
+ - Better error messages with specific error codes
30
+
31
+ ## Quick start
32
+
33
+ ### Simple product (no options)
34
+
35
+ ```typescript
36
+ import { VirtualdisplayClient } from '@virtualdisplay.io/client';
37
+
38
+ // That's it! Your 3D model is now displayed
39
+ const client = new VirtualdisplayClient({
40
+ parent: '#product-container',
41
+ license: 'your-license-key',
42
+ model: 'statue-model',
43
+ });
44
+ ```
45
+
46
+ ### Configurable product (with options)
47
+
48
+ ```typescript
49
+ import { VirtualdisplayClient } from '@virtualdisplay.io/client';
50
+
51
+ // Create client instance
52
+ const client = new VirtualdisplayClient({
53
+ parent: '#product-container',
54
+ license: 'your-license-key',
55
+ model: 'sneaker',
56
+ });
57
+
58
+ // Map product options to 3D parts
59
+ client.setMapping({
60
+ attributes: [
61
+ {
62
+ name: 'Color',
63
+ values: [
64
+ { value: 'Red', nodeIds: ['laces_red', 'sole_red'], isSelected: true },
65
+ { value: 'Blue', nodeIds: ['laces_blue', 'sole_blue'] },
66
+ ],
67
+ },
68
+ ],
69
+ });
70
+
71
+ // Control via product options
72
+ client.getAttribute('Color')?.select('Red');
73
+
74
+ // Or store the attribute for multiple operations
75
+ const sizeAttribute = client.getAttribute('Size');
76
+ if (sizeAttribute) {
77
+ sizeAttribute.select('Large');
78
+ }
79
+ ```
80
+
81
+ ## How it works
82
+
83
+ The 3D server hosts the viewer in an iframe, keeping WebGL complexity isolated
84
+ from your application. The client library handles all communication via
85
+ postMessage and manages state locally using an attribute mapping system.
86
+
87
+ **Key principles:**
88
+
89
+ - **Iframe architecture**: 3D server loads the viewer independently
90
+ - **Fire-and-forget**: Send messages without waiting for confirmation
91
+ - **Attribute mapping**: Connect your product options to 3D model parts
92
+ - **State synchronization**: Client and 3D server stay in sync automatically
93
+ - **Domain-driven design**: Clean separation of concerns with simplified
94
+ architecture
95
+ - **Event-driven**: Loosely coupled components communicate via events
96
+
97
+ ## Product options
98
+
99
+ ### When do you need mapping
100
+
101
+ Before diving in, it's important to understand when you need attribute mapping:
102
+
103
+ **No mapping needed:**
104
+
105
+ - Static 3D models that always look the same
106
+ - Product showcases without options
107
+ - Architectural visualizations
108
+ - Art pieces or sculptures
109
+ - Single-configuration products
110
+
111
+ **Mapping required:**
112
+
113
+ - Products where users can change colors (different textures/materials per option)
114
+ - Products with size options (different 3D meshes per size)
115
+ - Modular products (parts that can be added/removed)
116
+ - Any product where different options show different 3D elements
117
+
118
+ ### Attribute mapping
119
+
120
+ The mapping system bridges your business logic with the 3D visualization. It
121
+ serves multiple purposes:
122
+
123
+ **Why mapping is essential:**
124
+
125
+ - The 3D server is generic - it doesn't know your specific product options
126
+ - Your business rules (stock, pricing, combinations) change independently from
127
+ the 3D model
128
+ - You control exactly which parts of the model are shown for each option
129
+ - You can group multiple 3D nodes (meshes, materials) into logical product
130
+ choices
131
+
132
+ **How it works:** The mapping connects your product options to specific parts of
133
+ the 3D model:
134
+
135
+ ```typescript
136
+ client.setMapping({
137
+ attributes: [
138
+ {
139
+ name: 'Color',
140
+ values: [
141
+ {
142
+ value: 'Red',
143
+ nodeIds: ['mat_red_sole', 'mat_red_laces', 'mat_red_logo'],
144
+ isSelected: true,
145
+ },
146
+ {
147
+ value: 'Blue',
148
+ nodeIds: ['mat_blue_sole', 'mat_blue_laces', 'mat_blue_logo'],
149
+ },
150
+ ],
151
+ },
152
+ {
153
+ name: 'Material',
154
+ values: [
155
+ { value: 'Leather', nodeIds: ['material_leather_upper'] },
156
+ {
157
+ value: 'Canvas',
158
+ nodeIds: ['material_canvas_upper'],
159
+ isSelected: true,
160
+ },
161
+ ],
162
+ },
163
+ ],
164
+ });
165
+ ```
166
+
167
+ **Structure explained:**
168
+
169
+ - `attribute` - A product feature like Color, Size, or Material
170
+ - `value` - A specific option like Red, Blue, Small, or Large
171
+ - `nodeIds` - The 3D model parts that represent this option
172
+ - `isSelected` - Whether this option is selected by default
173
+
174
+ **Example benefits:**
175
+
176
+ ```typescript
177
+ // Group related 3D parts into one logical choice
178
+ {
179
+ value: 'Red',
180
+ nodeIds: [
181
+ 'mesh_sole_red', // Red sole mesh
182
+ 'material_laces_red', // Red laces material
183
+ 'texture_logo_red', // Red logo texture
184
+ 'mesh_stitching_red' // Red stitching details
185
+ ]
186
+ }
187
+
188
+ // The server automatically handles showing Red parts
189
+ // and hiding Blue/Green parts when Red is selected
190
+ ```
191
+
192
+ **Key advantages:**
193
+
194
+ - Full control over what's visible without modifying the 3D model
195
+ - Business logic stays in your application, not in the 3D server
196
+ - Easy to update when products or availability changes
197
+ - Group complex 3D structures into simple user choices
198
+
199
+ **Need help with mapping?**
200
+
201
+ - We help you connect your product catalog to your 3D models
202
+ - Visual mapping tool coming soon to simplify this process
203
+ - Contact <support@virtualdisplay.io> for mapping assistance
204
+
205
+ ### Complete flow
206
+
207
+ Here's how the client, mapping system, and 3D server work together:
208
+
209
+ **Phase by phase breakdown:**
210
+
211
+ #### Phase 0: Initialization (always happens)
212
+
213
+ - Client creates iframe and loads 3D server
214
+ - Server initializes the 3D model with all nodes visible
215
+ - Server sends complete node state to client
216
+ - Client now knows about all available nodes in the model
217
+
218
+ **Note:** For simple models without options, this is all you need!
219
+
220
+ #### Phase 1: Configuration (only for configurable products)
221
+
222
+ - You call `setMapping()` with your product structure
223
+ - Client stores the attribute mapping locally
224
+ - Client sends mutations for all `isSelected: true` values
225
+ - Server applies these changes and hides non-selected options
226
+ - Server sends back confirmed state
227
+ - Local state updates based on server response
228
+ - onChange callbacks fire for initial UI synchronization
229
+
230
+ #### Phase 2: User interaction (only for configurable products)
231
+
232
+ - User selects a different option in your UI
233
+ - You call `getAttribute('Color').select('Blue')`
234
+ - Client sends mutation request to server
235
+ - Your code continues immediately (doesn't wait for server response)
236
+ - Server updates the 3D model
237
+ - Server sends back the confirmed state
238
+ - Local state updates based on server response
239
+ - onChange callbacks fire with the actual state
240
+ - UI stays perfectly synchronized with 3D model
241
+
242
+ **Important:** The pattern is identical for both initial mapping and user
243
+ interactions. In both cases:
244
+
245
+ 1. Client sends mutations to server
246
+ 2. Server applies changes to 3D model
247
+ 3. Server sends back confirmed state
248
+ 4. Client updates local state based on server response
249
+ 5. onChange callbacks fire with the actual state
250
+
251
+ This ensures the server remains the single source of truth for all state
252
+ changes.
253
+
254
+ ## Advanced usage
255
+
256
+ ### Live state synchronization
257
+
258
+ Keep your UI in sync with the 3D server state using onChange callbacks:
259
+
260
+ ```typescript
261
+ const colorAttribute = client.getAttribute('Color');
262
+
263
+ colorAttribute?.getValues().forEach((value) => {
264
+ value.onChange = () => {
265
+ // Update UI when state changes
266
+ updateButton(value.value, value.isSelected);
267
+ };
268
+ });
269
+ ```
270
+
271
+ ### Mapping validation
272
+
273
+ Validate your mapping configuration during development:
274
+
275
+ ```typescript
276
+ import { mappingSchema } from '@virtualdisplay.io/client';
277
+ import Ajv from 'ajv';
278
+
279
+ const validate = new Ajv().compile(mappingSchema);
280
+ if (!validate(myMapping)) {
281
+ console.error('Invalid mapping:', validate.errors);
282
+ }
283
+ ```
284
+
285
+ ## Real-world integration examples
286
+
287
+ ### CMS integration
288
+
289
+ The Virtualdisplay client is CMS-agnostic. Store the mapping configuration in
290
+ your CMS alongside your product data:
291
+
292
+ ```typescript
293
+ // Fetch product with 3D mapping from your CMS
294
+ const product = await fetch('/api/products/sneaker-pro').then((r) => r.json());
295
+
296
+ // Use the stored mapping directly
297
+ client.setMapping(product.server3dMapping);
298
+ ```
299
+
300
+ **Best practices:**
301
+
302
+ - Store the complete mapping configuration with each product
303
+ - Update mappings when product options or availability changes
304
+ - Let your CMS handle filtering of unavailable combinations
305
+ - Version your mappings when 3D models are updated
306
+
307
+ ## Example
308
+
309
+ See the [color configurator example](./examples/color-configurator/) for a
310
+ complete working implementation that demonstrates:
311
+
312
+ - Setting up the client
313
+ - Defining attribute mappings
314
+ - Binding UI controls to attributes
315
+ - Real-time state synchronization
316
+
317
+ ## API reference
318
+
319
+ ### ClientOptions
320
+
321
+ ```typescript
322
+ interface ClientOptions {
323
+ parent: string | HTMLElement; // Container element or selector
324
+ license: string; // Your license key
325
+ model: string; // Model ID to load
326
+ debug?: boolean; // Enable debug logging (default: false)
327
+ language?: string; // Language for UI inside the iframe (default: 'nl', supported: 'nl', 'en', 'de')
328
+ }
329
+ ```
330
+
331
+ ### Methods
332
+
333
+ #### `setMapping(configuration: MappingConfiguration): void`
334
+
335
+ Configure attribute-to-node mapping for product variants. This is the primary
336
+ method for setting up your product configurator. Call this once with your
337
+ complete configuration - the client efficiently handles all updates.
338
+
339
+ ```typescript
340
+ client.setMapping({
341
+ attributes: [
342
+ {
343
+ name: 'Color',
344
+ values: [
345
+ { value: 'Red', nodeIds: ['node1', 'node2'], isSelected: true },
346
+ { value: 'Blue', nodeIds: ['node3', 'node4'] },
347
+ ],
348
+ },
349
+ ],
350
+ });
351
+ ```
352
+
353
+ #### `getAttribute(name: string): AttributeSelector | undefined`
354
+
355
+ Get an attribute selector for changing values. Returns undefined if the
356
+ attribute doesn't exist.
357
+
358
+ ```typescript
359
+ const colorAttr = client.getAttribute('Color');
360
+ if (colorAttr) {
361
+ colorAttr.select('Blue');
362
+ }
363
+ ```
364
+
365
+ #### `destroy(): void`
366
+
367
+ Clean up and remove the client connection. Always call this when unmounting your
368
+ component.
369
+
370
+ ```typescript
371
+ // React example
372
+ useEffect(() => {
373
+ const client = new VirtualdisplayClient({ ... });
374
+ return () => client.destroy();
375
+ }, []);
376
+ ```
377
+
378
+ ### Types
379
+
380
+ ```typescript
381
+ interface MappingConfiguration {
382
+ attributes: AttributeConfig[];
383
+ }
384
+
385
+ interface AttributeConfig {
386
+ name: string; // Attribute name (e.g., 'Color')
387
+ values: AttributeValueConfig[]; // Possible values
388
+ }
389
+
390
+ interface AttributeValueConfig {
391
+ value: string; // Value name (e.g., 'Red')
392
+ nodeIds: string[]; // 3D node IDs for this value
393
+ isSelected?: boolean; // Default selection state
394
+ }
395
+
396
+ class AttributeSelector {
397
+ // Properties
398
+ name: string; // Attribute name (getter)
399
+ currentValue: string | undefined; // Current selected value (getter)
400
+ availableValues: string[]; // All possible values (getter)
401
+
402
+ // Methods
403
+ select(value: string): AttributeSelector; // Select a value (chainable)
404
+ onChange(callback: () => void): AttributeSelector; // Register change callback (chainable)
405
+ getValues(): AttributeValue[]; // Get all AttributeValue objects
406
+ getValue(value: string): AttributeValue | undefined; // Get specific AttributeValue
407
+ }
408
+
409
+ class AttributeValue {
410
+ // Properties
411
+ value: string; // The value name (e.g., 'Red') - getter
412
+ nodeList: string[]; // Associated 3D node IDs - getter
413
+ isSelected: boolean; // Current selection state - getter
414
+ onChange?: () => void; // Callback when selection changes - property
415
+ }
416
+ ```
417
+
418
+ #### NodeSelector
419
+
420
+ The client exports `NodeSelector` for direct node manipulation. This is intended
421
+ for specialized tools like mapping editors and inspectors, not for typical
422
+ product configurators. For product configurators, use the attribute-based API.
423
+
424
+ ### Error handling
425
+
426
+ The client throws `VirtualdisplayError` for known error conditions:
427
+
428
+ ```typescript
429
+ import {
430
+ VirtualdisplayClient,
431
+ VirtualdisplayError,
432
+ ERROR_CODES,
433
+ } from '@virtualdisplay.io/client';
434
+
435
+ try {
436
+ client.getAttribute('NonExistent').select('Value');
437
+ } catch (error) {
438
+ if (error instanceof VirtualdisplayError) {
439
+ switch (error.code) {
440
+ case ERROR_CODES.ATTRIBUTE_NOT_FOUND:
441
+ console.error('Attribute does not exist');
442
+ break;
443
+ case ERROR_CODES.NO_MAPPING:
444
+ console.error('Call setMapping() first');
445
+ break;
446
+ // Handle other error codes
447
+ }
448
+ }
449
+ }
450
+ ```
451
+
452
+ **Error codes:**
453
+
454
+ - `NO_MAPPING` - No mapping configuration set
455
+ - `ATTRIBUTE_NOT_FOUND` - Requested attribute doesn't exist
456
+ - `VALUE_NOT_FOUND` - Requested value doesn't exist for attribute
457
+ - `INVALID_MAPPING` - Mapping configuration is invalid
458
+ - `PARENT_NOT_FOUND` - Parent element for iframe not found
459
+
460
+ ## Contributing
461
+
462
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup and guidelines.
463
+
464
+ ## Troubleshooting
465
+
466
+ ### Common issues
467
+
468
+ **Iframe not loading:**
469
+
470
+ - Check that the parent element exists in the DOM
471
+ - Verify your license key is valid
472
+ - Ensure the model ID matches your license
473
+
474
+ **Attributes not working:**
475
+
476
+ - Make sure you call `setMapping()` before using `getAttribute()`
477
+ - Verify attribute names match exactly (case-sensitive)
478
+ - Check that node IDs in your mapping exist in the 3D model
479
+
480
+ ## Changelog
481
+
482
+ See the [GitHub releases](https://github.com/virtualdisplay-io/client/releases)
483
+ for release notes and version history.