feat(phase-11): implement comprehensive non-destructive layer effects system
Adds Photoshop-style layer effects with full non-destructive editing support: **Core Architecture:** - Type system with 10 effect types and discriminated unions - Zustand store with Map-based storage and localStorage persistence - Canvas-based rendering engine with intelligent padding calculation - Effects applied at render time without modifying original layer data **Implemented Effects (6 core effects):** - Drop Shadow - Customizable shadow with angle, distance, size, and spread - Outer Glow - Soft glow around layer edges with spread control - Inner Shadow - Shadow effect inside layer boundaries - Inner Glow - Inward glow from edges with choke parameter - Stroke/Outline - Configurable stroke with position options - Color Overlay - Solid color overlay with blend modes **Rendering Engine Features:** - Smart padding calculation for effects extending beyond layer bounds - Effect stacking: Background → Layer → Modifying → Overlay - Canvas composition for complex effects (inner shadow/glow) - Global light system for consistent shadow angles - Blend mode support for all effects - Opacity control per effect **User Interface:** - Integrated effects panel in layers sidebar - Collapsible panel with effect count badge - Add effect dropdown with 6 effect types - Individual effect controls (visibility toggle, duplicate, delete) - Master enable/disable for all layer effects - Visual feedback with toast notifications **Store Features:** - Per-layer effects configuration - Effect reordering support - Copy/paste effects between layers - Duplicate effects within layer - Persistent storage across sessions - Global light angle/altitude management **Technical Implementation:** - Non-destructive: Original layer canvas never modified - Performance optimized with canvas padding only where needed - Type-safe with full TypeScript discriminated unions - Effects rendered in optimal order for visual quality - Map serialization for Zustand persistence **New Files:** - types/layer-effects.ts - Complete type definitions for all effects - store/layer-effects-store.ts - Zustand store with persistence - lib/layer-effects-renderer.ts - Canvas rendering engine - components/layers/layer-effects-panel.tsx - UI controls **Modified Files:** - components/canvas/canvas-with-tools.tsx - Integrated effects rendering - components/layers/layers-panel.tsx - Added effects panel to sidebar **Effects Planned (not yet implemented):** - Bevel & Emboss - 3D depth with highlights and shadows - Gradient Overlay - Gradient fills with angle control - Pattern Overlay - Repeating pattern fills - Satin - Soft interior shading effect All effects are fully functional, persistent, and can be toggled on/off without data loss. The system provides a solid foundation for advanced layer styling similar to professional image editors. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,9 +6,11 @@ import { useHistoryStore } from '@/store/history-store';
|
||||
import { useSelectionStore } from '@/store/selection-store';
|
||||
import { useTextStore } from '@/store/text-store';
|
||||
import { useContextMenuStore } from '@/store/context-menu-store';
|
||||
import { useLayerEffectsStore } from '@/store/layer-effects-store';
|
||||
import { drawMarchingAnts } from '@/lib/selection-utils';
|
||||
import { getContext, drawGrid, drawCheckerboard } from '@/lib/canvas-utils';
|
||||
import { renderText } from '@/lib/text-utils';
|
||||
import { applyLayerEffects } from '@/lib/layer-effects-renderer';
|
||||
import { DrawCommand } from '@/core/commands';
|
||||
import { getTool, preloadCommonTools } from '@/lib/tool-loader';
|
||||
import { useTouchGestures } from '@/hooks/use-touch-gestures';
|
||||
@@ -54,6 +56,7 @@ export function CanvasWithTools() {
|
||||
const { activeSelection, selectionType, isMarching, clearSelection, selectAll } = useSelectionStore();
|
||||
const { textObjects, editingTextId, isOnCanvasEditorActive } = useTextStore();
|
||||
const { showContextMenu } = useContextMenuStore();
|
||||
const { getLayerEffects } = useLayerEffectsStore();
|
||||
const [marchingOffset, setMarchingOffset] = useState(0);
|
||||
|
||||
const [isPanning, setIsPanning] = useState(false);
|
||||
@@ -160,9 +163,15 @@ export function CanvasWithTools() {
|
||||
.forEach((layer) => {
|
||||
if (!layer.canvas) return;
|
||||
|
||||
// Get layer effects configuration
|
||||
const effectsConfig = getLayerEffects(layer.id);
|
||||
|
||||
// Apply effects to layer if any exist
|
||||
const layerWithEffects = applyLayerEffects(layer.canvas, effectsConfig);
|
||||
|
||||
ctx.globalAlpha = layer.opacity;
|
||||
ctx.globalCompositeOperation = layer.blendMode as GlobalCompositeOperation;
|
||||
ctx.drawImage(layer.canvas, layer.x, layer.y);
|
||||
ctx.drawImage(layerWithEffects, layer.x, layer.y);
|
||||
});
|
||||
|
||||
// Reset composite operation
|
||||
|
||||
Reference in New Issue
Block a user