diff --git a/pyproject.toml b/pyproject.toml index cbe637d..89eca17 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "comfyui_fill-nodes" description = "Fill-Nodes is a versatile collection of custom nodes for ComfyUI that extends functionality across multiple domains. Features include advanced image processing (pixelation, slicing, masking), visual effects generation (glitch, halftone, pixel art), comprehensive file handling (PDF creation/extraction, Google Drive integration), AI model interfaces (GPT, DALL-E, Hugging Face), utility nodes for workflow enhancement, and specialized tools for video processing, captioning, and batch operations. The pack provides both practical workflow solutions and creative tools within a unified node collection." -version = "2.0.8" +version = "2.0.9" license = "LICENSE" dependencies = ["diffusers", "librosa", "sounddevice", "glitch_this", "PyOpenGL", "glfw", "scipy>=1.13.1", "requests", "aiohttp", "moviepy", "matplotlib", "reportlab", "openai", "PyPDF2", "pdf2image", "PyMuPDF", "reportlab", "PyPDF2", "ollama", "kornia", "opencv-python", "gdown", "open_clip_torch", "google-genai"] diff --git a/web/nodes/wip/FL_PathAnimator.js b/web/nodes/wip/FL_PathAnimator.js index e31aa5d..89101fe 100644 --- a/web/nodes/wip/FL_PathAnimator.js +++ b/web/nodes/wip/FL_PathAnimator.js @@ -1,6 +1,6 @@ /** * File: FL_PathAnimator.js - * Project: ComfyUI_Fill-Nodes + * Project: ComfyUI_FL-Path-Animator * * Interactive path animator with modal drawing editor */ @@ -8,6 +8,31 @@ import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; +// SVG Icon Helper Functions +const Icons = { + pencil: () => ``, + + pin: () => ``, + + trash: () => ``, + + cursor: () => ``, + + image: () => ``, + + xCircle: () => ``, + + lock: () => ``, + + edit: () => ``, + + close: () => ``, + + arrowRight: () => ``, + + target: () => ``, +}; + function moveWidgetToTop(node, widget) { if (!widget) return; @@ -417,7 +442,7 @@ class PathEditorModal { `; const title = document.createElement('h2'); - title.textContent = '✏️ Path Animator Editor'; + title.innerHTML = `${Icons.edit()} Path Animator Editor`; title.style.cssText = ` margin: 0; color: #fff; @@ -425,6 +450,8 @@ class PathEditorModal { font-weight: 600; letter-spacing: -0.5px; text-shadow: 0 2px 4px rgba(0,0,0,0.3); + display: flex; + align-items: center; `; const subtitle = document.createElement('div'); @@ -439,13 +466,12 @@ class PathEditorModal { titleContainer.appendChild(subtitle); const closeBtn = document.createElement('button'); - closeBtn.textContent = '✕'; + closeBtn.innerHTML = Icons.close(); closeBtn.style.cssText = ` background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 6px; color: #fff; - font-size: 24px; cursor: pointer; padding: 0; width: 36px; @@ -594,9 +620,9 @@ class PathEditorModal { this.container.appendChild(content); } - createToolbarButton(icon, title, isActive = false) { + createToolbarButton(iconSvg, title, isActive = false) { const btn = document.createElement('button'); - btn.textContent = icon; + btn.innerHTML = iconSvg; btn.title = title; btn.style.cssText = ` width: 50px; @@ -606,9 +632,12 @@ class PathEditorModal { color: #fff; cursor: pointer; border-radius: 8px; - font-size: 20px; transition: all 0.2s ease; box-shadow: ${isActive ? '0 0 12px rgba(78, 205, 196, 0.3)' : 'none'}; + display: flex; + align-items: center; + justify-content: center; + padding: 0; `; btn.onmouseover = () => { if (!isActive) { @@ -641,12 +670,12 @@ class PathEditorModal { `; // Add image upload button - const uploadBtn = this.createToolbarButton('🖼️', 'Load Background Image'); + const uploadBtn = this.createToolbarButton(Icons.image(), 'Load Background Image'); uploadBtn.onclick = () => this.loadImage(); toolbar.appendChild(uploadBtn); // Add clear image button - const clearImgBtn = this.createToolbarButton('🚫', 'Clear Background Image'); + const clearImgBtn = this.createToolbarButton(Icons.xCircle(), 'Clear Background Image'); clearImgBtn.onclick = () => this.clearImage(); toolbar.appendChild(clearImgBtn); @@ -660,10 +689,10 @@ class PathEditorModal { toolbar.appendChild(separator); const tools = [ - { name: 'pencil', icon: '✏️', title: 'Draw Path (Motion)' }, - { name: 'point', icon: '📍', title: 'Add Static Point (Anchor)' }, - { name: 'eraser', icon: '🗑️', title: 'Erase Path' }, - { name: 'select', icon: '↖️', title: 'Select Path' }, + { name: 'pencil', icon: Icons.pencil(), title: 'Draw Path (Motion)' }, + { name: 'point', icon: Icons.pin(), title: 'Add Static Point (Anchor)' }, + { name: 'eraser', icon: Icons.trash(), title: 'Erase Path' }, + { name: 'select', icon: Icons.cursor(), title: 'Select Path' }, ]; const toolButtons = []; @@ -700,7 +729,7 @@ class PathEditorModal { toolbar.appendChild(separator2); // Add Lock Perimeter button - const lockPerimeterBtn = this.createToolbarButton('🔒', 'Lock Perimeter - Add static shapes around border'); + const lockPerimeterBtn = this.createToolbarButton(Icons.lock(), 'Lock Perimeter - Add static shapes around border'); lockPerimeterBtn.onclick = () => this.lockPerimeter(); toolbar.appendChild(lockPerimeterBtn); @@ -710,7 +739,7 @@ class PathEditorModal { toolbar.appendChild(separator3); // Add clear all button - const clearBtn = this.createToolbarButton('🗑️', 'Clear All Paths'); + const clearBtn = this.createToolbarButton(Icons.trash(), 'Clear All Paths'); clearBtn.style.marginTop = 'auto'; clearBtn.onclick = () => { if (confirm('Clear all paths?')) { @@ -1116,7 +1145,7 @@ class PathEditorModal { if (isSelected) { this.ctx.fillStyle = neonGreen; this.ctx.font = `bold ${12 * scale}px sans-serif`; - this.ctx.fillText('📍 Static', point.x + 10 * scale, point.y - 10 * scale); + this.ctx.fillText('Static', point.x + 10 * scale, point.y - 10 * scale); } } else if (path.points.length >= 2) { // Draw multi-point path (motion path) @@ -1128,7 +1157,7 @@ class PathEditorModal { } this.ctx.strokeStyle = isSelected ? neonGreen : path.color; - this.ctx.lineWidth = (isSelected ? this.pathThickness + 3 : this.pathThickness) * scale; + this.ctx.lineWidth = (isSelected ? this.pathThickness + 1 : this.pathThickness) * scale; this.ctx.lineCap = 'round'; this.ctx.lineJoin = 'round'; this.ctx.stroke(); @@ -1179,7 +1208,7 @@ class PathEditorModal { const midPoint = path.points[Math.floor(path.points.length / 2)]; this.ctx.fillStyle = neonGreen; this.ctx.font = `bold ${12 * scale}px sans-serif`; - this.ctx.fillText(`↗️ Motion (${path.points.length} pts)`, midPoint.x + 10 * scale, midPoint.y - 10 * scale); + this.ctx.fillText(`Motion (${path.points.length} pts)`, midPoint.x + 10 * scale, midPoint.y - 10 * scale); } } } @@ -1281,12 +1310,14 @@ class PathEditorModal { `; const typeLabel = document.createElement('span'); - typeLabel.textContent = isSinglePoint - ? '📍 Static (1 pt)' - : `↗️ Motion (${path.points.length} pts)`; + typeLabel.innerHTML = isSinglePoint + ? `${Icons.target()} Static (1 pt)` + : `${Icons.arrowRight()} Motion (${path.points.length} pts)`; typeLabel.style.cssText = ` font-size: 10px; color: ${isSelected ? neonGreen : (isSinglePoint ? '#F7DC6F' : '#4ECDC4')}; + display: flex; + align-items: center; `; nameContainer.appendChild(name);