@holoscript/cdn 1.0.0 → 1.0.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/README.md +10 -0
- package/dist/index.cdn.js +4 -4
- package/dist/index.cdn.js.map +1 -1
- package/dist/index.cdn.mjs +4 -4
- package/dist/index.cdn.mjs.map +1 -1
- package/package.json +19 -13
- package/error-tsc-utf8.log +0 -0
- package/error-tsc.log +0 -0
- package/error-utf8.log +0 -262
- package/error.log +0 -0
- package/src/HoloSceneElement.ts +0 -40
- package/src/HoloSceneRenderer.ts +0 -159
- package/src/__tests__/Sprint44.test.d.ts +0 -1
- package/src/__tests__/Sprint44.test.js +0 -152
- package/src/__tests__/Sprint44.test.ts +0 -188
- package/src/config.ts +0 -44
- package/src/index.ts +0 -17
- package/src/types.ts +0 -44
- package/tsconfig.json +0 -21
- package/tsup.config.d.ts +0 -2
- package/tsup.config.js +0 -12
- package/tsup.config.ts +0 -13
- package/vitest.config.ts +0 -9
package/README.md
CHANGED
|
@@ -17,3 +17,13 @@ Include the built bundle in a web page to register the `<holo-scene>` custom ele
|
|
|
17
17
|
pnpm dev # Build with watch mode (tsup)
|
|
18
18
|
pnpm test # Run tests (vitest)
|
|
19
19
|
```
|
|
20
|
+
|
|
21
|
+
## Package boundary & release posture
|
|
22
|
+
|
|
23
|
+
`@holoscript/cdn` targets **external, public** web developers and **agent framework** integrators embedding a HoloScript scene into an existing web page via a single `<script>` tag and the `<holo-scene>` custom element. The package boundary is a browser bundle plus a config surface (`HoloCDNConfig`, `defaultCDNConfig`): it **does not ship** scene content, a build pipeline, or hosting — you bring your own `.hs`/`.hsplus` scene file (via the `src` attribute) or inline markup, and can point it at your own CDN base URL by overriding `cdnBase` instead of the bundled `https://cdn.holoscript.net` default; nothing here assumes founder-local config.
|
|
24
|
+
|
|
25
|
+
**Known limitations (v0-preview):** target auto-detection (`detectOptimalTarget`) degrades to `threejs` when WebXR/WebGPU are unavailable, and only the `threejs` fallback is currently implemented end-to-end — `babylon`, `unity`, `godot`, `visionos`, and `android-xr` targets are declared in the type surface but not all are production-validated yet. Run `pnpm test` to validate the custom element registration and target-detection logic before embedding in a production page.
|
|
26
|
+
|
|
27
|
+
## License
|
|
28
|
+
|
|
29
|
+
MIT
|
package/dist/index.cdn.js
CHANGED
|
@@ -93,7 +93,7 @@ var HoloSceneRenderer = class {
|
|
|
93
93
|
pre.textContent = compiledOutput.substring(0, 500) + (compiledOutput.length > 500 ? "\n..." : "");
|
|
94
94
|
this.container.appendChild(pre);
|
|
95
95
|
}
|
|
96
|
-
addVRButton(
|
|
96
|
+
addVRButton(_options) {
|
|
97
97
|
const btn = document.createElement("button");
|
|
98
98
|
btn.textContent = "Enter VR";
|
|
99
99
|
btn.style.cssText = `
|
|
@@ -112,8 +112,8 @@ var HoloSceneRenderer = class {
|
|
|
112
112
|
btn.addEventListener("click", async () => {
|
|
113
113
|
if ("xr" in navigator) {
|
|
114
114
|
try {
|
|
115
|
-
const
|
|
116
|
-
const session = await
|
|
115
|
+
const xrSystem = navigator.xr;
|
|
116
|
+
const session = await xrSystem.requestSession("immersive-vr");
|
|
117
117
|
session.addEventListener("end", () => {
|
|
118
118
|
btn.textContent = "Enter VR";
|
|
119
119
|
});
|
|
@@ -126,7 +126,7 @@ var HoloSceneRenderer = class {
|
|
|
126
126
|
this.container.style.position = "relative";
|
|
127
127
|
this.container.appendChild(btn);
|
|
128
128
|
}
|
|
129
|
-
addARButton(
|
|
129
|
+
addARButton(_options) {
|
|
130
130
|
const btn = document.createElement("button");
|
|
131
131
|
btn.textContent = "Enter AR";
|
|
132
132
|
btn.style.cssText = `
|
package/dist/index.cdn.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/HoloSceneRenderer.ts","../src/HoloSceneElement.ts","../src/config.ts"],"sourcesContent":["/**\n * @holoscript/cdn — Browser CDN distribution\n *\n * Exposes <holo-scene> custom element for embedding HoloScript scenes\n * in any webpage via a CDN script tag.\n *\n * Usage:\n * <script src=\"https://cdn.holoscript.net/v4.min.js\"></script>\n * <holo-scene src=\"./my-world.hs\" target=\"webxr\" fallback=\"threejs\"></holo-scene>\n *\n * @version 1.0.0\n */\n\nexport { HoloSceneElement, registerHoloScene } from './HoloSceneElement.js';\nexport { HoloSceneRenderer } from './HoloSceneRenderer.js';\nexport { HoloCDNConfig, defaultCDNConfig } from './config.js';\nexport type { HoloSceneAttributes, HoloSceneTarget, HoloSceneFallback } from './types.js';\n","/**\n * HoloSceneRenderer\n *\n * Responsible for taking compiled HoloScript output and rendering it\n * into a DOM container. Supports Three.js, WebXR, and static preview modes.\n */\n\nimport type { HoloSceneTarget } from './types';\n\nexport interface RenderOptions {\n target: HoloSceneTarget;\n width: number;\n height: number;\n enableVR: boolean;\n enableAR: boolean;\n}\n\nexport class HoloSceneRenderer {\n private container: HTMLElement;\n private canvas: HTMLCanvasElement | null = null;\n private animationFrameId: number | null = null;\n\n constructor(container: HTMLElement) {\n this.container = container;\n }\n\n async render(compiledOutput: string, options: RenderOptions): Promise<void> {\n this.cleanup();\n\n this.canvas = document.createElement('canvas');\n this.canvas.width = options.width;\n this.canvas.height = options.height;\n this.canvas.style.width = '100%';\n this.canvas.style.height = '100%';\n this.container.appendChild(this.canvas);\n\n switch (options.target) {\n case 'webxr':\n case 'threejs':\n await this.renderThreeJS(compiledOutput, options);\n break;\n case 'auto':\n await this.renderThreeJS(compiledOutput, options);\n break;\n default:\n this.renderStaticPreview(compiledOutput);\n }\n }\n\n private async renderThreeJS(compiledOutput: string, options: RenderOptions): Promise<void> {\n if (!this.canvas) return;\n\n const ctx = this.canvas.getContext('2d');\n if (!ctx) return;\n\n const gradient = ctx.createLinearGradient(0, 0, 0, options.height);\n gradient.addColorStop(0, '#0a0a1a');\n gradient.addColorStop(1, '#1a1a2e');\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, options.width, options.height);\n\n ctx.fillStyle = 'rgba(100, 200, 255, 0.9)';\n ctx.font = `bold ${Math.floor(options.width / 20)}px monospace`;\n ctx.textAlign = 'center';\n ctx.fillText('HoloScript Scene', options.width / 2, options.height / 2 - 20);\n ctx.font = `${Math.floor(options.width / 30)}px monospace`;\n ctx.fillStyle = 'rgba(150, 150, 200, 0.7)';\n ctx.fillText(`Target: ${options.target}`, options.width / 2, options.height / 2 + 20);\n\n if (options.enableVR) {\n this.addVRButton(options);\n }\n if (options.enableAR) {\n this.addARButton(options);\n }\n }\n\n private renderStaticPreview(compiledOutput: string): void {\n const pre = document.createElement('pre');\n pre.style.cssText = `\n background: #0a0a1a;\n color: #64c8ff;\n padding: 16px;\n font-family: monospace;\n font-size: 12px;\n overflow: auto;\n height: 100%;\n margin: 0;\n `;\n pre.textContent =\n compiledOutput.substring(0, 500) + (compiledOutput.length > 500 ? '\\n...' : '');\n this.container.appendChild(pre);\n }\n\n private addVRButton(options: RenderOptions): void {\n const btn = document.createElement('button');\n btn.textContent = 'Enter VR';\n btn.style.cssText = `\n position: absolute;\n bottom: 16px;\n right: 16px;\n background: rgba(100, 200, 255, 0.9);\n color: #000;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-family: monospace;\n cursor: pointer;\n font-size: 14px;\n `;\n btn.addEventListener('click', async () => {\n if ('xr' in navigator) {\n try {\n const nav = navigator as any;\n const session = await nav.xr.requestSession('immersive-vr');\n session.addEventListener('end', () => {\n btn.textContent = 'Enter VR';\n });\n btn.textContent = 'In VR...';\n } catch (e) {\n console.warn('WebXR session failed:', e);\n }\n }\n });\n this.container.style.position = 'relative';\n this.container.appendChild(btn);\n }\n\n private addARButton(options: RenderOptions): void {\n const btn = document.createElement('button');\n btn.textContent = 'Enter AR';\n btn.style.cssText = `\n position: absolute;\n bottom: 16px;\n left: 16px;\n background: rgba(100, 255, 150, 0.9);\n color: #000;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-family: monospace;\n cursor: pointer;\n font-size: 14px;\n `;\n this.container.style.position = 'relative';\n this.container.appendChild(btn);\n }\n\n cleanup(): void {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n while (this.container.firstChild) {\n this.container.removeChild(this.container.firstChild);\n }\n this.canvas = null;\n }\n}\n","import type { HoloSceneTarget, HoloSceneFallback } from './types';\nimport { HoloSceneRenderer } from './HoloSceneRenderer';\n\nexport class HoloSceneElement extends HTMLElement {\n private renderer: HoloSceneRenderer | null = null;\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n if (!this.shadowRoot) return;\n const container = document.createElement('div');\n container.style.width = '100%';\n container.style.height = '100%';\n this.shadowRoot.appendChild(container);\n this.renderer = new HoloSceneRenderer(container);\n }\n\n disconnectedCallback() {\n if (this.renderer) {\n this.renderer.cleanup();\n }\n }\n\n get src(): string {\n return this.getAttribute('src') || '';\n }\n\n get target(): HoloSceneTarget {\n return (this.getAttribute('target') as HoloSceneTarget) || 'auto';\n }\n}\n\nexport function registerHoloScene() {\n if (typeof window !== 'undefined' && !customElements.get('holo-scene')) {\n customElements.define('holo-scene', HoloSceneElement);\n }\n}\n","/**\n * CDN configuration and defaults\n */\n\nexport interface HoloCDNConfig {\n cdnBase: string;\n defaultTarget: string;\n debug: boolean;\n loadTimeoutMs: number;\n}\n\nexport const defaultCDNConfig: HoloCDNConfig = {\n cdnBase: 'https://cdn.holoscript.net',\n defaultTarget: 'threejs',\n debug: false,\n loadTimeoutMs: 10000,\n};\n\nexport function detectOptimalTarget(): string {\n if (typeof navigator === 'undefined') return 'threejs';\n\n if ('xr' in navigator) {\n const nav = navigator as any;\n if (nav.xr?.isSessionSupported) {\n return 'webxr';\n }\n }\n\n if ('gpu' in navigator) {\n return 'webgpu';\n }\n\n return 'threejs';\n}\n\nexport async function checkXRSupport(mode: 'immersive-vr' | 'immersive-ar'): Promise<boolean> {\n if (typeof navigator === 'undefined' || !('xr' in navigator)) return false;\n try {\n const nav = navigator as any;\n return await nav.xr.isSessionSupported(mode);\n } catch {\n return false;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/HoloSceneRenderer.ts","../src/HoloSceneElement.ts","../src/config.ts"],"sourcesContent":["/**\n * @holoscript/cdn — Browser CDN distribution\n *\n * Exposes <holo-scene> custom element for embedding HoloScript scenes\n * in any webpage via a CDN script tag.\n *\n * Usage:\n * <script src=\"https://cdn.holoscript.net/v4.min.js\"></script>\n * <holo-scene src=\"./my-world.hs\" target=\"webxr\" fallback=\"threejs\"></holo-scene>\n *\n * @version 1.0.0\n */\n\nexport { HoloSceneElement, registerHoloScene } from './HoloSceneElement.js';\nexport { HoloSceneRenderer } from './HoloSceneRenderer.js';\nexport { HoloCDNConfig, defaultCDNConfig } from './config.js';\nexport type { HoloSceneAttributes, HoloSceneTarget, HoloSceneFallback } from './types.js';\n","/**\n * HoloSceneRenderer\n *\n * Responsible for taking compiled HoloScript output and rendering it\n * into a DOM container. Supports Three.js, WebXR, and static preview modes.\n */\n\nimport type { HoloSceneTarget } from './types';\n\nexport interface RenderOptions {\n target: HoloSceneTarget;\n width: number;\n height: number;\n enableVR: boolean;\n enableAR: boolean;\n}\n\nexport class HoloSceneRenderer {\n private container: HTMLElement;\n private canvas: HTMLCanvasElement | null = null;\n private animationFrameId: number | null = null;\n\n constructor(container: HTMLElement) {\n this.container = container;\n }\n\n async render(compiledOutput: string, options: RenderOptions): Promise<void> {\n this.cleanup();\n\n this.canvas = document.createElement('canvas');\n this.canvas.width = options.width;\n this.canvas.height = options.height;\n this.canvas.style.width = '100%';\n this.canvas.style.height = '100%';\n this.container.appendChild(this.canvas);\n\n switch (options.target) {\n case 'webxr':\n case 'threejs':\n await this.renderThreeJS(compiledOutput, options);\n break;\n case 'auto':\n await this.renderThreeJS(compiledOutput, options);\n break;\n default:\n this.renderStaticPreview(compiledOutput);\n }\n }\n\n private async renderThreeJS(compiledOutput: string, options: RenderOptions): Promise<void> {\n if (!this.canvas) return;\n\n const ctx = this.canvas.getContext('2d');\n if (!ctx) return;\n\n const gradient = ctx.createLinearGradient(0, 0, 0, options.height);\n gradient.addColorStop(0, '#0a0a1a');\n gradient.addColorStop(1, '#1a1a2e');\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, options.width, options.height);\n\n ctx.fillStyle = 'rgba(100, 200, 255, 0.9)';\n ctx.font = `bold ${Math.floor(options.width / 20)}px monospace`;\n ctx.textAlign = 'center';\n ctx.fillText('HoloScript Scene', options.width / 2, options.height / 2 - 20);\n ctx.font = `${Math.floor(options.width / 30)}px monospace`;\n ctx.fillStyle = 'rgba(150, 150, 200, 0.7)';\n ctx.fillText(`Target: ${options.target}`, options.width / 2, options.height / 2 + 20);\n\n if (options.enableVR) {\n this.addVRButton(options);\n }\n if (options.enableAR) {\n this.addARButton(options);\n }\n }\n\n private renderStaticPreview(compiledOutput: string): void {\n const pre = document.createElement('pre');\n pre.style.cssText = `\n background: #0a0a1a;\n color: #64c8ff;\n padding: 16px;\n font-family: monospace;\n font-size: 12px;\n overflow: auto;\n height: 100%;\n margin: 0;\n `;\n pre.textContent =\n compiledOutput.substring(0, 500) + (compiledOutput.length > 500 ? '\\n...' : '');\n this.container.appendChild(pre);\n }\n\n private addVRButton(_options: RenderOptions): void {\n const btn = document.createElement('button');\n btn.textContent = 'Enter VR';\n btn.style.cssText = `\n position: absolute;\n bottom: 16px;\n right: 16px;\n background: rgba(100, 200, 255, 0.9);\n color: #000;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-family: monospace;\n cursor: pointer;\n font-size: 14px;\n `;\n btn.addEventListener('click', async () => {\n if ('xr' in navigator) {\n try {\n const xrSystem = (\n navigator as Navigator & {\n xr?: {\n requestSession(\n mode: string\n ): Promise<{ addEventListener(type: string, cb: () => void): void }>;\n };\n }\n ).xr!;\n const session = await xrSystem.requestSession('immersive-vr');\n session.addEventListener('end', () => {\n btn.textContent = 'Enter VR';\n });\n btn.textContent = 'In VR...';\n } catch (e) {\n console.warn('WebXR session failed:', e);\n }\n }\n });\n this.container.style.position = 'relative';\n this.container.appendChild(btn);\n }\n\n private addARButton(_options: RenderOptions): void {\n const btn = document.createElement('button');\n btn.textContent = 'Enter AR';\n btn.style.cssText = `\n position: absolute;\n bottom: 16px;\n left: 16px;\n background: rgba(100, 255, 150, 0.9);\n color: #000;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-family: monospace;\n cursor: pointer;\n font-size: 14px;\n `;\n this.container.style.position = 'relative';\n this.container.appendChild(btn);\n }\n\n cleanup(): void {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n while (this.container.firstChild) {\n this.container.removeChild(this.container.firstChild);\n }\n this.canvas = null;\n }\n}\n","import type { HoloSceneTarget, HoloSceneFallback } from './types';\nimport { HoloSceneRenderer } from './HoloSceneRenderer';\n\nexport class HoloSceneElement extends HTMLElement {\n private renderer: HoloSceneRenderer | null = null;\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n if (!this.shadowRoot) return;\n const container = document.createElement('div');\n container.style.width = '100%';\n container.style.height = '100%';\n this.shadowRoot.appendChild(container);\n this.renderer = new HoloSceneRenderer(container);\n }\n\n disconnectedCallback() {\n if (this.renderer) {\n this.renderer.cleanup();\n }\n }\n\n get src(): string {\n return this.getAttribute('src') || '';\n }\n\n get target(): HoloSceneTarget {\n return (this.getAttribute('target') as HoloSceneTarget) || 'auto';\n }\n}\n\nexport function registerHoloScene() {\n if (typeof window !== 'undefined' && !customElements.get('holo-scene')) {\n customElements.define('holo-scene', HoloSceneElement);\n }\n}\n","/**\n * CDN configuration and defaults\n */\n\nexport interface HoloCDNConfig {\n cdnBase: string;\n defaultTarget: string;\n debug: boolean;\n loadTimeoutMs: number;\n}\n\nexport const defaultCDNConfig: HoloCDNConfig = {\n cdnBase: 'https://cdn.holoscript.net',\n defaultTarget: 'threejs',\n debug: false,\n loadTimeoutMs: 10000,\n};\n\nexport function detectOptimalTarget(): string {\n if (typeof navigator === 'undefined') return 'threejs';\n\n if ('xr' in navigator) {\n const xrSystem = (\n navigator as Navigator & { xr?: { isSessionSupported(mode: string): Promise<boolean> } }\n ).xr;\n if (xrSystem?.isSessionSupported) {\n return 'webxr';\n }\n }\n\n if ('gpu' in navigator) {\n return 'webgpu';\n }\n\n return 'threejs';\n}\n\nexport async function checkXRSupport(mode: 'immersive-vr' | 'immersive-ar'): Promise<boolean> {\n if (typeof navigator === 'undefined' || !('xr' in navigator)) return false;\n try {\n const xrSystem = (\n navigator as Navigator & { xr?: { isSessionSupported(mode: string): Promise<boolean> } }\n ).xr;\n return await xrSystem!.isSessionSupported(mode);\n } catch {\n return false;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.cdn.mjs
CHANGED
|
@@ -64,7 +64,7 @@ var HoloSceneRenderer = class {
|
|
|
64
64
|
pre.textContent = compiledOutput.substring(0, 500) + (compiledOutput.length > 500 ? "\n..." : "");
|
|
65
65
|
this.container.appendChild(pre);
|
|
66
66
|
}
|
|
67
|
-
addVRButton(
|
|
67
|
+
addVRButton(_options) {
|
|
68
68
|
const btn = document.createElement("button");
|
|
69
69
|
btn.textContent = "Enter VR";
|
|
70
70
|
btn.style.cssText = `
|
|
@@ -83,8 +83,8 @@ var HoloSceneRenderer = class {
|
|
|
83
83
|
btn.addEventListener("click", async () => {
|
|
84
84
|
if ("xr" in navigator) {
|
|
85
85
|
try {
|
|
86
|
-
const
|
|
87
|
-
const session = await
|
|
86
|
+
const xrSystem = navigator.xr;
|
|
87
|
+
const session = await xrSystem.requestSession("immersive-vr");
|
|
88
88
|
session.addEventListener("end", () => {
|
|
89
89
|
btn.textContent = "Enter VR";
|
|
90
90
|
});
|
|
@@ -97,7 +97,7 @@ var HoloSceneRenderer = class {
|
|
|
97
97
|
this.container.style.position = "relative";
|
|
98
98
|
this.container.appendChild(btn);
|
|
99
99
|
}
|
|
100
|
-
addARButton(
|
|
100
|
+
addARButton(_options) {
|
|
101
101
|
const btn = document.createElement("button");
|
|
102
102
|
btn.textContent = "Enter AR";
|
|
103
103
|
btn.style.cssText = `
|
package/dist/index.cdn.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/HoloSceneRenderer.ts","../src/HoloSceneElement.ts","../src/config.ts"],"sourcesContent":["/**\n * HoloSceneRenderer\n *\n * Responsible for taking compiled HoloScript output and rendering it\n * into a DOM container. Supports Three.js, WebXR, and static preview modes.\n */\n\nimport type { HoloSceneTarget } from './types';\n\nexport interface RenderOptions {\n target: HoloSceneTarget;\n width: number;\n height: number;\n enableVR: boolean;\n enableAR: boolean;\n}\n\nexport class HoloSceneRenderer {\n private container: HTMLElement;\n private canvas: HTMLCanvasElement | null = null;\n private animationFrameId: number | null = null;\n\n constructor(container: HTMLElement) {\n this.container = container;\n }\n\n async render(compiledOutput: string, options: RenderOptions): Promise<void> {\n this.cleanup();\n\n this.canvas = document.createElement('canvas');\n this.canvas.width = options.width;\n this.canvas.height = options.height;\n this.canvas.style.width = '100%';\n this.canvas.style.height = '100%';\n this.container.appendChild(this.canvas);\n\n switch (options.target) {\n case 'webxr':\n case 'threejs':\n await this.renderThreeJS(compiledOutput, options);\n break;\n case 'auto':\n await this.renderThreeJS(compiledOutput, options);\n break;\n default:\n this.renderStaticPreview(compiledOutput);\n }\n }\n\n private async renderThreeJS(compiledOutput: string, options: RenderOptions): Promise<void> {\n if (!this.canvas) return;\n\n const ctx = this.canvas.getContext('2d');\n if (!ctx) return;\n\n const gradient = ctx.createLinearGradient(0, 0, 0, options.height);\n gradient.addColorStop(0, '#0a0a1a');\n gradient.addColorStop(1, '#1a1a2e');\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, options.width, options.height);\n\n ctx.fillStyle = 'rgba(100, 200, 255, 0.9)';\n ctx.font = `bold ${Math.floor(options.width / 20)}px monospace`;\n ctx.textAlign = 'center';\n ctx.fillText('HoloScript Scene', options.width / 2, options.height / 2 - 20);\n ctx.font = `${Math.floor(options.width / 30)}px monospace`;\n ctx.fillStyle = 'rgba(150, 150, 200, 0.7)';\n ctx.fillText(`Target: ${options.target}`, options.width / 2, options.height / 2 + 20);\n\n if (options.enableVR) {\n this.addVRButton(options);\n }\n if (options.enableAR) {\n this.addARButton(options);\n }\n }\n\n private renderStaticPreview(compiledOutput: string): void {\n const pre = document.createElement('pre');\n pre.style.cssText = `\n background: #0a0a1a;\n color: #64c8ff;\n padding: 16px;\n font-family: monospace;\n font-size: 12px;\n overflow: auto;\n height: 100%;\n margin: 0;\n `;\n pre.textContent =\n compiledOutput.substring(0, 500) + (compiledOutput.length > 500 ? '\\n...' : '');\n this.container.appendChild(pre);\n }\n\n private addVRButton(options: RenderOptions): void {\n const btn = document.createElement('button');\n btn.textContent = 'Enter VR';\n btn.style.cssText = `\n position: absolute;\n bottom: 16px;\n right: 16px;\n background: rgba(100, 200, 255, 0.9);\n color: #000;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-family: monospace;\n cursor: pointer;\n font-size: 14px;\n `;\n btn.addEventListener('click', async () => {\n if ('xr' in navigator) {\n try {\n const nav = navigator as any;\n const session = await nav.xr.requestSession('immersive-vr');\n session.addEventListener('end', () => {\n btn.textContent = 'Enter VR';\n });\n btn.textContent = 'In VR...';\n } catch (e) {\n console.warn('WebXR session failed:', e);\n }\n }\n });\n this.container.style.position = 'relative';\n this.container.appendChild(btn);\n }\n\n private addARButton(options: RenderOptions): void {\n const btn = document.createElement('button');\n btn.textContent = 'Enter AR';\n btn.style.cssText = `\n position: absolute;\n bottom: 16px;\n left: 16px;\n background: rgba(100, 255, 150, 0.9);\n color: #000;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-family: monospace;\n cursor: pointer;\n font-size: 14px;\n `;\n this.container.style.position = 'relative';\n this.container.appendChild(btn);\n }\n\n cleanup(): void {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n while (this.container.firstChild) {\n this.container.removeChild(this.container.firstChild);\n }\n this.canvas = null;\n }\n}\n","import type { HoloSceneTarget, HoloSceneFallback } from './types';\nimport { HoloSceneRenderer } from './HoloSceneRenderer';\n\nexport class HoloSceneElement extends HTMLElement {\n private renderer: HoloSceneRenderer | null = null;\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n if (!this.shadowRoot) return;\n const container = document.createElement('div');\n container.style.width = '100%';\n container.style.height = '100%';\n this.shadowRoot.appendChild(container);\n this.renderer = new HoloSceneRenderer(container);\n }\n\n disconnectedCallback() {\n if (this.renderer) {\n this.renderer.cleanup();\n }\n }\n\n get src(): string {\n return this.getAttribute('src') || '';\n }\n\n get target(): HoloSceneTarget {\n return (this.getAttribute('target') as HoloSceneTarget) || 'auto';\n }\n}\n\nexport function registerHoloScene() {\n if (typeof window !== 'undefined' && !customElements.get('holo-scene')) {\n customElements.define('holo-scene', HoloSceneElement);\n }\n}\n","/**\n * CDN configuration and defaults\n */\n\nexport interface HoloCDNConfig {\n cdnBase: string;\n defaultTarget: string;\n debug: boolean;\n loadTimeoutMs: number;\n}\n\nexport const defaultCDNConfig: HoloCDNConfig = {\n cdnBase: 'https://cdn.holoscript.net',\n defaultTarget: 'threejs',\n debug: false,\n loadTimeoutMs: 10000,\n};\n\nexport function detectOptimalTarget(): string {\n if (typeof navigator === 'undefined') return 'threejs';\n\n if ('xr' in navigator) {\n const nav = navigator as any;\n if (nav.xr?.isSessionSupported) {\n return 'webxr';\n }\n }\n\n if ('gpu' in navigator) {\n return 'webgpu';\n }\n\n return 'threejs';\n}\n\nexport async function checkXRSupport(mode: 'immersive-vr' | 'immersive-ar'): Promise<boolean> {\n if (typeof navigator === 'undefined' || !('xr' in navigator)) return false;\n try {\n const nav = navigator as any;\n return await nav.xr.isSessionSupported(mode);\n } catch {\n return false;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/HoloSceneRenderer.ts","../src/HoloSceneElement.ts","../src/config.ts"],"sourcesContent":["/**\n * HoloSceneRenderer\n *\n * Responsible for taking compiled HoloScript output and rendering it\n * into a DOM container. Supports Three.js, WebXR, and static preview modes.\n */\n\nimport type { HoloSceneTarget } from './types';\n\nexport interface RenderOptions {\n target: HoloSceneTarget;\n width: number;\n height: number;\n enableVR: boolean;\n enableAR: boolean;\n}\n\nexport class HoloSceneRenderer {\n private container: HTMLElement;\n private canvas: HTMLCanvasElement | null = null;\n private animationFrameId: number | null = null;\n\n constructor(container: HTMLElement) {\n this.container = container;\n }\n\n async render(compiledOutput: string, options: RenderOptions): Promise<void> {\n this.cleanup();\n\n this.canvas = document.createElement('canvas');\n this.canvas.width = options.width;\n this.canvas.height = options.height;\n this.canvas.style.width = '100%';\n this.canvas.style.height = '100%';\n this.container.appendChild(this.canvas);\n\n switch (options.target) {\n case 'webxr':\n case 'threejs':\n await this.renderThreeJS(compiledOutput, options);\n break;\n case 'auto':\n await this.renderThreeJS(compiledOutput, options);\n break;\n default:\n this.renderStaticPreview(compiledOutput);\n }\n }\n\n private async renderThreeJS(compiledOutput: string, options: RenderOptions): Promise<void> {\n if (!this.canvas) return;\n\n const ctx = this.canvas.getContext('2d');\n if (!ctx) return;\n\n const gradient = ctx.createLinearGradient(0, 0, 0, options.height);\n gradient.addColorStop(0, '#0a0a1a');\n gradient.addColorStop(1, '#1a1a2e');\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, options.width, options.height);\n\n ctx.fillStyle = 'rgba(100, 200, 255, 0.9)';\n ctx.font = `bold ${Math.floor(options.width / 20)}px monospace`;\n ctx.textAlign = 'center';\n ctx.fillText('HoloScript Scene', options.width / 2, options.height / 2 - 20);\n ctx.font = `${Math.floor(options.width / 30)}px monospace`;\n ctx.fillStyle = 'rgba(150, 150, 200, 0.7)';\n ctx.fillText(`Target: ${options.target}`, options.width / 2, options.height / 2 + 20);\n\n if (options.enableVR) {\n this.addVRButton(options);\n }\n if (options.enableAR) {\n this.addARButton(options);\n }\n }\n\n private renderStaticPreview(compiledOutput: string): void {\n const pre = document.createElement('pre');\n pre.style.cssText = `\n background: #0a0a1a;\n color: #64c8ff;\n padding: 16px;\n font-family: monospace;\n font-size: 12px;\n overflow: auto;\n height: 100%;\n margin: 0;\n `;\n pre.textContent =\n compiledOutput.substring(0, 500) + (compiledOutput.length > 500 ? '\\n...' : '');\n this.container.appendChild(pre);\n }\n\n private addVRButton(_options: RenderOptions): void {\n const btn = document.createElement('button');\n btn.textContent = 'Enter VR';\n btn.style.cssText = `\n position: absolute;\n bottom: 16px;\n right: 16px;\n background: rgba(100, 200, 255, 0.9);\n color: #000;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-family: monospace;\n cursor: pointer;\n font-size: 14px;\n `;\n btn.addEventListener('click', async () => {\n if ('xr' in navigator) {\n try {\n const xrSystem = (\n navigator as Navigator & {\n xr?: {\n requestSession(\n mode: string\n ): Promise<{ addEventListener(type: string, cb: () => void): void }>;\n };\n }\n ).xr!;\n const session = await xrSystem.requestSession('immersive-vr');\n session.addEventListener('end', () => {\n btn.textContent = 'Enter VR';\n });\n btn.textContent = 'In VR...';\n } catch (e) {\n console.warn('WebXR session failed:', e);\n }\n }\n });\n this.container.style.position = 'relative';\n this.container.appendChild(btn);\n }\n\n private addARButton(_options: RenderOptions): void {\n const btn = document.createElement('button');\n btn.textContent = 'Enter AR';\n btn.style.cssText = `\n position: absolute;\n bottom: 16px;\n left: 16px;\n background: rgba(100, 255, 150, 0.9);\n color: #000;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-family: monospace;\n cursor: pointer;\n font-size: 14px;\n `;\n this.container.style.position = 'relative';\n this.container.appendChild(btn);\n }\n\n cleanup(): void {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n while (this.container.firstChild) {\n this.container.removeChild(this.container.firstChild);\n }\n this.canvas = null;\n }\n}\n","import type { HoloSceneTarget, HoloSceneFallback } from './types';\nimport { HoloSceneRenderer } from './HoloSceneRenderer';\n\nexport class HoloSceneElement extends HTMLElement {\n private renderer: HoloSceneRenderer | null = null;\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n if (!this.shadowRoot) return;\n const container = document.createElement('div');\n container.style.width = '100%';\n container.style.height = '100%';\n this.shadowRoot.appendChild(container);\n this.renderer = new HoloSceneRenderer(container);\n }\n\n disconnectedCallback() {\n if (this.renderer) {\n this.renderer.cleanup();\n }\n }\n\n get src(): string {\n return this.getAttribute('src') || '';\n }\n\n get target(): HoloSceneTarget {\n return (this.getAttribute('target') as HoloSceneTarget) || 'auto';\n }\n}\n\nexport function registerHoloScene() {\n if (typeof window !== 'undefined' && !customElements.get('holo-scene')) {\n customElements.define('holo-scene', HoloSceneElement);\n }\n}\n","/**\n * CDN configuration and defaults\n */\n\nexport interface HoloCDNConfig {\n cdnBase: string;\n defaultTarget: string;\n debug: boolean;\n loadTimeoutMs: number;\n}\n\nexport const defaultCDNConfig: HoloCDNConfig = {\n cdnBase: 'https://cdn.holoscript.net',\n defaultTarget: 'threejs',\n debug: false,\n loadTimeoutMs: 10000,\n};\n\nexport function detectOptimalTarget(): string {\n if (typeof navigator === 'undefined') return 'threejs';\n\n if ('xr' in navigator) {\n const xrSystem = (\n navigator as Navigator & { xr?: { isSessionSupported(mode: string): Promise<boolean> } }\n ).xr;\n if (xrSystem?.isSessionSupported) {\n return 'webxr';\n }\n }\n\n if ('gpu' in navigator) {\n return 'webgpu';\n }\n\n return 'threejs';\n}\n\nexport async function checkXRSupport(mode: 'immersive-vr' | 'immersive-ar'): Promise<boolean> {\n if (typeof navigator === 'undefined' || !('xr' in navigator)) return false;\n try {\n const xrSystem = (\n navigator as Navigator & { xr?: { isSessionSupported(mode: string): Promise<boolean> } }\n ).xr;\n return await xrSystem!.isSessionSupported(mode);\n } catch {\n return false;\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holoscript/cdn",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Browser CDN distribution for HoloScript — embed spatial scenes with <holo-scene>",
|
|
5
|
-
"main": "dist/
|
|
6
|
-
"module": "dist/
|
|
5
|
+
"main": "dist/index.cdn.js",
|
|
6
|
+
"module": "dist/index.cdn.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"LICENSE",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
8
13
|
"exports": {
|
|
9
14
|
".": {
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.cdn.mjs",
|
|
17
|
+
"require": "./dist/index.cdn.js"
|
|
13
18
|
}
|
|
14
19
|
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"dev": "tsup --watch",
|
|
24
|
+
"test:coverage": "vitest run --coverage"
|
|
25
|
+
},
|
|
15
26
|
"keywords": [
|
|
16
27
|
"holoscript",
|
|
17
28
|
"cdn",
|
|
@@ -29,15 +40,10 @@
|
|
|
29
40
|
},
|
|
30
41
|
"sideEffects": false,
|
|
31
42
|
"devDependencies": {
|
|
32
|
-
"vitest": "^4.1.
|
|
43
|
+
"vitest": "^4.1.5"
|
|
33
44
|
},
|
|
34
45
|
"homepage": "https://github.com/brianonbased-dev/HoloScript#readme",
|
|
35
46
|
"bugs": {
|
|
36
47
|
"url": "https://github.com/brianonbased-dev/HoloScript/issues"
|
|
37
|
-
},
|
|
38
|
-
"scripts": {
|
|
39
|
-
"build": "tsup",
|
|
40
|
-
"test": "vitest run",
|
|
41
|
-
"dev": "tsup --watch"
|
|
42
48
|
}
|
|
43
|
-
}
|
|
49
|
+
}
|
package/error-tsc-utf8.log
DELETED
|
File without changes
|
package/error-tsc.log
DELETED
|
File without changes
|
package/error-utf8.log
DELETED
|
@@ -1,262 +0,0 @@
|
|
|
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
DELETED
|
Binary file
|
package/src/HoloSceneElement.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
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
|
-
}
|
package/src/HoloSceneRenderer.ts
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,152 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1,188 +0,0 @@
|
|
|
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, type HoloCDNConfig } from '../config';
|
|
14
|
-
|
|
15
|
-
// ═══════════════════════════════════════════════
|
|
16
|
-
// defaultCDNConfig
|
|
17
|
-
// ═══════════════════════════════════════════════
|
|
18
|
-
describe('defaultCDNConfig', () => {
|
|
19
|
-
it('is defined', () => {
|
|
20
|
-
expect(defaultCDNConfig).toBeDefined();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('cdnBase is a valid URL string', () => {
|
|
24
|
-
expect(typeof defaultCDNConfig.cdnBase).toBe('string');
|
|
25
|
-
expect(defaultCDNConfig.cdnBase).toContain('holoscript');
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('defaultTarget is a string', () => {
|
|
29
|
-
expect(typeof defaultCDNConfig.defaultTarget).toBe('string');
|
|
30
|
-
expect(defaultCDNConfig.defaultTarget.length).toBeGreaterThan(0);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('debug defaults to false', () => {
|
|
34
|
-
expect(defaultCDNConfig.debug).toBe(false);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('loadTimeoutMs is a positive number', () => {
|
|
38
|
-
expect(typeof defaultCDNConfig.loadTimeoutMs).toBe('number');
|
|
39
|
-
expect(defaultCDNConfig.loadTimeoutMs).toBeGreaterThan(0);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('has all HoloCDNConfig required fields', () => {
|
|
43
|
-
const config: HoloCDNConfig = defaultCDNConfig;
|
|
44
|
-
expect(config).toHaveProperty('cdnBase');
|
|
45
|
-
expect(config).toHaveProperty('defaultTarget');
|
|
46
|
-
expect(config).toHaveProperty('debug');
|
|
47
|
-
expect(config).toHaveProperty('loadTimeoutMs');
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// ═══════════════════════════════════════════════
|
|
52
|
-
// detectOptimalTarget
|
|
53
|
-
// ═══════════════════════════════════════════════
|
|
54
|
-
describe('detectOptimalTarget', () => {
|
|
55
|
-
it('is a function', () => {
|
|
56
|
-
expect(typeof detectOptimalTarget).toBe('function');
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('returns a string', () => {
|
|
60
|
-
const target = detectOptimalTarget();
|
|
61
|
-
expect(typeof target).toBe('string');
|
|
62
|
-
expect(target.length).toBeGreaterThan(0);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('returns a valid HoloSceneTarget value', () => {
|
|
66
|
-
const valid = [
|
|
67
|
-
'webxr',
|
|
68
|
-
'threejs',
|
|
69
|
-
'babylon',
|
|
70
|
-
'unity',
|
|
71
|
-
'godot',
|
|
72
|
-
'visionos',
|
|
73
|
-
'android-xr',
|
|
74
|
-
'auto',
|
|
75
|
-
'webgpu',
|
|
76
|
-
];
|
|
77
|
-
const target = detectOptimalTarget();
|
|
78
|
-
expect(valid).toContain(target);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('returns "threejs" in jsdom (no WebXR or WebGPU)', () => {
|
|
82
|
-
// jsdom has no navigator.xr or navigator.gpu
|
|
83
|
-
const target = detectOptimalTarget();
|
|
84
|
-
expect(target).toBe('threejs');
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// ═══════════════════════════════════════════════
|
|
89
|
-
// checkXRSupport
|
|
90
|
-
// ═══════════════════════════════════════════════
|
|
91
|
-
describe('checkXRSupport', () => {
|
|
92
|
-
it('is a function', () => {
|
|
93
|
-
expect(typeof checkXRSupport).toBe('function');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('returns a Promise', () => {
|
|
97
|
-
const result = checkXRSupport('immersive-vr');
|
|
98
|
-
expect(result).toBeInstanceOf(Promise);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('resolves to false in jsdom (no XR)', async () => {
|
|
102
|
-
const result = await checkXRSupport('immersive-vr');
|
|
103
|
-
expect(result).toBe(false);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('resolves to false for immersive-ar in jsdom', async () => {
|
|
107
|
-
const result = await checkXRSupport('immersive-ar');
|
|
108
|
-
expect(result).toBe(false);
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
// ═══════════════════════════════════════════════
|
|
113
|
-
// HoloSceneRenderer
|
|
114
|
-
// ═══════════════════════════════════════════════
|
|
115
|
-
describe('HoloSceneRenderer', () => {
|
|
116
|
-
it('constructs with a DOM container', () => {
|
|
117
|
-
const container = document.createElement('div');
|
|
118
|
-
const renderer = new HoloSceneRenderer(container);
|
|
119
|
-
expect(renderer).toBeDefined();
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('render() returns a Promise', () => {
|
|
123
|
-
const container = document.createElement('div');
|
|
124
|
-
const renderer = new HoloSceneRenderer(container);
|
|
125
|
-
const result = renderer.render('cube { @color(red) }', {
|
|
126
|
-
target: 'threejs',
|
|
127
|
-
width: 640,
|
|
128
|
-
height: 480,
|
|
129
|
-
enableVR: false,
|
|
130
|
-
enableAR: false,
|
|
131
|
-
});
|
|
132
|
-
expect(result).toBeInstanceOf(Promise);
|
|
133
|
-
return result; // let it resolve
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('render() resolves without throwing for threejs target', async () => {
|
|
137
|
-
const container = document.createElement('div');
|
|
138
|
-
document.body.appendChild(container);
|
|
139
|
-
const renderer = new HoloSceneRenderer(container);
|
|
140
|
-
await expect(
|
|
141
|
-
renderer.render('cube { @color(red) }', {
|
|
142
|
-
target: 'threejs',
|
|
143
|
-
width: 320,
|
|
144
|
-
height: 240,
|
|
145
|
-
enableVR: false,
|
|
146
|
-
enableAR: false,
|
|
147
|
-
})
|
|
148
|
-
).resolves.not.toThrow();
|
|
149
|
-
document.body.removeChild(container);
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('render() resolves for "auto" target', async () => {
|
|
153
|
-
const container = document.createElement('div');
|
|
154
|
-
const renderer = new HoloSceneRenderer(container);
|
|
155
|
-
await expect(
|
|
156
|
-
renderer.render('sphere { @color(blue) }', {
|
|
157
|
-
target: 'auto',
|
|
158
|
-
width: 100,
|
|
159
|
-
height: 100,
|
|
160
|
-
enableVR: false,
|
|
161
|
-
enableAR: false,
|
|
162
|
-
})
|
|
163
|
-
).resolves.not.toThrow();
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('render() resolves for static target (unity)', async () => {
|
|
167
|
-
const container = document.createElement('div');
|
|
168
|
-
const renderer = new HoloSceneRenderer(container);
|
|
169
|
-
await expect(
|
|
170
|
-
renderer.render('cube {}', {
|
|
171
|
-
target: 'unity',
|
|
172
|
-
width: 100,
|
|
173
|
-
height: 100,
|
|
174
|
-
enableVR: false,
|
|
175
|
-
enableAR: false,
|
|
176
|
-
})
|
|
177
|
-
).resolves.not.toThrow();
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('creates two renderers independently', () => {
|
|
181
|
-
const c1 = document.createElement('div');
|
|
182
|
-
const c2 = document.createElement('div');
|
|
183
|
-
const r1 = new HoloSceneRenderer(c1);
|
|
184
|
-
const r2 = new HoloSceneRenderer(c2);
|
|
185
|
-
expect(r1).toBeDefined();
|
|
186
|
-
expect(r2).toBeDefined();
|
|
187
|
-
});
|
|
188
|
-
});
|
package/src/config.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CDN configuration and defaults
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export interface HoloCDNConfig {
|
|
6
|
-
cdnBase: string;
|
|
7
|
-
defaultTarget: string;
|
|
8
|
-
debug: boolean;
|
|
9
|
-
loadTimeoutMs: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const defaultCDNConfig: HoloCDNConfig = {
|
|
13
|
-
cdnBase: 'https://cdn.holoscript.net',
|
|
14
|
-
defaultTarget: 'threejs',
|
|
15
|
-
debug: false,
|
|
16
|
-
loadTimeoutMs: 10000,
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export function detectOptimalTarget(): string {
|
|
20
|
-
if (typeof navigator === 'undefined') return 'threejs';
|
|
21
|
-
|
|
22
|
-
if ('xr' in navigator) {
|
|
23
|
-
const nav = navigator as any;
|
|
24
|
-
if (nav.xr?.isSessionSupported) {
|
|
25
|
-
return 'webxr';
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if ('gpu' in navigator) {
|
|
30
|
-
return 'webgpu';
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return 'threejs';
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export async function checkXRSupport(mode: 'immersive-vr' | 'immersive-ar'): Promise<boolean> {
|
|
37
|
-
if (typeof navigator === 'undefined' || !('xr' in navigator)) return false;
|
|
38
|
-
try {
|
|
39
|
-
const nav = navigator as any;
|
|
40
|
-
return await nav.xr.isSessionSupported(mode);
|
|
41
|
-
} catch {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @holoscript/cdn — Browser CDN distribution
|
|
3
|
-
*
|
|
4
|
-
* Exposes <holo-scene> custom element for embedding HoloScript scenes
|
|
5
|
-
* in any webpage via a CDN script tag.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* <script src="https://cdn.holoscript.net/v4.min.js"></script>
|
|
9
|
-
* <holo-scene src="./my-world.hs" target="webxr" fallback="threejs"></holo-scene>
|
|
10
|
-
*
|
|
11
|
-
* @version 1.0.0
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export { HoloSceneElement, registerHoloScene } from './HoloSceneElement.js';
|
|
15
|
-
export { HoloSceneRenderer } from './HoloSceneRenderer.js';
|
|
16
|
-
export { HoloCDNConfig, defaultCDNConfig } from './config.js';
|
|
17
|
-
export type { HoloSceneAttributes, HoloSceneTarget, HoloSceneFallback } from './types.js';
|
package/src/types.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HoloScene custom element attribute types
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export type HoloSceneTarget =
|
|
6
|
-
| 'webxr'
|
|
7
|
-
| 'threejs'
|
|
8
|
-
| 'babylon'
|
|
9
|
-
| 'unity'
|
|
10
|
-
| 'godot'
|
|
11
|
-
| 'visionos'
|
|
12
|
-
| 'android-xr'
|
|
13
|
-
| 'auto';
|
|
14
|
-
|
|
15
|
-
export type HoloSceneFallback = 'threejs' | 'canvas2d' | 'static-image' | 'none';
|
|
16
|
-
|
|
17
|
-
export type HoloSceneLoadingState = 'idle' | 'loading' | 'compiling' | 'rendering' | 'error';
|
|
18
|
-
|
|
19
|
-
export interface HoloSceneAttributes {
|
|
20
|
-
src?: string;
|
|
21
|
-
inline?: string;
|
|
22
|
-
target?: HoloSceneTarget;
|
|
23
|
-
fallback?: HoloSceneFallback;
|
|
24
|
-
width?: string | number;
|
|
25
|
-
height?: string | number;
|
|
26
|
-
autoplay?: boolean;
|
|
27
|
-
vr?: boolean;
|
|
28
|
-
ar?: boolean;
|
|
29
|
-
loading?: boolean;
|
|
30
|
-
class?: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface HoloSceneLoadEvent {
|
|
34
|
-
type: 'holo-load';
|
|
35
|
-
source: string;
|
|
36
|
-
target: HoloSceneTarget;
|
|
37
|
-
compileTimeMs: number;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface HoloSceneErrorEvent {
|
|
41
|
-
type: 'holo-error';
|
|
42
|
-
message: string;
|
|
43
|
-
source?: string;
|
|
44
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"lib": ["ES2022", "DOM"],
|
|
7
|
-
"types": ["node"],
|
|
8
|
-
"outDir": "./dist",
|
|
9
|
-
"rootDir": "./src",
|
|
10
|
-
"strict": true,
|
|
11
|
-
"esModuleInterop": true,
|
|
12
|
-
"skipLibCheck": true,
|
|
13
|
-
"forceConsistentCasingInFileNames": true,
|
|
14
|
-
"declaration": true,
|
|
15
|
-
"declarationMap": true,
|
|
16
|
-
"sourceMap": true,
|
|
17
|
-
"resolveJsonModule": true
|
|
18
|
-
},
|
|
19
|
-
"include": ["src/**/*"],
|
|
20
|
-
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
21
|
-
}
|
package/tsup.config.d.ts
DELETED
package/tsup.config.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'tsup';
|
|
2
|
-
export default defineConfig({
|
|
3
|
-
entry: ['src/index.ts'],
|
|
4
|
-
format: ['cjs', 'esm'],
|
|
5
|
-
dts: true,
|
|
6
|
-
clean: true,
|
|
7
|
-
sourcemap: true,
|
|
8
|
-
outDir: 'dist',
|
|
9
|
-
outExtension({ format }) {
|
|
10
|
-
return { js: format === 'esm' ? '.cdn.mjs' : '.cdn.js' };
|
|
11
|
-
},
|
|
12
|
-
});
|
package/tsup.config.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'tsup';
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
entry: ['src/index.ts'],
|
|
5
|
-
format: ['cjs', 'esm'],
|
|
6
|
-
dts: true,
|
|
7
|
-
clean: true,
|
|
8
|
-
sourcemap: true,
|
|
9
|
-
outDir: 'dist',
|
|
10
|
-
outExtension({ format }) {
|
|
11
|
-
return { js: format === 'esm' ? '.cdn.mjs' : '.cdn.js' };
|
|
12
|
-
},
|
|
13
|
-
});
|