@multisetai/vps 1.0.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/LICENSE +21 -0
- package/README.md +377 -0
- package/dist/core/index.d.ts +201 -0
- package/dist/core/index.js +152 -0
- package/dist/core/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +398 -0
- package/dist/index.js.map +1 -0
- package/dist/webxr/index.d.ts +32 -0
- package/dist/webxr/index.js +252 -0
- package/dist/webxr/index.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { MultisetClient, ILocalizeAndMapDetails } from '../core/index.js';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
|
|
4
|
+
interface IWebxrControllerOptions {
|
|
5
|
+
client: MultisetClient;
|
|
6
|
+
canvas?: HTMLCanvasElement;
|
|
7
|
+
overlayRoot?: HTMLElement;
|
|
8
|
+
buttonContainer?: HTMLElement;
|
|
9
|
+
onARButtonCreated?: (button: HTMLButtonElement) => void;
|
|
10
|
+
onSessionStart?: () => void;
|
|
11
|
+
onSessionEnd?: () => void;
|
|
12
|
+
}
|
|
13
|
+
declare class WebxrController {
|
|
14
|
+
private readonly options;
|
|
15
|
+
private renderer;
|
|
16
|
+
private camera;
|
|
17
|
+
private scene;
|
|
18
|
+
private animationLoop;
|
|
19
|
+
private arButton;
|
|
20
|
+
private resizeHandler;
|
|
21
|
+
private isSessionActive;
|
|
22
|
+
constructor(options: IWebxrControllerOptions);
|
|
23
|
+
initialize(buttonContainer?: HTMLElement): Promise<HTMLButtonElement>;
|
|
24
|
+
getScene(): THREE.Scene;
|
|
25
|
+
getCamera(): THREE.PerspectiveCamera;
|
|
26
|
+
getRenderer(): THREE.WebGLRenderer;
|
|
27
|
+
hasActiveSession(): boolean;
|
|
28
|
+
captureFrame(): Promise<ILocalizeAndMapDetails | null>;
|
|
29
|
+
dispose(): void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { type IWebxrControllerOptions, WebxrController };
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { ARButton } from 'three/examples/jsm/webxr/ARButton.js';
|
|
3
|
+
|
|
4
|
+
// src/lib/webxr/index.ts
|
|
5
|
+
var WebxrController = class {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.options = options;
|
|
8
|
+
this.renderer = null;
|
|
9
|
+
this.camera = null;
|
|
10
|
+
this.scene = null;
|
|
11
|
+
this.animationLoop = null;
|
|
12
|
+
this.arButton = null;
|
|
13
|
+
this.resizeHandler = null;
|
|
14
|
+
this.isSessionActive = false;
|
|
15
|
+
}
|
|
16
|
+
async initialize(buttonContainer) {
|
|
17
|
+
var _a, _b, _c, _d;
|
|
18
|
+
if (this.renderer) {
|
|
19
|
+
return this.arButton;
|
|
20
|
+
}
|
|
21
|
+
if (!window.isSecureContext) {
|
|
22
|
+
throw new Error("WebXR requires a secure context (HTTPS).");
|
|
23
|
+
}
|
|
24
|
+
const canvas = (_a = this.options.canvas) != null ? _a : document.createElement("canvas");
|
|
25
|
+
const renderer = new THREE.WebGLRenderer({
|
|
26
|
+
canvas,
|
|
27
|
+
antialias: true,
|
|
28
|
+
alpha: true
|
|
29
|
+
});
|
|
30
|
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
31
|
+
renderer.setPixelRatio(window.devicePixelRatio);
|
|
32
|
+
renderer.xr.enabled = true;
|
|
33
|
+
renderer.xr.addEventListener("sessionstart", () => {
|
|
34
|
+
var _a2, _b2;
|
|
35
|
+
this.isSessionActive = true;
|
|
36
|
+
(_b2 = (_a2 = this.options).onSessionStart) == null ? void 0 : _b2.call(_a2);
|
|
37
|
+
});
|
|
38
|
+
renderer.xr.addEventListener("sessionend", () => {
|
|
39
|
+
var _a2, _b2;
|
|
40
|
+
this.isSessionActive = false;
|
|
41
|
+
(_b2 = (_a2 = this.options).onSessionEnd) == null ? void 0 : _b2.call(_a2);
|
|
42
|
+
});
|
|
43
|
+
const camera = new THREE.PerspectiveCamera(
|
|
44
|
+
45,
|
|
45
|
+
window.innerWidth / window.innerHeight,
|
|
46
|
+
0.2,
|
|
47
|
+
1e4
|
|
48
|
+
);
|
|
49
|
+
const scene = new THREE.Scene();
|
|
50
|
+
const animationLoop = () => {
|
|
51
|
+
renderer.render(scene, camera);
|
|
52
|
+
};
|
|
53
|
+
renderer.setAnimationLoop(animationLoop);
|
|
54
|
+
const resizeHandler = () => {
|
|
55
|
+
camera.aspect = window.innerWidth / window.innerHeight;
|
|
56
|
+
camera.updateProjectionMatrix();
|
|
57
|
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
58
|
+
};
|
|
59
|
+
window.addEventListener("resize", resizeHandler);
|
|
60
|
+
const overlayRoot = (_b = this.options.overlayRoot) != null ? _b : document.body;
|
|
61
|
+
const arButton = ARButton.createButton(renderer, {
|
|
62
|
+
requiredFeatures: ["camera-access", "dom-overlay"],
|
|
63
|
+
domOverlay: { root: overlayRoot }
|
|
64
|
+
});
|
|
65
|
+
const buttonParent = buttonContainer && buttonContainer instanceof HTMLElement ? buttonContainer : this.options.buttonContainer && this.options.buttonContainer instanceof HTMLElement ? this.options.buttonContainer : overlayRoot;
|
|
66
|
+
if (!buttonParent.contains(arButton)) {
|
|
67
|
+
buttonParent.appendChild(arButton);
|
|
68
|
+
}
|
|
69
|
+
this.renderer = renderer;
|
|
70
|
+
this.camera = camera;
|
|
71
|
+
this.scene = scene;
|
|
72
|
+
this.animationLoop = animationLoop;
|
|
73
|
+
this.arButton = arButton;
|
|
74
|
+
this.resizeHandler = resizeHandler;
|
|
75
|
+
(_d = (_c = this.options).onARButtonCreated) == null ? void 0 : _d.call(_c, arButton);
|
|
76
|
+
return arButton;
|
|
77
|
+
}
|
|
78
|
+
getScene() {
|
|
79
|
+
if (!this.scene) {
|
|
80
|
+
throw new Error("Scene: WebXR controller has not been initialized.");
|
|
81
|
+
}
|
|
82
|
+
return this.scene;
|
|
83
|
+
}
|
|
84
|
+
getCamera() {
|
|
85
|
+
if (!this.camera) {
|
|
86
|
+
throw new Error("Camera: WebXR controller has not been initialized.");
|
|
87
|
+
}
|
|
88
|
+
return this.camera;
|
|
89
|
+
}
|
|
90
|
+
getRenderer() {
|
|
91
|
+
if (!this.renderer) {
|
|
92
|
+
throw new Error("Renderer: WebXR controller has not been initialized.");
|
|
93
|
+
}
|
|
94
|
+
return this.renderer;
|
|
95
|
+
}
|
|
96
|
+
hasActiveSession() {
|
|
97
|
+
var _a;
|
|
98
|
+
return this.isSessionActive && ((_a = this.renderer) == null ? void 0 : _a.xr.isPresenting) === true;
|
|
99
|
+
}
|
|
100
|
+
async captureFrame() {
|
|
101
|
+
var _a, _b;
|
|
102
|
+
const renderer = this.renderer;
|
|
103
|
+
const camera = this.camera;
|
|
104
|
+
if (!renderer || !camera) {
|
|
105
|
+
throw new Error("WebXR: WebXR controller has not been initialized.");
|
|
106
|
+
}
|
|
107
|
+
const session = (_b = (_a = renderer.xr).getSession) == null ? void 0 : _b.call(_a);
|
|
108
|
+
if (!session) {
|
|
109
|
+
throw new Error("WebXR Session: No active WebXR session. Start AR before capturing.");
|
|
110
|
+
}
|
|
111
|
+
const referenceSpace = renderer.xr.getReferenceSpace();
|
|
112
|
+
if (!referenceSpace) {
|
|
113
|
+
throw new Error("WebXR Reference Space: Unable to acquire XR reference space.");
|
|
114
|
+
}
|
|
115
|
+
const gl = renderer.getContext();
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
session.requestAnimationFrame(async (_time, xrFrame) => {
|
|
118
|
+
var _a2, _b2, _c, _d;
|
|
119
|
+
try {
|
|
120
|
+
const viewerPose = xrFrame.getViewerPose(referenceSpace);
|
|
121
|
+
if (!viewerPose) {
|
|
122
|
+
resolve(null);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
for (const view of viewerPose.views) {
|
|
126
|
+
const xrCamera = view.camera;
|
|
127
|
+
if (!xrCamera) continue;
|
|
128
|
+
const gl2 = gl;
|
|
129
|
+
const bindingCtor = XRWebGLBinding;
|
|
130
|
+
const binding = new bindingCtor(session, gl2);
|
|
131
|
+
const cameraTexture = (_b2 = (_a2 = binding.getCameraImage) == null ? void 0 : _a2.call(binding, xrCamera)) != null ? _b2 : null;
|
|
132
|
+
if (!cameraTexture) continue;
|
|
133
|
+
const width = xrCamera.width;
|
|
134
|
+
const height = xrCamera.height;
|
|
135
|
+
if (!width || !height) continue;
|
|
136
|
+
const frameData = await getCameraTextureAsImage(
|
|
137
|
+
renderer,
|
|
138
|
+
cameraTexture,
|
|
139
|
+
width,
|
|
140
|
+
height
|
|
141
|
+
);
|
|
142
|
+
const intrinsics = getCameraIntrinsics(view.projectionMatrix, {
|
|
143
|
+
width,
|
|
144
|
+
height,
|
|
145
|
+
x: 0,
|
|
146
|
+
y: 0
|
|
147
|
+
});
|
|
148
|
+
if (frameData && intrinsics) {
|
|
149
|
+
const result = await this.options.client.localizeWithFrame(
|
|
150
|
+
frameData,
|
|
151
|
+
intrinsics
|
|
152
|
+
);
|
|
153
|
+
resolve(result);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
resolve(null);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
reject(error);
|
|
160
|
+
} finally {
|
|
161
|
+
gl.bindFramebuffer(
|
|
162
|
+
gl.FRAMEBUFFER,
|
|
163
|
+
(_d = (_c = session.renderState.baseLayer) == null ? void 0 : _c.framebuffer) != null ? _d : null
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
dispose() {
|
|
170
|
+
var _a;
|
|
171
|
+
if (this.resizeHandler) {
|
|
172
|
+
window.removeEventListener("resize", this.resizeHandler);
|
|
173
|
+
}
|
|
174
|
+
if (this.renderer) {
|
|
175
|
+
this.renderer.dispose();
|
|
176
|
+
this.renderer = null;
|
|
177
|
+
}
|
|
178
|
+
this.animationLoop = null;
|
|
179
|
+
this.camera = null;
|
|
180
|
+
this.scene = null;
|
|
181
|
+
if ((_a = this.arButton) == null ? void 0 : _a.parentElement) {
|
|
182
|
+
this.arButton.parentElement.removeChild(this.arButton);
|
|
183
|
+
}
|
|
184
|
+
this.arButton = null;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
function getCameraIntrinsics(projectionMatrix, viewport) {
|
|
188
|
+
const p = projectionMatrix;
|
|
189
|
+
const u0 = (1 - p[8]) * viewport.width / 2 + viewport.x;
|
|
190
|
+
const v0 = (1 - p[9]) * viewport.height / 2 + viewport.y;
|
|
191
|
+
const ax = viewport.width / 2 * p[0];
|
|
192
|
+
const ay = viewport.height / 2 * p[5];
|
|
193
|
+
return {
|
|
194
|
+
fx: ax,
|
|
195
|
+
fy: ay,
|
|
196
|
+
px: u0,
|
|
197
|
+
py: v0,
|
|
198
|
+
width: viewport.width,
|
|
199
|
+
height: viewport.height
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
async function compressToJpeg(buffer, width, height, quality = 0.8) {
|
|
203
|
+
const canvas = document.createElement("canvas");
|
|
204
|
+
const ctx = canvas.getContext("2d");
|
|
205
|
+
canvas.width = width;
|
|
206
|
+
canvas.height = height;
|
|
207
|
+
const imageData = new ImageData(new Uint8ClampedArray(buffer), width, height);
|
|
208
|
+
ctx == null ? void 0 : ctx.putImageData(imageData, 0, 0);
|
|
209
|
+
return new Promise((resolve) => {
|
|
210
|
+
canvas.toBlob((blob) => resolve(blob != null ? blob : new Blob()), "image/jpeg", quality);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
async function getCameraTextureAsImage(renderer, webGLTexture, width, height) {
|
|
214
|
+
const gl = renderer.getContext();
|
|
215
|
+
if (!gl) return null;
|
|
216
|
+
const framebuffer = gl.createFramebuffer();
|
|
217
|
+
if (!framebuffer) return null;
|
|
218
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
|
|
219
|
+
gl.framebufferTexture2D(
|
|
220
|
+
gl.FRAMEBUFFER,
|
|
221
|
+
gl.COLOR_ATTACHMENT0,
|
|
222
|
+
gl.TEXTURE_2D,
|
|
223
|
+
webGLTexture,
|
|
224
|
+
0
|
|
225
|
+
);
|
|
226
|
+
const pixelBuffer = new Uint8Array(width * height * 4);
|
|
227
|
+
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixelBuffer);
|
|
228
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
229
|
+
gl.deleteFramebuffer(framebuffer);
|
|
230
|
+
const flippedData = new Uint8ClampedArray(pixelBuffer.length);
|
|
231
|
+
for (let row = 0; row < height; row += 1) {
|
|
232
|
+
const sourceStart = row * width * 4;
|
|
233
|
+
const destStart = (height - row - 1) * width * 4;
|
|
234
|
+
flippedData.set(
|
|
235
|
+
pixelBuffer.subarray(sourceStart, sourceStart + width * 4),
|
|
236
|
+
destStart
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
const blob = await compressToJpeg(flippedData.buffer, width, height, 0.7);
|
|
240
|
+
if (!blob.size) {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
blob,
|
|
245
|
+
width,
|
|
246
|
+
height
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export { WebxrController };
|
|
251
|
+
//# sourceMappingURL=index.js.map
|
|
252
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/webxr/index.ts"],"names":["_a","_b"],"mappings":"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","file":"index.js","sourcesContent":["import * as THREE from 'three';\nimport { ARButton } from 'three/examples/jsm/webxr/ARButton.js';\n\nimport type {\n MultisetClient,\n ICameraIntrinsicsEvent,\n IFrameCaptureEvent,\n ILocalizeAndMapDetails,\n} from '../core';\n\nexport interface IWebxrControllerOptions {\n client: MultisetClient;\n canvas?: HTMLCanvasElement;\n overlayRoot?: HTMLElement;\n buttonContainer?: HTMLElement;\n onARButtonCreated?: (button: HTMLButtonElement) => void;\n onSessionStart?: () => void;\n onSessionEnd?: () => void;\n}\n\ntype XRViewWithCamera = XRView & {\n camera?: {\n width: number;\n height: number;\n [key: string]: unknown;\n };\n};\n\ntype XRWebGLBindingLike = {\n getCameraImage: (camera: XRViewWithCamera['camera']) => WebGLTexture | null;\n};\n\nexport class WebxrController {\n private renderer: THREE.WebGLRenderer | null = null;\n private camera: THREE.PerspectiveCamera | null = null;\n private scene: THREE.Scene | null = null;\n private animationLoop: (() => void) | null = null;\n private arButton: HTMLButtonElement | null = null;\n private resizeHandler: (() => void) | null = null;\n private isSessionActive: boolean = false;\n\n constructor(private readonly options: IWebxrControllerOptions) { }\n\n async initialize(buttonContainer?: HTMLElement): Promise<HTMLButtonElement> {\n if (this.renderer) {\n return this.arButton!;\n }\n\n if (!window.isSecureContext) {\n throw new Error('WebXR requires a secure context (HTTPS).');\n }\n\n const canvas = this.options.canvas ?? document.createElement('canvas');\n\n const renderer = new THREE.WebGLRenderer({\n canvas,\n antialias: true,\n alpha: true,\n });\n renderer.setSize(window.innerWidth, window.innerHeight);\n renderer.setPixelRatio(window.devicePixelRatio);\n renderer.xr.enabled = true;\n\n // Listen for session start/end events\n renderer.xr.addEventListener('sessionstart', () => {\n this.isSessionActive = true;\n this.options.onSessionStart?.();\n });\n\n renderer.xr.addEventListener('sessionend', () => {\n this.isSessionActive = false;\n this.options.onSessionEnd?.();\n });\n\n const camera = new THREE.PerspectiveCamera(\n 45,\n window.innerWidth / window.innerHeight,\n 0.2,\n 10000\n );\n\n const scene = new THREE.Scene();\n\n const animationLoop = () => {\n renderer.render(scene, camera);\n };\n renderer.setAnimationLoop(animationLoop);\n\n const resizeHandler = () => {\n camera.aspect = window.innerWidth / window.innerHeight;\n camera.updateProjectionMatrix();\n renderer.setSize(window.innerWidth, window.innerHeight);\n };\n window.addEventListener('resize', resizeHandler);\n\n const overlayRoot = this.options.overlayRoot ?? document.body;\n const arButton = ARButton.createButton(renderer, {\n requiredFeatures: ['camera-access', 'dom-overlay'],\n domOverlay: { root: overlayRoot },\n }) as HTMLButtonElement;\n\n // Get container at initialization time (like App.tsx does with getElementById)\n // This ensures the container exists in the DOM when we try to append\n // Priority: passed parameter > options.buttonContainer > overlayRoot\n const buttonParent = (buttonContainer && buttonContainer instanceof HTMLElement)\n ? buttonContainer\n : (this.options.buttonContainer && this.options.buttonContainer instanceof HTMLElement)\n ? this.options.buttonContainer\n : overlayRoot;\n\n if (!buttonParent.contains(arButton)) {\n buttonParent.appendChild(arButton);\n }\n\n this.renderer = renderer;\n this.camera = camera;\n this.scene = scene;\n this.animationLoop = animationLoop;\n this.arButton = arButton;\n this.resizeHandler = resizeHandler;\n\n this.options.onARButtonCreated?.(arButton);\n return arButton;\n }\n\n getScene(): THREE.Scene {\n if (!this.scene) {\n throw new Error('Scene: WebXR controller has not been initialized.');\n }\n return this.scene;\n }\n\n getCamera(): THREE.PerspectiveCamera {\n if (!this.camera) {\n throw new Error('Camera: WebXR controller has not been initialized.');\n }\n return this.camera;\n }\n\n getRenderer(): THREE.WebGLRenderer {\n if (!this.renderer) {\n throw new Error('Renderer: WebXR controller has not been initialized.');\n }\n return this.renderer;\n }\n\n hasActiveSession(): boolean {\n return this.isSessionActive && this.renderer?.xr.isPresenting === true;\n }\n\n async captureFrame(): Promise<ILocalizeAndMapDetails | null> {\n const renderer = this.renderer;\n const camera = this.camera;\n if (!renderer || !camera) {\n throw new Error('WebXR: WebXR controller has not been initialized.');\n }\n\n const session = renderer.xr.getSession?.();\n if (!session) {\n throw new Error('WebXR Session: No active WebXR session. Start AR before capturing.');\n }\n\n const referenceSpace = renderer.xr.getReferenceSpace();\n if (!referenceSpace) {\n throw new Error('WebXR Reference Space: Unable to acquire XR reference space.');\n }\n\n const gl = renderer.getContext();\n\n return new Promise((resolve, reject) => {\n session.requestAnimationFrame(async (_time: number, xrFrame: XRFrame) => {\n try {\n const viewerPose = xrFrame.getViewerPose(referenceSpace);\n if (!viewerPose) {\n resolve(null);\n return;\n }\n\n for (const view of viewerPose.views as XRViewWithCamera[]) {\n const xrCamera = view.camera;\n if (!xrCamera) continue;\n\n const gl2 = gl as unknown as WebGL2RenderingContext;\n const bindingCtor = XRWebGLBinding as unknown as {\n new(session: XRSession, context: WebGL2RenderingContext): XRWebGLBindingLike;\n };\n const binding = new bindingCtor(session, gl2);\n const cameraTexture = binding.getCameraImage?.(xrCamera) ?? null;\n if (!cameraTexture) continue;\n\n const width = xrCamera.width;\n const height = xrCamera.height;\n if (!width || !height) continue;\n\n const frameData = await getCameraTextureAsImage(\n renderer,\n cameraTexture,\n width,\n height\n );\n\n const intrinsics = getCameraIntrinsics(view.projectionMatrix, {\n width,\n height,\n x: 0,\n y: 0,\n });\n\n if (frameData && intrinsics) {\n const result = await this.options.client.localizeWithFrame(\n frameData,\n intrinsics\n );\n\n resolve(result);\n return;\n }\n }\n\n resolve(null);\n } catch (error) {\n reject(error);\n } finally {\n gl.bindFramebuffer(\n gl.FRAMEBUFFER,\n session.renderState.baseLayer?.framebuffer ?? null\n );\n }\n });\n });\n }\n\n dispose(): void {\n if (this.resizeHandler) {\n window.removeEventListener('resize', this.resizeHandler);\n }\n\n if (this.renderer) {\n this.renderer.dispose();\n this.renderer = null;\n }\n\n this.animationLoop = null;\n this.camera = null;\n this.scene = null;\n\n if (this.arButton?.parentElement) {\n this.arButton.parentElement.removeChild(this.arButton);\n }\n this.arButton = null;\n }\n}\n\nfunction getCameraIntrinsics(\n projectionMatrix: Float32Array,\n viewport: XRViewport\n): ICameraIntrinsicsEvent {\n const p = projectionMatrix;\n const u0 = ((1 - p[8]) * viewport.width) / 2 + viewport.x;\n const v0 = ((1 - p[9]) * viewport.height) / 2 + viewport.y;\n const ax = (viewport.width / 2) * p[0];\n const ay = (viewport.height / 2) * p[5];\n\n return {\n fx: ax,\n fy: ay,\n px: u0,\n py: v0,\n width: viewport.width,\n height: viewport.height,\n };\n}\n\nasync function compressToJpeg(\n buffer: ArrayBuffer,\n width: number,\n height: number,\n quality = 0.8\n): Promise<Blob> {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n canvas.width = width;\n canvas.height = height;\n\n const imageData = new ImageData(new Uint8ClampedArray(buffer), width, height);\n ctx?.putImageData(imageData, 0, 0);\n\n return new Promise((resolve) => {\n canvas.toBlob((blob) => resolve(blob ?? new Blob()), 'image/jpeg', quality);\n });\n}\n\nasync function getCameraTextureAsImage(\n renderer: THREE.WebGLRenderer,\n webGLTexture: WebGLTexture,\n width: number,\n height: number\n): Promise<IFrameCaptureEvent | null> {\n const gl = renderer.getContext();\n if (!gl) return null;\n\n const framebuffer = gl.createFramebuffer();\n if (!framebuffer) return null;\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);\n gl.framebufferTexture2D(\n gl.FRAMEBUFFER,\n gl.COLOR_ATTACHMENT0,\n gl.TEXTURE_2D,\n webGLTexture,\n 0\n );\n\n const pixelBuffer = new Uint8Array(width * height * 4);\n gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixelBuffer);\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.deleteFramebuffer(framebuffer);\n\n const flippedData = new Uint8ClampedArray(pixelBuffer.length);\n for (let row = 0; row < height; row += 1) {\n const sourceStart = row * width * 4;\n const destStart = (height - row - 1) * width * 4;\n flippedData.set(\n pixelBuffer.subarray(sourceStart, sourceStart + width * 4),\n destStart\n );\n }\n\n const blob = await compressToJpeg(flippedData.buffer, width, height, 0.7);\n\n if (!blob.size) {\n return null;\n }\n\n return {\n blob,\n width,\n height,\n };\n}\n\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@multisetai/vps",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "Multiset VPS WebXR SDK - Core client and WebXR controller.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsup",
|
|
11
|
+
"publish:github": "npm run build && npm publish --registry=https://npm.pkg.github.com",
|
|
12
|
+
"publish:npm": "npm run build && npm publish --access public --registry=https://registry.npmjs.org/"
|
|
13
|
+
},
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"require": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./core": {
|
|
21
|
+
"types": "./dist/core/index.d.ts",
|
|
22
|
+
"import": "./dist/core/index.js",
|
|
23
|
+
"require": "./dist/core/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./webxr": {
|
|
26
|
+
"types": "./dist/webxr/index.d.ts",
|
|
27
|
+
"import": "./dist/webxr/index.js",
|
|
28
|
+
"require": "./dist/webxr/index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"keywords": [
|
|
35
|
+
"multiset",
|
|
36
|
+
"webxr",
|
|
37
|
+
"three",
|
|
38
|
+
"ar",
|
|
39
|
+
"localization",
|
|
40
|
+
"vps",
|
|
41
|
+
"visual-positioning",
|
|
42
|
+
"augmented-reality"
|
|
43
|
+
],
|
|
44
|
+
"author": "",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/MultiSet-AI/multiset-vps-webxr.git"
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"three": ">=0.176.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/three": "^0.176.0",
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "^8.30.1",
|
|
59
|
+
"@typescript-eslint/parser": "^8.30.1",
|
|
60
|
+
"eslint": "^9.25.0",
|
|
61
|
+
"eslint-config-prettier": "^9.1.0",
|
|
62
|
+
"rimraf": "^6.0.1",
|
|
63
|
+
"tsup": "^8.1.0",
|
|
64
|
+
"typescript": "~5.8.3"
|
|
65
|
+
},
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"axios": "^1.9.0"
|
|
68
|
+
}
|
|
69
|
+
}
|