updated to v2.0.0
added new features such as dynamic sum adjustment and sum-lock dynamics
This commit is contained in:
@@ -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
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
`;
|
||||
```
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user