@holoscript/cdn 1.0.0
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 +19 -0
- package/dist/index.cdn.js +207 -0
- package/dist/index.cdn.js.map +1 -0
- package/dist/index.cdn.mjs +177 -0
- package/dist/index.cdn.mjs.map +1 -0
- package/dist/index.d.mts +68 -0
- package/dist/index.d.ts +68 -0
- package/error-tsc-utf8.log +0 -0
- package/error-tsc.log +0 -0
- package/error-utf8.log +262 -0
- package/error.log +0 -0
- package/package.json +43 -0
- package/src/HoloSceneElement.ts +40 -0
- package/src/HoloSceneRenderer.ts +159 -0
- package/src/__tests__/Sprint44.test.d.ts +1 -0
- package/src/__tests__/Sprint44.test.js +152 -0
- package/src/__tests__/Sprint44.test.ts +188 -0
- package/src/config.ts +44 -0
- package/src/index.ts +17 -0
- package/src/types.ts +44 -0
- package/tsconfig.json +21 -0
- package/tsup.config.d.ts +2 -0
- package/tsup.config.js +12 -0
- package/tsup.config.ts +13 -0
- package/vitest.config.ts +9 -0
package/error-utf8.log
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
node.exe : Γû▓ [WARNING] The condition
|
|
2
|
+
"types" here will never be used as it
|
|
3
|
+
comes after both "import" and
|
|
4
|
+
"require" [package.json]
|
|
5
|
+
At line:1 char:1
|
|
6
|
+
+ & "C:\Program Files\nodejs/node.exe"
|
|
7
|
+
"C:\Users\josep\AppData\Roaming\ ...
|
|
8
|
+
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
9
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
10
|
+
+ CategoryInfo :
|
|
11
|
+
NotSpecif ied: (Γû▓ [WARNING] T...
|
|
12
|
+
[package.j son]:String) [],
|
|
13
|
+
RemoteException
|
|
14
|
+
+ FullyQualifiedErrorId :
|
|
15
|
+
NativeCom mandError
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
package.json:12:6:
|
|
19
|
+
12 Γöé "types":
|
|
20
|
+
"./dist/index.d.ts"
|
|
21
|
+
Γò╡ ~~~~~~~
|
|
22
|
+
|
|
23
|
+
The "import" condition comes earlier
|
|
24
|
+
and will be used for all "import"
|
|
25
|
+
statements:
|
|
26
|
+
|
|
27
|
+
package.json:10:6:
|
|
28
|
+
10 Γöé "import":
|
|
29
|
+
"./dist/holoscript.cdn.mjs",
|
|
30
|
+
Γò╡ ~~~~~~~~
|
|
31
|
+
|
|
32
|
+
The "require" condition comes
|
|
33
|
+
earlier and will be used for all
|
|
34
|
+
"require" calls:
|
|
35
|
+
|
|
36
|
+
package.json:11:6:
|
|
37
|
+
11 Γöé "require":
|
|
38
|
+
"./dist/holoscript.cdn.js",
|
|
39
|
+
Γò╡ ~~~~~~~~~
|
|
40
|
+
|
|
41
|
+
[34mCLI[39m Building entry: src/index.ts
|
|
42
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
43
|
+
[34mCLI[39m tsup v8.5.1
|
|
44
|
+
[34mCLI[39m Using tsup config: C:\Users\josep\Documents\GitHub\HoloScript\packages\holoscript-cdn\tsup.config.ts
|
|
45
|
+
[34mCLI[39m Target: es2022
|
|
46
|
+
[34mCLI[39m Cleaning output folder
|
|
47
|
+
[34mCJS[39m Build start
|
|
48
|
+
[34mESM[39m Build start
|
|
49
|
+
|
|
50
|
+
[43m[30m WARN [39m[49m [33mΓû▓
|
|
51
|
+
[43;33m[[43;30mWARNING[43;33m][0m
|
|
52
|
+
[1mThe condition "types" here will
|
|
53
|
+
never be used as it comes after both
|
|
54
|
+
"import" and "require"[0m
|
|
55
|
+
[package.json]
|
|
56
|
+
|
|
57
|
+
package.json:12:6:
|
|
58
|
+
[37m 12 Γöé
|
|
59
|
+
[32m"types"[37m: "./dist/index.d.ts"
|
|
60
|
+
Γò╡ [32m~~~~~~~[0m
|
|
61
|
+
|
|
62
|
+
The "import" condition comes earlier
|
|
63
|
+
and will be used for all "import"
|
|
64
|
+
statements:
|
|
65
|
+
|
|
66
|
+
package.json:10:6:
|
|
67
|
+
[37m 10 Γöé
|
|
68
|
+
[32m"import"[37m:
|
|
69
|
+
"./dist/holoscript.cdn.mjs",
|
|
70
|
+
Γò╡ [32m~~~~~~~~[0m
|
|
71
|
+
|
|
72
|
+
The "require" condition comes
|
|
73
|
+
earlier and will be used for all
|
|
74
|
+
"require" calls:
|
|
75
|
+
|
|
76
|
+
package.json:11:6:
|
|
77
|
+
[37m 11 Γöé
|
|
78
|
+
[32m"require"[37m:
|
|
79
|
+
"./dist/holoscript.cdn.js",
|
|
80
|
+
Γò╡ [32m~~~~~~~~~[0m
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
[43m[30m WARN [39m[49m [33mΓû▓
|
|
86
|
+
[43;33m[[43;30mWARNING[43;33m][0m
|
|
87
|
+
[1mImport "HoloSceneElement" will
|
|
88
|
+
always be undefined because the file
|
|
89
|
+
"src/HoloSceneElement.js" has no
|
|
90
|
+
exports[0m [import-is-undefined]
|
|
91
|
+
|
|
92
|
+
src/index.ts:14:9:
|
|
93
|
+
[37m 14 Γöé export {
|
|
94
|
+
[32mHoloSceneElement[37m,
|
|
95
|
+
registerHoloScene } from
|
|
96
|
+
'./HoloSceneEl...
|
|
97
|
+
Γò╡
|
|
98
|
+
[32m~~~~~~~~~~~~~~~~[0m
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
[43m[30m WARN [39m[49m [33mΓû▓
|
|
104
|
+
[43;33m[[43;30mWARNING[43;33m][0m
|
|
105
|
+
[1mImport "registerHoloScene" will
|
|
106
|
+
always be undefined because the file
|
|
107
|
+
"src/HoloSceneElement.js" has no
|
|
108
|
+
exports[0m [import-is-undefined]
|
|
109
|
+
|
|
110
|
+
src/index.ts:14:27:
|
|
111
|
+
[37m 14 Γöé ...rt {
|
|
112
|
+
HoloSceneElement,
|
|
113
|
+
[32mregisterHoloScene[37m } from
|
|
114
|
+
'./HoloSceneEle...
|
|
115
|
+
Γò╡
|
|
116
|
+
[32m~~~~~~~~~~~~~~~~~[0m
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
[43m[30m WARN [39m[49m [33mΓû▓
|
|
122
|
+
[43;33m[[43;30mWARNING[43;33m][0m
|
|
123
|
+
[1mThe condition "types" here will
|
|
124
|
+
never be used as it comes after both
|
|
125
|
+
"import" and "require"[0m
|
|
126
|
+
[package.json]
|
|
127
|
+
|
|
128
|
+
package.json:12:6:
|
|
129
|
+
[37m 12 Γöé
|
|
130
|
+
[32m"types"[37m: "./dist/index.d.ts"
|
|
131
|
+
Γò╡ [32m~~~~~~~[0m
|
|
132
|
+
|
|
133
|
+
The "import" condition comes earlier
|
|
134
|
+
and will be used for all "import"
|
|
135
|
+
statements:
|
|
136
|
+
|
|
137
|
+
package.json:10:6:
|
|
138
|
+
[37m 10 Γöé
|
|
139
|
+
[32m"import"[37m:
|
|
140
|
+
"./dist/holoscript.cdn.mjs",
|
|
141
|
+
Γò╡ [32m~~~~~~~~[0m
|
|
142
|
+
|
|
143
|
+
The "require" condition comes
|
|
144
|
+
earlier and will be used for all
|
|
145
|
+
"require" calls:
|
|
146
|
+
|
|
147
|
+
package.json:11:6:
|
|
148
|
+
[37m 11 Γöé
|
|
149
|
+
[32m"require"[37m:
|
|
150
|
+
"./dist/holoscript.cdn.js",
|
|
151
|
+
Γò╡ [32m~~~~~~~~~[0m
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
[43m[30m WARN [39m[49m [33mΓû▓
|
|
157
|
+
[43;33m[[43;30mWARNING[43;33m][0m
|
|
158
|
+
[1mImport "HoloSceneElement" will
|
|
159
|
+
always be undefined because the file
|
|
160
|
+
"src/HoloSceneElement.js" has no
|
|
161
|
+
exports[0m [import-is-undefined]
|
|
162
|
+
|
|
163
|
+
src/index.ts:14:9:
|
|
164
|
+
[37m 14 Γöé export {
|
|
165
|
+
[32mHoloSceneElement[37m,
|
|
166
|
+
registerHoloScene } from
|
|
167
|
+
'./HoloSceneEl...
|
|
168
|
+
Γò╡
|
|
169
|
+
[32m~~~~~~~~~~~~~~~~[0m
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
[43m[30m WARN [39m[49m [33mΓû▓
|
|
175
|
+
[43;33m[[43;30mWARNING[43;33m][0m
|
|
176
|
+
[1mImport "registerHoloScene" will
|
|
177
|
+
always be undefined because the file
|
|
178
|
+
"src/HoloSceneElement.js" has no
|
|
179
|
+
exports[0m [import-is-undefined]
|
|
180
|
+
|
|
181
|
+
src/index.ts:14:27:
|
|
182
|
+
[37m 14 Γöé ...rt {
|
|
183
|
+
HoloSceneElement,
|
|
184
|
+
[32mregisterHoloScene[37m } from
|
|
185
|
+
'./HoloSceneEle...
|
|
186
|
+
Γò╡
|
|
187
|
+
[32m~~~~~~~~~~~~~~~~~[0m
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
[32mESM[39m [1mdist\index.cdn.mjs [22m[32m4.28 KB[39m
|
|
192
|
+
[32mESM[39m [1mdist\index.cdn.mjs.map [22m[32m7.87 KB[39m
|
|
193
|
+
[32mESM[39m ⚡️ Build success in 38ms
|
|
194
|
+
[32mCJS[39m [1mdist\index.cdn.js [22m[32m5.28 KB[39m
|
|
195
|
+
[32mCJS[39m [1mdist\index.cdn.js.map [22m[32m8.60 KB[39m
|
|
196
|
+
[32mCJS[39m ⚡️ Build success in 38ms
|
|
197
|
+
[34mDTS[39m Build start
|
|
198
|
+
[31mRollupError: "HoloSceneElement"
|
|
199
|
+
is not exported by
|
|
200
|
+
"src/HoloSceneElement.ts", imported by
|
|
201
|
+
"src/index.ts".
|
|
202
|
+
at getRollupError (C:\Users\josep\D
|
|
203
|
+
ocuments\GitHub\HoloScript\node_modules
|
|
204
|
+
\.pnpm\rollup@4.55.1\node_modules\rollu
|
|
205
|
+
p\dist\shared\parseAst.js:285:41)
|
|
206
|
+
at Object.error (C:\Users\josep\Doc
|
|
207
|
+
uments\GitHub\HoloScript\node_modules\.
|
|
208
|
+
pnpm\rollup@4.55.1\node_modules\rollup\
|
|
209
|
+
dist\shared\parseAst.js:281:42)
|
|
210
|
+
at Module.error (C:\Users\josep\Doc
|
|
211
|
+
uments\GitHub\HoloScript\node_modules\.
|
|
212
|
+
pnpm\rollup@4.55.1\node_modules\rollup\
|
|
213
|
+
dist\shared\rollup.js:18625:28)
|
|
214
|
+
at Module.getVariableForExportName
|
|
215
|
+
(C:\Users\josep\Documents\GitHub\HoloSc
|
|
216
|
+
ript\node_modules\.pnpm\rollup@4.55.1\n
|
|
217
|
+
ode_modules\rollup\dist\shared\rollup.j
|
|
218
|
+
s:18791:29)
|
|
219
|
+
at Module.includeAllExports (C:\Use
|
|
220
|
+
rs\josep\Documents\GitHub\HoloScript\no
|
|
221
|
+
de_modules\.pnpm\rollup@4.55.1\node_mod
|
|
222
|
+
ules\rollup\dist\shared\rollup.js:18875
|
|
223
|
+
:37)
|
|
224
|
+
at Graph.includeStatements (C:\User
|
|
225
|
+
s\josep\Documents\GitHub\HoloScript\nod
|
|
226
|
+
e_modules\.pnpm\rollup@4.55.1\node_modu
|
|
227
|
+
les\rollup\dist\shared\rollup.js:23209:
|
|
228
|
+
36)
|
|
229
|
+
at Graph.build (C:\Users\josep\Docu
|
|
230
|
+
ments\GitHub\HoloScript\node_modules\.p
|
|
231
|
+
npm\rollup@4.55.1\node_modules\rollup\d
|
|
232
|
+
ist\shared\rollup.js:23139:14)
|
|
233
|
+
at async C:\Users\josep\Documents\G
|
|
234
|
+
itHub\HoloScript\node_modules\.pnpm\rol
|
|
235
|
+
lup@4.55.1\node_modules\rollup\dist\sha
|
|
236
|
+
red\rollup.js:23792:13
|
|
237
|
+
at async
|
|
238
|
+
catchUnfinishedHookActions (C:\Users\jo
|
|
239
|
+
sep\Documents\GitHub\HoloScript\node_mo
|
|
240
|
+
dules\.pnpm\rollup@4.55.1\node_modules\
|
|
241
|
+
rollup\dist\shared\rollup.js:23297:16)
|
|
242
|
+
at async rollupInternal (C:\Users\j
|
|
243
|
+
osep\Documents\GitHub\HoloScript\node_m
|
|
244
|
+
odules\.pnpm\rollup@4.55.1\node_modules
|
|
245
|
+
\rollup\dist\shared\rollup.js:23787:5)
|
|
246
|
+
[39m
|
|
247
|
+
[31mError: error occurred in dts build
|
|
248
|
+
at Worker.<anonymous> (C:\Users\jos
|
|
249
|
+
ep\Documents\GitHub\HoloScript\node_mod
|
|
250
|
+
ules\.pnpm\tsup@8.5.1_postcss@8.5.6_tsx
|
|
251
|
+
@4.21.0_typescript@5.9.3\node_modules\t
|
|
252
|
+
sup\dist\index.js:1545:26)
|
|
253
|
+
at Worker.emit (node:events:519:28)
|
|
254
|
+
at MessagePort.<anonymous>
|
|
255
|
+
(node:internal/worker:270:53)
|
|
256
|
+
at
|
|
257
|
+
[nodejs.internal.kHybridDispatch]
|
|
258
|
+
(node:internal/event_target:827:20)
|
|
259
|
+
at MessagePort.<anonymous> (node:in
|
|
260
|
+
ternal/per_context/messageport:23:28)[
|
|
261
|
+
39m
|
|
262
|
+
[31mDTS[39m [31mBuild error[39m
|
package/error.log
ADDED
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@holoscript/cdn",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Browser CDN distribution for HoloScript — embed spatial scenes with <holo-scene>",
|
|
5
|
+
"main": "dist/holoscript.cdn.js",
|
|
6
|
+
"module": "dist/holoscript.cdn.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/holoscript.cdn.mjs",
|
|
11
|
+
"require": "./dist/holoscript.cdn.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"holoscript",
|
|
17
|
+
"cdn",
|
|
18
|
+
"web-component",
|
|
19
|
+
"spatial",
|
|
20
|
+
"xr",
|
|
21
|
+
"3d"
|
|
22
|
+
],
|
|
23
|
+
"author": "HoloScript Team",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/brianonbased-dev/HoloScript.git",
|
|
28
|
+
"directory": "packages/holoscript-cdn"
|
|
29
|
+
},
|
|
30
|
+
"sideEffects": false,
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"vitest": "^4.1.0"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/brianonbased-dev/HoloScript#readme",
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/brianonbased-dev/HoloScript/issues"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsup",
|
|
40
|
+
"test": "vitest run",
|
|
41
|
+
"dev": "tsup --watch"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { HoloSceneTarget, HoloSceneFallback } from './types';
|
|
2
|
+
import { HoloSceneRenderer } from './HoloSceneRenderer';
|
|
3
|
+
|
|
4
|
+
export class HoloSceneElement extends HTMLElement {
|
|
5
|
+
private renderer: HoloSceneRenderer | null = null;
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
super();
|
|
9
|
+
this.attachShadow({ mode: 'open' });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
connectedCallback() {
|
|
13
|
+
if (!this.shadowRoot) return;
|
|
14
|
+
const container = document.createElement('div');
|
|
15
|
+
container.style.width = '100%';
|
|
16
|
+
container.style.height = '100%';
|
|
17
|
+
this.shadowRoot.appendChild(container);
|
|
18
|
+
this.renderer = new HoloSceneRenderer(container);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
disconnectedCallback() {
|
|
22
|
+
if (this.renderer) {
|
|
23
|
+
this.renderer.cleanup();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get src(): string {
|
|
28
|
+
return this.getAttribute('src') || '';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get target(): HoloSceneTarget {
|
|
32
|
+
return (this.getAttribute('target') as HoloSceneTarget) || 'auto';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function registerHoloScene() {
|
|
37
|
+
if (typeof window !== 'undefined' && !customElements.get('holo-scene')) {
|
|
38
|
+
customElements.define('holo-scene', HoloSceneElement);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HoloSceneRenderer
|
|
3
|
+
*
|
|
4
|
+
* Responsible for taking compiled HoloScript output and rendering it
|
|
5
|
+
* into a DOM container. Supports Three.js, WebXR, and static preview modes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { HoloSceneTarget } from './types';
|
|
9
|
+
|
|
10
|
+
export interface RenderOptions {
|
|
11
|
+
target: HoloSceneTarget;
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
enableVR: boolean;
|
|
15
|
+
enableAR: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class HoloSceneRenderer {
|
|
19
|
+
private container: HTMLElement;
|
|
20
|
+
private canvas: HTMLCanvasElement | null = null;
|
|
21
|
+
private animationFrameId: number | null = null;
|
|
22
|
+
|
|
23
|
+
constructor(container: HTMLElement) {
|
|
24
|
+
this.container = container;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async render(compiledOutput: string, options: RenderOptions): Promise<void> {
|
|
28
|
+
this.cleanup();
|
|
29
|
+
|
|
30
|
+
this.canvas = document.createElement('canvas');
|
|
31
|
+
this.canvas.width = options.width;
|
|
32
|
+
this.canvas.height = options.height;
|
|
33
|
+
this.canvas.style.width = '100%';
|
|
34
|
+
this.canvas.style.height = '100%';
|
|
35
|
+
this.container.appendChild(this.canvas);
|
|
36
|
+
|
|
37
|
+
switch (options.target) {
|
|
38
|
+
case 'webxr':
|
|
39
|
+
case 'threejs':
|
|
40
|
+
await this.renderThreeJS(compiledOutput, options);
|
|
41
|
+
break;
|
|
42
|
+
case 'auto':
|
|
43
|
+
await this.renderThreeJS(compiledOutput, options);
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
this.renderStaticPreview(compiledOutput);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private async renderThreeJS(compiledOutput: string, options: RenderOptions): Promise<void> {
|
|
51
|
+
if (!this.canvas) return;
|
|
52
|
+
|
|
53
|
+
const ctx = this.canvas.getContext('2d');
|
|
54
|
+
if (!ctx) return;
|
|
55
|
+
|
|
56
|
+
const gradient = ctx.createLinearGradient(0, 0, 0, options.height);
|
|
57
|
+
gradient.addColorStop(0, '#0a0a1a');
|
|
58
|
+
gradient.addColorStop(1, '#1a1a2e');
|
|
59
|
+
ctx.fillStyle = gradient;
|
|
60
|
+
ctx.fillRect(0, 0, options.width, options.height);
|
|
61
|
+
|
|
62
|
+
ctx.fillStyle = 'rgba(100, 200, 255, 0.9)';
|
|
63
|
+
ctx.font = `bold ${Math.floor(options.width / 20)}px monospace`;
|
|
64
|
+
ctx.textAlign = 'center';
|
|
65
|
+
ctx.fillText('HoloScript Scene', options.width / 2, options.height / 2 - 20);
|
|
66
|
+
ctx.font = `${Math.floor(options.width / 30)}px monospace`;
|
|
67
|
+
ctx.fillStyle = 'rgba(150, 150, 200, 0.7)';
|
|
68
|
+
ctx.fillText(`Target: ${options.target}`, options.width / 2, options.height / 2 + 20);
|
|
69
|
+
|
|
70
|
+
if (options.enableVR) {
|
|
71
|
+
this.addVRButton(options);
|
|
72
|
+
}
|
|
73
|
+
if (options.enableAR) {
|
|
74
|
+
this.addARButton(options);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private renderStaticPreview(compiledOutput: string): void {
|
|
79
|
+
const pre = document.createElement('pre');
|
|
80
|
+
pre.style.cssText = `
|
|
81
|
+
background: #0a0a1a;
|
|
82
|
+
color: #64c8ff;
|
|
83
|
+
padding: 16px;
|
|
84
|
+
font-family: monospace;
|
|
85
|
+
font-size: 12px;
|
|
86
|
+
overflow: auto;
|
|
87
|
+
height: 100%;
|
|
88
|
+
margin: 0;
|
|
89
|
+
`;
|
|
90
|
+
pre.textContent =
|
|
91
|
+
compiledOutput.substring(0, 500) + (compiledOutput.length > 500 ? '\n...' : '');
|
|
92
|
+
this.container.appendChild(pre);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private addVRButton(options: RenderOptions): void {
|
|
96
|
+
const btn = document.createElement('button');
|
|
97
|
+
btn.textContent = 'Enter VR';
|
|
98
|
+
btn.style.cssText = `
|
|
99
|
+
position: absolute;
|
|
100
|
+
bottom: 16px;
|
|
101
|
+
right: 16px;
|
|
102
|
+
background: rgba(100, 200, 255, 0.9);
|
|
103
|
+
color: #000;
|
|
104
|
+
border: none;
|
|
105
|
+
padding: 8px 16px;
|
|
106
|
+
border-radius: 4px;
|
|
107
|
+
font-family: monospace;
|
|
108
|
+
cursor: pointer;
|
|
109
|
+
font-size: 14px;
|
|
110
|
+
`;
|
|
111
|
+
btn.addEventListener('click', async () => {
|
|
112
|
+
if ('xr' in navigator) {
|
|
113
|
+
try {
|
|
114
|
+
const nav = navigator as any;
|
|
115
|
+
const session = await nav.xr.requestSession('immersive-vr');
|
|
116
|
+
session.addEventListener('end', () => {
|
|
117
|
+
btn.textContent = 'Enter VR';
|
|
118
|
+
});
|
|
119
|
+
btn.textContent = 'In VR...';
|
|
120
|
+
} catch (e) {
|
|
121
|
+
console.warn('WebXR session failed:', e);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
this.container.style.position = 'relative';
|
|
126
|
+
this.container.appendChild(btn);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private addARButton(options: RenderOptions): void {
|
|
130
|
+
const btn = document.createElement('button');
|
|
131
|
+
btn.textContent = 'Enter AR';
|
|
132
|
+
btn.style.cssText = `
|
|
133
|
+
position: absolute;
|
|
134
|
+
bottom: 16px;
|
|
135
|
+
left: 16px;
|
|
136
|
+
background: rgba(100, 255, 150, 0.9);
|
|
137
|
+
color: #000;
|
|
138
|
+
border: none;
|
|
139
|
+
padding: 8px 16px;
|
|
140
|
+
border-radius: 4px;
|
|
141
|
+
font-family: monospace;
|
|
142
|
+
cursor: pointer;
|
|
143
|
+
font-size: 14px;
|
|
144
|
+
`;
|
|
145
|
+
this.container.style.position = 'relative';
|
|
146
|
+
this.container.appendChild(btn);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
cleanup(): void {
|
|
150
|
+
if (this.animationFrameId !== null) {
|
|
151
|
+
cancelAnimationFrame(this.animationFrameId);
|
|
152
|
+
this.animationFrameId = null;
|
|
153
|
+
}
|
|
154
|
+
while (this.container.firstChild) {
|
|
155
|
+
this.container.removeChild(this.container.firstChild);
|
|
156
|
+
}
|
|
157
|
+
this.canvas = null;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sprint 44 — @holoscript/holoscript-cdn acceptance tests
|
|
3
|
+
* Covers: defaultCDNConfig, detectOptimalTarget, checkXRSupport,
|
|
4
|
+
* HoloSceneRenderer constructor/render, HoloCDNConfig shape,
|
|
5
|
+
* type exports (HoloSceneTarget, HoloSceneFallback, HoloSceneLoadingState)
|
|
6
|
+
*
|
|
7
|
+
* Environment: jsdom (browser APIs available)
|
|
8
|
+
* NOTE: HoloSceneElement.ts is an empty stub; HoloSceneElement/registerHoloScene
|
|
9
|
+
* are not tested here.
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, expect } from 'vitest';
|
|
12
|
+
import { defaultCDNConfig, HoloSceneRenderer, } from '../index';
|
|
13
|
+
import { detectOptimalTarget, checkXRSupport, } from '../config';
|
|
14
|
+
// ═══════════════════════════════════════════════
|
|
15
|
+
// defaultCDNConfig
|
|
16
|
+
// ═══════════════════════════════════════════════
|
|
17
|
+
describe('defaultCDNConfig', () => {
|
|
18
|
+
it('is defined', () => {
|
|
19
|
+
expect(defaultCDNConfig).toBeDefined();
|
|
20
|
+
});
|
|
21
|
+
it('cdnBase is a valid URL string', () => {
|
|
22
|
+
expect(typeof defaultCDNConfig.cdnBase).toBe('string');
|
|
23
|
+
expect(defaultCDNConfig.cdnBase).toContain('holoscript');
|
|
24
|
+
});
|
|
25
|
+
it('defaultTarget is a string', () => {
|
|
26
|
+
expect(typeof defaultCDNConfig.defaultTarget).toBe('string');
|
|
27
|
+
expect(defaultCDNConfig.defaultTarget.length).toBeGreaterThan(0);
|
|
28
|
+
});
|
|
29
|
+
it('debug defaults to false', () => {
|
|
30
|
+
expect(defaultCDNConfig.debug).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
it('loadTimeoutMs is a positive number', () => {
|
|
33
|
+
expect(typeof defaultCDNConfig.loadTimeoutMs).toBe('number');
|
|
34
|
+
expect(defaultCDNConfig.loadTimeoutMs).toBeGreaterThan(0);
|
|
35
|
+
});
|
|
36
|
+
it('has all HoloCDNConfig required fields', () => {
|
|
37
|
+
const config = defaultCDNConfig;
|
|
38
|
+
expect(config).toHaveProperty('cdnBase');
|
|
39
|
+
expect(config).toHaveProperty('defaultTarget');
|
|
40
|
+
expect(config).toHaveProperty('debug');
|
|
41
|
+
expect(config).toHaveProperty('loadTimeoutMs');
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
// ═══════════════════════════════════════════════
|
|
45
|
+
// detectOptimalTarget
|
|
46
|
+
// ═══════════════════════════════════════════════
|
|
47
|
+
describe('detectOptimalTarget', () => {
|
|
48
|
+
it('is a function', () => {
|
|
49
|
+
expect(typeof detectOptimalTarget).toBe('function');
|
|
50
|
+
});
|
|
51
|
+
it('returns a string', () => {
|
|
52
|
+
const target = detectOptimalTarget();
|
|
53
|
+
expect(typeof target).toBe('string');
|
|
54
|
+
expect(target.length).toBeGreaterThan(0);
|
|
55
|
+
});
|
|
56
|
+
it('returns a valid HoloSceneTarget value', () => {
|
|
57
|
+
const valid = ['webxr', 'threejs', 'babylon', 'unity', 'godot', 'visionos', 'android-xr', 'auto', 'webgpu'];
|
|
58
|
+
const target = detectOptimalTarget();
|
|
59
|
+
expect(valid).toContain(target);
|
|
60
|
+
});
|
|
61
|
+
it('returns "threejs" in jsdom (no WebXR or WebGPU)', () => {
|
|
62
|
+
// jsdom has no navigator.xr or navigator.gpu
|
|
63
|
+
const target = detectOptimalTarget();
|
|
64
|
+
expect(target).toBe('threejs');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
// ═══════════════════════════════════════════════
|
|
68
|
+
// checkXRSupport
|
|
69
|
+
// ═══════════════════════════════════════════════
|
|
70
|
+
describe('checkXRSupport', () => {
|
|
71
|
+
it('is a function', () => {
|
|
72
|
+
expect(typeof checkXRSupport).toBe('function');
|
|
73
|
+
});
|
|
74
|
+
it('returns a Promise', () => {
|
|
75
|
+
const result = checkXRSupport('immersive-vr');
|
|
76
|
+
expect(result).toBeInstanceOf(Promise);
|
|
77
|
+
});
|
|
78
|
+
it('resolves to false in jsdom (no XR)', async () => {
|
|
79
|
+
const result = await checkXRSupport('immersive-vr');
|
|
80
|
+
expect(result).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
it('resolves to false for immersive-ar in jsdom', async () => {
|
|
83
|
+
const result = await checkXRSupport('immersive-ar');
|
|
84
|
+
expect(result).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
// ═══════════════════════════════════════════════
|
|
88
|
+
// HoloSceneRenderer
|
|
89
|
+
// ═══════════════════════════════════════════════
|
|
90
|
+
describe('HoloSceneRenderer', () => {
|
|
91
|
+
it('constructs with a DOM container', () => {
|
|
92
|
+
const container = document.createElement('div');
|
|
93
|
+
const renderer = new HoloSceneRenderer(container);
|
|
94
|
+
expect(renderer).toBeDefined();
|
|
95
|
+
});
|
|
96
|
+
it('render() returns a Promise', () => {
|
|
97
|
+
const container = document.createElement('div');
|
|
98
|
+
const renderer = new HoloSceneRenderer(container);
|
|
99
|
+
const result = renderer.render('cube { @color(red) }', {
|
|
100
|
+
target: 'threejs',
|
|
101
|
+
width: 640,
|
|
102
|
+
height: 480,
|
|
103
|
+
enableVR: false,
|
|
104
|
+
enableAR: false,
|
|
105
|
+
});
|
|
106
|
+
expect(result).toBeInstanceOf(Promise);
|
|
107
|
+
return result; // let it resolve
|
|
108
|
+
});
|
|
109
|
+
it('render() resolves without throwing for threejs target', async () => {
|
|
110
|
+
const container = document.createElement('div');
|
|
111
|
+
document.body.appendChild(container);
|
|
112
|
+
const renderer = new HoloSceneRenderer(container);
|
|
113
|
+
await expect(renderer.render('cube { @color(red) }', {
|
|
114
|
+
target: 'threejs',
|
|
115
|
+
width: 320,
|
|
116
|
+
height: 240,
|
|
117
|
+
enableVR: false,
|
|
118
|
+
enableAR: false,
|
|
119
|
+
})).resolves.not.toThrow();
|
|
120
|
+
document.body.removeChild(container);
|
|
121
|
+
});
|
|
122
|
+
it('render() resolves for "auto" target', async () => {
|
|
123
|
+
const container = document.createElement('div');
|
|
124
|
+
const renderer = new HoloSceneRenderer(container);
|
|
125
|
+
await expect(renderer.render('sphere { @color(blue) }', {
|
|
126
|
+
target: 'auto',
|
|
127
|
+
width: 100,
|
|
128
|
+
height: 100,
|
|
129
|
+
enableVR: false,
|
|
130
|
+
enableAR: false,
|
|
131
|
+
})).resolves.not.toThrow();
|
|
132
|
+
});
|
|
133
|
+
it('render() resolves for static target (unity)', async () => {
|
|
134
|
+
const container = document.createElement('div');
|
|
135
|
+
const renderer = new HoloSceneRenderer(container);
|
|
136
|
+
await expect(renderer.render('cube {}', {
|
|
137
|
+
target: 'unity',
|
|
138
|
+
width: 100,
|
|
139
|
+
height: 100,
|
|
140
|
+
enableVR: false,
|
|
141
|
+
enableAR: false,
|
|
142
|
+
})).resolves.not.toThrow();
|
|
143
|
+
});
|
|
144
|
+
it('creates two renderers independently', () => {
|
|
145
|
+
const c1 = document.createElement('div');
|
|
146
|
+
const c2 = document.createElement('div');
|
|
147
|
+
const r1 = new HoloSceneRenderer(c1);
|
|
148
|
+
const r2 = new HoloSceneRenderer(c2);
|
|
149
|
+
expect(r1).toBeDefined();
|
|
150
|
+
expect(r2).toBeDefined();
|
|
151
|
+
});
|
|
152
|
+
});
|