@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 +94 -0
- package/dist/ThreeAdapter.d.ts +67 -0
- package/dist/ThreeRenderer.d.ts +89 -0
- package/dist/index.d.ts +2 -123
- package/dist/index.js +226 -77
- package/dist/index.mjs +226 -77
- package/package.json +2 -2
- package/dist/index.d.mts +0 -123
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
|
+
[](https://www.npmjs.com/package/@vectojs/three)
|
|
6
|
+
[](https://github.com/vectojs/vectojs/actions/workflows/ci.yml)
|
|
7
|
+
[](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
|
-
|
|
2
|
-
|
|
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';
|