Replace static arrow.png with dynamically generated SVG arrows that match
the source object's color from the toolbox palette.
Changes:
- Replace arrow.png loading with inline SVG generation (32x32 right-pointing triangle)
- Add CreateColoredTexture() method to generate arrows in any hex color
- Extract color from source mesh using three-priority fallback system:
1. mesh.metadata.color (most reliable)
2. sourceMesh.id parsing (e.g., "tool-#box-template-#FF0000")
3. material color extraction (backwards compatibility)
- Match extracted color to closest of 16 toolbox colors using Euclidean distance
- Track all textures in Set for synchronized animation
- Add proper texture disposal to prevent memory leaks
Benefits:
- No external arrow.png dependency
- Connections visually match their source object's toolbox color
- Consistent 16-color palette across all connections
- Efficient texture sharing for matching colors
- SVG scales perfectly at any resolution
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add 6 face handles for single-axis scaling (in addition to 8 corner handles for uniform scaling)
- Implement single-axis scaling for face handles vs uniform scaling for corners
- Add automatic handle position updates when target mesh moves or rotates
- Track mesh transform changes using quaternions for accurate rotation detection
- Update handles in real-time during scaling to match new bounding box
- Add FACE_POSITIONS constant array to enums.ts
- Fix handle sizing to use consistent size calculation for all handles
🤖 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>
Implemented a single button in the toolbox that cycles through four rendering modes:
1. Lightmap + Lighting - diffuseColor + lightmapTexture with lighting enabled
2. Emissive Texture - emissiveColor + emissiveTexture with lighting disabled (default)
3. Flat Color - emissiveColor only with lighting disabled
4. Diffuse + Lights - diffuseColor with two dynamic scene lights enabled
Features:
- Single clickable button displays current mode and cycles to next on click
- Automatically manages two scene lights (HemisphericLight + PointLight) for Diffuse + Lights mode
- UI materials (buttons, handles, labels) are excluded from mode changes to remain readable
- Button positioned below color grid with user-adjusted scaling
- Added comprehensive naming conventions documentation
- Updated inspector hotkey to Ctrl+Shift+I
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed from lightmapTexture with lighting enabled to emissiveTexture with lighting disabled for better performance. The new approach provides the same lighting illusion without expensive per-pixel lighting calculations.
- Added LightmapGenerator.ENABLED toggle for performance testing
- Updated buildColor.ts to use emissiveColor + emissiveTexture with disableLighting = true
- Updated buildMissingMaterial() to match new rendering approach
- Fixed buildTool.ts to access emissiveColor instead of diffuseColor for material color detection
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace emissive-only rendering with diffuse + lightmap system to achieve realistic lighting appearance without dynamic light overhead.
- Create LightmapGenerator class with canvas-based radial gradient generation
- Generate one lightmap per color (16 total) using top-left directional light simulation
- Cache lightmaps in static Map for reuse across all instances
- Preload all lightmaps at toolbox initialization for instant availability
- Update buildColor() to use diffuseColor + lightmapTexture instead of emissiveColor
- Update buildMissingMaterial() to use lightmap-based rendering
- Enable lighting calculations (disableLighting = false) to apply lightmaps
Lightmap details:
- 512x512 resolution RGBA textures
- Radial gradient: center (color × 1.5), mid (base color), edge (color × 0.3)
- Simulates top-left key light with smooth falloff
- Total memory: ~16 MB for all lightmaps
- Zero per-frame performance cost
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Refactored exit XR button creation from rigplatform to toolbox for better organization and UI cohesion.
- Add setXR() methods to DiagramManager, DiagramMenuManager, and Toolbox to pass WebXRDefaultExperience after initialization
- Create setupXRButton() in Toolbox class that creates button when entering XR
- Position button at bottom-right of toolbox (x: 0.5, y: -0.35, z: 0)
- Use Y-axis rotation (Math.PI) for correct orientation within toolbox coordinate system
- Scale button to 0.2 for appropriate size
- Remove button creation code from rigplatform
Exit button now moves with toolbox and is logically grouped with other UI elements.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Use camera.getDirection() instead of manual Euler angle calculation to properly account for camera transform hierarchy
- Negate forward offsets to position objects in -Z direction (user faces -Z by design)
- Replace expensive HighlightLayer hover effect with lightweight EdgesRenderer (20-50x faster)
- Add comprehensive debug logging for position calculations
The camera has a parent transform with 180° Y rotation, causing the user to face -Z in world space. Components now correctly position in front of the user when entering XR.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Lighting changes:
- Disabled HemisphericLight in customEnvironment
- Changed all materials from diffuse to emissive colors
- Added disableLighting=true to all StandardMaterials
- Updated toolbox colors, diagram entities, and spinner
Bug fix:
- Fixed "Cannot read properties of undefined (reading 'pickedMesh')" error
- Added defensive check in DiagramObject.updateConnection()
- Now validates hit array has at least 2 elements before accessing
Materials now render at full brightness with unlit/flat shading.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When entering immersive mode, toolbox and input text view now position
themselves relative to the user's initial camera position:
- Toolbox: 0.5m ahead, 0.5m below, 0.2m to the left
- Input text view: 0.5m ahead, 0.5m below (centered)
Uses camera world Y position to ensure vertical offset is consistent
regardless of head pitch/tilt when entering XR.
Also added CLAUDE.md documentation for the codebase.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>