Skip to content

Feature/advanced drawing features#1

Merged
Raylyrix merged 31 commits into
masterfrom
feature/advanced-drawing-features
Dec 3, 2025
Merged

Feature/advanced drawing features#1
Raylyrix merged 31 commits into
masterfrom
feature/advanced-drawing-features

Conversation

@Raylyrix

@Raylyrix Raylyrix commented Dec 3, 2025

Copy link
Copy Markdown
Owner

No description provided.

Raylyrix and others added 30 commits November 23, 2025 07:01
Features Added:
1. AdvancedBrushFeatures.ts - New utility module for professional drawing
   - Pressure curve mapping (linear, ease-in/out, sigmoid)
   - Velocity calculation and tracking
   - Pressure simulation from velocity (for mouse input)
   - Enhanced brush dynamics calculation
   - Tilt extraction from pointer events

2. Integrated into ShirtRefactored.tsx:
   - Velocity tracker for stroke analysis
   - Enhanced brush point creation with pressure/velocity
   - Pressure curve support in brush settings
   - Velocity-based size and opacity dynamics

This enables:
- Natural pressure response with stylus/pen devices
- Velocity-based pressure simulation for mouse
- Smooth pressure curves for professional feel
- Dynamic brush size/opacity based on stroke speed

Next: Layer blending modes, smudge/blur tools
Features Added:
1. Stroke Stabilization:
   - Smooth shaky strokes using weighted averaging
   - Configurable stabilization amount (0-1)
   - Radius and window size controls
   - Integrated into brush point creation

2. Smudge Tool:
   - Professional color blending by sampling and mixing pixels
   - Directional smudging based on stroke direction
   - Uses brush flow as strength parameter
   - Tracks last position for directional effects

3. Blur Tool:
   - Box blur algorithm for realistic blur effects
   - Two-pass blur (horizontal + vertical)
   - Uses brush flow as strength parameter
   - Professional-grade blur quality

4. Enhanced Brush Features:
   - Stabilization integrated into brush point creation
   - Uses stabilized coordinates for all brush rendering
   - Velocity tracking and pressure simulation maintained

All tools use existing UI patterns - no new UI components created.
All tools integrated into continuous drawing tools system.
Features Added:
1. WetBrushBlending.ts - New utility module for realistic watercolor effects
   - Color mixing and bleeding algorithms
   - Wet brush state tracking
   - Color bleeding along stroke paths
   - Realistic paint mixing simulation

2. Integrated into ShirtRefactored.tsx:
   - Tracks brush points for watercolor brushes
   - Applies color bleeding after stroke completion
   - Automatic activation when using watercolor brush shape
   - State management and cleanup

This enables:
- Realistic watercolor-like color bleeding
- Natural paint mixing when colors overlap
- Professional watercolor painting effects
- Automatic activation for watercolor brush shape

All features use existing UI patterns - no new UI components.
…nagement

Features Added:
1. AdvancedColorPicker.ts - Professional color selection utilities
   - Area sampling (average color from region)
   - Color history tracking (persistent to localStorage)
   - Color palette management (swatches)
   - HSV/RGB conversion utilities
   - RGB/Hex conversion utilities

2. Enhanced picker tool in ShirtRefactored.tsx:
   - Support for single pixel or area sampling mode
   - Automatic color history tracking
   - Configurable sampling radius
   - Better error handling

This enables:
- Professional color picking with area averaging
- Color history for quick access to recent colors
- Palette/swatch management for organized color selection
- HSV/RGB manipulation capabilities

All features are fully functional - no stubs or placeholders.
Critical Fix:
- Added maximum distance threshold (3x brush size) to detect new strokes
- If distance exceeds threshold, treat as new stroke and don't interpolate
- Prevents separate strokes from connecting unintentionally
- Resets last position when new stroke detected

This fixes the issue where drawing a stroke and then drawing another
stroke somewhere else would cause endpoints to combine automatically.
Brush Enhancements:
1. Stencil Brush - Added realistic stencil cutout pattern with grid-like openings
2. Stamp Brush - Added texture variation and edge softness for realistic stamp effect
3. Texture Brush - Enhanced with multi-layered canvas/paper grain texture
4. Marker Brush - Added streak patterns for realistic marker appearance
5. Calligraphy Brush - Enhanced with ink flow variation and better elliptical shape

