- Add express-pouchdb for self-hosted PouchDB sync server
- Public databases (/db/public/:db) accessible without auth
- Add auth middleware for public/private database access
- Simplify share button to copy current URL to clipboard
- Move feature config from static JSON to dynamic API endpoint
- Add PouchDB sync to PouchData class for real-time collaboration
- Fix Express 5 compatibility by patching req.query
- Skip express.json() for /pouchdb routes (stream handling)
- Remove unused PouchdbPersistenceManager and old share system
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Express server with vite-express for combined frontend/API serving
- Create modular API route structure (server/api/)
- Implement Claude API proxy with proper header injection
- Support split deployment via API_ONLY and ALLOWED_ORIGINS env vars
- Remove Claude proxy from Vite config (now handled by Express)
- Add migration plan documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implemented comprehensive VR onboarding experience for Quest users:
- Add demo database template with pre-built architecture diagram
- Implement automatic demo template loading on first visit
- Create VREntryPrompt component for seamless VR mode entry
- Add device detection utilities for Quest/VR headset identification
- Integrate export/import functionality for diagram templates
- Add About page with device-aware CTA and VR benefits
- Remove legacy tutorial and FirstVisitVr modal for demo flow
- Add upgrade prompts and tiered feature configuration
Quest users now see prominent VR entry prompt when navigating to /db/** paths,
providing one-tap entry into immersive mode after scene initialization.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Label Positioning Fixes:
- Fix labels accounting for mesh scaling using maximumWorld coordinates
- Labels now properly positioned on scaled objects (spheres, boxes, etc.)
- Restore world→local coordinate transformation in updateLabelPosition
Billboard Mode Implementation:
- Add configurable label rendering modes: fixed, billboard, dynamic, distance-based
- Implement billboard mode (labels always face camera using BILLBOARDMODE_Y)
- Add label rendering mode to AppConfig with default 'billboard'
- Add UI selector in ConfigModal for label rendering mode
- Observable pattern updates all existing labels when mode changes
XR Entry Positioning Fix:
- Synchronize desktop camera position to platform before entering XR
- Transfer camera world position and rotation to prevent scene shift
- Reset physics velocity on XR entry to prevent drift
- Add debug logging for position synchronization
Config System Architecture Fix:
- Create singleton appConfigInstance to ensure single source of truth
- Update DiagramObject to use singleton instead of creating instances
- Update DiagramManager to use singleton
- Fix ConfigModal to update AppConfig directly (was only updating legacy config)
- ConfigModal now triggers Observable notifications via appConfigInstance setters
- Maintain legacy config for backward compatibility
- Fixes issue where label rendering mode changes didn't take effect
Files Modified:
- src/diagram/diagramObject.ts - Label positioning, billboard mode, singleton config
- src/diagram/diagramManager.ts - Use singleton config
- src/util/appConfig.ts - Add labelRenderingMode, export singleton
- src/util/appConfigType.ts - Add LabelRenderingMode type
- src/react/pages/configModal.tsx - Update AppConfig directly, add label mode UI
- src/util/functions/groundMeshObserver.ts - Add camera position sync on XR entry
- public/api/user/features - Update test config
- package.json - Version bump
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement comprehensive feature toggle system allowing menu options and features
to be controlled via JSON configuration fetched from API endpoint or static files.
Core System:
- Create FeatureConfig type system with page, feature, and limit-based flags
- Add React Context (FeatureProvider) that fetches from /api/user/features
- Implement custom hooks (useFeatures, useIsFeatureEnabled, useFeatureLimit, etc.)
- Default config disables everything except home page
Integration:
- Update PageHeader to filter menu items based on page flags
- Add ProtectedRoute component to guard routes
- Update VR menu to conditionally render items based on feature flags
- Update CreateDiagramModal to enable/disable options (private, encrypted, invite)
- Update ManageDiagramsModal to use configurable maxDiagrams limit
Configuration Files:
- Add static JSON files for local testing (none, free, basic, pro tiers)
- Add dev proxy for /api/user/features endpoint
- Include README with testing instructions
Updates:
- Complete CLAUDE.md naming conventions section
- Version bump to 0.0.8-27
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Clean up AbstractController by removing references to old ResizeGizmo implementation:
- Remove utility layer mesh filtering logic
- Remove auto-show gizmo on hover
- Remove gizmo handle click filtering
- Remove unused Ray import
- Bump version to 0.0.8-26
These changes complete the migration to the new simplified ResizeGizmo architecture.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 1 & 2: Handle positioning and wireframe improvements
- Move handles 5% outward from bounding box (was inward)
- Rename boundingBoxPadding → handleOffset for clarity
- Add wireframePadding (3% breathing room around mesh)
Hover boundary detection (prevent loss in whitespace):
- Add isPointerInsideHandleBoundary() with ray-AABB intersection
- Use local space transformation for accurate OBB handling
- Keep HOVER_MESH state when pointer in handle boundary
- Fix: Trust ResizeGizmo state instead of recreating with fake rays
Prevent main scene mesh grab during handle interaction:
- Add ResizeGizmo state check in pointer observable
- Add defense-in-depth guard in grab() method
- Prevents controller from grabbing diagram mesh when hovering handle
- Two-level protection against race conditions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Handle meshes now correctly rotate to match the target mesh's world-space
orientation instead of appearing axis-aligned.
Root Cause:
- Handle positions from HandleGeometry are calculated in world space
- Setting mesh.position treats values as local space
- This created coordinate system mismatch when rotation was also set
- Result: rotation appeared to have no effect
Solution:
- Extract rotation from mesh world matrix using quaternion decomposition
- Set rotation FIRST (before position)
- Use setAbsolutePosition() for world-space positioning
- This ensures rotation and position work correctly together
Changes:
- Import Quaternion from @babylonjs/core
- Update createHandleMeshes(): decompose world matrix, set rotation,
then use setAbsolutePosition()
- Rename updateHandlePositions() to updateHandleTransforms()
- Update updateHandleTransforms(): same rotation-then-position approach
- Add null check for _targetMesh in updateHandleTransforms()
Technical Details:
- computeWorldMatrix(true) gets complete transform including parent
- decompose() extracts pure rotation as quaternion (avoids gimbal lock)
- setAbsolutePosition() correctly handles world-space coords with rotation
- Order matters: rotation before position for correct transformation
Result:
✅ Handle box shapes visually tilt/rotate with mesh
✅ Handles remain correctly positioned on OBB
✅ Both wireframe and individual handles rotate together
Files modified:
- ResizeGizmoVisuals.ts: Handle rotation implementation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Implement comprehensive WebXR resize gizmo system with three handle types:
- Corner handles: uniform scaling (all axes)
- Edge handles: two-axis planar scaling
- Face handles: single-axis scaling
- Use "virtual stick" metaphor for intuitive scaling:
- Fixed-length projection from controller to handle intersection
- Distance-ratio based scaling from mesh pivot point
- Works naturally with controller rotation and movement
- Add world-space coordinate transformations for VR rig parenting
- Implement manual ray picking for utility layer handle detection
- Add motion controller initialization handling for grip button
- Fix color persistence bug in diagram entities:
- DiagramEntityAdapter now uses toDiagramEntity() converter
- Store color in mesh metadata for persistence
- Add dependency injection for loose coupling
- Extract DiagramEntityAdapter to integration layer:
- Move from src/gizmos/ResizeGizmo/ to src/integration/gizmo/
- Add dependency injection for mesh-to-entity converter
- Keep ResizeGizmo pure and reusable without diagram dependencies
- Add closest color matching for missing toolbox colors
- Handle size now relative to bounding box (20% of avg dimension)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>