updated to v2.0.0

added new features such as dynamic sum adjustment and sum-lock dynamics
This commit is contained in:
FunnyFinger
2025-04-19 20:22:11 +03:00
parent 218d28b435
commit a92aaa7159
29 changed files with 2562 additions and 269 deletions
+56
View File
@@ -0,0 +1,56 @@
---
description:
globs:
alwaysApply: true
---
# Clean Code Guidelines
## Constants Over Magic Numbers
- Replace hard-coded values with named constants
- Use descriptive constant names that explain the value's purpose
- Keep constants at the top of the file or in a dedicated constants file
## Meaningful Names
- Variables, functions, and classes should reveal their purpose
- Names should explain why something exists and how it's used
- Avoid abbreviations unless they're universally understood
## Smart Comments
- Don't comment on what the code does - make the code self-documenting
- Use comments to explain why something is done a certain way
- Document APIs, complex algorithms, and non-obvious side effects
## Single Responsibility
- Each function should do exactly one thing
- Functions should be small and focused
- If a function needs a comment to explain what it does, it should be split
## DRY (Don't Repeat Yourself)
- Extract repeated code into reusable functions
- Share common logic through proper abstraction
- Maintain single sources of truth
## Clean Structure
- Keep related code together
- Organize code in a logical hierarchy
- Use consistent file and folder naming conventions
## Encapsulation
- Hide implementation details
- Expose clear interfaces
- Move nested conditionals into well-named functions
## Code Quality Maintenance
- Refactor continuously
- Fix technical debt early
- Leave code cleaner than you found it
## Testing
- Write tests before fixing bugs
- Keep tests readable and maintainable
- Test edge cases and error conditions
## Version Control
- Write clear commit messages
- Make small, focused commits
- Use meaningful branch names
+48
View File
@@ -0,0 +1,48 @@
---
description:
globs:
alwaysApply: true
---
# Code Quality Guidelines
## Verify Information
Always verify information before presenting it. Do not make assumptions or speculate without clear evidence.
## File-by-File Changes
Make changes file by file and give me a chance to spot mistakes.
## No Apologies
Never use apologies.
## No Understanding Feedback
Avoid giving feedback about understanding in comments or documentation.
## No Whitespace Suggestions
Don't suggest whitespace changes.
## No Summaries
Don't summarize changes made.
## No Inventions
Don't invent changes other than what's explicitly requested.
## No Unnecessary Confirmations
Don't ask for confirmation of information already provided in the context.
## Preserve Existing Code
Don't remove unrelated code or functionalities. Pay attention to preserving existing structures.
## Single Chunk Edits
Provide all edits in a single chunk instead of multiple-step instructions or explanations for the same file.
## No Implementation Checks
Don't ask the user to verify implementations that are visible in the provided context.
## No Unnecessary Updates
Don't suggest updates or changes to files when there are no actual modifications needed.
## Provide Real File Links
Always provide links to the real files, not x.md.
## No Current Implementation
Don't show or discuss the current implementation unless specifically requested.
+51
View File
@@ -0,0 +1,51 @@
---
description:
globs:
alwaysApply: true
---
# ComfyUI Backend (Python) Node Development Guidelines
These rules supplement general clean code guidelines and focus specifically on creating Python backend code for ComfyUI custom nodes, based on official documentation patterns.
## Node Class Structure
- **Define nodes as Python classes.**
- **Implement `INPUT_TYPES(cls)`:**
- Return a dictionary with keys `"required"`, `"optional"`, and potentially `"hidden"`.
- Each value should be a dictionary mapping input names (strings) to input definitions.
- Input definitions are tuples: `(TYPE_STRING, OPTIONS_DICT)`.
- **Implement `RETURN_TYPES`:** Define as a tuple of output type strings (e.g., `("IMAGE", "MASK")`).
- **Implement `RETURN_NAMES`:** Define as a tuple of output name strings, matching `RETURN_TYPES`.
- **Implement `FUNCTION`:** String name of the main execution method.
- **Define `CATEGORY`:** String specifying the node's category in the UI menu (e.g., `"MyNodes/Utils"`).
- **Define `OUTPUT_NODE`:** Set to `True` if the node doesn't modify inputs for the execution graph (useful for display nodes, save nodes, etc.), otherwise `False` (or omit).
## Naming Conventions
- **Use `NODE_CLASS_MAPPINGS`:** Dictionary mapping an internal node name (string) to the node class.
- **Use `NODE_DISPLAY_NAME_MAPPINGS`:** Dictionary mapping the internal node name to a user-friendly display name.
- **Choose descriptive display names.** Internal names can be more specific if needed for uniqueness.
## Input/Output Handling
- **Main Function Signature:** The method named in `FUNCTION` must accept arguments corresponding *exactly* to the keys defined in the `"required"` and `"optional"` dictionaries within `INPUT_TYPES`. Use `**kwargs` to handle arbitrary inputs if using dynamic input techniques.
- **Input Options (`OPTIONS_DICT`):**
- Use standard options like `default`, `min`, `max`, `step` for numerical types.
- Use `multiline` for STRING inputs.
- Use `forceInput: True` for custom datatypes or types that should *always* be inputs, never widgets.
- **Return Values:** The main function *must* return a tuple with values corresponding exactly in order and type to `RETURN_TYPES`. Ensure return types are correct even during error conditions where possible.
- **Datatypes:** Use standard ComfyUI types (e.g., `INT`, `FLOAT`, `STRING`, `IMAGE`, `MASK`, `MODEL`, `CLIP`, `VAE`, `LATENT`, `CONDITIONING`). Custom types are possible but require `forceInput`.
- **Wildcard Inputs (`*`)**: Use sparingly. If using `"*"`, the node must be prepared to handle any datatype and potentially skip backend validation (e.g., by accepting `input_types` in `VALIDATE_INPUTS`).
## Hidden Inputs
- Use the `"hidden"` dictionary in `INPUT_TYPES` to access specific server information.
- **`"unique_id": "UNIQUE_ID"`:** Gets the node's unique ID from the workflow.
- **`"prompt": "PROMPT"`:** Gets the full prompt JSON structure.
- **`"extra_pnginfo": "EXTRA_PNGINFO"`:** Gets a dictionary to which metadata can be added for saving in output PNGs.
## Node Lifecycle & Behavior
- **`IS_CHANGED(self, ...)`:** Implement this method for inputs (often hidden/internal ones like prompts or seeds) where the *value* itself might not change, but its *meaning* or the desired output does. Return a hash or unique value based on the relevant changing data. This helps ComfyUI invalidate caches correctly.
- **`VALIDATE_INPUTS(self, ...)`:** Implement this optional method to perform custom validation *before* the main function executes. Return `True` if valid, `False` or raise an exception if invalid. Can accept `input_types` argument to handle wildcard inputs.
- **State:** Avoid storing excessive state directly on the node class instance if possible, as node instances might be reused unexpectedly. Prefer recalculating based on inputs.
## Error Handling & Logging
- Use standard Python `try...except` blocks for operations that might fail (e.g., file access, model loading, complex computations).
- Provide informative error messages using `print()` or Python's `logging` module.
- Ensure the node returns data matching `RETURN_TYPES` even in case of handled errors (e.g., return default values or empty structures), or raise an exception for unrecoverable errors.
+283
View File
@@ -0,0 +1,283 @@
---
description:
globs:
alwaysApply: false
---
# ComfyUI Custom Node Development Guidelines
## Specialization
- You are an AI assistant specialized in ComfyUI custom node development.
## General Guidelines
- Follow these guidelines when helping with this project:
## Project Context
- This is a custom node for ComfyUI called "Dynamic Sliders Stack"
- The node provides dynamic slider widgets that can be configured and controlled as a group
- It has both Python backend (defining node structure and processing) and JavaScript frontend (UI behavior)
- ComfyUI has significantly changed its frontend architecture, requiring adaptation for compatibility
## Architecture Knowledge
- ComfyUI nodes are defined as Python classes with specific methods like INPUT_TYPES() and FUNCTION
- Node UI behavior is controlled by JavaScript files that use ComfyUI extension system
- Communication between frontend and backend happens through serialized values
- ComfyUI uses a node-based graph structure where nodes perform operations and are connected via links
- Workflow data is stored in JSON format that defines nodes, connections, and widget values
- The modern ComfyUI frontend is built with Vue 3, TypeScript, and Pinia for state management
- The legacy frontend and new frontend can have different API patterns and requirements
## Frontend Architecture Versions
- Legacy: Vanilla JavaScript-based system
- Modern: Vue 3 + TypeScript with PrimeVue and TailwindCSS
- Custom nodes need to detect and adapt to the frontend version being used
- The modern frontend uses a different extension registration pattern and API
## JavaScript (Frontend) Patterns - Legacy
- Use `app.registerExtension({})` to register UI behavior
- Use the nodeCreated callback to initialize node behavior
- Widget values should be intercepted to handle user interactions
- Always prevent feedback loops when programmatically changing widget values
- Add `_isUpdatingInternally` flags to prevent update loops
- Consider using DOM mutation observers to detect changes to node elements
- Set up proper cleanup in onRemoved callbacks to prevent memory leaks
## JavaScript (Frontend) Patterns - Modern
- Use the new extension registration API with proper naming conventions
- Handle UI components through Vue composition APIs rather than direct DOM manipulation
- Use the new dialog, toast, and settings APIs for user interactions
- Rely on the component system rather than direct DOM manipulation
- Use the new event system for communication between components
- Follow the TypeScript typing conventions for better integration
- Consider using the new sidebar, commands, and keybinding registration APIs
## Compatibility Strategy
- Consider supporting both legacy and modern frontends using feature detection
- Create proper cleanup for event listeners and DOM modifications
- Use the frontend version flags to conditionally use appropriate APIs
- Test thoroughly on both legacy and modern frontends
- Consider using the ComfyUI Legacy Frontend option during transition
- Import legacy paths conditionally and with fallbacks
- Consider gradual migration rather than complete rewrite when feasible
- Use the new import paths for modern frontend: `app.extensionManager.*` APIs
## Python (Backend) Patterns
- Define INPUT_TYPES() to specify node inputs and widgets
- Define RETURN_TYPES and RETURN_NAMES for outputs
- Implement the main processing function as specified in FUNCTION
- Use good error handling for invalid inputs
- Properly type cast values received from the frontend
- Follow the node definition schema for proper integration with ComfyUI
- Consider adding category, display_name and description attributes for better organization
## Node Definition Structure
- Each node must define INPUT_TYPES() method returning a dictionary of inputs
- Widget types include INT, FLOAT, STRING, BOOLEAN, COMBO with appropriate parameters
- Widgets can have properties like default, min/max, step, display type
- Optional attributes like 'hidden', 'default_input', and 'tooltip' provide additional control
- RETURN_TYPES defines the output data types that other nodes can connect to
- FUNCTION attribute specifies the main method that processes inputs and returns outputs
- Define CATEGORY to organize where your node appears in the menu
## Modern Frontend APIs
- Use `app.registerExtension({name: 'MyExtension', ...})` for registration
- For dialog interfaces: `app.extensionManager.dialog.prompt/confirm/alert()`
- For notifications: `app.extensionManager.toast.add()`
- For settings: Register with `app.registerExtension({settings: [...]})`
- For accessing settings: `app.extensionManager.setting.get/set()`
- For custom UI: Use the sidebar tab API, bottom panel tabs API, and toolbox APIs
- For keybindings: Register with `app.registerExtension({commands: [...], keybindings: [...]})`
- For menus: Add to topbar with `app.registerExtension({menuCommands: [...]})`
## Workflow JSON Understanding
- ComfyUI workflows are stored as JSON with nodes, links, and widget values
- Each node has an ID, type, position, inputs, outputs, and widget values
- Links connect outputs of one node to inputs of another
- Understanding the JSON structure helps with debugging and programmatic workflow creation
- Custom nodes should properly serialize/deserialize their state within this format
## Styling and Conventions
- Use camelCase for JavaScript variables and functions
- Use snake_case for Python variables and functions
- Add detailed comments for complex logic
- Follow the existing code formatting conventions
- Keep logic modular and functions focused on a single responsibility
- For modern frontend, follow Vue 3 and TypeScript conventions
- Consider using PrimeVue icons and components for consistent UI
## Specific Project Knowledge
- Slider values can be normalized to maintain relative proportions
- The "total_sum" widget shows the sum of all active sliders
- Widget values are intercepted to handle complex interactions
- The node UI updates dynamically based on slider_count changes
## Read-Only Widget Implementation
- For truly read-only widgets, use a multi-layered constraint approach:
1. Replace the widget's DOM element with a styled read-only display
2. Constrain the widget's min/max values to be extremely close to the actual value
3. Use periodic checks to ensure constraints are maintained
4. Add mutation observers to detect DOM changes and reapply protection
5. Set both inputEl.readOnly and style.pointerEvents to block interaction
- The `constrainWidgetRange` function is the preferred way to make widgets immovable
- Key components needed:
- A function to calculate the precise epsilon based on widget precision
- A display element that visually indicates read-only state
- A value property interceptor that maintains constraints
- A periodic check interval for persistent protection
- Apply this pattern to any widgets that should display calculated values without user modification
- For modern frontend, investigate component-based approaches rather than DOM manipulation
## Preventing Overshooting in Interactive UI Elements
- When implementing interactive UI elements with rapid value changes, use these techniques to prevent overshooting:
1. Use immutable reference values to maintain stable relationships between values
- Store original relative values (like offsets or ratios) separate from current state
- Never modify these reference values during user interactions
- Always derive new values from these stable references, not from current values
2. Implement precise mathematical boundaries
- Pre-calculate the exact theoretical minimum and maximum values
- Consider all constraints and relationships between elements when determining limits
- Apply hard limits before any UI updates occur
3. Use direct value calculation instead of incremental changes
- Prefer formula-based updates over incremental adjustments
- Calculate target values directly from input parameters
- Avoid chains of operations that can accumulate rounding errors
4. Handle edge cases explicitly with special logic
- Implement special handling for boundary values (minimum, maximum)
- At boundaries, set exact values rather than attempting to calculate them
- For grouped elements, consider relative relationships at boundaries
5. Use atomic updates for related elements
- Calculate all new values before applying any changes
- Apply all updates in a single batch to prevent inconsistent intermediate states
- Verify the resulting state meets expected constraints
6. Implement post-update verification
- Check if any values exceed defined limits after updates
- Add correction mechanisms for any unexpected values
- Use appropriate flags to prevent recursive update loops
7. Consider the timing of events
- Be aware of when events fire during rapid user interactions
- Add appropriate flags to track update source (user vs. programmatic)
- Avoid recalculating reference values during interaction-driven updates
## Publishing and Distribution
- Add proper documentation and examples to help users understand your node
- Create a comprehensive README.md with installation instructions and examples
- Consider following the Registry standards for better integration with ComfyUI Manager
- Include a pyproject.toml file with metadata about your custom node
- Set up proper version control and tagging for releases
- Test your node on different platforms and ComfyUI versions
- Specify frontend version compatibility in your documentation
- Consider providing legacy and modern versions if needed
## Best Practices
- Always test suggested changes with edge cases
- Ensure backward compatibility where possible
- Keep performance in mind, especially for operations that might run many times
- Use descriptive variable names that reflect their purpose
- Validate user inputs before processing
- Clean up intervals and observers when nodes are removed
- Prefer component-based approaches over direct DOM manipulation in modern frontend
- Consider adding tooltips to explain widget functionality
- Refactor whenever possible
- Test with both legacy and modern frontend versions
- simplyfy the code as much as possible
- factorize the code as much as possible
- use the best practices for the modern frontend
- use loops and arrays as much as possible
- reduce the number of lines of code as much as possible
- use default and native methods as much as possible
- do not reinvent the wheel, use the best tools and libraries available
- do nit exceed 500 lines of code in any file
## Common Challenges
- DOM elements might not be available immediately after node creation
- Widget value updates can cause infinite loops if not carefully managed
- ComfyUI might use older JavaScript standards, avoid very modern syntax
- Consider both desktop and mobile interactions for widgets
- Widget elements may be regenerated by ComfyUI, requiring reapplication of custom behavior
- Handle backward compatibility when updating node definitions
- Import paths may change between frontend versions
- Extension registration patterns differ between legacy and modern frontends
- Component-based UIs require different interaction patterns than direct DOM manipulation
## Testing
- Test with different slider counts
- Verify sum calculations are accurate
- Check that normalization preserves relative proportions
- Ensure read-only widgets remain non-interactive under all conditions
- Test with rapid interactions to verify stability
- Test your node with different workflows and edge cases
- Verify proper cleanup when nodes are removed from the workflow
- Test with both legacy and modern frontend versions
- Test with different frontend version flags
## Troubleshooting Frontend Version Issues
- Run ComfyUI with legacy frontend for testing: `--front-end-version Comfy-Org/ComfyUI_legacy_frontend@latest`
- Try specific versions for compatibility testing: `--front-end-version Comfy-Org/ComfyUI_frontend@x.y.z`
- Check browser console for API-related errors
- Use feature detection rather than version checking when possible
- Implement graceful fallbacks for unsupported features
- Consider conditional imports based on detected frontend version
- Watch for API deprecation warnings in console output
- for debugging, avoid triggering many logs in loops
-
## Vue 3 Composition API .cursorrules
## Vue 3 Composition API best practices
```javascript
const vue3CompositionApiBestPractices = [
"Use setup() function for component logic",
"Utilize ref and reactive for reactive state",
"Implement computed properties with computed()",
"Use watch and watchEffect for side effects",
"Implement lifecycle hooks with onMounted, onUpdated, etc.",
"Utilize provide/inject for dependency injection",
"Use vue 3.5 style of default prop declaration. Example:",
"const { nodes, showTotal = true } = defineProps<{",
" nodes: ApiNodeCost[]",
" showTotal?: boolean",
"}>()",
"",
"",
"Organize vue component in <template> <script> <style> order",
]
```
## Folder structure
```
const folderStructure = `
src/
components/
constants/
composables/
views/
stores/
services/
App.vue
main.ts
`;
```
## Tailwind CSS best practices
```javascript
const tailwindCssBestPractices = [
"Use Tailwind CSS for styling",
"Implement responsive design with Tailwind CSS",
]
```
## Additional instructions
```
const additionalInstructions = `
1. Leverage VueUse functions for performance-enhancing styles
2. Use lodash for utility functions
3. Use TypeScript for type safety
4. Implement proper props and emits definitions
5. Utilize Vue 3's Teleport component when needed
6. Use Suspense for async components
7. Implement proper error handling
8. Follow Vue 3 style guide and naming conventions
9. Use Vite for fast development and building
10. Use vue-i18n in composition API for any string literals. Place new translation
entries in src/locales/en/main.json.
`;
```
+52
View File
@@ -0,0 +1,52 @@
---
description:
globs:
alwaysApply: true
---
# ComfyUI Frontend (JavaScript) Node Development Guidelines
These rules supplement general clean code guidelines and focus specifically on creating JavaScript frontend code for ComfyUI custom nodes, based on official documentation patterns.
## Extension Structure
- **Use `app.registerExtension({...})`:** Define all frontend logic within this structure.
- **Provide a unique `name`:** Use a pattern like `"Comfy.MyAuthorName.MyNodeOrFeatureName"`.
- **Use appropriate hooks:** Implement methods within the extension object corresponding to ComfyUI hooks (`nodeCreated`, `beforeRegisterNodeDef`, `setup`, etc.).
## Key JavaScript Hooks
- **`beforeRegisterNodeDef(nodeType, nodeData, app)`:**
- Called *once per node type* before registration.
- Use this to modify the *prototype* for all future instances of a specific node type.
- Identify the target node type using `nodeData.name` (the internal Python class name mapping key).
- Common use: Hijacking existing prototype methods (e.g., `onDrawForeground`, `onConfigure`, `onConnectionsChange`) to add custom behavior. Remember to store and call the original method using `originalMethod.apply(this, arguments)`.
- **`nodeCreated(node)`:**
- Called *every time* a specific node *instance* is created (either new or loaded).
- Use this for instance-specific setup, like adding listeners to that node's widgets or applying initial state based on properties.
- Identify the target node using `node.type` (internal name) or `node.title` (display name), or custom checks.
- **`setup(app)`:**
- Called once after the core UI (graph, canvas) is initialized but before nodes might be loaded.
- Use for global setup, adding overall UI elements, or registering global listeners.
- **`nodeSetup(node)` / `loadedGraphNode(node)`:** (Often used interchangeably or via hijacking `onConfigure`/`onAdded` within `beforeRegisterNodeDef`)
- Called when nodes are loaded as part of a workflow.
- Useful for applying state or UI modifications to existing nodes based on saved workflow data.
## Widget Manipulation
- **Access Widgets:** Use `node.widgets` (an array) or helper functions like `node.widgets.find(w => w.name === 'widget_name')`.
- **Intercept Value Changes:** Use `Object.defineProperty(widget, 'value', { get(){...}, set(newVal){...} })` to react when a widget's value is changed by the user or programmatically.
- **Dynamic Visibility (Standard Method):**
- **Hide:** Set `widget.hidden = true; widget.computeSize = () => [0, -4];`
- **Show:** Set `widget.hidden = false; widget.computeSize = originalComputeSize || null;` (Restore cached original `computeSize` function or set to null/default).
- Cache original widget properties (`type`, `computeSize`, `hidden`) before modifying them for hiding.
- **Modifying Other Properties:** You can change `widget.type`, `widget.options`, `widget.name` etc., but be cautious as it might break expected behavior.
## Node Appearance & Drawing
- **Basic Styling:** Set `node.bgcolor`, `node.color`, `node.shape` directly on the node instance (often in `nodeCreated` or hijacked `onAdded`/`onConfigure`).
- **Advanced Styling (CSS):** Inject CSS using `document.createElement('style')` and `document.head.appendChild()` for complex rules or overriding theme styles. Use specific selectors targeting node type (`[data-type="NodeType"]`) or title (`[title="NodeTitle"]`) and potentially internal elements (`.litenode-title`, `.widget-container`). Use `!important` judiciously.
- **Custom Drawing (`onDrawForeground`):** Hijack `nodeType.prototype.onDrawForeground` in `beforeRegisterNodeDef`. Use the `ctx` (CanvasRenderingContext2D) argument to draw directly onto the node's canvas *after* the default node is drawn. Useful for overlays or completely custom looks. Call the original method first.
- **Redrawing:** After making visual changes (widget visibility, color, size), call `node.setDirtyCanvas(true, true)` to tell LiteGraph to redraw. If node dimensions changed, calculate the new size (`node.computeSize()`) and set it (`node.setSize([w, h])`), preserving width if only height changed.
- **Use `requestAnimationFrame`:** Wrap UI updates (especially those involving size or visibility changes) in `requestAnimationFrame(() => { ... })` to ensure they run after the browser has finished its current rendering cycle, preventing layout issues and race conditions.
## Compatibility & Best Practices
- **Identify Nodes Reliably:** Check both `node.type` (internal name) and `node.title` (display name) or use specific widget checks, as titles can sometimes be changed by users or other nodes.
- **Minimize Core Hijacking:** Avoid modifying core `app` or `LiteGraph` prototype methods unless absolutely necessary, as this is prone to break with ComfyUI updates or conflicts with other extensions.
- **Check for Existence:** Always check if objects and methods exist before using them (e.g., `if (node.graph) { node.graph.setDirtyCanvas(...) }`, `if (originalMethod) { originalMethod.apply(...) }`).
- **Clean Console:** Remove debug `console.log` statements before finalizing, keeping only essential loading messages or error logs.