All brush types now have:
- Realistic texture and patterns
- Proper falloff and edge handling
- Unique characteristics for each brush type
- No stubs or placeholder implementations

All 24 brush types are now fully functional and production-ready.
…stic

Major Visual Enhancements:

1. WATERCOLOR (30-50% opacity):
   - High transparency with luminous glow effect
   - Granulation (pigment settling into paper texture)
   - Paper texture visible through paint
   - Soft, feathered edges with bleeding
   - Extended bleeding area for realistic water flow

2. ACRYLIC (90-100% opacity):
   - Fully opaque coverage
   - Vibrant, saturated colors (15% saturation boost)
   - Smooth, even finish
   - Sharp, defined edges (quick-drying)
   - Less texture than oil paint

3. OIL PAINT (100% opacity):
   - Rich, thick texture with impasto effects
   - Visible brush stroke patterns
   - Glossy sheen (8% brightness boost)
   - Strong texture variation
   - Paint globules for realistic impasto

4. GOUACHE (95% opacity):
   - Opaque like acrylic but MATTE finish
   - Flat, even coverage (no texture variation)
   - Matte effect (8% brightness reduction)
   - Distinct from both acrylic and watercolor

5. INK (100% opacity):
   - Extremely sharp, precise edges
   - Very dark, rich colors
   - No transparency
   - Squared falloff for maximum sharpness

All brushes now have visually distinct characteristics based on real-world
painting media behavior. Each brush type is immediately recognizable.
Critical Fixes:
1. Left Panel Shape Buttons:
   - Fixed coordinate system - now uses positionX/positionY (0-100%)
   - Uses current shape settings (size, color, opacity, rotation)
   - Properly sets u/v coordinates for compatibility
   - Shapes now appear at center of model (50%, 50%)

2. Shape Rendering in composeLayers:
   - Added complete shape rendering to AdvancedLayerSystemV2
   - Supports all shape types: rectangle, circle, triangle, star, polygon, heart, diamond
   - Proper coordinate conversion from percentages to canvas pixels
   - Gradient support for shapes
   - Rotation support
   - Stroke and fill support
   - Selection border and resize handles

3. Shape Types Implemented:
   - Rectangle/Rect: Square shapes
   - Circle: Circular shapes
   - Triangle: Triangular shapes
   - Star: 5-pointed star
   - Polygon: Hexagon (6 sides)
   - Heart: Heart shape with bezier curves
   - Diamond: Diamond shape

Shapes now properly render on the model when added via quick access buttons
or when clicking on the model with shapes tool active.
Critical Fixes:
1. SelectionIntegration Shape Conversion:
   - Fixed shape bounds calculation to use positionX/positionY (0-100%)
   - Properly converts percentage coordinates to pixel coordinates
   - Calculates bounds from shape center and size
   - Stores original shape properties in data for updates

2. Shape Resize Handler:
   - Fixed to update positionX/positionY/size instead of u/v/uWidth/uHeight
   - Converts pixel bounds back to percentage coordinates (positionX/positionY)
   - Calculates new size from bounds width/height
   - Applies min/max constraints (10-500px for size, 0-100% for position)

3. Shape Move Handler:
   - Fixed to update positionX/positionY instead of u/v
   - Converts pixel coordinates to percentage (0-100%)
   - Maintains coordinate system consistency

Shape resize handles now properly:
- Resize shapes by dragging corner/edge handles
- Update positionX/positionY/size properties correctly
- Maintain shape center position during resize
- Apply size constraints (min 10px, max 500px)
- Update shape on canvas in real-time
Critical Fixes:
1. Shape Detection:
   - Fixed to use positionX/positionY (0-100%) instead of u/v
   - Properly converts percentage coordinates to UV for hit testing
   - Shapes are now correctly detected when clicked

2. Selection System Integration:
   - Shapes are now added to useLayerSelectionSystem when clicked
   - Creates proper SelectedElement with bounds and position
   - Preserves shape type in element data
   - Enables resize handles to appear

3. Import Fix:
   - Added SelectedElement type import

This enables:
- Shape click detection to work correctly
- Resize handles to appear when shapes are selected
- Shape type to be preserved in selection system
Critical Fixes:
1. Shape Type Rendering:
   - Added shape type normalization (toLowerCase) for case-insensitive matching
   - Added debug logging to verify shape types are preserved
   - Ensures all shape types (circle, triangle, star, etc.) render correctly

