diff --git a/src/devkit/sceneStatsStore.ts b/src/devkit/sceneStatsStore.ts new file mode 100644 index 0000000..ae9290f --- /dev/null +++ b/src/devkit/sceneStatsStore.ts @@ -0,0 +1,80 @@ +/** + * DEVKIT — global mutable snapshot of scene + XR session diagnostics. + * + * Written every frame by SceneStatsProbe (inside Canvas), read by DevPanel + * (HTML overlay) and XRDevHud (in-world). Plain object to avoid re-renders. + */ +import * as THREE from 'three'; + +export interface SceneStats { + fps: number; + meshCount: number; + triCount: number; + modelBboxSize: [number, number, number]; + modelGroupPos: [number, number, number]; + modelGroupRotDeg: [number, number, number]; + modelGroupScale: number; + xrMode: string | null; + xrPlanesCount: number; + xrHitTestActive: boolean; + xrInputCount: number; + lastUpdate: number; +} + +export const sceneStats: SceneStats = { + fps: 0, + meshCount: 0, + triCount: 0, + modelBboxSize: [0, 0, 0], + modelGroupPos: [0, 0, 0], + modelGroupRotDeg: [0, 0, 0], + modelGroupScale: 1, + xrMode: null, + xrPlanesCount: 0, + xrHitTestActive: false, + xrInputCount: 0, + lastUpdate: 0, +}; + +export function snapshotStats(): SceneStats { + return { ...sceneStats }; +} + +const _v = new THREE.Vector3(); +const _q = new THREE.Quaternion(); +const _e = new THREE.Euler(); +const _box = new THREE.Box3(); + +export function updateModelStats(group: THREE.Object3D | null) { + if (!group) return; + group.updateWorldMatrix(true, true); + group.getWorldPosition(_v); + sceneStats.modelGroupPos = [_v.x, _v.y, _v.z]; + group.getWorldQuaternion(_q); + _e.setFromQuaternion(_q); + sceneStats.modelGroupRotDeg = [ + THREE.MathUtils.radToDeg(_e.x), + THREE.MathUtils.radToDeg(_e.y), + THREE.MathUtils.radToDeg(_e.z), + ]; + group.getWorldScale(_v); + sceneStats.modelGroupScale = _v.x; + + let meshes = 0; + let tris = 0; + group.traverse((o) => { + if (o instanceof THREE.Mesh && o.geometry) { + meshes++; + const idx = o.geometry.index; + const pos = o.geometry.attributes.position; + if (idx) tris += idx.count / 3; + else if (pos) tris += pos.count / 3; + } + }); + sceneStats.meshCount = meshes; + sceneStats.triCount = Math.round(tris); + + _box.setFromObject(group); + _box.getSize(_v); + sceneStats.modelBboxSize = [_v.x, _v.y, _v.z]; +}