@vectojs/three 0.1.2 → 0.1.4

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/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # @vectojs/three
2
+
3
+ > Put a live VectoJS 2D interface into Three.js/WebXR and route 3D pointer input back to the canvas.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@vectojs/three?color=22d3ee)](https://www.npmjs.com/package/@vectojs/three)
6
+ [![CI](https://github.com/vectojs/vectojs/actions/workflows/ci.yml/badge.svg)](https://github.com/vectojs/vectojs/actions/workflows/ci.yml)
7
+ [![MIT](https://img.shields.io/badge/license-MIT-6366f1.svg)](https://github.com/vectojs/vectojs/blob/main/LICENSE)
8
+
9
+ `@vectojs/three` renders a VectoJS `Scene` into a canvas-backed Three.js texture. The adapter maps
10
+ raycast UV coordinates into the Scene's logical coordinate space, forwards pointer/hover/wheel
11
+ events, and keeps texture uploads synchronized with VectoJS rendering.
12
+
13
+ [Live 3D demo](https://vectojs.xuepoo.xyz/demos/dimension/) ·
14
+ [Reference](https://vectojs.xuepoo.xyz/reference/three/) ·
15
+ [Main repository](https://github.com/vectojs/vectojs)
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ bun add @vectojs/core @vectojs/ui @vectojs/three three
21
+ ```
22
+
23
+ `@vectojs/core` and `three` are peer dependencies. `@vectojs/ui` is used by the example and is
24
+ optional when you supply your own core entities.
25
+
26
+ ## Basic usage
27
+
28
+ ```ts
29
+ import { Button, Stack, Text } from '@vectojs/ui';
30
+ import { ThreeAdapter } from '@vectojs/three';
31
+ import * as THREE from 'three';
32
+
33
+ const scene3d = new THREE.Scene();
34
+ const camera = new THREE.PerspectiveCamera(50, innerWidth / innerHeight, 0.1, 100);
35
+ const renderer = new THREE.WebGLRenderer({ antialias: true });
36
+
37
+ const adapter = new ThreeAdapter({
38
+ width: 800,
39
+ height: 500,
40
+ });
41
+
42
+ const panel = new Stack({ direction: 'vertical', gap: 16 });
43
+ panel.setPosition(36, 36);
44
+ panel.add(new Text('VectoJS in 3D', { font: '700 28px Inter' }));
45
+ panel.add(new Button('Select', { onClick: () => console.log('selected') }));
46
+ adapter.vectoScene.add(panel);
47
+ adapter.vectoScene.start();
48
+
49
+ // Use the adapter's texture/material with a mesh in your Three.js scene.
50
+ scene3d.add(adapter.mesh);
51
+ ```
52
+
53
+ See the [reference](https://vectojs.xuepoo.xyz/reference/three/) for the exact constructor and
54
+ mesh/material customization supported by the installed version.
55
+
56
+ ## Coordinate and event model
57
+
58
+ - VectoJS layout uses the logical `width`/`height` passed to the adapter.
59
+ - The backing canvas may be larger on HiDPI displays; raycast UVs are still mapped to logical space.
60
+ - Pointer intersections are translated into VectoJS events and routed through its normal hit-test,
61
+ capture, target, and bubble phases.
62
+ - Hover state is tracked per pointer, including pointer leave boundaries.
63
+ - WebXR controllers can use the same raycast-to-2D route when supplied by the host application.
64
+
65
+ The adapter does not own the application's Three.js render loop, camera, controls, or raycaster.
66
+
67
+ ## Texture synchronization
68
+
69
+ The adapter wraps the VectoJS Scene render path so `texture.needsUpdate` is set after a dirty frame.
70
+ On-demand VectoJS scenes therefore upload only when their visual state changes; the Three.js host
71
+ still decides when to render its own frame.
72
+
73
+ ## Lifecycle
74
+
75
+ ```ts
76
+ adapter.dispose();
77
+ ```
78
+
79
+ `dispose()` restores the Scene render hook, releases adapter-owned Three.js resources, destroys the
80
+ inner VectoJS Scene, and detaches event state. Call it when removing the panel or unmounting the host
81
+ component.
82
+
83
+ ## Constraints
84
+
85
+ - The default output is a flat textured plane; it is not DOM rendered in 3D.
86
+ - Canvas clipping and logical hit-testing remain 2D even when the mesh is rotated in world space.
87
+ - The host must provide correct raycast intersections and account for occlusion.
88
+ - Texture resolution affects sharpness and upload cost. Choose logical size and DPR for the target
89
+ viewing distance rather than always maximizing both.
90
+ - Three.js releases outside the declared peer range are not guaranteed.
91
+
92
+ ## License
93
+
94
+ [MIT](https://github.com/vectojs/vectojs/blob/main/LICENSE) © 2026 Xuepoo
@@ -0,0 +1,67 @@
1
+ import * as THREE from 'three';
2
+ import { Scene as VectoScene, SceneOptions } from '@vectojs/core';
3
+ export interface ThreeAdapterOptions {
4
+ /** Physical layout width of the 2D UI canvas. */
5
+ width: number;
6
+ /** Physical layout height of the 2D UI canvas. */
7
+ height: number;
8
+ /** Optional pre-existing canvas element. If omitted, a new canvas is created. */
9
+ canvas?: HTMLCanvasElement;
10
+ /** Options passed to the VectoScene constructor. */
11
+ sceneOptions?: SceneOptions;
12
+ }
13
+ /**
14
+ * Adapts a VectoJS Scene into a Three.js CanvasTexture, allowing VectoJS
15
+ * components to be rendered in 3D space (e.g. on a plane, screen, or VR dashboard).
16
+ */
17
+ export declare class ThreeAdapter {
18
+ /** The Three.js CanvasTexture wrapping the offscreen Vecto canvas. */
19
+ texture: THREE.CanvasTexture;
20
+ /** The active VectoJS Scene instance. */
21
+ vectoScene: VectoScene;
22
+ /** The offscreen HTMLCanvasElement on which Vecto draws. */
23
+ canvas: HTMLCanvasElement;
24
+ /** A pre-built THREE.Mesh with PlaneGeometry and this texture for immediate use. */
25
+ mesh: THREE.Mesh;
26
+ /** Track hover states independently per pointerId for WebXR / Multi-Touch. */
27
+ private activePointers;
28
+ /**
29
+ * Holds the original `vectoScene.render` reference so {@link dispose} can
30
+ * restore it. Without restoring, a later render call would write
31
+ * `needsUpdate` on a disposed (deleted) `CanvasTexture`, which Three.js
32
+ * flags with `"THREE.Texture: trying to use deleted texture"`.
33
+ */
34
+ private _originalRender;
35
+ /** Tracks whether this adapter owns the canvas it is rendering to. */
36
+ private _ownsCanvas;
37
+ private _disposed;
38
+ constructor(options: ThreeAdapterOptions);
39
+ /**
40
+ * Processes 3D Raycasting intersections and forwards pointer/scroll events.
41
+ * Call this from window/document event listeners passing the raycaster.
42
+ *
43
+ * @param raycaster Three.js Raycaster instance.
44
+ * @param type Pointer event type: 'pointerdown' | 'pointerup' | 'pointermove' | 'wheel' | 'click'.
45
+ * @param originalEvent Optional original DOM Event to forward scroll deltas or button states.
46
+ * @returns true if the ray intersected the VectoJS mesh; false otherwise.
47
+ */
48
+ updateIntersection(raycaster: THREE.Raycaster, type: 'pointerdown' | 'pointerup' | 'pointermove' | 'wheel' | 'click', originalEvent?: Event): boolean;
49
+ /**
50
+ * Dispatches pointer events mapped from UV coordinates [0, 1] to VectoJS entities.
51
+ */
52
+ private dispatchAtUv;
53
+ /**
54
+ * Routes events to the associated A11y DOM element, or Vecto's own event dispatch system.
55
+ */
56
+ private dispatchEventToTarget;
57
+ private createDOMEvent;
58
+ private findEntityById;
59
+ /**
60
+ * Resizes the offscreen canvas and VectoScene dimensions.
61
+ */
62
+ resize(width: number, height: number): void;
63
+ /**
64
+ * Disposes of Three.js textures, geometries, and VectoJS scenes to prevent memory leaks.
65
+ */
66
+ dispose(): void;
67
+ }
@@ -0,0 +1,89 @@
1
+ import { IRenderer } from '@vectojs/core';
2
+ import * as THREE from 'three';
3
+ export declare class WebGLGradient {
4
+ x0: number;
5
+ y0: number;
6
+ x1: number;
7
+ y1: number;
8
+ colorStops: {
9
+ stop: number;
10
+ color: string;
11
+ }[];
12
+ type: string;
13
+ constructor(x0: number, y0: number, x1: number, y1: number, colorStops: {
14
+ stop: number;
15
+ color: string;
16
+ }[]);
17
+ }
18
+ /**
19
+ * WebGL/Three.js implementation of {@link IRenderer}.
20
+ *
21
+ * Bridges VectoJS's 2D canvas API to Three.js for 3D hardware-accelerated rendering.
22
+ */
23
+ export declare class ThreeRenderer implements IRenderer {
24
+ scene: THREE.Scene;
25
+ camera: THREE.OrthographicCamera;
26
+ renderer: THREE.WebGLRenderer;
27
+ private width;
28
+ private height;
29
+ private matrix;
30
+ private stack;
31
+ private globalAlpha;
32
+ private alphaStack;
33
+ private currentPath;
34
+ private activeObjects;
35
+ private scissorStack;
36
+ constructor(canvas: HTMLCanvasElement);
37
+ resize(width: number, height: number): void;
38
+ clear(): void;
39
+ private disposeActiveObjects;
40
+ save(): void;
41
+ restore(): void;
42
+ translate(x: number, y: number): void;
43
+ scale(x: number, y: number): void;
44
+ rotate(angle: number): void;
45
+ setGlobalAlpha(alpha: number): void;
46
+ clip(x: number, y: number, width: number, height: number): void;
47
+ beginPath(): void;
48
+ moveTo(x: number, y: number): void;
49
+ lineTo(x: number, y: number): void;
50
+ bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void;
51
+ closePath(): void;
52
+ arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void;
53
+ roundRect(x: number, y: number, width: number, height: number, radii: number | number[]): void;
54
+ drawImage(source: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;
55
+ fill(colorOrGradient: string | any): void;
56
+ private fillSolidShape;
57
+ stroke(colorOrGradient: string | any, lineWidth?: number): void;
58
+ /**
59
+ * Rasterized fillText textures keyed by `font|color|text`, LRU-evicted.
60
+ * HUD-style UIs redraw the same labels every frame; without the cache each
61
+ * call allocated a canvas, rasterized it, and uploaded a fresh GPU texture.
62
+ * Entries are skipped by {@link disposeActiveObjects} (flagged via
63
+ * `userData.vectoCached`) and released on eviction or {@link dispose}.
64
+ */
65
+ private textTextureCache;
66
+ private textTextureCacheLimit;
67
+ fillText(text: string, x: number, y: number, font: string, color: string | any): void;
68
+ fillCircle(cx: number, cy: number, radius: number, color: string, alpha?: number): void;
69
+ private frameDirty;
70
+ private presentScheduled;
71
+ /**
72
+ * The Scene calls flush() around every non-batched node (it commits the
73
+ * Canvas2D circle batch there). Rendering the whole Three scene on each of
74
+ * those calls made a frame cost O(N²) in entity count, so flush() only marks
75
+ * the frame dirty; the actual GL render happens once, in {@link present}.
76
+ *
77
+ * A microtask fallback keeps older `@vectojs/core` Scenes (that never call
78
+ * `present()`) painting: the many same-tick flushes coalesce into one render.
79
+ */
80
+ flush(): void;
81
+ /** Render the accumulated frame once. Called by Scene at the end of each render pass. */
82
+ present(): void;
83
+ createLinearGradient(x0: number, y0: number, x1: number, y1: number, colorStops: {
84
+ stop: number;
85
+ color: string;
86
+ }[]): any;
87
+ private disposed;
88
+ dispose(): void;
89
+ }
package/dist/index.d.ts CHANGED
@@ -1,123 +1,2 @@
1
- import { IRenderer, Scene, SceneOptions } from '@vectojs/core';
2
- import * as THREE from 'three';
3
-
4
- declare class WebGLGradient {
5
- x0: number;
6
- y0: number;
7
- x1: number;
8
- y1: number;
9
- colorStops: {
10
- stop: number;
11
- color: string;
12
- }[];
13
- type: string;
14
- constructor(x0: number, y0: number, x1: number, y1: number, colorStops: {
15
- stop: number;
16
- color: string;
17
- }[]);
18
- }
19
- /**
20
- * WebGL/Three.js implementation of {@link IRenderer}.
21
- *
22
- * Bridges VectoJS's 2D canvas API to Three.js for 3D hardware-accelerated rendering.
23
- */
24
- declare class ThreeRenderer implements IRenderer {
25
- scene: THREE.Scene;
26
- camera: THREE.OrthographicCamera;
27
- renderer: THREE.WebGLRenderer;
28
- private width;
29
- private height;
30
- private matrix;
31
- private stack;
32
- private globalAlpha;
33
- private alphaStack;
34
- private currentPath;
35
- private activeObjects;
36
- private scissorStack;
37
- constructor(canvas: HTMLCanvasElement);
38
- resize(width: number, height: number): void;
39
- clear(): void;
40
- save(): void;
41
- restore(): void;
42
- translate(x: number, y: number): void;
43
- scale(x: number, y: number): void;
44
- rotate(angle: number): void;
45
- setGlobalAlpha(alpha: number): void;
46
- clip(x: number, y: number, width: number, height: number): void;
47
- beginPath(): void;
48
- moveTo(x: number, y: number): void;
49
- lineTo(x: number, y: number): void;
50
- bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void;
51
- closePath(): void;
52
- arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void;
53
- roundRect(x: number, y: number, width: number, height: number, radii: number | number[]): void;
54
- drawImage(source: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;
55
- fill(colorOrGradient: string | any): void;
56
- private fillSolidShape;
57
- stroke(colorOrGradient: string | any, lineWidth?: number): void;
58
- fillText(text: string, x: number, y: number, font: string, color: string | any): void;
59
- fillCircle(cx: number, cy: number, radius: number, color: string, alpha?: number): void;
60
- flush(): void;
61
- createLinearGradient(x0: number, y0: number, x1: number, y1: number, colorStops: {
62
- stop: number;
63
- color: string;
64
- }[]): any;
65
- }
66
-
67
- interface ThreeAdapterOptions {
68
- /** Physical layout width of the 2D UI canvas. */
69
- width: number;
70
- /** Physical layout height of the 2D UI canvas. */
71
- height: number;
72
- /** Optional pre-existing canvas element. If omitted, a new canvas is created. */
73
- canvas?: HTMLCanvasElement;
74
- /** Options passed to the VectoScene constructor. */
75
- sceneOptions?: SceneOptions;
76
- }
77
- /**
78
- * Adapts a VectoJS Scene into a Three.js CanvasTexture, allowing VectoJS
79
- * components to be rendered in 3D space (e.g. on a plane, screen, or VR dashboard).
80
- */
81
- declare class ThreeAdapter {
82
- /** The Three.js CanvasTexture wrapping the offscreen Vecto canvas. */
83
- texture: THREE.CanvasTexture;
84
- /** The active VectoJS Scene instance. */
85
- vectoScene: Scene;
86
- /** The offscreen HTMLCanvasElement on which Vecto draws. */
87
- canvas: HTMLCanvasElement;
88
- /** A pre-built THREE.Mesh with PlaneGeometry and this texture for immediate use. */
89
- mesh: THREE.Mesh;
90
- /** Track hover states independently per pointerId for WebXR / Multi-Touch. */
91
- private activePointers;
92
- constructor(options: ThreeAdapterOptions);
93
- /**
94
- * Processes 3D Raycasting intersections and forwards pointer/scroll events.
95
- * Call this from window/document event listeners passing the raycaster.
96
- *
97
- * @param raycaster Three.js Raycaster instance.
98
- * @param type Pointer event type: 'pointerdown' | 'pointerup' | 'pointermove' | 'wheel' | 'click'.
99
- * @param originalEvent Optional original DOM Event to forward scroll deltas or button states.
100
- * @returns true if the ray intersected the VectoJS mesh; false otherwise.
101
- */
102
- updateIntersection(raycaster: THREE.Raycaster, type: 'pointerdown' | 'pointerup' | 'pointermove' | 'wheel' | 'click', originalEvent?: Event): boolean;
103
- /**
104
- * Dispatches pointer events mapped from UV coordinates [0, 1] to VectoJS entities.
105
- */
106
- private dispatchAtUv;
107
- /**
108
- * Routes events to the associated A11y DOM element, or Vecto's own event dispatch system.
109
- */
110
- private dispatchEventToTarget;
111
- private createDOMEvent;
112
- private findEntityById;
113
- /**
114
- * Resizes the offscreen canvas and VectoScene dimensions.
115
- */
116
- resize(width: number, height: number): void;
117
- /**
118
- * Disposes of Three.js textures, geometries, and VectoJS scenes to prevent memory leaks.
119
- */
120
- dispose(): void;
121
- }
122
-
123
- export { ThreeAdapter, type ThreeAdapterOptions, ThreeRenderer, WebGLGradient };
1
+ export * from './ThreeRenderer';
2
+ export * from './ThreeAdapter';