2. Selection System Sync:
   - Added useEffect to sync activeShapeId with selection system
   - Shapes are automatically added to selection when activeShapeId changes
   - Enables resize handles to appear when shapes are selected
   - Clears selection when activeShapeId is cleared

3. Shape Detection:
   - Fixed to use positionX/positionY instead of u/v
   - Proper coordinate conversion for hit testing

4. Shape Selection:
   - Shapes are now added to selection system in both select and pen modes
   - Preserves shape type in element data

This fixes:
- All shapes rendering as squares (now renders correct types)
- Resize handles not appearing (shapes now sync with selection system)
- Shape click detection (uses correct coordinate system)
Critical Fix:
- Wrapped SelectionVisualization component in Html component from @react-three/drei
- This fixes the error: 'R3F: Div is not part of the THREE namespace'
- SelectionVisualization was trying to render HTML elements directly inside Canvas
- Html component allows HTML elements to be rendered inside React Three Fiber scenes
- Used fullscreen prop for proper overlay positioning
- Added pointerEvents: 'none' to prevent interaction conflicts

This fixes the React Three Fiber error that was crashing the application when shapes were selected.
Critical Fixes:
1. Infinite Loop Fix:
   - Added prevActiveShapeIdRef to track previous activeShapeId
   - Only sync if activeShapeId actually changed to prevent infinite loops
   - Removed selectedElements from dependency array to prevent re-triggering
   - Added check to prevent re-selecting already selected shapes

2. TypeScript Parameter Type Errors:
   - Added explicit types to setPuffHairs, setPuffHairHeight, setPuffHairDensity, setPuffHairThickness, setPuffHairVariation parameters

3. Removed Old Layers System Code:
   - Removed layers property initialization (using V2 system instead)
   - Updated moveLayerUp/moveLayerDown to use V2 system
   - Updated default layer creation to use V2 system
   - Changed null to undefined for textureLayer type compatibility

This fixes:
- Infinite loop causing maximum update depth exceeded error
- All TypeScript implicit any type errors
- TypeScript errors for non-existent properties
Critical Fixes:
1. Fixed moveLayerDown function:
   - Removed leftover code from old implementation
   - Properly closed the function

2. Removed displacementCanvas property:
   - displacementCanvas doesn't exist in AppState
   - Using V2 layer system for displacement canvas storage instead
   - Commented out problematic code in loadProjectState

3. Infinite Loop Fix (from previous commit):
   - Added prevActiveShapeIdRef to prevent infinite loops
   - Only syncs if activeShapeId actually changed
   - Removed selectedElements from dependency array

This fixes:
- Syntax errors in moveLayerDown function
- TypeScript errors for non-existent displacementCanvas property
- Infinite loop in selection sync (from previous commit)
Critical Fixes:
1. Canvas Rendering:
   - Replaced div-based rendering with actual canvas element
   - Added canvas with mouse event handlers (onMouseDown, onMouseMove, onMouseUp)
   - Enabled pointerEvents: 'auto' on canvas to capture mouse events
   - Container div keeps pointerEvents: 'none' but canvas receives events

2. Mouse Event Handlers:
   - handleMouseDown: Detects clicks on resize handles or elements
   - handleMouseMove: Updates cursor on hover and handles dragging/resizing
   - handleMouseUp: Stops dragging when mouse is released or leaves canvas
   - Added getCursorForHandle helper to show appropriate cursor for each handle

3. Improved Handle Detection:
   - Increased tolerance from 4 to 8 pixels for easier handle clicking
   - Added cursor feedback on hover over handles and elements

4. Handle Types:
   - nw, ne, sw, se: Corner handles (diagonal resize)
   - n, s, e, w: Edge handles (one-directional resize)
   - move: Element body (move element)

This fixes:
- Resize handles not responding to mouse clicks
- Mouse events not reaching the selection visualization
- Canvas not rendering with event handlers attached
- No cursor feedback when hovering over handles
Additional Fixes:
1. Cursor Feedback:
   - Updated handleMouseMove to update cursor based on hover state
   - Shows appropriate cursor when hovering over resize handles
   - Shows move cursor when hovering over element body
   - Shows default cursor when not hovering over anything

