From 3155cc930ff84b5f40b5180016fd06b0b9a95502 Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Tue, 13 Jan 2026 15:06:18 -0600 Subject: [PATCH] Fix camera positioning, label z-fighting, and remove dead code - Fix desktop camera to be directly above platform by resetting local position - Increase label back offset from 0.001 to 0.005 to prevent z-fighting - Use refreshBoundingInfo({}) for consistency with codebase - Remove unused copyToPublic from pouchData.ts - Remove dead DiagramEntityAdapter and integration/gizmo module - Remove unused netlify functions and integration utilities - Clean up unused imports and commented code across multiple files Co-Authored-By: Claude Opus 4.5 --- netlify/functions/nerdgraph/nerdgraph.ts | 49 ---- netlify/functions/users/users.mts | 216 ------------------ netlify/functions/voice/voice.ts | 22 -- package.json | 2 +- src/controllers/functions/buildRig.ts | 2 + src/diagram/diagramObject.ts | 4 +- src/gizmos/ResizeGizmo/ResizeGizmo.ts | 6 +- src/integration/database/pouchData.ts | 52 +---- src/integration/functions/checkDb.ts | 27 --- src/integration/functions/hexFunctions.ts | 17 -- src/integration/functions/syncDoc.ts | 59 ----- src/integration/gizmo/DiagramEntityAdapter.ts | 166 -------------- src/integration/gizmo/index.ts | 6 - src/util/animatedLineTexture.ts | 46 ---- src/util/appConfig.ts | 26 --- src/util/customEnvironment.ts | 2 - src/util/customPhysics.ts | 50 +--- src/util/deviceDetection.ts | 8 +- src/util/functions/getPath.ts | 27 --- src/util/functions/groundMeshObserver.ts | 53 ----- src/util/functions/sceneInspector.ts | 17 -- src/util/lightmapGenerator.ts | 1 - 22 files changed, 13 insertions(+), 845 deletions(-) delete mode 100644 netlify/functions/nerdgraph/nerdgraph.ts delete mode 100644 netlify/functions/users/users.mts delete mode 100644 netlify/functions/voice/voice.ts delete mode 100644 src/integration/functions/checkDb.ts delete mode 100644 src/integration/functions/hexFunctions.ts delete mode 100644 src/integration/functions/syncDoc.ts delete mode 100644 src/integration/gizmo/DiagramEntityAdapter.ts delete mode 100644 src/integration/gizmo/index.ts diff --git a/netlify/functions/nerdgraph/nerdgraph.ts b/netlify/functions/nerdgraph/nerdgraph.ts deleted file mode 100644 index a8e6f84..0000000 --- a/netlify/functions/nerdgraph/nerdgraph.ts +++ /dev/null @@ -1,49 +0,0 @@ -import {Handler, HandlerContext, HandlerEvent} from "@netlify/functions"; -import axios from 'axios'; - -export const handler: Handler = async (event: HandlerEvent, context: HandlerContext) => { - try { - switch (event.httpMethod) { - case 'POST': - const apiKey = event.headers['api-key']; - const query = event.body; - const response = await axios.post('https://api.newrelic.com/graphql', - query, - {headers: {'Api-Key': apiKey, 'Content-Type': 'application/json'}}); - const data = await response.data; - return { - headers: { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin': 'https://cameras.immersiveidea.com', - 'Access-Control-Allow-Credentials': 'true' - }, - statusCode: 200, - body: JSON.stringify(data) - } - break; - case 'OPTIONS': - const headers = { - 'Access-Control-Allow-Origin': 'https://cameras.immersiveidea.com', - 'Access-Control-Allow-Credentials': 'true', - 'Access-Control-Allow-Headers': 'content-type, api-key', - 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE' - }; - return { - statusCode: 204, - headers - } - break; - default: - return { - statusCode: 405, - body: 'Method Not Allowed' - } - } - } catch (error) { - console.log(error); - return { - statusCode: 500, - body: JSON.stringify(error) - } - } -}; \ No newline at end of file diff --git a/netlify/functions/users/users.mts b/netlify/functions/users/users.mts deleted file mode 100644 index 21a14b6..0000000 --- a/netlify/functions/users/users.mts +++ /dev/null @@ -1,216 +0,0 @@ -import axios from 'axios'; - -const baseurl = 'https://syncdb-service-d3f974de56ef.herokuapp.com/'; -const auth = 'admin:stM8Lnm@Cuf-tWZHv'; -const authToken = Buffer.from(auth).toString('base64'); - - -type Params = { - username: string, - password: string, - db: string -} - -async function checkDB(auth: string, db: string) { - try { - console.log('Checking for DB'); - const exist = await axios.head(baseurl + db, - {headers: {'Authorization': 'Basic ' + auth}}); - if (exist && exist.status == 200) { - console.log("DB Found"); - return true; - } - } catch (err) { - console.log("DB not Found"); - //console.log(err); - } - return false; -} - -enum Access { - DENIED, - MISSING, - ALLOWED, -} - -function getUserToken(params: Params) { - const userAuth = params.username + ':' + params.password; - return Buffer.from(userAuth).toString('base64'); -} - -async function checkIfDbExists(params: Params): Promise { - console.log("Checking if DB exists"); - if (!params.username || !params.password || !params.db) { - throw new Error('No share key provided'); - } - - if (await checkDB(getUserToken(params), params.db)) { - return Access.ALLOWED; - } - if (await checkDB(authToken, params.db)) { - return Access.DENIED; - } - return Access.MISSING; - -} - -async function createDB(params: Params) { - console.log("Creating DB"); - - const response = await axios.put( - baseurl + params.db, - {}, - { - headers: { - 'Authorization': 'Basic ' + authToken, - 'Content-Type': 'application/json', - 'Accept': 'application/json' - } - }); - console.log(response.status); - console.log(response.data); - return response; -} - -async function createUser(params: Params) { - try { - console.log("Checking for User"); - const userResponse = await axios.head( - baseurl + '_users/org.couchdb.user:' + params.username, - { - headers: { - 'Authorization': 'Basic ' + getUserToken(params), - 'Content-Type': 'application/json', - 'Accept': 'application/json' - } - }); - if (userResponse.status == 200) { - console.log("User Found"); - return userResponse; - } - } catch (err) { - console.log("User Missing"); - } - console.log("Creating User"); - const userResponse = await axios.put( - baseurl + '_users/org.couchdb.user:' + params.username, - { - _id: 'org.couchdb.user:' + params.username, - name: params.username, - password: params.password, roles: [], type: 'user' - }, - { - headers: { - 'Authorization': 'Basic ' + authToken, - 'Content-Type': 'application/json', - 'Accept': 'application/json' - } - }); - return userResponse; -} - -async function authorizeUser(params: Params) { - console.log("Authorizing User"); - return await axios.put( - baseurl + params.db + '/_security', - {admins: {names: [], roles: []}, members: {names: [params.username], roles: []}}, - { - headers: { - 'Authorization': 'Basic ' + authToken, - 'Content-Type': 'application/json', - 'Accept': 'application/json' - } - }); -} - -export default async (req: Request): Promise => { - console.log(req.method); - - try { - if (req.method == 'OPTIONS') { - const origin = req.headers.get('Origin'); - const headers = req.headers.get('Access-Control-Request-Headers'); - console.log(origin); - return new Response( - 'OK', - { - headers: { - 'Allow': 'POST', - 'Max-Age': '30', - 'Access-Control-Allow-Methods': 'POST', - 'Access-Control-Allow-Origin': origin ? origin : 'https://cameras.immersiveidea.com', - 'Access-Control-Allow-Credentials': 'true', - 'Access-Control-Allow-Headers': headers ? headers : 'Content-Type' - }, - status: 200 - }); - } - } catch (err) { - return new Response( - JSON.stringify(err), - { - headers: { - 'Allow': 'POST', - 'Max-Age': '30', - 'Access-Control-Allow-Methods': 'POST', - 'Access-Control-Allow-Origin': origin ? origin : 'https://cameras.immersiveidea.com', - 'Access-Control-Allow-Credentials': 'true' - }, - status: 500 - }); - } - - - try { - const params = JSON.parse(await req.text()); - console.log(params); - const createUserResponse = await createUser(params); - console.log(createUserResponse.status); - if (createUserResponse.status != 201 && createUserResponse.status != 200) { - throw new Error('Could not create User'); - } - - const exists = await checkIfDbExists(params); - switch (exists) { - case Access.ALLOWED: - console.log('Allowed'); - return new Response('OK', {status: 200}); - case Access.DENIED: - console.log('Denied'); - return new Response('Denied', {status: 401}); - case Access.MISSING: - console.log('Creating Missing DB'); - const createDbResponse = await createDB(params); - if (createDbResponse.status != 201) { - throw new Error('Could not create DB'); - } - - - } - - - const authorizeUserResponse = await authorizeUser(params); - if (authorizeUserResponse.status != 200) { - throw new Error('could not authorize user'); - } - const origin = req.headers.get('origin'); - console.log(origin); - return new Response( - 'OK', - { - headers: [ - ['Content-Type', 'application/json'], - ['Access-Control-Allow-Origin', origin], - ['Access-Control-Allow-Credentials', 'true'] - ], - status: 200 - } - ) - } catch (err) { - console.log(err); - const response = {err: err}; - return new Response('Error', - {status: 500} - ) - } -} \ No newline at end of file diff --git a/netlify/functions/voice/voice.ts b/netlify/functions/voice/voice.ts deleted file mode 100644 index a9dae37..0000000 --- a/netlify/functions/voice/voice.ts +++ /dev/null @@ -1,22 +0,0 @@ -import {Handler, HandlerContext, HandlerEvent} from "@netlify/functions"; -import axios from 'axios'; - -export const handler: Handler = async (event: HandlerEvent, context: HandlerContext) => { - try { - const response = await axios.post('https://api.assemblyai.com/v2/realtime/token', // use account token to get a temp user token - {expires_in: 3600}, // can set a TTL timer in seconds. - {headers: {authorization: process.env.VOICE_TOKEN}}); - - const data = await response.data; - return { - headers: {'Content-Type': 'application/json'}, - statusCode: 200, - body: JSON.stringify(data) - } - } catch (error) { - return { - statusCode: 500, - body: JSON.stringify(error) - } - } -}; \ No newline at end of file diff --git a/package.json b/package.json index 9e10078..5c5a0e9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "immersive", "private": true, - "version": "0.0.8-46", + "version": "0.0.8-47", "type": "module", "license": "MIT", "engines": { diff --git a/src/controllers/functions/buildRig.ts b/src/controllers/functions/buildRig.ts index bd579e0..5b83ec4 100644 --- a/src/controllers/functions/buildRig.ts +++ b/src/controllers/functions/buildRig.ts @@ -25,10 +25,12 @@ export function buildRig(xr: WebXRDefaultExperience): Mesh { }); for (const cam of scene.cameras) { cam.parent = cameratransform; + cam.position = new Vector3(0, 1.6, 0); // Reset to local position above platform } scene.onActiveCameraChanged.add(() => { for (const cam of scene.cameras) { cam.parent = cameratransform; + cam.position = new Vector3(0, 1.6, 0); // Reset to local position above platform } }); diff --git a/src/diagram/diagramObject.ts b/src/diagram/diagramObject.ts index 3426ad2..3f6c789 100644 --- a/src/diagram/diagramObject.ts +++ b/src/diagram/diagramObject.ts @@ -314,7 +314,7 @@ export class DiagramObject { this._label.rotation.y = 0; this._labelBack.rotation.y = Math.PI; // Back face still needs to be flipped } - this._labelBack.position.z = 0.001; + this._labelBack.position.z = 0.005; } else { // Standard object labels - convert world space to parent's local space // This accounts for mesh scaling, which is not included in boundingBox.maximum @@ -326,7 +326,7 @@ export class DiagramObject { temp.dispose(); this._label.position.y = y + 0.06; this._labelBack.rotation.y = Math.PI; - this._labelBack.position.z = 0.001; + this._labelBack.position.z = 0.005; } } } diff --git a/src/gizmos/ResizeGizmo/ResizeGizmo.ts b/src/gizmos/ResizeGizmo/ResizeGizmo.ts index a14c92f..3cf754a 100644 --- a/src/gizmos/ResizeGizmo/ResizeGizmo.ts +++ b/src/gizmos/ResizeGizmo/ResizeGizmo.ts @@ -16,7 +16,7 @@ import { } from '@babylonjs/core'; import log from 'loglevel'; -import { HandleState, CORNER_POSITIONS, FACE_POSITIONS} from './enums'; +import { CORNER_POSITIONS, FACE_POSITIONS} from './enums'; import { ResizeGizmoEvent } from './types'; /** @@ -110,7 +110,7 @@ export class ResizeGizmo { private createHandles(): void { // Ensure world matrix and bounding info are current this._targetMesh.computeWorldMatrix(true); - this._targetMesh.refreshBoundingInfo(); + this._targetMesh.refreshBoundingInfo({}); // Get bounding box for positioning const targetBoundingInfo = this._targetMesh.getBoundingInfo(); @@ -489,7 +489,7 @@ export class ResizeGizmo { private updateHandleTransforms(): void { // Ensure world matrix and bounding info are current this._targetMesh.computeWorldMatrix(true); - this._targetMesh.refreshBoundingInfo(); + this._targetMesh.refreshBoundingInfo({}); const targetBoundingInfo = this._targetMesh.getBoundingInfo(); const boundingBox = targetBoundingInfo.boundingBox; diff --git a/src/integration/database/pouchData.ts b/src/integration/database/pouchData.ts index a0dbd5c..663d1f2 100644 --- a/src/integration/database/pouchData.ts +++ b/src/integration/database/pouchData.ts @@ -74,12 +74,12 @@ export class PouchData { } }) .on('paused', (info) => { - this._logger.debug('[Sync] Paused - up to date'); + this._logger.debug(`[Sync] Paused - up to date ${info}`); }) .on('active', () => { this._logger.debug('[Sync] Active - syncing'); }) - .on('error', (err) => { + .on('error', (err: any) => { this._logger.error('[Sync] Error:', err); }); } @@ -202,52 +202,4 @@ export class PouchData { this._logger.warn('CONFLICTS!', doc._conflicts); } } - - /** - * Copy all documents from this database to a new public database. - * Used when sharing a local diagram to make it publicly accessible. - * @param newDbName - The name for the new public database - * @returns The URL path to the new public diagram - */ - public async copyToPublic(newDbName: string): Promise { - this._logger.info(`[Copy] Starting copy to public-${newDbName}`); - - // Create the remote public database - const remoteUrl = `${window.location.origin}/pouchdb/public-${newDbName}`; - const remoteDb = new PouchDB(remoteUrl); - - try { - // Get all docs from local database - const allDocs = await this._db.allDocs({ include_docs: true }); - this._logger.debug(`[Copy] Found ${allDocs.rows.length} documents to copy`); - - // Copy each document to the remote database - for (const row of allDocs.rows) { - if (row.doc) { - // Remove PouchDB internal fields for clean insert - const { _rev, ...docWithoutRev } = row.doc; - try { - await remoteDb.put(docWithoutRev); - } catch (err) { - // Document might already exist if this is a retry - this._logger.warn(`[Copy] Failed to copy doc ${row.id}:`, err); - } - } - } - - this._logger.info(`[Copy] Successfully copied ${allDocs.rows.length} documents`); - return `/db/public/${newDbName}`; - } catch (err) { - this._logger.error('[Copy] Error copying to public:', err); - throw err; - } - } - - /** - * Get all documents in the database (for export/copy operations) - */ - public async getAllDocs(): Promise { - const result = await this._db.allDocs({ include_docs: true }); - return result.rows.map(row => row.doc).filter(doc => doc && doc.id !== 'metadata'); - } } \ No newline at end of file diff --git a/src/integration/functions/checkDb.ts b/src/integration/functions/checkDb.ts deleted file mode 100644 index 1190722..0000000 --- a/src/integration/functions/checkDb.ts +++ /dev/null @@ -1,27 +0,0 @@ -import axios from "axios"; -import log from "loglevel"; - -export async function checkDb(localName: string, remoteDbName: string, password: string) { - const logger = log.getLogger('checkDb'); - const dbs = await axios.get(import.meta.env.VITE_SYNCDB_ENDPOINT + 'list'); - logger.debug(dbs.data); - if (dbs.data.indexOf(remoteDbName) == -1) { - logger.warn('sync target missing attempting to create'); - const newdb = await axios.post(import.meta.env.VITE_CREATE_ENDPOINT, - { - "_id": "org.couchdb.user:" + localName, - "name": localName, - "password": password, - "roles": ["readers"], - "type": "user" - } - ); - if (newdb.status == 201) { - logger.info('sync target created'); - } else { - logger.warn('sync target not created', newdb); - return false; - } - } - return true; -} \ No newline at end of file diff --git a/src/integration/functions/hexFunctions.ts b/src/integration/functions/hexFunctions.ts deleted file mode 100644 index 11cc117..0000000 --- a/src/integration/functions/hexFunctions.ts +++ /dev/null @@ -1,17 +0,0 @@ -export function hex_to_ascii(input) { - const hex = input.toString(); - let output = ''; - for (let n = 0; n < hex.length; n += 2) { - output += String.fromCharCode(parseInt(hex.substr(n, 2), 16)); - } - return output; -} - -export function ascii_to_hex(str) { - const arr1 = []; - for (let n = 0, l = str.length; n < l; n++) { - const hex = Number(str.charCodeAt(n)).toString(16); - arr1.push(hex); - } - return arr1.join(''); -} \ No newline at end of file diff --git a/src/integration/functions/syncDoc.ts b/src/integration/functions/syncDoc.ts deleted file mode 100644 index b345c65..0000000 --- a/src/integration/functions/syncDoc.ts +++ /dev/null @@ -1,59 +0,0 @@ -import log from "loglevel"; -import {DiagramEntity, DiagramEntityType} from "../../diagram/types/diagramEntity"; -import {Observable} from "@babylonjs/core"; -import {Encryption} from "../encryption"; -import {DiagramEventObserverMask} from "../../diagram/types/diagramEventObserverMask"; - -export async function syncDoc(info: any, onDBRemoveObservable: Observable, onDBUpdateObservable: Observable, - encryption: Encryption, key: string) { - const logger = log.getLogger('syncDoc'); - logger.debug(info); - if (info.direction == 'pull') { - // @ts-ignore - const docs = info.change.docs; - let salt = null; - for (const doc of docs) { - if (doc.encrypted) { - if (salt != doc.encrypted.salt || (key && !encryption.ready)) { - await encryption.setPassword(key, doc.encrypted.salt); - salt = doc.encrypted.salt - } - const decrypted = await encryption.decryptToObject(doc.encrypted.encrypted, doc.encrypted.iv); - if (decrypted.type == DiagramEntityType.USER) { - //onUserObservable.notifyObservers(doc, -1); - } else { - logger.debug(decrypted); - if (doc._deleted) { - logger.debug('Delete', doc); - onDBRemoveObservable.notifyObservers({ - id: doc._id, - template: decrypted.template, - type: doc.type - }, DiagramEventObserverMask.FROM_DB); - } else { - onDBUpdateObservable.notifyObservers(decrypted, DiagramEventObserverMask.FROM_DB); - } - } - } else { - if (doc.type == 'user') { - //onUserObservable.notifyObservers(doc, -1); - } else { - logger.debug(doc); - if (doc._deleted) { - logger.debug('Delete', doc); - onDBRemoveObservable.notifyObservers({ - id: doc._id, - template: doc.template, - type: doc.type - }, DiagramEventObserverMask.FROM_DB); - } else { - if (doc.template) { - onDBUpdateObservable.notifyObservers(doc, DiagramEventObserverMask.FROM_DB); - } - - } - } - } - } - } -} \ No newline at end of file diff --git a/src/integration/gizmo/DiagramEntityAdapter.ts b/src/integration/gizmo/DiagramEntityAdapter.ts deleted file mode 100644 index edd3f48..0000000 --- a/src/integration/gizmo/DiagramEntityAdapter.ts +++ /dev/null @@ -1,166 +0,0 @@ -/** - * DiagramEntity Integration Adapter for ResizeGizmo - * Bridges ResizeGizmo events to DiagramManager's persistence system - * - * This adapter lives in the integration layer to keep the ResizeGizmo - * system pure and reusable without diagram-specific dependencies. - */ - -import { AbstractMesh } from "@babylonjs/core"; -import { ResizeGizmoManager } from "../../gizmos/ResizeGizmo"; -import { ResizeGizmoEvent } from "../../gizmos/ResizeGizmo"; - -/** - * Type definitions for DiagramManager integration (loosely coupled) - * These match the actual types in the codebase without importing them - */ - -interface DiagramEntity { - id?: string; - template?: string; - position?: { x: number; y: number; z: number }; - rotation?: { x: number; y: number; z: number }; - scale?: { x: number; y: number; z: number }; - [key: string]: any; -} - -enum DiagramEventType { - MODIFY = "MODIFY" -} - -interface DiagramEvent { - type: DiagramEventType; - entity: DiagramEntity; -} - -enum DiagramEventObserverMask { - TO_DB = 2, - ALL = -1 -} - -interface DiagramEventNotifier { - notifyObservers(event: DiagramEvent, mask?: number): void; -} - -interface DiagramManager { - onDiagramEventObservable: DiagramEventNotifier; -} - -/** - * Converter function type for transforming BabylonJS meshes to DiagramEntities - */ -export type MeshToEntityConverter = (mesh: AbstractMesh) => DiagramEntity; - -/** - * Adapter that connects ResizeGizmo to DiagramManager for persistence - * Uses dependency injection to remain loosely coupled from diagram internals - * - * @example - * ```typescript - * import { DiagramEntityAdapter } from './integration/gizmo'; - * import { toDiagramEntity } from './diagram/functions/toDiagramEntity'; - * - * // Create resize gizmo - * const gizmo = new ResizeGizmoManager(scene, { - * mode: ResizeGizmoMode.ALL - * }); - * - * // Create adapter with injected converter - * const adapter = new DiagramEntityAdapter( - * gizmo, - * diagramManager, - * toDiagramEntity, // Injected dependency - * false // Don't persist on drag - * ); - * - * // Now scale changes will automatically persist to database - * gizmo.attachToMesh(myDiagramMesh); - * ``` - */ -export class DiagramEntityAdapter { - private _gizmo: ResizeGizmoManager; - private _diagramManager: DiagramManager; - private _meshConverter: MeshToEntityConverter; - private _persistOnDrag: boolean; - - /** - * Create adapter - * @param gizmo ResizeGizmoManager instance - * @param diagramManager DiagramManager instance (or object with onDiagramEventObservable) - * @param meshConverter Function to convert BabylonJS mesh to DiagramEntity (injected dependency) - * @param persistOnDrag If true, persist on every drag update (can be expensive). If false, only persist on scale end. - */ - constructor( - gizmo: ResizeGizmoManager, - diagramManager: DiagramManager, - meshConverter: MeshToEntityConverter, - persistOnDrag: boolean = false - ) { - this._gizmo = gizmo; - this._diagramManager = diagramManager; - this._meshConverter = meshConverter; - this._persistOnDrag = persistOnDrag; - - this.setupEventListeners(); - } - - /** - * Setup event listeners - */ - private setupEventListeners(): void { - // Persist on scale end (always) - this._gizmo.onScaleEnd((event) => { - this.persistScaleChange(event); - }); - - // Optionally persist on drag - if (this._persistOnDrag) { - this._gizmo.onScaleDrag((event) => { - this.persistScaleChange(event); - }); - } - } - - /** - * Persist scale change to DiagramManager - */ - private persistScaleChange(event: ResizeGizmoEvent): void { - const mesh = event.mesh; - - // Convert mesh to DiagramEntity using injected converter - // This properly extracts color from material and all other properties - const entity = this._meshConverter(mesh); - - // Notify DiagramManager - this._diagramManager.onDiagramEventObservable.notifyObservers( - { - type: DiagramEventType.MODIFY, - entity - }, - DiagramEventObserverMask.TO_DB - ); - } - - /** - * Enable/disable drag persistence - */ - setPersistOnDrag(enabled: boolean): void { - if (this._persistOnDrag === enabled) { - return; - } - - this._persistOnDrag = enabled; - - // Re-setup listeners - // Note: In a production implementation, you'd want to properly remove/add observers - // For now, this is a simplified version - console.warn("[DiagramEntityAdapter] Changing persistOnDrag at runtime may cause duplicate events"); - } - - /** - * Get persist on drag setting - */ - getPersistOnDrag(): boolean { - return this._persistOnDrag; - } -} diff --git a/src/integration/gizmo/index.ts b/src/integration/gizmo/index.ts deleted file mode 100644 index d928433..0000000 --- a/src/integration/gizmo/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Gizmo Integration Layer - * Adapters for integrating gizmo systems with diagram persistence - */ - -export { DiagramEntityAdapter, type MeshToEntityConverter } from './DiagramEntityAdapter'; diff --git a/src/util/animatedLineTexture.ts b/src/util/animatedLineTexture.ts index a0793cc..7f3a594 100644 --- a/src/util/animatedLineTexture.ts +++ b/src/util/animatedLineTexture.ts @@ -84,30 +84,6 @@ export class AnimatedLineTexture { return texture; } - /** - * Removes a texture from the animation set when disposed - * WARNING: Do NOT call this on cached textures! Only for non-cached textures. - * Cached textures are shared across multiple connections. - * Use ClearCache() to dispose cached textures properly. - * @param texture - The texture to stop animating - */ - public static DisposeTexture(texture: Texture): void { - // Safety check: prevent disposing cached textures (they're shared!) - for (const [color, cachedTexture] of this._coloredTextureCache.entries()) { - if (cachedTexture === texture) { - console.error( - `AnimatedLineTexture.DisposeTexture: Attempted to dispose cached texture ` + - `"${texture.name}" (color: ${color}). This will break texture sharing! ` + - `Cached textures should not be disposed individually. Use ClearCache() instead.` - ); - return; // Don't dispose - it's shared across multiple connections - } - } - - // Only dispose non-cached textures - this._animatedTextures.delete(texture); - texture.dispose(); - } /** * Preload textures for common colors to prevent first-render stutter @@ -119,27 +95,5 @@ export class AnimatedLineTexture { }); } - /** - * Clear the texture cache and dispose all cached textures - * Use with caution - only call when no connections are using these textures - */ - public static ClearCache(): void { - this._coloredTextureCache.forEach((texture) => { - this._animatedTextures.delete(texture); - texture.dispose(); - }); - this._coloredTextureCache.clear(); - } - /** - * Get cache statistics for debugging - * @returns Object with cache stats - */ - public static GetCacheStats(): { cachedColors: number; totalAnimatedTextures: number; colors: string[] } { - return { - cachedColors: this._coloredTextureCache.size, - totalAnimatedTextures: this._animatedTextures.size, - colors: Array.from(this._coloredTextureCache.keys()) - }; - } } \ No newline at end of file diff --git a/src/util/appConfig.ts b/src/util/appConfig.ts index 91b845e..65b2c74 100644 --- a/src/util/appConfig.ts +++ b/src/util/appConfig.ts @@ -149,32 +149,6 @@ export class AppConfig { this.save(); } - /** - * Remove handle configuration by ID - * @param id Handle ID to remove - */ - public removeHandleConfig(id: string) { - if (!this._currentConfig.handles) { - return; - } - - const initialLength = this._currentConfig.handles.length; - this._currentConfig.handles = this._currentConfig.handles.filter(h => h.id !== id); - - if (this._currentConfig.handles.length < initialLength) { - this._logger.debug(`Removed handle config for ${id}`); - this.save(); - } - } - - /** - * Get all handle configurations - * @returns Array of all HandleConfig objects - */ - public getAllHandleConfigs(): HandleConfig[] { - return this._currentConfig.handles || []; - } - private save() { localStorage.setItem('appConfig', JSON.stringify(this._currentConfig)); this.onConfigChangedObservable.notifyObservers(this._currentConfig, -1); diff --git a/src/util/customEnvironment.ts b/src/util/customEnvironment.ts index 7ac56b6..8c5a8db 100644 --- a/src/util/customEnvironment.ts +++ b/src/util/customEnvironment.ts @@ -4,13 +4,11 @@ import { Material, MeshBuilder, Observable, - PBRMaterial, PhysicsAggregate, PhysicsShapeType, PointsCloudSystem, Scene, Sound, - Texture, TransformNode, Vector3 } from "@babylonjs/core"; diff --git a/src/util/customPhysics.ts b/src/util/customPhysics.ts index 82a9f31..9285a18 100644 --- a/src/util/customPhysics.ts +++ b/src/util/customPhysics.ts @@ -1,14 +1,9 @@ -import {HavokPlugin, Quaternion, Scene, Vector3} from "@babylonjs/core"; +import {HavokPlugin, Scene, Vector3} from "@babylonjs/core"; import HavokPhysics from "@babylonjs/havok"; -import {snapGridVal} from "./functions/snapGridVal"; -import {snapRotateVal} from "./functions/snapRotateVal"; -import {isDiagramEntity} from "../diagram/functions/isDiagramEntity"; -import {appConfigInstance} from "./appConfig"; export class CustomPhysics { private readonly scene: Scene; - constructor(scene: Scene) { this.scene = scene; } @@ -17,47 +12,6 @@ export class CustomPhysics { const havok = await HavokPhysics(); const havokPlugin = new HavokPlugin(true, havok); const scene = this.scene; - const physicsEnable = scene.enablePhysics(new Vector3(0, -9.8, 0), havokPlugin); - - scene.collisionsEnabled = true; - scene.onAfterPhysicsObservable.add(() => { - const config = appConfigInstance.current; - scene.meshes.forEach((mesh) => { - if (isDiagramEntity(mesh) && mesh.physicsBody) { - const body = mesh.physicsBody; - const linearVelocity = new Vector3(); - body.getLinearVelocityToRef(linearVelocity); - if (linearVelocity.length() < .1) { - - body.disablePreStep = false; - - // Apply location snap if enabled - if (config.locationSnap > 0) { - const pos: Vector3 = body.getObjectCenterWorld(); - const val: Vector3 = snapGridVal(pos, config.locationSnap); - body.transformNode.position.set(val.x, val.y, val.z); - } - - // Apply rotation snap if enabled - if (config.rotateSnap > 0) { - const rot: Quaternion = - Quaternion.FromEulerVector( - snapRotateVal(body.transformNode.rotationQuaternion.toEulerAngles(), - config.rotateSnap)); - - body.transformNode.rotationQuaternion.set( - rot.x, rot.y, rot.z, rot.w - ); - } - - scene.onAfterRenderObservable.addOnce(() => { - body.disablePreStep = true; - }); - } - } - - }); - } - ); + scene.enablePhysics(new Vector3(0, -9.8, 0), havokPlugin); } } \ No newline at end of file diff --git a/src/util/deviceDetection.ts b/src/util/deviceDetection.ts index 704c5dc..cd5b727 100644 --- a/src/util/deviceDetection.ts +++ b/src/util/deviceDetection.ts @@ -1,8 +1,3 @@ -/** - * Device detection utilities for VR capability and device type - */ -import {Scene, WebXRDefaultExperience} from "@babylonjs/core"; - export interface DeviceCapabilities { isVRCapable: boolean; isMobileVR: boolean; @@ -64,5 +59,4 @@ export async function getDeviceCapabilities(): Promise { isDesktop, deviceType }; -} - +} \ No newline at end of file diff --git a/src/util/functions/getPath.ts b/src/util/functions/getPath.ts index fc6cdef..1e6a67c 100644 --- a/src/util/functions/getPath.ts +++ b/src/util/functions/getPath.ts @@ -11,33 +11,6 @@ export function getPath(): string { return null; } -/** - * Check if the current path is a local database (no sync) - * Local paths: /db/local/:db - */ -export function isLocalPath(): boolean { - const path = window.location.pathname.split('/'); - return path.length >= 3 && path[1] === 'db' && path[2] === 'local'; -} - -/** - * Check if the current path is a public database - * Public paths: /db/public/:db - */ -export function isPublicPath(): boolean { - const path = window.location.pathname.split('/'); - return path.length >= 3 && path[1] === 'db' && path[2] === 'public'; -} - -/** - * Check if the current path is a private database - * Private paths: /db/private/:db - */ -export function isPrivatePath(): boolean { - const path = window.location.pathname.split('/'); - return path.length >= 3 && path[1] === 'db' && path[2] === 'private'; -} - /** * Get the database type from the current path */ diff --git a/src/util/functions/groundMeshObserver.ts b/src/util/functions/groundMeshObserver.ts index 3bf7b8d..df7af5e 100644 --- a/src/util/functions/groundMeshObserver.ts +++ b/src/util/functions/groundMeshObserver.ts @@ -157,8 +157,6 @@ function positionComponentsRelativeToCamera(scene: Scene, diagramManager: Diagra logger.info('Horizontal left:', horizontalLeft); logger.info('Platform world position:', platform.getAbsolutePosition()); - // Position toolbox: Camera-relative positioning disabled to respect default/saved positions - // Handles now use their configured defaults or saved localStorage positions const toolbox = diagramManager.diagramMenuManager.toolbox; if (toolbox && toolbox.handleMesh) { logger.info('Toolbox handleMesh using default/saved position:', { @@ -166,64 +164,13 @@ function positionComponentsRelativeToCamera(scene: Scene, diagramManager: Diagra absolutePosition: toolbox.handleMesh.getAbsolutePosition().clone(), rotation: toolbox.handleMesh.rotation.clone() }); - - // Camera-relative positioning commented out - handles use their own defaults - /* - // Position at 45 degrees to the left, 0.45m away, slightly below eye level - // NOTE: User faces -Z direction by design, so negate forward offset - const forwardOffset = horizontalForward.scale(-0.3); - const leftOffset = horizontalLeft.scale(0.35); - const toolboxWorldPos = cameraWorldPos.add(forwardOffset).add(leftOffset); - toolboxWorldPos.y = cameraWorldPos.y - 0.3; // Below eye level - - logger.info('Calculated toolbox world position:', toolboxWorldPos); - logger.info('Forward offset:', forwardOffset); - logger.info('Left offset:', leftOffset); - - const toolboxLocalPos = Vector3.TransformCoordinates(toolboxWorldPos, platform.getWorldMatrix().invert()); - logger.info('Calculated toolbox local position:', toolboxLocalPos); - - toolbox.handleMesh.position = toolboxLocalPos; - - // Orient toolbox to face the user - const toolboxToCamera = cameraWorldPos.subtract(toolboxWorldPos).normalize(); - const toolboxYaw = Math.atan2(toolboxToCamera.x, toolboxToCamera.z); - toolbox.handleMesh.rotation.y = toolboxYaw; - - logger.info('Toolbox handleMesh AFTER positioning:', { - position: toolbox.handleMesh.position.clone(), - absolutePosition: toolbox.handleMesh.getAbsolutePosition().clone(), - rotation: toolbox.handleMesh.rotation.clone() - }); - */ } - // Position input text view: Camera-relative positioning disabled to respect default/saved positions - // Handles now use their configured defaults or saved localStorage positions const inputTextView = diagramManager.diagramMenuManager['_inputTextView']; if (inputTextView && inputTextView.handleMesh) { logger.info('InputTextView handleMesh using default/saved position:', { position: inputTextView.handleMesh.position.clone(), absolutePosition: inputTextView.handleMesh.getAbsolutePosition().clone() }); - - // Camera-relative positioning commented out - handles use their own defaults - /* - // NOTE: User faces -Z direction by design, so negate forward offset - const inputWorldPos = cameraWorldPos.add(horizontalForward.scale(-0.5)); - inputWorldPos.y = cameraWorldPos.y - 0.4; // Below eye level - - logger.info('Calculated input world position:', inputWorldPos); - - const inputLocalPos = Vector3.TransformCoordinates(inputWorldPos, platform.getWorldMatrix().invert()); - logger.info('Calculated input local position:', inputLocalPos); - - inputTextView.handleMesh.position = inputLocalPos; - - logger.info('InputTextView handleMesh AFTER positioning:', { - position: inputTextView.handleMesh.position.clone(), - absolutePosition: inputTextView.handleMesh.getAbsolutePosition().clone() - }); - */ } } \ No newline at end of file diff --git a/src/util/functions/sceneInspector.ts b/src/util/functions/sceneInspector.ts index 115dc28..1cf125b 100644 --- a/src/util/functions/sceneInspector.ts +++ b/src/util/functions/sceneInspector.ts @@ -23,23 +23,6 @@ export function addSceneInspector() { }); }); } - - /*import("@babylonjs/core/Debug").then(() => { - import("@babylonjs/inspector").then(() => { - const web = document.querySelector('#webApp'); - if (scene.debugLayer.isVisible()) { - if (web) { - (web as HTMLDivElement).style.display = 'block'; - } - scene.debugLayer.hide(); - } else { - scene.debugLayer.show(); - if (web) { - (web as HTMLDivElement).style.display = 'none'; - } - } - }); - });*/ } }); } diff --git a/src/util/lightmapGenerator.ts b/src/util/lightmapGenerator.ts index a323e92..614d49a 100644 --- a/src/util/lightmapGenerator.ts +++ b/src/util/lightmapGenerator.ts @@ -1,5 +1,4 @@ import {Color3, DynamicTexture, HemisphericLight, PointLight, Scene, StandardMaterial, Vector3} from "@babylonjs/core"; -import {DefaultScene} from "../defaultScene"; import {RenderingMode} from "./renderingMode"; export class LightmapGenerator {