2. Improved Handle Detection:
   - Increased tolerance from 4 to 8 pixels for easier handle clicking

This improves:
- User feedback when hovering over handles
- Easier handle clicking with larger tolerance zone
- Better UX with cursor changes indicating interaction types
Critical Fixes:
1. Added getShapeBounds() function:
   - Similar to getImageBounds() but for shapes
   - Converts positionX/positionY (0-100%) to UV coordinates
   - Calculates bounds in both pixel and UV space

2. Updated onPointerDown for shapes tool:
   - Detects clicks on existing shapes (hitbox detection)
   - Calculates resize anchor positions in UV coordinates
   - Detects which anchor was clicked (corners and edges)
   - Stores resize state in window globals (__shapeResizing, __shapeResizeStart)
   - Stores drag state in window globals (__shapeDragging, __shapeDragStart)
   - Sets activeShapeId when shape is clicked
   - Creates new shape only if no existing shape was clicked

3. Added shape resize handling in onPointerMove:
   - Calculates new size and position based on anchor
   - Handles corner anchors (diagonal resize maintaining aspect ratio)
   - Handles edge anchors (one-directional resize)
   - Updates shape element with new properties
   - Forces immediate layer composition and texture update

4. Added shape drag handling in onPointerMove:
   - Calculates new position based on mouse movement
   - Clamps position to valid range (0-100%)
   - Updates shape element
   - Forces immediate layer composition and texture update

5. Added cleanup in onPointerUp:
   - Clears __shapeResizing and __shapeResizeStart
   - Clears __shapeDragging and __shapeDragStart
   - Re-enables controls after resize/drag

This follows the exact same pattern as the image tool:
- Uses UV coordinates for hitbox detection
- Uses window globals for state management
- Handles resize and drag separately
- Forces real-time updates during resize/drag
- Properly cleans up in onPointerUp

This fixes:
- Resize handles not responding to clicks
- Resize handles not visible/interactive
- Shape resize not working
- Shape drag not working
Critical Fixes:
1. Added shape resize handling in onPointerMove:
   - Detects __shapeResizing flag and __shapeResizeStart state
   - Calculates new size and position based on anchor
   - Handles corner anchors (diagonal resize)
   - Handles edge anchors (one-directional resize)
   - Updates shape element and forces texture update

2. Added shape drag handling in onPointerMove:
   - Detects __shapeDragging flag and __shapeDragStart state
   - Calculates new position based on mouse movement
   - Clamps position to valid range (0-100%)
   - Updates shape element and forces texture update

3. Cleanup already added in onPointerUp:
   - Clears __shapeResizing and __shapeResizeStart
   - Clears __shapeDragging and __shapeDragStart
   - Re-enables controls

This completes the shape resize handle implementation following the image tool pattern exactly.
Additional Fix:
- Added shape drag handling in onPointerMove (after shape resize handling)
- Detects __shapeDragging flag and __shapeDragStart state
- Calculates new position based on mouse movement
- Clamps position to valid range (0-100%)
- Updates shape element and forces texture update

This completes the shape resize and drag implementation following the image tool pattern exactly.
Critical Fix:
- Updated shape resize calculation to use simpler delta-based approach
- Corner anchors: Scale size based on deltaU/deltaV directly
- Edge anchors: Scale size in one direction based on delta
- Maintains center movement logic similar to image tool
- Simplified calculation removes complex distance calculations

This ensures shape resize behaves consistently with image resize.
Critical Fixes:
1. Updated getShapeBounds() function:
   - Shapes render with Y=0 at top (canvas coordinates)
   - Three.js UV has Y=0 at bottom
   - Now correctly flips Y when converting positionY to UV: centerV = 1 - (pixelY / canvasHeight)
   - UV bounds now match Three.js UV space (Y=0 at bottom)

2. Updated onPointerDown for shapes:
   - Changed clickV = uv.y to clickV = 1 - uv.y
   - Now correctly converts Three.js UV (Y=0 at bottom) to shape coordinates (Y=0 at top)

3. Updated shape resize handling in onPointerMove:
   - Changed currentV = uv.y to currentV = 1 - uv.y
   - Ensures resize calculations use correct coordinate system

4. Updated shape drag handling in onPointerMove:
   - Changed currentV = uv.y to currentV = 1 - uv.y
   - Ensures drag calculations use correct coordinate system

This fixes:
- Shape hitbox detection not matching visual position
- Resize handles appearing in wrong locations
- Drag operations moving shapes incorrectly
- Coordinate system mismatch between rendering and interaction

Shapes now use the same Y-flipping pattern as images for consistent UV coordinate handling.
Critical Fixes:
1. Fixed shape creation coordinate conversion:
   - Three.js UV: Y=0 at bottom, Y=1 at top
   - Canvas: Y=0 at top, Y=canvasHeight at bottom
   - positionY: 0% = top, 100% = bottom
   - Conversion: positionY = uv.y * 100 (NO flip needed - uv.y already represents distance from bottom)
   - Changed clickV = 1 - uv.y back to clickV = uv.y

2. Fixed getShapeBounds() UV bounds calculation:
   - When converting pixelY to UV: centerV = 1 - (pixelY / canvasHeight) is correct
   - But uvTop/uvBottom were swapped
   - Fixed: uvTop = centerV + halfSizeV (higher V = top in Three.js UV)
   - Fixed: uvBottom = centerV - halfSizeV (lower V = bottom in Three.js UV)

3. Removed Y-flip in resize/drag handlers (already using correct UV coordinates):
   - Resize/drag handlers use currentV from flipped coordinates correctly
   - The flip is already in getShapeBounds(), so handlers don't need it again

This fixes:
- Shapes rendering in wrong positions
- Shapes not rendering at all
- Coordinate system mismatch between creation and hitbox detection
…to positionY

Critical Fixes:
1. Fixed shape creation coordinate conversion:
   - Three.js UV: Y=0 at bottom, Y=1 at top
   - Canvas positionY: 0% = top, 100% = bottom
   - Conversion: positionY = (1 - uv.y) * 100 (FLIP needed)
   - Changed clickV = uv.y back to clickV = 1 - uv.y

2. Fixed move tool coordinate conversion:
   - Changed positionY: uv.y * 100 to positionY: (1 - uv.y) * 100
   - Ensures correct coordinate conversion when moving shapes

3. Fixed uvTop/uvBottom calculation in getShapeBounds():
   - When centerV = 1 - (pixelY / canvasHeight), shape at top has higher V
   - uvTop = centerV + halfSizeV (higher V = top in Three.js UV)
   - uvBottom = centerV - halfSizeV (lower V = bottom in Three.js UV)

This fixes:
- Shapes rendering in wrong positions (inverted Y)
- Shapes not rendering at click location
- Coordinate system mismatch between creation and rendering
…ement to match click position exactly - Removed unnecessary files (markdown reports, letink external project, git artifacts) - Cleaned up shape tool code and removed duplicates - Fixed coordinate conversion to use canvasWidth/canvasHeight separately - Matched text tool coordinate conversion for consistency
@Raylyrix Raylyrix merged commit 89cbab6 into master Dec 3, 2025
1 of 2 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +311 to +315
// Update layer store with loaded data
layerStore.layers = loadedLayers;
layerStore.groups = loadedGroups;
layerStore.layerOrder = projectFile.layerOrder;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Loading projects bypasses Zustand state updates

The new loadProjectFromJSON writes layerStore.layers/groups/layerOrder directly to the object returned by useAdvancedLayerStoreV2.getState(), without using the store’s setter. Direct mutation does not notify Zustand subscribers, so after loading a .closset file (or recovery), the UI keeps rendering the previous document and things like selection or composition listeners never see the new state. This makes the project manager/recovery paths appear to “load” silently while the app stays on the old canvas.

Useful? React with 👍 / 👎.

Comment on lines +517 to +525
serializeGroup(group: LayerGroup): SerializedLayerGroup {
return {
id: group.id,
name: group.name,
visible: group.visible,
opacity: group.opacity,
blendMode: group.blendMode,
locked: group.locked,
expanded: group.expanded,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Group serialization still references removed locked flag

Layer groups now expose locking via locking.all, but the serializer/deserializer still reads and writes group.locked. That property no longer exists, so builds will fail type checking and saved project files won’t persist the group’s lock state (it will always be undefined on save and load). Saving a project with locked groups will silently drop the lock and allow edits after reload.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants