Conversation
📝 WalkthroughWalkthroughAdds PLY/splat support: workspace dependency and PLYEngine setting; new PLY parsers/loaders (FastPLYLoader, ASCII parser, optional Spark SplatMesh); exposes isSplatModel/isPlyModel flags to composables and UI; adds pointCloud material mode; updates loader, scene manager, service, and UI to handle PLY/splat models. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as User/UI
participant Load3D as Load3D Component
participant Composable as useLoad3d / useLoad3dViewer
participant LoaderMgr as LoaderManager
participant SceneMgr as SceneModelManager
participant Three as Three.js Scene
UI->>Load3D: upload/select .ply/.splat/.spz
Load3D->>Composable: loadModel(path)
Composable->>LoaderMgr: loadModelInternal(path)
alt PLYEngine == sparkjs
LoaderMgr->>LoaderMgr: construct SplatMesh (spark)
LoaderMgr->>SceneMgr: return SplatMesh group
else
LoaderMgr->>LoaderMgr: fetch -> arrayBuffer
LoaderMgr->>LoaderMgr: isASCII? -> parseASCIIPLY / FastPLY / PLYLoader.parse
LoaderMgr->>LoaderMgr: compute normals, detect vertex colors
alt material mode == pointCloud
LoaderMgr->>LoaderMgr: create Points (point cloud)
else
LoaderMgr->>LoaderMgr: create Mesh
end
LoaderMgr->>SceneMgr: return Object3D
end
SceneMgr->>SceneMgr: containsSplatMesh? -> special setup or handlePLYModeSwitch
SceneMgr->>Three: add model to scene (fit/camera/materials)
SceneMgr->>Composable: notify model ready
Composable->>Composable: set isSplatModel / isPlyModel
Composable->>Load3D: propagate flags
Load3D->>UI: adjust controls (hide material mode / enable pointCloud)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (24)
🧰 Additional context used📓 Path-based instructions (17)src/**/*.{vue,ts}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
src/**/*.ts📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
src/**/*.{ts,tsx,vue}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
src/**/*.{vue,ts,tsx}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
src/**/*.{js,ts,tsx,vue}📄 CodeRabbit inference engine (AGENTS.md)
Files:
src/**/*.{ts,tsx,vue,js}📄 CodeRabbit inference engine (AGENTS.md)
Files:
src/**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
src/**/*.vue📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
src/**/{composables,components}/**/*.{ts,tsx,vue}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
src/**/{components,composables}/**/*.{ts,tsx,vue}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
src/components/**/*.vue📄 CodeRabbit inference engine (src/components/CLAUDE.md)
Files:
src/components/**/*.{vue,css}📄 CodeRabbit inference engine (src/components/CLAUDE.md)
Files:
src/components/**/*.{vue,ts,js}📄 CodeRabbit inference engine (src/components/CLAUDE.md)
Files:
src/**/{services,composables}/**/*.{ts,tsx}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
src/composables/**/*.ts📄 CodeRabbit inference engine (AGENTS.md)
Files:
tests-ui/**/*.test.{js,ts,jsx,tsx}📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)
Files:
tests-ui/**/*.test.ts📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (42)📚 Learning: 2025-12-09T03:39:54.501ZApplied to files:
📚 Learning: 2025-12-13T11:03:11.264ZApplied to files:
📚 Learning: 2025-12-17T00:40:09.635ZApplied to files:
📚 Learning: 2025-12-11T12:25:15.470ZApplied to files:
📚 Learning: 2025-12-17T01:01:03.609ZApplied to files:
📚 Learning: 2025-11-24T19:48:03.270ZApplied to files:
📚 Learning: 2025-12-17T01:01:03.609ZApplied to files:
📚 Learning: 2025-11-24T19:48:03.270ZApplied to files:
📚 Learning: 2025-11-24T19:48:09.318ZApplied to files:
📚 Learning: 2025-11-24T19:47:56.371ZApplied to files:
📚 Learning: 2025-11-24T19:48:09.318ZApplied to files:
📚 Learning: 2025-12-17T01:01:03.609ZApplied to files:
📚 Learning: 2025-11-24T19:48:09.318ZApplied to files:
📚 Learning: 2025-12-17T01:01:03.609ZApplied to files:
📚 Learning: 2025-12-17T01:01:03.609ZApplied to files:
📚 Learning: 2025-11-24T19:48:09.318ZApplied to files:
📚 Learning: 2025-11-24T19:47:56.371ZApplied to files:
📚 Learning: 2025-11-24T19:48:03.270ZApplied to files:
📚 Learning: 2025-12-17T01:01:03.609ZApplied to files:
📚 Learning: 2025-12-16T22:26:49.463ZApplied to files:
📚 Learning: 2025-12-09T03:49:52.828ZApplied to files:
📚 Learning: 2025-12-09T21:40:12.361ZApplied to files:
📚 Learning: 2025-12-18T02:07:38.870ZApplied to files:
📚 Learning: 2025-12-18T21:15:46.862ZApplied to files:
📚 Learning: 2025-12-18T16:03:02.066ZApplied to files:
📚 Learning: 2025-11-24T19:47:56.371ZApplied to files:
📚 Learning: 2025-11-24T19:47:56.371ZApplied to files:
📚 Learning: 2025-11-24T19:47:45.616ZApplied to files:
📚 Learning: 2025-11-24T19:47:45.616ZApplied to files:
📚 Learning: 2025-12-17T01:01:03.609ZApplied to files:
📚 Learning: 2025-12-17T01:01:03.609ZApplied to files:
📚 Learning: 2025-12-10T03:09:13.807ZApplied to files:
📚 Learning: 2025-11-24T19:48:03.270ZApplied to files:
📚 Learning: 2025-11-24T19:48:03.270ZApplied to files:
📚 Learning: 2025-12-17T01:01:03.609ZApplied to files:
📚 Learning: 2025-12-18T20:39:30.137ZApplied to files:
📚 Learning: 2025-12-09T04:35:43.971ZApplied to files:
📚 Learning: 2025-11-24T19:47:22.909ZApplied to files:
📚 Learning: 2025-12-17T01:01:03.609ZApplied to files:
📚 Learning: 2025-11-24T19:47:45.616ZApplied to files:
📚 Learning: 2025-12-17T01:01:03.609ZApplied to files:
📚 Learning: 2025-11-24T19:47:34.324ZApplied to files:
🧬 Code graph analysis (6)src/extensions/core/load3d/loader/FastPLYLoader.ts (1)
src/composables/useLoad3d.ts (1)
tests-ui/tests/scripts/metadata/ply.test.ts (1)
src/extensions/core/load3d/SceneModelManager.ts (2)
src/extensions/core/load3d/LoaderManager.ts (4)
src/composables/useLoad3dViewer.ts (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
🔇 Additional comments (49)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Actionable comments posted: 12
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (15)
package.json(1 hunks)pnpm-workspace.yaml(1 hunks)src/components/load3d/Load3D.vue(2 hunks)src/components/load3d/Load3DControls.vue(3 hunks)src/components/load3d/controls/ModelControls.vue(3 hunks)src/composables/useLoad3d.ts(3 hunks)src/extensions/core/load3d.ts(2 hunks)src/extensions/core/load3d/Load3d.ts(1 hunks)src/extensions/core/load3d/LoaderManager.ts(3 hunks)src/extensions/core/load3d/SceneModelManager.ts(5 hunks)src/extensions/core/load3d/interfaces.ts(2 hunks)src/extensions/core/load3d/loader/FastPLYLoader.ts(1 hunks)src/locales/en/main.json(1 hunks)src/schemas/apiSchema.ts(1 hunks)src/services/load3dService.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (15)
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
src/**/*.{vue,ts}: Avoid usingrefandwatchtogether - usecomputedinstead if possible
Do not addrefif a prop would suffice; do not addcomputedif the ref/prop directly would work; usewatchonly whencomputedwon't accomplish the goal
Leverage VueUse functions for performance-enhancing styles
Files:
src/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
src/**/*.ts: Extract complex type definitions that are inlined in multiple related places - name them for reuse
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones
Files:
src/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/services/load3dService.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
src/**/*.{ts,tsx,vue}: ESLint rules: Vue + TS rules, no floating promises, unused imports disallowed, i18n raw text restrictions in templates
Use es-toolkit for utility functions
Avoid mutable state - prefer immutability and assignment at point of declaration
Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
src/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{js,ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively - no new JavaScript files
Files:
src/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,tsx,vue,js}: Indent with 2 spaces, use single quotes, no trailing semicolons, line width 80 - see.prettierrc
Sort and group imports by plugin, runpnpm formatbefore committing
Files:
src/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use function expressions - use function declarations instead when possible
Files:
src/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/services/load3dService.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
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
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
src/**/*.vue: Vue 3 SFCs must use Composition API only - no Options API
Use<script setup lang="ts">for component logic
Use Tailwind 4 utility classes for styling - avoid<style>blocks
Usecn()utility from@/utils/tailwindUtilto merge Tailwind class names - never use:class="[]"syntax
Never use thedark:Tailwind variant - use semantic values fromstyle.csstheme instead (e.g.,bg-node-component-surface)
Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - preferuseModelto prop/emit pairs, do not usewithDefaults
Do not import Vue macros unnecessarily
Use vue-i18n in composition API for string literals - place translation entries insrc/locales/en/main.json
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Avoid new usage of PrimeVue components
Files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/components/load3d/controls/ModelControls.vuesrc/composables/useLoad3d.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/components/load3d/controls/ModelControls.vuesrc/composables/useLoad3d.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
src/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue componentsVue components must be named in PascalCase (e.g.,
MenuHamburger.vue)
Files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
src/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package
Files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
src/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings
Files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/composables/useLoad3d.tssrc/services/load3dService.ts
src/composables/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Composables must follow the naming pattern
useXyz.ts
Files:
src/composables/useLoad3d.ts
🧠 Learnings (15)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
src/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/services/load3dService.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/SceneModelManager.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/services/load3dService.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/SceneModelManager.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/services/load3dService.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/SceneModelManager.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - prefer `useModel` to prop/emit pairs, do not use `withDefaults`
Applied to files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.
Applied to files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Avoid new usage of PrimeVue components
Applied to files:
pnpm-workspace.yamlpackage.json
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue TabMenu component with Tabs without panels
Applied to files:
package.json
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.
Applied to files:
src/locales/en/main.json
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use vue 3.5 style of default prop declaration
Applied to files:
src/components/load3d/Load3DControls.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Define proper props and emits definitions in Vue components
Applied to files:
src/components/load3d/Load3DControls.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Destructure props using Vue 3.5 style in Vue components
Applied to files:
src/components/load3d/Load3D.vue
🧬 Code graph analysis (2)
src/composables/useLoad3d.ts (1)
src/extensions/core/load3d/Load3d.ts (1)
isSplatModel(574-576)
src/extensions/core/load3d/SceneModelManager.ts (3)
src/lib/litegraph/src/subgraph/ExecutableNodeDTO.ts (1)
mode(80-82)src/extensions/core/load3d/interfaces.ts (1)
MaterialMode(10-15)src/extensions/core/load3d/Load3d.ts (1)
isSplatModel(574-576)
🪛 Biome (2.1.2)
src/extensions/core/load3d/LoaderManager.ts
[error] 206-206: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 207-207: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 209-209: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🔇 Additional comments (23)
package.json (1)
149-149: LGTM - Correctly references the catalog entry.The dependency correctly uses the
catalog:reference pattern to pull from the pnpm-workspace.yaml catalog definition. The alphabetical ordering is maintained, and placement in runtime dependencies (rather than devDependencies) is appropriate for this 3D rendering library.Note: Package verification for version validity and security was already requested in the pnpm-workspace.yaml review.
pnpm-workspace.yaml (1)
30-30: Verify package availability and source before adding to catalog.The
@sparkjsdev/sparkpackage references a legitimate GitHub repository for a 3D Gaussian Splatting renderer, with version 0.1.10 documented in the official repository. However, the package does not appear to be publicly available on the npm registry, making it unclear whether it can be installed as a dependency. Before adding this to the catalog, confirm:
- The package is properly published to a registry (npm or otherwise)
- Whether it should reference the direct GitHub URL instead of npm
- Version 0.1.10 is the intended release (version 0.1.9 is also referenced in the repository)
src/extensions/core/load3d.ts (2)
252-255: LGTM! File format expansion aligns with PLY/splat support.The expanded file input correctly adds
.ply,.spz,.splat, and.ksplatformats, which aligns with the PR's objective to support 3D Gaussian Splatting and PLY files. The format string is properly structured.
201-212: Setting is properly integrated and consumed by LoaderManager.tsThe PLYEngine setting correctly controls the PLY file loader selection. It's defined in the schema with the correct enum values, initialized with 'threejs' as default, and used in LoaderManager.ts:222 to branch between sparkjs for Gaussian Splatting and Three.js/FastPLYLoader for mesh/point cloud files.
src/schemas/apiSchema.ts (1)
511-511: LGTM! PLYEngine setting follows the established pattern.The new setting integrates cleanly with the existing Load3D configuration schema and uses appropriate Zod v3 syntax.
src/extensions/core/load3d/Load3d.ts (1)
574-576: LGTM! Clean delegation to model manager.The method follows the established pattern of delegating to specialized managers and provides a clear public API for splat model detection.
src/components/load3d/Load3DControls.vue (3)
89-91: LGTM! Proper Vue 3.5 style prop declaration.The prop declaration follows Vue 3.5 TypeScript style with reactive destructuring and default value.
108-113: LGTM! Appropriate UI adjustment for splat models.Excluding the 'light' category for splat models makes sense, as 3D Gaussian Splatting point clouds typically don't use traditional lighting models. The conditional logic is clean and maintainable.
50-50: LGTM! Clean prop binding to child component.The binding appropriately propagates splat model state to
ModelControlsfor conditional material mode visibility.src/extensions/core/load3d/interfaces.ts (2)
194-198: LGTM! Extension set properly expanded for PLY and splat formats.The additions align with the PR's objective to support 3D Gaussian Splatting and PLY files from various sources.
10-15: i18n translation for 'original(Advanced)' is properly defined. The keyload3d.materialModes.original(Advanced)with the value "Original (Point Cloud)" already exists in src/locales/en/main.json and is correctly nested alongside other material mode translations. No action required.src/composables/useLoad3d.ts (3)
66-66: LGTM! Reactive state follows Vue patterns.The initialization appropriately defaults to
falsefor non-splat models.
494-494: LGTM! Proper state synchronization on model load.The
isSplatModelstate is correctly updated when model loading completes, with defensive null-coalescing to handle edge cases.
566-566: LGTM! State properly exposed in public API.The
isSplatModelstate is now available to consuming components, completing the propagation chain.src/components/load3d/controls/ModelControls.vue (3)
31-60: LGTM! Clean conditional rendering for material mode UI.The
v-ifdirective appropriately hides the material mode section for splat models while preserving the up-direction controls.
74-76: LGTM! Proper Vue 3.5 style prop declaration.The prop declaration follows Vue 3.5 TypeScript style with reactive destructuring and default value.
94-104: LGTM! Material modes list expanded to include advanced option.The new
'original(Advanced)'mode is properly integrated into the options list. The computed property pattern is appropriate here for potential future dynamic filtering.src/components/load3d/Load3D.vue (2)
25-25: LGTM! Proper prop binding to child component.The
isSplatModelstate is correctly propagated from the composable toLoad3DControls, enabling splat-model-specific UI behavior.
113-113: LGTM! Composable state properly destructured.The
isSplatModelstate is correctly extracted from theuseLoad3dcomposable alongside other state properties.src/extensions/core/load3d/SceneModelManager.ts (4)
102-105: Guard clause logic is correct but could be clarified.The method returns early if
originalModelis not aBufferGeometry, which is the expected behavior for handling PLY files specifically. The implementation is correct.
334-351: Alias handling fororiginal(Advanced)mode is appropriate.Adding the
original(Advanced)case to fall through tooriginalbehavior ensures backward compatibility when restoring materials on non-PLY meshes. This is the correct approach.
422-422: ConsistentMainModelnaming improves lifecycle management.Tagging models with
name = 'MainModel'in bothaddModelToSceneandsetupModelenables reliable cleanup inhandlePLYModeSwitch. Good pattern for managing scene objects.Also applies to: 429-429
427-440: SplatMesh early return skips initial material and direction setup—verify if runtime changes are needed.When
isSplatModelis true,setupModelreturns early (line 439), skippingsetupModelMaterialsandsetUpDirectioninitialization. This is intentional since SplatMesh handles its own rendering. However, UI controls allow users to change material mode and up-direction after loading. WhilesetMaterialModesafely skips SplatMesh (traverses only Mesh children),setUpDirectionapplies rotations directly to currentModel. Consider whether splat models should support these runtime changes or if UI controls should be disabled for splat models to prevent unintended visual behavior.
| parse(arrayBuffer: ArrayBuffer): THREE.BufferGeometry { | ||
| const text = new TextDecoder().decode(arrayBuffer) | ||
| const lines = text.split('\n') |
There was a problem hiding this comment.
Missing error handling for malformed PLY files.
The parser assumes valid PLY format but doesn't validate the magic number (ply) at the start or handle cases where required properties (x, y, z) are missing. This could lead to silent failures or NaN values in the geometry.
🔎 Suggested improvement:
parse(arrayBuffer: ArrayBuffer): THREE.BufferGeometry {
const text = new TextDecoder().decode(arrayBuffer)
const lines = text.split('\n')
+
+ // Validate PLY magic number
+ if (!lines[0]?.trim().toLowerCase().startsWith('ply')) {
+ throw new Error('Invalid PLY file: missing PLY header')
+ }
// Parse header
let vertexCount = 0Also validate required properties after header parsing:
} else if (line === 'end_header') {
headerEndLine = i
break
}
}
+
+ if (xIndex < 0 || yIndex < 0 || zIndex < 0) {
+ throw new Error('Invalid PLY file: missing required position properties (x, y, z)')
+ }
+
+ if (vertexCount === 0) {
+ throw new Error('Invalid PLY file: no vertices defined')
+ }Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/extensions/core/load3d/loader/FastPLYLoader.ts around lines 9 to 11, the
parser decodes the buffer and splits lines but does not validate the PLY magic
header or ensure required vertex properties (x,y,z) exist; add explicit
validation after decoding: check the first non-empty token equals "ply" (throw
or return a clear error if not), parse the header to confirm vertex element and
that properties include x, y, z, and if any required property is missing throw a
descriptive error; also guard against malformed numeric data by validating
parsed floats (reject or skip vertices with NaN) and ensure the function returns
a predictable failure path instead of producing NaN coordinates.
| // Pre-allocate arrays | ||
| const positions = new Float32Array(vertexCount * 3) | ||
| const colors = hasColor ? new Float32Array(vertexCount * 3) : null |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Pre-allocated buffer may be larger than needed if vertices are skipped.
The buffer is pre-allocated based on vertexCount, but blank lines and lines with insufficient parts are skipped (lines 63, 66). This could leave trailing zeros in the buffer. Consider trimming the geometry or tracking actual vertex count.
🔎 Suggested approach:
After the parsing loop, trim the buffers if vertexIndex < vertexCount:
// Create geometry
const geometry = new THREE.BufferGeometry()
- geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
+ const actualPositions = vertexIndex < vertexCount
+ ? positions.slice(0, vertexIndex * 3)
+ : positions
+ geometry.setAttribute('position', new THREE.BufferAttribute(actualPositions, 3))
if (hasColor && colors) {
- geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3))
+ const actualColors = vertexIndex < vertexCount
+ ? colors.slice(0, vertexIndex * 3)
+ : colors
+ geometry.setAttribute('color', new THREE.BufferAttribute(actualColors, 3))
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/extensions/core/load3d/loader/FastPLYLoader.ts around lines 50 to 52, the
positions/colors Float32Array buffers are pre-allocated to vertexCount but some
input lines are skipped, leaving trailing zeros; after the parsing loop detect
if the actual vertexIndex is less than vertexCount and replace/truncate the
buffers to their used length (e.g., create subarrays or new typed arrays of
vertexIndex*3 length for positions and colors when hasColor), then use those
trimmed arrays when creating/setting the geometry attributes and update any
counts/drawRange accordingly so the resulting geometry contains only the parsed
vertices.
| positions[posIndex] = parseFloat(parts[xIndex]) | ||
| positions[posIndex + 1] = parseFloat(parts[yIndex]) | ||
| positions[posIndex + 2] = parseFloat(parts[zIndex]) |
There was a problem hiding this comment.
parseFloat returns NaN silently on invalid input.
If a line contains non-numeric data or the property indices are wrong, parseFloat will return NaN, causing corrupted geometry without any indication. Consider adding validation or at least a check for NaN.
🔎 Consider adding NaN checks:
// Position
- positions[posIndex] = parseFloat(parts[xIndex])
- positions[posIndex + 1] = parseFloat(parts[yIndex])
- positions[posIndex + 2] = parseFloat(parts[zIndex])
+ const x = parseFloat(parts[xIndex])
+ const y = parseFloat(parts[yIndex])
+ const z = parseFloat(parts[zIndex])
+
+ if (Number.isNaN(x) || Number.isNaN(y) || Number.isNaN(z)) {
+ continue // Skip malformed vertices
+ }
+
+ positions[posIndex] = x
+ positions[posIndex + 1] = y
+ positions[posIndex + 2] = z📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| positions[posIndex] = parseFloat(parts[xIndex]) | |
| positions[posIndex + 1] = parseFloat(parts[yIndex]) | |
| positions[posIndex + 2] = parseFloat(parts[zIndex]) | |
| // Position | |
| const x = parseFloat(parts[xIndex]) | |
| const y = parseFloat(parts[yIndex]) | |
| const z = parseFloat(parts[zIndex]) | |
| if (Number.isNaN(x) || Number.isNaN(y) || Number.isNaN(z)) { | |
| continue // Skip malformed vertices | |
| } | |
| positions[posIndex] = x | |
| positions[posIndex + 1] = y | |
| positions[posIndex + 2] = z |
🤖 Prompt for AI Agents
In src/extensions/core/load3d/loader/FastPLYLoader.ts around lines 71-73, the
code uses parseFloat without validating results which can silently produce NaN
and corrupt geometry; update the loader to validate each parsed coordinate after
parseFloat (use Number.isFinite or !Number.isNaN) and handle invalid values
explicitly: either throw a descriptive error including the line number/index and
offending property indices so the load fails fast, or skip the malformed vertex
(adjusting the write index accordingly) and log a warning. Ensure you do not
write NaN into the positions buffer (only write after validation) and include
clear context in any thrown/logged message so debugging identifies the exact
line and property.
| case 'spz': | ||
| case 'splat': | ||
| case 'ksplat': | ||
| const splatUrl = path + encodeURIComponent(filename) | ||
| const splatMesh = new SplatMesh({ url: splatUrl }) | ||
| this.modelManager.setOriginalModel(splatMesh) | ||
| const splatGroup = new THREE.Group() | ||
| splatGroup.add(splatMesh) | ||
| model = splatGroup | ||
| break |
There was a problem hiding this comment.
Wrap switch case declarations in blocks to prevent scope leakage.
Biome correctly flags that splatUrl, splatMesh, and splatGroup declarations can leak to other switch clauses. Wrap them in a block scope.
🔎 Apply this fix:
case 'spz':
case 'splat':
- case 'ksplat':
- const splatUrl = path + encodeURIComponent(filename)
- const splatMesh = new SplatMesh({ url: splatUrl })
- this.modelManager.setOriginalModel(splatMesh)
- const splatGroup = new THREE.Group()
- splatGroup.add(splatMesh)
- model = splatGroup
+ case 'ksplat': {
+ const splatUrl = path + encodeURIComponent(filename)
+ const splatMesh = new SplatMesh({ url: splatUrl })
+ this.modelManager.setOriginalModel(splatMesh)
+ const splatGroup = new THREE.Group()
+ splatGroup.add(splatMesh)
+ model = splatGroup
break
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case 'spz': | |
| case 'splat': | |
| case 'ksplat': | |
| const splatUrl = path + encodeURIComponent(filename) | |
| const splatMesh = new SplatMesh({ url: splatUrl }) | |
| this.modelManager.setOriginalModel(splatMesh) | |
| const splatGroup = new THREE.Group() | |
| splatGroup.add(splatMesh) | |
| model = splatGroup | |
| break | |
| case 'spz': | |
| case 'splat': | |
| case 'ksplat': { | |
| const splatUrl = path + encodeURIComponent(filename) | |
| const splatMesh = new SplatMesh({ url: splatUrl }) | |
| this.modelManager.setOriginalModel(splatMesh) | |
| const splatGroup = new THREE.Group() | |
| splatGroup.add(splatMesh) | |
| model = splatGroup | |
| break | |
| } |
🧰 Tools
🪛 Biome (2.1.2)
[error] 206-206: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 207-207: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 209-209: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🤖 Prompt for AI Agents
In src/extensions/core/load3d/LoaderManager.ts around lines 203 to 212, the
local variables splatUrl, splatMesh, and splatGroup declared in the
'spz'/'splat'/'ksplat' switch case can leak into other cases; wrap the case body
in its own block: add { ... } after the case labels, move the const declarations
and all related statements inside that block, and keep the final model =
splatGroup and break inside the block so the declarations remain scoped to this
case.
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 12/20/2025, 02:38:27 PM UTC 🔗 Links🎉 Your Storybook is ready for review! |
🎭 Playwright Test Results⏰ Completed at: 12/20/2025, 02:46:59 PM UTC 📈 Summary
📊 Test Reports by Browser
🎉 Click on the links above to view detailed test results for each browser configuration. |
af6e004 to
92da937
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/extensions/core/load3d/SceneModelManager.ts (1)
286-288: Type assertion violates coding guidelines—fix the underlying type issue.The
originalMaterialsWeakMap is typed forTHREE.Meshbut here stores aTHREE.Pointsobject usingas unknown as THREE.Mesh. This type coercion hides a design issue.🔎 Consider these solutions:
Option 1: Widen the WeakMap key type to accept both Mesh and Points:
- originalMaterials: WeakMap<THREE.Mesh, THREE.Material | THREE.Material[]> = - new WeakMap() + originalMaterials: WeakMap<THREE.Mesh | THREE.Points, THREE.Material | THREE.Material[]> = + new WeakMap()Then remove the cast:
- this.modelManager.originalMaterials.set( - plyPoints as unknown as THREE.Mesh, - pointMaterial - ) + this.modelManager.originalMaterials.set(plyPoints, pointMaterial)Option 2: Use a union type alias for clarity:
+type RenderableObject = THREE.Mesh | THREE.Points - originalMaterials: WeakMap<THREE.Mesh, THREE.Material | THREE.Material[]> = - new WeakMap() + originalMaterials: WeakMap<RenderableObject, THREE.Material | THREE.Material[]> = + new WeakMap()This change would also require updating related traversal code that checks
child instanceof THREE.Meshto also handleTHREE.Points.As per coding guidelines: avoid
astype assertions and fix the underlying type issue.
♻️ Duplicate comments (13)
src/locales/en/main.json (1)
1638-1638: Consider consistent key naming convention.The key
"original(Advanced)"deviates from the naming pattern used by other material mode keys in this section (e.g.,normal,wireframe,original). Consider using a more conventional format like"originalAdvanced"or"pointCloud"for better consistency and to avoid special characters in locale keys.🔎 Suggested alternatives:
- "original(Advanced)": "Original (Point Cloud)", + "originalAdvanced": "Original (Point Cloud)",Or:
- "original(Advanced)": "Original (Point Cloud)", + "pointCloud": "Original (Point Cloud)",Note: This change would require updating all references to this key throughout the codebase.
src/services/load3dService.ts (1)
78-102: Add error handling for splat models without originalURL.The logic correctly differentiates between splat models (which must be reloaded via URL) and regular models (which can be cloned). However, when a splat model lacks an
originalURL, the method silently skips model loading, which could lead to confusing behavior or silent failures.🔎 Consider adding explicit error handling:
if (source.isSplatModel()) { const originalURL = source.modelManager.originalURL if (originalURL) { await target.loadModel(originalURL) + } else { + console.warn('Cannot copy splat model: originalURL is missing') + // Optionally throw or handle gracefully } } else {Additional consideration: Verify whether
appliedTexturehandling (lines 98-101) should also apply to splat models, or if this is intentionally excluded due to technical limitations.src/extensions/core/load3d/loader/FastPLYLoader.ts (3)
9-11: Missing error handling for malformed PLY files.The parser doesn't validate the PLY magic header or required properties. This was flagged in a previous review.
50-52: Pre-allocated buffer may be larger than needed if vertices are skipped.This was flagged in a previous review - buffers should be trimmed to actual vertex count after parsing.
71-73:parseFloatreturnsNaNsilently on invalid input.This was flagged in a previous review - add NaN validation to prevent corrupted geometry.
src/extensions/core/load3d/SceneModelManager.ts (3)
111-131: Redundant scene traversal for MainModel removal.This traversal to find and remove
MainModelinstances is followed by another identical check at lines 206-212. This was previously flagged as inefficient.
206-212: Redundant double-check removal.This second traversal duplicates the removal logic from lines 111-131. If the first removal is working correctly, this shouldn't be necessary.
471-480:containsSplatMeshdoesn't short-circuit traversal.This method continues traversing the entire scene graph even after finding a SplatMesh. This was previously identified and a recursive solution was suggested.
src/extensions/core/load3d/LoaderManager.ts (5)
203-212: Wrap switch case declarations in blocks.Biome correctly flags that
splatUrl,splatMesh, andsplatGroupcan leak to other switch clauses. This was previously identified with a fix provided.
222-222: Use proper TypeScript type instead ofas stringcast.The setting value is cast to
string, which can hide type issues if the setting is undefined or another type. This was previously flagged with a suggestion to use nullish coalescing.
224-231: Duplicate SplatMesh creation logic.This SplatMesh creation duplicates lines 206-211. A helper method was previously suggested to eliminate this duplication.
234-236: Missingresponse.okcheck before reading response body.If the fetch fails with a 4xx/5xx status,
response.arrayBuffer()will still execute, potentially parsing an error page as binary data. This was previously identified with a fix provided.
273-293: Material creation logic duplicated with SceneModelManager.This Points/Mesh creation logic is duplicated in
SceneModelManager.handlePLYModeSwitch. This was previously noted as potentially acceptable given the different contexts (initial load vs. mode switching).Also applies to: 296-316
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
package.json(1 hunks)pnpm-workspace.yaml(1 hunks)src/components/load3d/Load3D.vue(2 hunks)src/components/load3d/Load3DControls.vue(3 hunks)src/components/load3d/controls/ModelControls.vue(3 hunks)src/composables/useLoad3d.ts(3 hunks)src/extensions/core/load3d.ts(2 hunks)src/extensions/core/load3d/Load3d.ts(1 hunks)src/extensions/core/load3d/LoaderManager.ts(3 hunks)src/extensions/core/load3d/SceneModelManager.ts(5 hunks)src/extensions/core/load3d/interfaces.ts(2 hunks)src/extensions/core/load3d/loader/FastPLYLoader.ts(1 hunks)src/locales/en/main.json(1 hunks)src/schemas/apiSchema.ts(1 hunks)src/services/load3dService.ts(1 hunks)tests-ui/tests/composables/useLoad3d.test.ts(1 hunks)vitest.setup.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (17)
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
src/**/*.{vue,ts}: Avoid usingrefandwatchtogether - usecomputedinstead if possible
Do not addrefif a prop would suffice; do not addcomputedif the ref/prop directly would work; usewatchonly whencomputedwon't accomplish the goal
Leverage VueUse functions for performance-enhancing styles
Files:
src/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.tssrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
src/**/*.ts: Extract complex type definitions that are inlined in multiple related places - name them for reuse
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones
Files:
src/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/services/load3dService.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/SceneModelManager.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
src/**/*.{ts,tsx,vue}: ESLint rules: Vue + TS rules, no floating promises, unused imports disallowed, i18n raw text restrictions in templates
Use es-toolkit for utility functions
Avoid mutable state - prefer immutability and assignment at point of declaration
Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
src/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.tssrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.tssrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/*.{js,ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively - no new JavaScript files
Files:
src/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.tssrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,tsx,vue,js}: Indent with 2 spaces, use single quotes, no trailing semicolons, line width 80 - see.prettierrc
Sort and group imports by plugin, runpnpm formatbefore committing
Files:
src/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.tssrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use function expressions - use function declarations instead when possible
Files:
src/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d.tssrc/schemas/apiSchema.tssrc/services/load3dService.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/SceneModelManager.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/services/load3dService.tssrc/composables/useLoad3d.ts
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
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
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
src/**/*.vue: Vue 3 SFCs must use Composition API only - no Options API
Use<script setup lang="ts">for component logic
Use Tailwind 4 utility classes for styling - avoid<style>blocks
Usecn()utility from@/utils/tailwindUtilto merge Tailwind class names - never use:class="[]"syntax
Never use thedark:Tailwind variant - use semantic values fromstyle.csstheme instead (e.g.,bg-node-component-surface)
Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - preferuseModelto prop/emit pairs, do not usewithDefaults
Do not import Vue macros unnecessarily
Use vue-i18n in composition API for string literals - place translation entries insrc/locales/en/main.json
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Avoid new usage of PrimeVue components
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vue
src/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue componentsVue components must be named in PascalCase (e.g.,
MenuHamburger.vue)
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
src/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
src/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
src/composables/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Composables must follow the naming pattern
useXyz.ts
Files:
src/composables/useLoad3d.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)
tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks
Files:
tests-ui/tests/composables/useLoad3d.test.ts
tests-ui/**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
tests-ui/**/*.test.ts: Write tests for all changes, especially bug fixes to catch future regressions
Unit/Component test files must use pattern**/*.test.ts
Do not write change detector tests - do not just assert that defaults are certain values
Do not write tests dependent on non-behavioral features like utility classes or styles
Be parsimonious in testing - do not write redundant tests
Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
For mocking, leverage Vitest's utilities where possible
Keep module mocks contained - do not use global mutable state within test files, usevi.hoisted()if necessary
For Component testing, use Vue Test Utils and follow advice about making components easy to test
Aim for behavioral coverage of critical and new features
Files:
tests-ui/tests/composables/useLoad3d.test.ts
🧠 Learnings (35)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
src/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d.tssrc/schemas/apiSchema.tsvitest.setup.tssrc/services/load3dService.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/SceneModelManager.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d.tssrc/schemas/apiSchema.tsvitest.setup.tssrc/services/load3dService.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/SceneModelManager.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d.tssrc/schemas/apiSchema.tsvitest.setup.tssrc/services/load3dService.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/SceneModelManager.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d.tssrc/schemas/apiSchema.tsvitest.setup.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.tssrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.
Applied to files:
src/locales/en/main.json
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : For mocking, leverage Vitest's utilities where possible
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Keep module mocks contained - do not use global mutable state within test files, use `vi.hoisted()` if necessary
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`
Applied to files:
vitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest
Applied to files:
vitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : For Component testing, use Vue Test Utils and follow advice about making components easy to test
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - prefer `useModel` to prop/emit pairs, do not use `withDefaults`
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use vue 3.5 style of default prop declaration
Applied to files:
src/components/load3d/Load3DControls.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Define proper props and emits definitions in Vue components
Applied to files:
src/components/load3d/Load3DControls.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Take advantage of `TypedArray` `subarray` when appropriate
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Destructure props using Vue 3.5 style in Vue components
Applied to files:
src/components/load3d/Load3D.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Applied to files:
src/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `as any` type assertions - fix the underlying type issue
Applied to files:
src/extensions/core/load3d/LoaderManager.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Avoid new usage of PrimeVue components
Applied to files:
pnpm-workspace.yamlpackage.json
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Be parsimonious in testing - do not write redundant tests
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Do not write change detector tests - do not just assert that defaults are certain values
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue TabMenu component with Tabs without panels
Applied to files:
package.json
🧬 Code graph analysis (3)
src/extensions/core/load3d/SceneModelManager.ts (3)
src/lib/litegraph/src/subgraph/ExecutableNodeDTO.ts (1)
mode(80-82)src/extensions/core/load3d/interfaces.ts (1)
MaterialMode(10-15)src/extensions/core/load3d/Load3d.ts (1)
isSplatModel(574-576)
src/composables/useLoad3d.ts (1)
src/extensions/core/load3d/Load3d.ts (1)
isSplatModel(574-576)
src/extensions/core/load3d/LoaderManager.ts (1)
src/extensions/core/load3d/loader/FastPLYLoader.ts (1)
FastPLYLoader(8-102)
🪛 Biome (2.1.2)
src/extensions/core/load3d/LoaderManager.ts
[error] 206-206: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 207-207: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 209-209: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: collect
- GitHub Check: comment-on-pr-start
🔇 Additional comments (26)
pnpm-workspace.yaml (1)
30-30: LGTM: SparkJS catalog entry added correctly.The workspace catalog entry for
@sparkjsdev/sparkfollows the established pattern and uses an appropriate version constraint.package.json (1)
149-149: LGTM: Runtime dependency correctly added.The SparkJS dependency is properly added using the workspace catalog reference, consistent with other dependencies in the project.
vitest.setup.ts (1)
4-9: LGTM: Appropriate test mock for WASM-dependent library.The mock correctly bypasses SparkJS's WASM dependencies for the Node.js test environment. The comment clearly explains the reasoning.
As per coding guidelines, leveraging Vitest utilities for mocking.
tests-ui/tests/composables/useLoad3d.test.ts (1)
108-108: LGTM: Mock method added consistently.The
isSplatModelmock follows the existing pattern and provides a reasonable default return value for non-splat model test scenarios.Consider adding test cases that cover splat model behavior (
isSplatModelreturningtrue) to ensure the new code paths are tested.As per coding guidelines, write tests for new features and aim for behavioral coverage of critical features.
src/extensions/core/load3d.ts (2)
252-255: LGTM: File extensions updated for PLY and splat formats.The updated file input filter appropriately includes the new supported formats (.ply, .spz, .splat, .ksplat) for 3D Gaussian Splatting and PLY files.
202-212: PLYEngine setting is properly consumed by loader logic.The
Comfy.Load3D.PLYEnginesetting is actively used inLoaderManager.ts:222to select the appropriate loader: Spark.js for Gaussian Splatting files, FastPLYLoader for ASCII point clouds, and Three.js PLYLoader as default.src/schemas/apiSchema.ts (1)
511-511: LGTM: Schema correctly updated for PLYEngine setting.The
Comfy.Load3D.PLYEnginesetting is properly added to the schema with an enum matching the extension definition. The values align with the three supported PLY loading engines.As per learnings, this follows Zod v3 patterns correctly.
src/extensions/core/load3d/Load3d.ts (1)
574-576: LGTM!Clean delegation to the model manager. The method is well-placed and provides a clear public API for checking if the current model is a splat mesh.
src/components/load3d/Load3DControls.vue (2)
89-91: LGTM!Prop declaration follows Vue 3.5+ style with reactive destructuring as per coding guidelines.
108-114: LGTM!Excluding the light category for splat models is appropriate since 3D Gaussian Splatting models have pre-baked radiance and don't respond to dynamic lighting.
src/composables/useLoad3d.ts (1)
66-66: LGTM!Proper initialization of the reactive state.
src/extensions/core/load3d/interfaces.ts (2)
10-15: LGTM!The MaterialMode type correctly extends to include the new point cloud rendering option.
189-199: LGTM!SUPPORTED_EXTENSIONS correctly expanded to include all PLY and splat-related file formats.
src/components/load3d/controls/ModelControls.vue (2)
74-76: LGTM!Prop declaration follows Vue 3.5+ style with reactive destructuring as per coding guidelines.
126-128: Remove this comment — no i18n issue exists.The key
load3d.materialModes.original(Advanced)is correctly defined insrc/locales/en/main.jsonas"original(Advanced)": "Original (Point Cloud)". Parentheses are not special characters in vue-i18n keys and pose no runtime issues. The implementation is functioning correctly.Likely an incorrect or invalid review comment.
src/components/load3d/Load3D.vue (2)
25-25: LGTM!Prop binding correctly wires
isSplatModelstate to Load3DControls using kebab-case in template.
113-113: LGTM!Correctly destructures
isSplatModelfrom the composable's return value.src/extensions/core/load3d/SceneModelManager.ts (5)
1-1: LGTM: SplatMesh import.The import is properly structured and necessary for the 3D Gaussian Splatting support.
248-252: LGTM: PLY special handling.The early return pattern cleanly separates PLY-specific mode switching from the general material mode logic.
335-335: LGTM: Added 'original(Advanced)' case.Correctly handles the new MaterialMode variant per the interface definition in interfaces.ts.
422-422: LGTM: Consistent model naming.Setting
name = 'MainModel'establishes a clear identifier for scene lifecycle management.
431-440: SplatMesh early return is appropriate.The early return pattern correctly bypasses standard mesh setup for SplatMesh models, which handle their own rendering. The default camera distance setup is reasonable.
Verify that the hardcoded
Vector3(5, 5, 5)provides appropriate framing for typical splat models. If splat models vary significantly in scale, consider computing a size hint from the SplatMesh bounds if available.src/extensions/core/load3d/LoaderManager.ts (4)
1-1: LGTM: New imports for PLY and splat support.All imports are properly structured and necessary for the new functionality.
Also applies to: 7-7, 11-11, 19-19
27-28: LGTM: Loader initialization.The PLY loaders follow the established pattern for other loaders in this class.
Also applies to: 45-46
199-201: LGTM: PLY case delegation.Cleanly delegates PLY loading to the dedicated method.
238-253: PLY format detection and parsing logic looks sound.The ASCII format detection and conditional loader selection is appropriate. The
plyLoader.setPath(path)at line 248 may be unnecessary sinceparse(arrayBuffer)is called directly with the buffer rather than loading a file, but this is harmless.
Bundle Size ReportSummary
Category Glance Per-category breakdownApp Entry Points — 3.22 MB (baseline 3.21 MB) • 🔴 +14.5 kBMain entry bundles and manifests
Status: 3 added / 3 removed Graph Workspace — 993 kB (baseline 993 kB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 6.54 kB (baseline 6.54 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 1 added / 1 removed Panels & Settings — 297 kB (baseline 297 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 6 added / 6 removed UI Components — 186 kB (baseline 185 kB) • 🔴 +843 BReusable component library chunks
Status: 8 added / 8 removed Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 BStores, services, APIs, and repositories
Status: 2 added / 2 removed Utilities & Hooks — 1.41 kB (baseline 1.41 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 1 added / 1 removed Vendor & Third-Party — 9.1 MB (baseline 8.46 MB) • 🔴 +644 kBExternal libraries and shared vendor chunks
Status: 1 added / 1 removed Other — 3.44 MB (baseline 3.44 MB) • ⚪ 0 BBundles that do not match a named category
Status: 20 added / 20 removed |
92da937 to
8b8b713
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (10)
src/locales/en/main.json (1)
1638-1638: Address the inconsistent key naming flagged in previous review.The key
"original(Advanced)"was previously flagged as inconsistent with other material mode keys in this section. The naming pattern deviates from the camelCase/lowercase convention used by other keys (normal,wireframe,original).As previously suggested, consider renaming to:
"pointCloud"or"originalAdvanced"Then update all references in the codebase to use the new key name.
src/services/load3dService.ts (1)
78-102: Splat-model copying silently fails without originalURL.The splat-model branch correctly differentiates splat models from cloneable models. However, when
originalURLis missing, the method silently skips model copying entirely, leaving the target in an inconsistent state.This is a duplicate of a previous review concern. Consider adding explicit error handling or a fallback when
originalURLis falsy for splat models.src/composables/useLoad3d.ts (1)
66-66:isSplatModelstate not reset on new model load attempt.If a splat model is successfully loaded (setting
isSplatModelto true) and the next load fails,isSplatModelretains the stale value. The state is set inmodelLoadingEnd(line 494) but never cleared inmodelLoadingStart.This is a duplicate of a previous review concern. Consider resetting
isSplatModel.value = falseinmodelLoadingStartto ensure UI consistency during new load attempts.src/extensions/core/load3d/loader/FastPLYLoader.ts (4)
9-48: Missing validation for PLY file format.The parser decodes and parses the header without validating:
- The PLY magic number at the start of the file
- Required vertex properties (x, y, z) are present
- Vertex count is non-zero
These omissions can lead to silent failures or corrupted geometry when loading malformed PLY files.
This duplicates a previous review concern. Consider adding validation after line 11 to check the first line starts with "ply", and after header parsing to ensure x/y/z indices are valid and vertexCount > 0.
71-73:parseFloatcan silently produce NaN coordinates.If the PLY file contains non-numeric data or the property indices are incorrect,
parseFloatreturnsNaNwithout any indication, leading to corrupted geometry.This duplicates a previous review concern. Consider validating parsed coordinates with
Number.isFinite()and either throwing a descriptive error or skipping malformed vertices.
84-86: Missing radix inparseIntcalls.
parseIntwithout an explicit radix can produce unexpected results with certain string formats. Always specify radix 10 for decimal parsing.This duplicates a previous review concern. Change to
parseInt(parts[...], 10)for all three color channel parsings.
50-98: Pre-allocated buffer may contain trailing zeros.The
positionsandcolorsbuffers are pre-allocated based onvertexCount, but lines 63 and 66 skip blank lines and lines with insufficient parts. This leaves trailing zeros when fewer vertices are actually parsed.This duplicates a previous review concern. Consider trimming the buffers after parsing by creating subarrays when
vertexIndex < vertexCountbefore creating the buffer attributes.src/extensions/core/load3d/SceneModelManager.ts (3)
111-131: Redundant scene traversal for MainModel removal.The scene is traversed to find and remove MainModel instances, then traversed again at lines 206-212 with a "Double check" comment. This redundancy suggests uncertainty about the cleanup logic and impacts performance.
This duplicates a previous review concern. If the first removal is working correctly, the second should be unnecessary. Consider removing the redundant check or documenting why it's needed.
107-107: Geometry cloning without error handling.The direct call to
this.originalModel.clone()could throw if the PLY geometry is corrupted or malformed, potentially crashing the rendering process.This duplicates a previous review concern. Consider wrapping the clone operation in a try-catch block or validating the geometry has a
positionattribute before cloning.
471-480:containsSplatMeshtraverses entire scene graph unnecessarily.The
traversemethod continues iterating through all children even after finding a SplatMesh, which is inefficient for large models.This duplicates a previous review concern. Consider using a manual stack-based traversal that returns early when a SplatMesh is found, or use a recursive helper that short-circuits.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
package.json(1 hunks)pnpm-workspace.yaml(2 hunks)src/components/load3d/Load3D.vue(2 hunks)src/components/load3d/Load3DControls.vue(3 hunks)src/components/load3d/controls/ModelControls.vue(3 hunks)src/composables/useLoad3d.ts(3 hunks)src/extensions/core/load3d.ts(2 hunks)src/extensions/core/load3d/Load3d.ts(1 hunks)src/extensions/core/load3d/LoaderManager.ts(3 hunks)src/extensions/core/load3d/SceneModelManager.ts(5 hunks)src/extensions/core/load3d/interfaces.ts(2 hunks)src/extensions/core/load3d/loader/FastPLYLoader.ts(1 hunks)src/locales/en/main.json(1 hunks)src/schemas/apiSchema.ts(1 hunks)src/services/load3dService.ts(1 hunks)tests-ui/tests/composables/useLoad3d.test.ts(1 hunks)vitest.setup.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (17)
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
src/**/*.{vue,ts}: Avoid usingrefandwatchtogether - usecomputedinstead if possible
Do not addrefif a prop would suffice; do not addcomputedif the ref/prop directly would work; usewatchonly whencomputedwon't accomplish the goal
Leverage VueUse functions for performance-enhancing styles
Files:
src/extensions/core/load3d/loader/FastPLYLoader.tssrc/services/load3dService.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d.tssrc/composables/useLoad3d.tssrc/schemas/apiSchema.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
src/**/*.ts: Extract complex type definitions that are inlined in multiple related places - name them for reuse
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones
Files:
src/extensions/core/load3d/loader/FastPLYLoader.tssrc/services/load3dService.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d.tssrc/composables/useLoad3d.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
src/**/*.{ts,tsx,vue}: ESLint rules: Vue + TS rules, no floating promises, unused imports disallowed, i18n raw text restrictions in templates
Use es-toolkit for utility functions
Avoid mutable state - prefer immutability and assignment at point of declaration
Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
src/extensions/core/load3d/loader/FastPLYLoader.tssrc/services/load3dService.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d.tssrc/composables/useLoad3d.tssrc/schemas/apiSchema.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/extensions/core/load3d/loader/FastPLYLoader.tssrc/services/load3dService.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d.tssrc/composables/useLoad3d.tssrc/schemas/apiSchema.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{js,ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively - no new JavaScript files
Files:
src/extensions/core/load3d/loader/FastPLYLoader.tssrc/services/load3dService.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d.tssrc/composables/useLoad3d.tssrc/schemas/apiSchema.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,tsx,vue,js}: Indent with 2 spaces, use single quotes, no trailing semicolons, line width 80 - see.prettierrc
Sort and group imports by plugin, runpnpm formatbefore committing
Files:
src/extensions/core/load3d/loader/FastPLYLoader.tssrc/services/load3dService.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d.tssrc/composables/useLoad3d.tssrc/schemas/apiSchema.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use function expressions - use function declarations instead when possible
Files:
src/extensions/core/load3d/loader/FastPLYLoader.tssrc/services/load3dService.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d.tssrc/composables/useLoad3d.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/SceneModelManager.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/services/load3dService.tssrc/composables/useLoad3d.ts
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
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
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
src/**/*.vue: Vue 3 SFCs must use Composition API only - no Options API
Use<script setup lang="ts">for component logic
Use Tailwind 4 utility classes for styling - avoid<style>blocks
Usecn()utility from@/utils/tailwindUtilto merge Tailwind class names - never use:class="[]"syntax
Never use thedark:Tailwind variant - use semantic values fromstyle.csstheme instead (e.g.,bg-node-component-surface)
Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - preferuseModelto prop/emit pairs, do not usewithDefaults
Do not import Vue macros unnecessarily
Use vue-i18n in composition API for string literals - place translation entries insrc/locales/en/main.json
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Avoid new usage of PrimeVue components
Files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/components/load3d/controls/ModelControls.vuesrc/composables/useLoad3d.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/components/load3d/controls/ModelControls.vuesrc/composables/useLoad3d.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
src/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue componentsVue components must be named in PascalCase (e.g.,
MenuHamburger.vue)
Files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
src/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package
Files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
src/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings
Files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
tests-ui/**/*.test.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)
tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks
Files:
tests-ui/tests/composables/useLoad3d.test.ts
tests-ui/**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
tests-ui/**/*.test.ts: Write tests for all changes, especially bug fixes to catch future regressions
Unit/Component test files must use pattern**/*.test.ts
Do not write change detector tests - do not just assert that defaults are certain values
Do not write tests dependent on non-behavioral features like utility classes or styles
Be parsimonious in testing - do not write redundant tests
Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
For mocking, leverage Vitest's utilities where possible
Keep module mocks contained - do not use global mutable state within test files, usevi.hoisted()if necessary
For Component testing, use Vue Test Utils and follow advice about making components easy to test
Aim for behavioral coverage of critical and new features
Files:
tests-ui/tests/composables/useLoad3d.test.ts
src/composables/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Composables must follow the naming pattern
useXyz.ts
Files:
src/composables/useLoad3d.ts
🧠 Learnings (37)
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.
Applied to files:
src/locales/en/main.json
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Avoid new usage of PrimeVue components
Applied to files:
package.jsonpnpm-workspace.yaml
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue TabMenu component with Tabs without panels
Applied to files:
package.json
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Take advantage of `TypedArray` `subarray` when appropriate
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.tssrc/services/load3dService.tssrc/extensions/core/load3d/interfaces.tstests-ui/tests/composables/useLoad3d.test.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d.tssrc/composables/useLoad3d.tssrc/schemas/apiSchema.tsvitest.setup.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/SceneModelManager.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.tssrc/services/load3dService.tssrc/extensions/core/load3d/interfaces.tstests-ui/tests/composables/useLoad3d.test.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d.tssrc/composables/useLoad3d.tssrc/schemas/apiSchema.tsvitest.setup.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/SceneModelManager.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.tssrc/services/load3dService.tssrc/extensions/core/load3d/interfaces.tstests-ui/tests/composables/useLoad3d.test.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d.tssrc/composables/useLoad3d.tssrc/schemas/apiSchema.tsvitest.setup.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/SceneModelManager.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.tssrc/services/load3dService.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/controls/ModelControls.vuetests-ui/tests/composables/useLoad3d.test.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d.tssrc/composables/useLoad3d.tssrc/schemas/apiSchema.tssrc/components/load3d/Load3DControls.vuevitest.setup.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/SceneModelManager.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - prefer `useModel` to prop/emit pairs, do not use `withDefaults`
Applied to files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.
Applied to files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.
Applied to files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests
Applied to files:
tests-ui/tests/composables/useLoad3d.test.tsvitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : For mocking, leverage Vitest's utilities where possible
Applied to files:
tests-ui/tests/composables/useLoad3d.test.tsvitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Keep module mocks contained - do not use global mutable state within test files, use `vi.hoisted()` if necessary
Applied to files:
tests-ui/tests/composables/useLoad3d.test.tsvitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
Applied to files:
tests-ui/tests/composables/useLoad3d.test.tsvitest.setup.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features
Applied to files:
tests-ui/tests/composables/useLoad3d.test.tsvitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible
Applied to files:
tests-ui/tests/composables/useLoad3d.test.tsvitest.setup.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks
Applied to files:
tests-ui/tests/composables/useLoad3d.test.tsvitest.setup.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-05T08:52:50.787Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7137
File: src/components/rightSidePanel/parameters/SectionWidgets.vue:41-49
Timestamp: 2025-12-05T08:52:50.787Z
Learning: In Vue 3.4+ SFCs with a build step, kebab-case prop shorthand (e.g., `:is-empty`) automatically resolves to the corresponding camelCase variable in scope (e.g., `isEmpty`). This is valid syntax combining same-name shorthand with automatic kebab-case-to-camelCase conversion and should not be flagged as an error.
Applied to files:
src/components/load3d/Load3DControls.vue
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`
Applied to files:
vitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : For Component testing, use Vue Test Utils and follow advice about making components easy to test
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Destructure props using Vue 3.5 style in Vue components
Applied to files:
src/components/load3d/Load3D.vue
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `as any` type assertions - fix the underlying type issue
Applied to files:
src/extensions/core/load3d/LoaderManager.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.{ts,tsx,vue} : ESLint rules: Vue + TS rules, no floating promises, unused imports disallowed, i18n raw text restrictions in templates
Applied to files:
pnpm-workspace.yaml
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.{ts,tsx,vue,js} : Indent with 2 spaces, use single quotes, no trailing semicolons, line width 80 - see `.prettierrc`
Applied to files:
pnpm-workspace.yaml
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.{js,ts,tsx,vue} : Use TypeScript exclusively - no new JavaScript files
Applied to files:
pnpm-workspace.yaml
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Run ESLint instead of manually figuring out whitespace fixes or other trivial style concerns using the `pnpm lint:fix` command
Applied to files:
pnpm-workspace.yaml
🧬 Code graph analysis (3)
src/composables/useLoad3d.ts (1)
src/extensions/core/load3d/Load3d.ts (1)
isSplatModel(574-576)
src/extensions/core/load3d/LoaderManager.ts (3)
src/extensions/core/load3d/interfaces.ts (1)
LoaderManagerInterface(177-187)src/extensions/core/load3d/loader/FastPLYLoader.ts (1)
FastPLYLoader(8-102)src/platform/settings/settingStore.ts (1)
useSettingStore(46-252)
src/extensions/core/load3d/SceneModelManager.ts (2)
src/extensions/core/load3d/interfaces.ts (1)
MaterialMode(10-15)src/extensions/core/load3d/Load3d.ts (1)
isSplatModel(574-576)
🪛 Biome (2.1.2)
src/extensions/core/load3d/LoaderManager.ts
[error] 206-206: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 207-207: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 209-209: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: setup
- GitHub Check: lint-and-format
- GitHub Check: test
- GitHub Check: collect
🔇 Additional comments (33)
src/schemas/apiSchema.ts (1)
511-511: LGTM! Schema entry aligns with extension setting.The new
Comfy.Load3D.PLYEnginesetting is properly defined using Zod v3 enum, matching the options declared in the extension (threejs,fastply,sparkjs). The schema integration is correct and follows the existing pattern.vitest.setup.ts (1)
4-9: LGTM! Properly mocks WASM-dependent library for tests.The mock for
@sparkjsdev/sparkcorrectly bypasses WASM dependencies that don't work in Node.js test environments. The minimal SplatMesh class implementation is appropriate for tests that verify logic without requiring full WASM functionality.The mock placement and structure follow Vitest best practices.
Based on learnings: Using Vitest's mock utilities as per guidelines.
src/extensions/core/load3d.ts (2)
202-212: LGTM! PLY Engine setting is well-documented and follows conventions.The new
Comfy.Load3D.PLYEnginesetting:
- Properly declares experimental status
- Provides clear tooltip explaining each engine option (threejs for mesh, fastply for ASCII point clouds, sparkjs for 3DGS)
- Follows the existing extension setting pattern
- Has a sensible default (
threejs)
252-254: LGTM! File extensions updated to support PLY and splat formats.The file input now accepts the new formats (
.ply,.spz,.splat,.ksplat) in addition to existing 3D formats. This aligns with the PR objectives to add PLY and 3DGS support.package.json (1)
149-149: LGTM! Dependency addition follows workspace catalog pattern.The
@sparkjsdev/sparkdependency correctly uses thecatalog:reference, which resolves to version^0.1.10defined inpnpm-workspace.yaml. This follows the repository's standard pattern for managing shared dependency versions.src/components/load3d/Load3DControls.vue (3)
89-91: LGTM! Prop definition follows Vue 3.5+ conventions.The new
isSplatModeloptional prop:
- Uses proper TypeScript typing with optional flag
- Has a sensible default value (
false)- Follows camelCase naming convention
- Uses Vue 3.5+ reactive destructuring style
As per coding guidelines: Vue 3.5+ TypeScript style default prop declaration with reactive destructuring.
108-114: LGTM! Conditional category logic is correct for splat models.The computed
availableCategoriesproperly:
- Removes the 'light' category when
isSplatModelis true (splat models use baked lighting and don't need traditional light controls)- Maintains all other categories (scene, model, camera, export)
- Follows a clean conditional pattern
This aligns well with the 3D Gaussian Splatting rendering approach where lighting is pre-baked into the splat representation.
50-50: LGTM! Prop binding correctly propagates splat model state.The
:hide-material-mode="isSplatModel"binding properly forwards the splat model detection toModelControls, enabling conditional UI behavior. This creates a clean data flow from the parent component down to the material mode controls.pnpm-workspace.yaml (1)
26-26: This dependency is acceptable for its specific purpose. @sparkjsdev/spark is an advanced 3D Gaussian Splatting renderer for THREE.js, and version 0.1.10 is the current version in official documentation. The caret constraint allows patch-level updates while maintaining compatibility, which is appropriate for a specialized rendering library serving discrete 3D visualization features in this project.src/composables/useLoad3d.ts (1)
494-494: Correctly updates splat-model state on load completion.The fallback to
falseensuresisSplatModelis always a boolean, even whenload3dis unavailable.src/extensions/core/load3d/Load3d.ts (1)
574-576: LGTM: Clean delegation to model manager.The
isSplatModel()method correctly delegates tomodelManager.containsSplatMesh(), providing a clear public API for detecting splat models.src/extensions/core/load3d/interfaces.ts (2)
10-15: LGTM: MaterialMode extension for point cloud rendering.The addition of
'original(Advanced)'to the MaterialMode union aligns with the new point cloud rendering capability introduced in this PR.
194-198: LGTM: Extension set updated for PLY/splat support.The new extensions (
.spz,.splat,.ply,.ksplat) correctly reflect the 3DGS and PLY file format support added in this PR.src/components/load3d/controls/ModelControls.vue (3)
74-76: LGTM: Prop definition follows Vue 3.5 style.The
hideMaterialModeprop is correctly defined using Vue 3.5 destructuring with a default value.
31-31: LGTM: Clean conditional rendering.The material mode UI is conditionally rendered based on the
hideMaterialModeprop, enabling splat-model-specific behavior.
97-97: LGTM: materialModes extended for point cloud rendering.The addition of
'original(Advanced)'aligns with the new MaterialMode variant and enables point cloud rendering in the UI.src/components/load3d/Load3D.vue (2)
113-113: LGTM: Clean state extraction from composable.The
isSplatModelstate is correctly destructured fromuseLoad3dfor propagation to child components.
25-25: LGTM: State correctly propagated to controls.The
isSplatModelstate is properly passed toLoad3DControls, enabling splat-model-specific UI behavior.src/extensions/core/load3d/SceneModelManager.ts (5)
102-239: Complex PLY mode switching logic.The
handlePLYModeSwitchmethod correctly handles the reconstruction of PLY models for different rendering modes (Points vs Mesh). The logic appropriately:
- Cleans up old MainModel instances
- Creates Points geometry for
original(Advanced)mode- Creates Mesh geometry for other modes
- Applies proper centering and scaling
However, note the efficiency concerns mentioned in related comments below.
248-252: LGTM: Clean routing for PLY mode changes.The early return correctly routes PLY BufferGeometry through the specialized
handlePLYModeSwitchmethod, avoiding the general material switching logic.
335-335: LGTM: Material mode restoration includes advanced option.The addition of the
'original(Advanced)'case ensures proper material restoration for point cloud rendering mode.
431-440: LGTM: Efficient path for splat models.The early detection and handling of splat models correctly bypasses standard fitting and material setup, as SplatMesh handles its own rendering.
1-1: The@sparkjsdev/sparkdependency is already properly configured inpackage.jsonunder the project's package management system (using the "catalog:" protocol for dependency resolution). The import is correctly used in the codebase with instantiation patterns inLoaderManager.tsand proper type checking inSceneModelManager.ts. Tests mockSplatMeshappropriately invitest.setup.ts, confirming integration completeness.src/extensions/core/load3d/LoaderManager.ts (10)
1-1: LGTM - Imports are appropriate.The new imports properly support PLY and splat format loading with the necessary loaders and dependencies.
Also applies to: 7-7, 11-11, 19-19
27-28: LGTM - Loader fields follow existing patterns.The new public loader fields are consistent with the existing loader architecture and properly expose the PLY loading capabilities.
45-46: LGTM - Loader initialization is correct.The new loaders are properly initialized following the established pattern.
199-201: LGTM - PLY case properly delegates to loadPLY.The switch case cleanly delegates PLY loading to the dedicated method.
218-221: LGTM - Method signature is well-defined.The private method signature correctly defines the PLY loading interface with appropriate types.
238-241: LGTM - Format detection is appropriate.The ASCII format detection safely inspects the PLY header without risk of out-of-bounds access.
243-250: LGTM - Loader selection logic is correct.The conditional selection between FastPLYLoader and standard PLYLoader appropriately handles different formats and user preferences.
252-257: LGTM - Geometry initialization follows best practices.The geometry is properly registered, normals are computed, and attributes are inspected before rendering decisions.
259-284: LGTM - Points rendering is well-implemented.The centering, scaling, and Points rendering for the original(Advanced) mode properly handles point cloud visualization with appropriate material configurations.
Also applies to: 290-294
296-317: LGTM - Mesh rendering properly handles materials and geometry.The mesh rendering path correctly creates appropriate materials based on vertex color presence and applies sensible defaults (DoubleSide, appropriate metalness/roughness).
8b8b713 to
bafd460
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/services/load3dService.ts (2)
9-9: Replaceanywith proper TypeScript type.The
anytype violates coding guidelines. Define the viewer type based on the return type ofuseLoad3dViewer.🔎 Apply this diff to use proper typing:
+import type { ReturnType } from 'es-toolkit' + +type Load3dViewer = ReturnType<typeof useLoad3dViewer> + -const viewerInstances = new Map<NodeId, any>() +const viewerInstances = new Map<NodeId, Load3dViewer>()As per coding guidelines: "Never use
anytype - use proper TypeScript types."
120-120: Replaceas anywith proper TypeScript type.The
as anytype assertion violates coding guidelines. Define a proper type for the Scene Config properties.🔎 Apply this diff to use proper typing:
+interface SceneConfig { + backgroundImage?: string + // Add other Scene Config properties as needed +} + - const sceneConfig = sourceNode?.properties?.['Scene Config'] as any + const sceneConfig = sourceNode?.properties?.['Scene Config'] as SceneConfig | undefined const backgroundPath = sceneConfig?.backgroundImageAs per coding guidelines: "Never use
as anytype assertions - fix the underlying type issue."
♻️ Duplicate comments (15)
src/services/load3dService.ts (1)
78-102: Add error handling for missing splat model URL and clarify why splat models don't copy material properties.The splat model branch (lines 78-82) silently continues if
originalURLis missing without warning or error handling. Add error handling to log or handle this case.Additionally, splat models have embedded rendering properties from their source file and don't support dynamic
materialMode,upDirection, orappliedTexturechanges like polygon models do. Add a comment clarifying why these properties aren't copied for splat models to prevent future confusion.Suggested fix:
if (source.isSplatModel()) { const originalURL = source.modelManager.originalURL if (originalURL) { await target.loadModel(originalURL) + } else { + console.warn('Cannot copy splat model: originalURL is missing') + } + // Splat models are loaded with embedded rendering properties from their + // source file and don't support dynamic material/texture/direction changes } else {tests-ui/tests/composables/useLoad3d.test.ts (1)
108-109: Test coverage for splat/PLY model scenarios remains incomplete.The mocks correctly expose
isSplatModelandisPlyModelfor the test surface, but both returnfalse, which only tests the non-splat/non-ply code path. Consider adding test cases that verify behavior when these flags returntrue, such as material mode option changes and UI adjustments specific to splat or PLY models.Based on learnings: Write tests for all changes, especially new features.
src/composables/useLoad3d.ts (1)
492-497: Reset model type flags at the start of model loading to prevent stale state.If a splat or PLY model loads successfully and a subsequent load fails, the flags
isSplatModelandisPlyModelretain their previous values. This can cause the UI to display incorrect controls. Consider resetting both flags inmodelLoadingStartto ensure UI consistency during new load attempts.🔎 Apply this diff to reset the flags:
modelLoadingStart: () => { loadingMessage.value = t('load3d.loadingModel') loading.value = true + isSplatModel.value = false + isPlyModel.value = false },src/extensions/core/load3d/loader/FastPLYLoader.ts (4)
9-48: Add validation for PLY file format and required properties.The parser assumes a valid PLY format but doesn't validate the magic number (
ply) at the start or verify that required properties (x, y, z) are present. This could lead to silent failures or corrupted geometry with NaN values.🔎 Add validation after decoding:
parse(arrayBuffer: ArrayBuffer): THREE.BufferGeometry { const text = new TextDecoder().decode(arrayBuffer) const lines = text.split('\n') + + // Validate PLY magic number + if (!lines[0]?.trim().toLowerCase().startsWith('ply')) { + throw new Error('Invalid PLY file: missing PLY header') + }And after header parsing:
} else if (line === 'end_header') { headerEndLine = i break } } + + if (xIndex < 0 || yIndex < 0 || zIndex < 0) { + throw new Error('Invalid PLY file: missing required position properties (x, y, z)') + } + + if (vertexCount === 0) { + throw new Error('Invalid PLY file: no vertices defined') + }
50-52: Pre-allocated buffers may contain trailing zeros if vertices are skipped.The
positionsandcolorsbuffers are pre-allocated based onvertexCount, but blank lines and lines with insufficient parts are skipped (lines 63, 66). This leaves trailing zeros in the buffer ifvertexIndex < vertexCount.🔎 Trim buffers after parsing:
// Create geometry const geometry = new THREE.BufferGeometry() - geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)) + const actualPositions = vertexIndex < vertexCount + ? positions.slice(0, vertexIndex * 3) + : positions + geometry.setAttribute('position', new THREE.BufferAttribute(actualPositions, 3)) if (hasColor && colors) { - geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3)) + const actualColors = vertexIndex < vertexCount + ? colors.slice(0, vertexIndex * 3) + : colors + geometry.setAttribute('color', new THREE.BufferAttribute(actualColors, 3)) }Also applies to: 93-98
71-73: Validate parseFloat results to prevent NaN in geometry.
parseFloatreturnsNaNsilently on invalid input. If a line contains non-numeric data or property indices are wrong, this produces corrupted geometry without any indication.🔎 Add NaN validation:
// Position - positions[posIndex] = parseFloat(parts[xIndex]) - positions[posIndex + 1] = parseFloat(parts[yIndex]) - positions[posIndex + 2] = parseFloat(parts[zIndex]) + const x = parseFloat(parts[xIndex]) + const y = parseFloat(parts[yIndex]) + const z = parseFloat(parts[zIndex]) + + if (Number.isNaN(x) || Number.isNaN(y) || Number.isNaN(z)) { + continue // Skip malformed vertices + } + + positions[posIndex] = x + positions[posIndex + 1] = y + positions[posIndex + 2] = z
84-86: Specify radix for parseInt to ensure decimal parsing.
parseIntwithout a radix argument can produce unexpected results with certain string formats. Always specify radix 10 for decimal parsing.🔎 Add radix parameter:
- colors[posIndex] = parseInt(parts[redIndex]) / 255 - colors[posIndex + 1] = parseInt(parts[greenIndex]) / 255 - colors[posIndex + 2] = parseInt(parts[blueIndex]) / 255 + colors[posIndex] = parseInt(parts[redIndex], 10) / 255 + colors[posIndex + 1] = parseInt(parts[greenIndex], 10) / 255 + colors[posIndex + 2] = parseInt(parts[blueIndex], 10) / 255src/extensions/core/load3d/SceneModelManager.ts (3)
102-239: Consolidate redundant MainModel removal logic.The scene is traversed twice to find and remove
MainModelobjects (lines 111-131 and 206-212). The second traversal with the "Double check" comment suggests uncertainty about the first cleanup. This is inefficient and may indicate a code smell.🔎 Remove redundant traversal:
If the first removal is working correctly, the second is unnecessary. If there's a race condition or re-entrancy concern, document it clearly. Otherwise:
- // Double check: remove any remaining MainModel before adding new one - const remainingMainModels: THREE.Object3D[] = [] - this.scene.traverse((obj) => { - if (obj.name === 'MainModel') { - remainingMainModels.push(obj) - } - }) - remainingMainModels.forEach((obj) => this.scene.remove(obj)) this.currentModel = newModel newModel.name = 'MainModel'
107-107: Add defensive validation before cloning PLY geometry.If the PLY geometry is corrupted or missing required attributes,
clone()could throw. Consider validating the geometry before cloning to provide clearer error messages.🔎 Add attribute validation:
private handlePLYModeSwitch(mode: MaterialMode): void { if (!(this.originalModel instanceof THREE.BufferGeometry)) { return } + + if (!this.originalModel.attributes.position) { + console.error('Invalid PLY geometry: missing position attribute') + return + } const plyGeometry = this.originalModel.clone()
471-480: Optimize containsSplatMesh to short-circuit traversal.
THREE.Object3D.traversedoesn't support early exit. Once aSplatMeshis found, the traversal continues unnecessarily through the entire scene graph, which is wasteful for large models.🔎 Use recursive helper for early exit:
containsSplatMesh(model?: THREE.Object3D | null): boolean { const target = model ?? this.currentModel if (!target) return false if (target instanceof SplatMesh) return true - let found = false - target.traverse((child) => { - if (child instanceof SplatMesh) found = true - }) - return found + // Use a recursive helper that can short-circuit + function checkChildren(obj: THREE.Object3D): boolean { + for (const child of obj.children) { + if (child instanceof SplatMesh) return true + if (checkChildren(child)) return true + } + return false + } + return checkChildren(target) }src/extensions/core/load3d/LoaderManager.ts (5)
203-212: Wrap switch case declarations in block scope to prevent variable leakage.The local variables
splatUrl,splatMesh, andsplatGroupdeclared in the splat format cases can erroneously leak to other switch clauses. Biome static analysis correctly flags this as a correctness issue.🔎 Wrap in block scope:
case 'spz': case 'splat': - case 'ksplat': - const splatUrl = path + encodeURIComponent(filename) - const splatMesh = new SplatMesh({ url: splatUrl }) - this.modelManager.setOriginalModel(splatMesh) - const splatGroup = new THREE.Group() - splatGroup.add(splatMesh) - model = splatGroup + case 'ksplat': { + const splatUrl = path + encodeURIComponent(filename) + const splatMesh = new SplatMesh({ url: splatUrl }) + this.modelManager.setOriginalModel(splatMesh) + const splatGroup = new THREE.Group() + splatGroup.add(splatMesh) + model = splatGroup break + }As per coding guidelines: Avoid using TypeScript
anytype and fix underlying type issues.
222-222: Replace type assertion with safe default value.The setting value is cast to
stringusingas string, which can hideundefinedor non-string values and violates the coding guideline againstastype assertions.🔎 Use nullish coalescing with default:
- const plyEngine = useSettingStore().get('Comfy.Load3D.PLYEngine') as string + const plyEngine = useSettingStore().get('Comfy.Load3D.PLYEngine') ?? 'threejs'This provides a sensible default if the setting is undefined.
As per coding guidelines: Never use
as anytype assertions - fix the underlying type issue.
224-231: Extract duplicate SplatMesh creation logic into a helper method.The sparkjs path in
loadPLY(lines 224-231) duplicates the splat case logic (lines 203-212). This code duplication makes maintenance harder and risks divergence.🔎 Extract helper method:
+ private createSplatModel(url: string): THREE.Group { + const splatMesh = new SplatMesh({ url }) + this.modelManager.setOriginalModel(splatMesh) + const group = new THREE.Group() + group.add(splatMesh) + return group + }Then use in both locations:
case 'spz': case 'splat': case 'ksplat': { const splatUrl = path + encodeURIComponent(filename) - const splatMesh = new SplatMesh({ url: splatUrl }) - this.modelManager.setOriginalModel(splatMesh) - const splatGroup = new THREE.Group() - splatGroup.add(splatMesh) - model = splatGroup + model = this.createSplatModel(splatUrl) break }if (plyEngine === 'sparkjs') { const splatUrl = path + encodeURIComponent(filename) - const splatMesh = new SplatMesh({ url: splatUrl }) - this.modelManager.setOriginalModel(splatMesh) - const splatGroup = new THREE.Group() - splatGroup.add(splatMesh) - return splatGroup + return this.createSplatModel(splatUrl) }
234-236: Validate HTTP response status before reading body.If
fetchfails with a 4xx/5xx status,response.arrayBuffer()will still execute but may return an error page or empty data, leading to confusing parsing errors downstream.🔎 Add response validation:
// Use Three.js PLYLoader or FastPLYLoader for point cloud PLY files const fullUrl = path + filename const response = await fetch(fullUrl) + if (!response.ok) { + throw new Error(`Failed to load PLY file: ${response.status} ${response.statusText}`) + } const arrayBuffer = await response.arrayBuffer()
286-289: Type assertion indicates underlying type definition issue.The
as unknown as THREE.Meshcast when storingplyPointsintooriginalMaterialssuggests thatoriginalMaterialsis typed asWeakMap<THREE.Mesh, ...>but needs to storeTHREE.Pointsas well.The proper fix requires widening the WeakMap type in
SceneModelManager(whereoriginalMaterialsis defined) to accept bothTHREE.Mesh | THREE.Points. Once that's fixed, remove this cast to maintain type safety.As per coding guidelines: Never use
as anytype assertions - fix the underlying type issue.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
package.json(1 hunks)pnpm-workspace.yaml(2 hunks)src/components/load3d/Load3D.vue(2 hunks)src/components/load3d/Load3DControls.vue(3 hunks)src/components/load3d/controls/ModelControls.vue(3 hunks)src/composables/useLoad3d.ts(3 hunks)src/extensions/core/load3d.ts(2 hunks)src/extensions/core/load3d/Load3d.ts(1 hunks)src/extensions/core/load3d/LoaderManager.ts(3 hunks)src/extensions/core/load3d/SceneModelManager.ts(5 hunks)src/extensions/core/load3d/interfaces.ts(2 hunks)src/extensions/core/load3d/loader/FastPLYLoader.ts(1 hunks)src/locales/en/main.json(1 hunks)src/schemas/apiSchema.ts(1 hunks)src/services/load3dService.ts(1 hunks)tests-ui/tests/composables/useLoad3d.test.ts(1 hunks)vitest.setup.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (17)
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
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
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
src/**/*.vue: Vue 3 SFCs must use Composition API only - no Options API
Use<script setup lang="ts">for component logic
Use Tailwind 4 utility classes for styling - avoid<style>blocks
Usecn()utility from@/utils/tailwindUtilto merge Tailwind class names - never use:class="[]"syntax
Never use thedark:Tailwind variant - use semantic values fromstyle.csstheme instead (e.g.,bg-node-component-surface)
Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - preferuseModelto prop/emit pairs, do not usewithDefaults
Do not import Vue macros unnecessarily
Use vue-i18n in composition API for string literals - place translation entries insrc/locales/en/main.json
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Avoid new usage of PrimeVue components
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
src/**/*.{vue,ts}: Avoid usingrefandwatchtogether - usecomputedinstead if possible
Do not addrefif a prop would suffice; do not addcomputedif the ref/prop directly would work; usewatchonly whencomputedwon't accomplish the goal
Leverage VueUse functions for performance-enhancing styles
Files:
src/components/load3d/Load3DControls.vuesrc/extensions/core/load3d.tssrc/services/load3dService.tssrc/schemas/apiSchema.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/interfaces.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/SceneModelManager.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
src/**/*.{ts,tsx,vue}: ESLint rules: Vue + TS rules, no floating promises, unused imports disallowed, i18n raw text restrictions in templates
Use es-toolkit for utility functions
Avoid mutable state - prefer immutability and assignment at point of declaration
Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
src/components/load3d/Load3DControls.vuesrc/extensions/core/load3d.tssrc/services/load3dService.tssrc/schemas/apiSchema.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/interfaces.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/SceneModelManager.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vue
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/components/load3d/Load3DControls.vuesrc/extensions/core/load3d.tssrc/services/load3dService.tssrc/schemas/apiSchema.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/interfaces.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/SceneModelManager.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vue
src/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue componentsVue components must be named in PascalCase (e.g.,
MenuHamburger.vue)
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
src/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
src/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
src/**/*.{js,ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively - no new JavaScript files
Files:
src/components/load3d/Load3DControls.vuesrc/extensions/core/load3d.tssrc/services/load3dService.tssrc/schemas/apiSchema.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/interfaces.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/SceneModelManager.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,tsx,vue,js}: Indent with 2 spaces, use single quotes, no trailing semicolons, line width 80 - see.prettierrc
Sort and group imports by plugin, runpnpm formatbefore committing
Files:
src/components/load3d/Load3DControls.vuesrc/extensions/core/load3d.tssrc/services/load3dService.tssrc/schemas/apiSchema.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/interfaces.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/SceneModelManager.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
src/**/*.ts: Extract complex type definitions that are inlined in multiple related places - name them for reuse
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones
Files:
src/extensions/core/load3d.tssrc/services/load3dService.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/interfaces.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/SceneModelManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use function expressions - use function declarations instead when possible
Files:
src/extensions/core/load3d.tssrc/services/load3dService.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/interfaces.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/SceneModelManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/Load3d.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/services/load3dService.tssrc/composables/useLoad3d.ts
src/composables/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Composables must follow the naming pattern
useXyz.ts
Files:
src/composables/useLoad3d.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)
tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks
Files:
tests-ui/tests/composables/useLoad3d.test.ts
tests-ui/**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
tests-ui/**/*.test.ts: Write tests for all changes, especially bug fixes to catch future regressions
Unit/Component test files must use pattern**/*.test.ts
Do not write change detector tests - do not just assert that defaults are certain values
Do not write tests dependent on non-behavioral features like utility classes or styles
Be parsimonious in testing - do not write redundant tests
Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
For mocking, leverage Vitest's utilities where possible
Keep module mocks contained - do not use global mutable state within test files, usevi.hoisted()if necessary
For Component testing, use Vue Test Utils and follow advice about making components easy to test
Aim for behavioral coverage of critical and new features
Files:
tests-ui/tests/composables/useLoad3d.test.ts
🧠 Learnings (43)
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : For mocking, leverage Vitest's utilities where possible
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Keep module mocks contained - do not use global mutable state within test files, use `vi.hoisted()` if necessary
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`
Applied to files:
vitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest
Applied to files:
vitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : For Component testing, use Vue Test Utils and follow advice about making components easy to test
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
vitest.setup.tssrc/extensions/core/load3d.tssrc/services/load3dService.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/interfaces.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/SceneModelManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/LoaderManager.tstests-ui/tests/composables/useLoad3d.test.tssrc/extensions/core/load3d/Load3d.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
vitest.setup.tssrc/extensions/core/load3d.tssrc/services/load3dService.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/interfaces.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/SceneModelManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/LoaderManager.tstests-ui/tests/composables/useLoad3d.test.tssrc/extensions/core/load3d/Load3d.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
vitest.setup.tssrc/extensions/core/load3d.tssrc/services/load3dService.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/interfaces.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/SceneModelManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/LoaderManager.tstests-ui/tests/composables/useLoad3d.test.tssrc/extensions/core/load3d/Load3d.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
vitest.setup.tssrc/components/load3d/Load3DControls.vuesrc/extensions/core/load3d.tssrc/services/load3dService.tssrc/schemas/apiSchema.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/interfaces.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/SceneModelManager.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d/LoaderManager.tstests-ui/tests/composables/useLoad3d.test.tssrc/extensions/core/load3d/Load3d.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - prefer `useModel` to prop/emit pairs, do not use `withDefaults`
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Define proper props and emits definitions in Vue components
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Avoid new usage of PrimeVue components
Applied to files:
package.jsonpnpm-workspace.yaml
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue TabMenu component with Tabs without panels
Applied to files:
package.json
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Destructure props using Vue 3.5 style in Vue components
Applied to files:
src/components/load3d/Load3D.vue
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Implement proper props and emits definitions in Vue components
Applied to files:
src/components/load3d/Load3D.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use vue 3.5 style of default prop declaration
Applied to files:
src/components/load3d/Load3D.vue
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.
Applied to files:
src/locales/en/main.json
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Take advantage of `TypedArray` `subarray` when appropriate
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.{ts,tsx,vue} : ESLint rules: Vue + TS rules, no floating promises, unused imports disallowed, i18n raw text restrictions in templates
Applied to files:
pnpm-workspace.yaml
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.{ts,tsx,vue,js} : Indent with 2 spaces, use single quotes, no trailing semicolons, line width 80 - see `.prettierrc`
Applied to files:
pnpm-workspace.yaml
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.{js,ts,tsx,vue} : Use TypeScript exclusively - no new JavaScript files
Applied to files:
pnpm-workspace.yaml
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Run ESLint instead of manually figuring out whitespace fixes or other trivial style concerns using the `pnpm lint:fix` command
Applied to files:
pnpm-workspace.yaml
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `as any` type assertions - fix the underlying type issue
Applied to files:
src/extensions/core/load3d/LoaderManager.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Aim for behavioral coverage of critical and new features
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Be parsimonious in testing - do not write redundant tests
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
🧬 Code graph analysis (2)
src/composables/useLoad3d.ts (1)
src/extensions/core/load3d/Load3d.ts (2)
isSplatModel(574-576)isPlyModel(578-580)
src/extensions/core/load3d/LoaderManager.ts (2)
src/extensions/core/load3d/loader/FastPLYLoader.ts (1)
FastPLYLoader(8-102)src/platform/settings/settingStore.ts (1)
useSettingStore(46-252)
🪛 Biome (2.1.2)
src/extensions/core/load3d/LoaderManager.ts
[error] 206-206: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 207-207: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 209-209: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: deploy-and-comment
- GitHub Check: setup
- GitHub Check: lint-and-format
- GitHub Check: test
- GitHub Check: collect
🔇 Additional comments (23)
package.json (1)
149-149: LGTM: SparkJS dependency added correctly.The addition of
@sparkjsdev/sparkas a runtime dependency follows the established catalog pattern and aligns with the PR's objective to support 3D Gaussian Splatting.pnpm-workspace.yaml (1)
26-26: LGTM: SparkJS catalog entry added correctly.The catalog entry for
@sparkjsdev/sparkat version ^0.1.10 is properly formatted and will be referenced by package.json.src/extensions/core/load3d.ts (2)
202-212: LGTM: PLY Engine setting configured properly.The new
Comfy.Load3D.PLYEnginesetting is well-defined with:
- Clear tooltip explaining each engine option
- Appropriate default ('threejs')
- Proper experimental flag
The three engine options (threejs, fastply, sparkjs) align with the PR's multi-engine PLY support strategy.
252-255: LGTM: File input extended for PLY formats.The accept attribute now correctly includes
.ply,.spz,.splat, and.ksplatextensions, matching the SUPPORTED_EXTENSIONS set defined in interfaces.ts.vitest.setup.ts (1)
4-9: LGTM: SparkJS mock properly configured for tests.The mock implementation of SplatMesh with an empty constructor is appropriate for bypassing WASM dependencies during Node.js test execution. The comment clearly explains the rationale.
src/locales/en/main.json (1)
1638-1638: LGTM: Point Cloud translation added with consistent naming.The new
"pointCloud": "Point Cloud"entry follows the established camelCase naming pattern used by other material modes in this section.src/components/load3d/Load3DControls.vue (3)
90-93: LGTM: Props defined correctly with Vue 3.5 style.The
isSplatModelandisPlyModelprops are properly defined using reactive destructuring with appropriate defaults. This follows the project's Vue 3.5+ coding guidelines.
111-116: LGTM: Light controls appropriately hidden for splat models.The conditional logic to exclude the 'light' category for splat models makes sense, as 3D Gaussian Splatting models have different rendering characteristics that don't require traditional lighting controls.
50-51: ModelControls component correctly accepts the new props.The component receives
:hide-material-mode="isSplatModel"and:is-ply-model="isPlyModel"and ModelControls properly defines both props ashideMaterialMode?: booleanandisPlyModel?: booleanwith appropriate defaults and TypeScript types.src/extensions/core/load3d/interfaces.ts (2)
10-15: LGTM: Point Cloud material mode added to MaterialMode type.The addition of
'pointCloud'to the MaterialMode union type is consistent with the locale translation added insrc/locales/en/main.jsonand supports the new PLY rendering capabilities.
194-198: LoaderManager properly supports all PLY-related file extensions.Verified that LoaderManager (lines 199-212) includes case handlers for all four extensions:
.plyuses intelligent engine selection (SparkJS, FastPLYLoader, or ThreeJS PLYLoader).spz,.splat,.ksplatuse SplatMesh from SparkJSAll required loaders are imported and initialized. No action needed.
src/schemas/apiSchema.ts (1)
511-511: Enum values match extension setting definition.The PLY Engine enum values in the schema (
'threejs','fastply','sparkjs') match exactly with the options defined insrc/extensions/core/load3d.ts.src/composables/useLoad3d.ts (2)
66-67: LGTM!The reactive state variables
isSplatModelandisPlyModelare correctly declared and will be properly exposed in the composable's return object.
568-569: LGTM!The model type flags are correctly exposed in the composable's public API for consumption by UI components.
src/extensions/core/load3d/Load3d.ts (1)
574-580: LGTM!The new public methods
isSplatModel()andisPlyModel()correctly delegate to the model manager and provide clean type detection for downstream consumers. The implementation is straightforward and appropriate.src/components/load3d/Load3D.vue (1)
25-26: LGTM!The model type flags are correctly destructured from
useLoad3dand passed down toLoad3DControls. This enables the child component to adjust its UI based on whether the loaded model is a splat or PLY model.Also applies to: 114-115
src/components/load3d/controls/ModelControls.vue (2)
31-31: LGTM!The
hideMaterialModeprop correctly controls visibility of the material mode UI, and both props are properly typed and destructured following Vue 3.5 patterns.Also applies to: 74-77
95-109: LGTM!The computed
materialModescorrectly includes thepointCloudoption only for PLY models, inserting it at index 1 as intended. The conditional logic is clear and appropriate.src/extensions/core/load3d/SceneModelManager.ts (3)
1-1: LGTM!The
SplatMeshimport from@sparkjsdev/sparkis correctly added to support 3D Gaussian Splatting detection and handling.
248-252: LGTM!The early return to route PLY BufferGeometry models through
handlePLYModeSwitchis correct and prevents the standard material mode logic from incorrectly processing PLY models.
431-440: LGTM!The SplatMesh early-return path correctly skips the standard model fitting and material setup, which is appropriate since SplatMesh handles its own rendering. The default camera distance provides reasonable viewing.
src/extensions/core/load3d/LoaderManager.ts (2)
1-1: LGTM!The imports and initialization of
PLYLoaderandFastPLYLoaderare correctly added to support the new PLY loading pathways.Also applies to: 7-7, 11-11, 19-19, 27-28, 45-46
199-201: LGTM!The
'ply'case correctly delegates to the newloadPLYmethod, maintaining clean separation of loading logic by file type.
bafd460 to
bed0d3f
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
♻️ Duplicate comments (9)
src/services/load3dService.ts (1)
78-102: Silent failure when splat model lacks originalURL.The code correctly differentiates between splat models (which must be reloaded via URL) and cloneable models. However, when a splat model lacks an
originalURL(line 79-82), the method silently skips model copying entirely, leaving the target without a model. This is a silent failure that could cause confusing behavior for users.🔎 Recommended fix: Add error handling
if (source.isSplatModel()) { const originalURL = source.modelManager.originalURL if (originalURL) { await target.loadModel(originalURL) + } else { + console.error('Cannot copy splat model: originalURL is missing') + throw new Error('Cannot copy splat model: originalURL is required for splat models') } } else {This ensures the issue is surfaced to the developer/user rather than silently failing. If throwing is too aggressive for your use case, at minimum add the console.error to help with debugging.
src/composables/useLoad3d.ts (1)
488-497: Reset model-type flags at the start of loading to prevent stale state.If a user loads a splat/PLY model (setting
isSplatModel/isPlyModelto true), then attempts to load a different model that fails, these flags retain stale values from the previous successful load. Reset both flags inmodelLoadingStartfor consistency.🔎 Suggested fix:
modelLoadingStart: () => { loadingMessage.value = t('load3d.loadingModel') loading.value = true + isSplatModel.value = false + isPlyModel.value = false },tests-ui/tests/composables/useLoad3d.test.ts (1)
108-109: Mock methods correctly added.The mock properly includes
isSplatModelandisPlyModelmethods returningfalse. Consider adding test cases that verify behavior when these returntrueto ensure complete coverage of splat/PLY model code paths.src/extensions/core/load3d/SceneModelManager.ts (1)
471-480: Consider short-circuiting the traversal for performance.As noted in a prior review,
traversecontinues through the entire scene graph even after finding aSplatMesh. For large models, consider using a manual recursive traversal that can return early.🔎 Optional optimization:
containsSplatMesh(model?: THREE.Object3D | null): boolean { const target = model ?? this.currentModel if (!target) return false if (target instanceof SplatMesh) return true - let found = false - target.traverse((child) => { - if (child instanceof SplatMesh) found = true - }) - return found + function checkChildren(obj: THREE.Object3D): boolean { + for (const child of obj.children) { + if (child instanceof SplatMesh) return true + if (checkChildren(child)) return true + } + return false + } + return checkChildren(target) }src/extensions/core/load3d/LoaderManager.ts (5)
204-213: Wrap switch case declarations in block scope.The variable declarations in the splat cases can leak to other cases. This issue has been flagged by both Biome linting and in previous review comments.
As suggested in the previous review, wrap the case body in braces:
🔎 Apply this fix
case 'spz': case 'splat': - case 'ksplat': - const splatUrl = path + encodeURIComponent(filename) - const splatMesh = new SplatMesh({ url: splatUrl }) - this.modelManager.setOriginalModel(splatMesh) - const splatGroup = new THREE.Group() - splatGroup.add(splatMesh) - model = splatGroup + case 'ksplat': { + const splatUrl = path + encodeURIComponent(filename) + const splatMesh = new SplatMesh({ url: splatUrl }) + this.modelManager.setOriginalModel(splatMesh) + const splatGroup = new THREE.Group() + splatGroup.add(splatMesh) + model = splatGroup break + }
223-223: Use type guard or default value instead of type assertion.The
as stringcast can hide type issues if the setting returnsundefinedor another type. This was previously flagged.As suggested in the previous review, use nullish coalescing with a default:
- const plyEngine = useSettingStore().get('Comfy.Load3D.PLYEngine') as string + const plyEngine = useSettingStore().get('Comfy.Load3D.PLYEngine') ?? 'threejs'As per coding guidelines, avoid
astype assertions when possible.
225-232: Extract duplicate SplatMesh creation logic.This code duplicates the splat case logic from lines 204-213. As previously suggested, extract a helper method to reduce duplication.
The previous review suggested creating a
createSplatModelhelper:🔎 Recommended refactor
+ private createSplatModel(url: string): THREE.Group { + const splatMesh = new SplatMesh({ url }) + this.modelManager.setOriginalModel(splatMesh) + const group = new THREE.Group() + group.add(splatMesh) + return group + }Then use it in both places to eliminate duplication.
234-237: Add response status validation before reading body.The code calls
response.arrayBuffer()without checkingresponse.ok. If the fetch returns a 4xx/5xx error, this could lead to parsing errors. This was flagged in a previous review.🔎 Apply this fix
const fullUrl = path + filename const response = await fetch(fullUrl) + if (!response.ok) { + throw new Error(`Failed to load PLY file: ${response.status} ${response.statusText}`) + } const arrayBuffer = await response.arrayBuffer()
284-287: Type assertion indicates WeakMap typing issue.The cast
as unknown as THREE.Meshreveals a type mismatch whereoriginalMaterialsexpectsTHREE.Meshbut receivesTHREE.Points. This was previously flagged and requires updating the WeakMap type definition.As noted in the previous review, fix the root cause by updating
originalMaterialstype in SceneModelManager toWeakMap<THREE.Mesh | THREE.Points, MaterialType>, then remove this cast.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (18)
package.json(1 hunks)pnpm-workspace.yaml(1 hunks)src/components/load3d/Load3D.vue(2 hunks)src/components/load3d/Load3DControls.vue(3 hunks)src/components/load3d/controls/ModelControls.vue(3 hunks)src/composables/useLoad3d.ts(3 hunks)src/extensions/core/load3d.ts(2 hunks)src/extensions/core/load3d/Load3d.ts(1 hunks)src/extensions/core/load3d/LoaderManager.ts(3 hunks)src/extensions/core/load3d/SceneModelManager.ts(5 hunks)src/extensions/core/load3d/interfaces.ts(2 hunks)src/extensions/core/load3d/loader/FastPLYLoader.ts(1 hunks)src/locales/en/main.json(1 hunks)src/schemas/apiSchema.ts(1 hunks)src/scripts/metadata/ply.ts(1 hunks)src/services/load3dService.ts(1 hunks)tests-ui/tests/composables/useLoad3d.test.ts(1 hunks)vitest.setup.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (17)
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
src/**/*.{vue,ts}: Avoid usingrefandwatchtogether - usecomputedinstead if possible
Do not addrefif a prop would suffice; do not addcomputedif the ref/prop directly would work; usewatchonly whencomputedwon't accomplish the goal
Leverage VueUse functions for performance-enhancing styles
Files:
src/schemas/apiSchema.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/composables/useLoad3d.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/LoaderManager.tssrc/scripts/metadata/ply.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
src/**/*.ts: Extract complex type definitions that are inlined in multiple related places - name them for reuse
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones
Files:
src/schemas/apiSchema.tssrc/services/load3dService.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/LoaderManager.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
src/**/*.{ts,tsx,vue}: ESLint rules: Vue + TS rules, no floating promises, unused imports disallowed, i18n raw text restrictions in templates
Use es-toolkit for utility functions
Avoid mutable state - prefer immutability and assignment at point of declaration
Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
src/schemas/apiSchema.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/composables/useLoad3d.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/LoaderManager.tssrc/scripts/metadata/ply.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/schemas/apiSchema.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/composables/useLoad3d.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/LoaderManager.tssrc/scripts/metadata/ply.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{js,ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively - no new JavaScript files
Files:
src/schemas/apiSchema.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/composables/useLoad3d.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/LoaderManager.tssrc/scripts/metadata/ply.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,tsx,vue,js}: Indent with 2 spaces, use single quotes, no trailing semicolons, line width 80 - see.prettierrc
Sort and group imports by plugin, runpnpm formatbefore committing
Files:
src/schemas/apiSchema.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuesrc/composables/useLoad3d.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/LoaderManager.tssrc/scripts/metadata/ply.tssrc/components/load3d/Load3D.vuesrc/extensions/core/load3d/SceneModelManager.ts
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use function expressions - use function declarations instead when possible
Files:
src/schemas/apiSchema.tssrc/services/load3dService.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/LoaderManager.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/SceneModelManager.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/services/load3dService.tssrc/composables/useLoad3d.ts
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
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
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
src/**/*.vue: Vue 3 SFCs must use Composition API only - no Options API
Use<script setup lang="ts">for component logic
Use Tailwind 4 utility classes for styling - avoid<style>blocks
Usecn()utility from@/utils/tailwindUtilto merge Tailwind class names - never use:class="[]"syntax
Never use thedark:Tailwind variant - use semantic values fromstyle.csstheme instead (e.g.,bg-node-component-surface)
Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - preferuseModelto prop/emit pairs, do not usewithDefaults
Do not import Vue macros unnecessarily
Use vue-i18n in composition API for string literals - place translation entries insrc/locales/en/main.json
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Avoid new usage of PrimeVue components
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/components/load3d/Load3DControls.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/components/load3d/Load3DControls.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
src/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue componentsVue components must be named in PascalCase (e.g.,
MenuHamburger.vue)
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
src/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
src/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
src/composables/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Composables must follow the naming pattern
useXyz.ts
Files:
src/composables/useLoad3d.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)
tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks
Files:
tests-ui/tests/composables/useLoad3d.test.ts
tests-ui/**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
tests-ui/**/*.test.ts: Write tests for all changes, especially bug fixes to catch future regressions
Unit/Component test files must use pattern**/*.test.ts
Do not write change detector tests - do not just assert that defaults are certain values
Do not write tests dependent on non-behavioral features like utility classes or styles
Be parsimonious in testing - do not write redundant tests
Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
For mocking, leverage Vitest's utilities where possible
Keep module mocks contained - do not use global mutable state within test files, usevi.hoisted()if necessary
For Component testing, use Vue Test Utils and follow advice about making components easy to test
Aim for behavioral coverage of critical and new features
Files:
tests-ui/tests/composables/useLoad3d.test.ts
🧠 Learnings (41)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
src/schemas/apiSchema.tssrc/services/load3dService.tsvitest.setup.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/LoaderManager.tssrc/scripts/metadata/ply.tstests-ui/tests/composables/useLoad3d.test.tssrc/extensions/core/load3d/SceneModelManager.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/schemas/apiSchema.tssrc/services/load3dService.tsvitest.setup.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/LoaderManager.tssrc/scripts/metadata/ply.tstests-ui/tests/composables/useLoad3d.test.tssrc/extensions/core/load3d/SceneModelManager.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/schemas/apiSchema.tssrc/services/load3dService.tsvitest.setup.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/LoaderManager.tssrc/scripts/metadata/ply.tstests-ui/tests/composables/useLoad3d.test.tssrc/extensions/core/load3d/SceneModelManager.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/schemas/apiSchema.tssrc/services/load3dService.tssrc/components/load3d/Load3DControls.vuevitest.setup.tssrc/composables/useLoad3d.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/extensions/core/load3d.tssrc/components/load3d/controls/ModelControls.vuesrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/LoaderManager.tssrc/scripts/metadata/ply.tssrc/components/load3d/Load3D.vuetests-ui/tests/composables/useLoad3d.test.tssrc/extensions/core/load3d/SceneModelManager.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - prefer `useModel` to prop/emit pairs, do not use `withDefaults`
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Define proper props and emits definitions in Vue components
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use vue 3.5 style of default prop declaration
Applied to files:
src/components/load3d/Load3DControls.vue
📚 Learning: 2025-12-18T20:39:25.533Z
Learnt from: jtydhr88
Repo: Comfy-Org/ComfyUI_frontend PR: 7621
File: src/components/load3d/Load3DScene.vue:4-4
Timestamp: 2025-12-18T20:39:25.533Z
Learning: In src/components/load3d/Load3DScene.vue, the scoped `<style>` block with `!important` declarations for the canvas element is necessary because Three.js dynamically creates the canvas with inline styles, preventing direct application of Tailwind classes. This is a valid exception to the Tailwind-only styling guideline.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Implement proper props and emits definitions in Vue components
Applied to files:
src/components/load3d/Load3DControls.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : For mocking, leverage Vitest's utilities where possible
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Keep module mocks contained - do not use global mutable state within test files, use `vi.hoisted()` if necessary
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`
Applied to files:
vitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : For Component testing, use Vue Test Utils and follow advice about making components easy to test
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Take advantage of `TypedArray` `subarray` when appropriate
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Avoid new usage of PrimeVue components
Applied to files:
package.jsonpnpm-workspace.yaml
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue TabMenu component with Tabs without panels
Applied to files:
package.json
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `as any` type assertions - fix the underlying type issue
Applied to files:
src/extensions/core/load3d/LoaderManager.ts
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.
Applied to files:
src/locales/en/main.json
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Destructure props using Vue 3.5 style in Vue components
Applied to files:
src/components/load3d/Load3D.vue
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Aim for behavioral coverage of critical and new features
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Be parsimonious in testing - do not write redundant tests
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
🧬 Code graph analysis (4)
src/composables/useLoad3d.ts (1)
src/extensions/core/load3d/Load3d.ts (2)
isSplatModel(574-576)isPlyModel(578-580)
src/extensions/core/load3d/loader/FastPLYLoader.ts (1)
src/scripts/metadata/ply.ts (1)
parseASCIIPLY(137-145)
src/extensions/core/load3d/LoaderManager.ts (3)
src/extensions/core/load3d/loader/FastPLYLoader.ts (1)
FastPLYLoader(10-33)src/platform/settings/settingStore.ts (1)
useSettingStore(46-252)src/scripts/metadata/ply.ts (1)
isPLYAsciiFormat(150-153)
src/extensions/core/load3d/SceneModelManager.ts (2)
src/extensions/core/load3d/interfaces.ts (1)
MaterialMode(10-15)src/extensions/core/load3d/Load3d.ts (1)
isSplatModel(574-576)
🪛 Biome (2.1.2)
src/extensions/core/load3d/LoaderManager.ts
[error] 207-207: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 208-208: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 210-210: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: lint-and-format
- GitHub Check: setup
- GitHub Check: collect
- GitHub Check: test
🔇 Additional comments (25)
package.json (1)
150-150: LGTM - Correctly references workspace catalog.The addition of
"@sparkjsdev/spark": "catalog:"correctly references the catalog entry defined inpnpm-workspace.yamlline 30, following the established pattern for workspace dependencies.Note: The version verification comment on
pnpm-workspace.yamlalso applies here.src/locales/en/main.json (1)
1638-1638: LGTM - Addresses previous naming feedback.The
"pointCloud": "Point Cloud"entry uses a consistent, lowercase key that aligns with the naming pattern of other material modes. This addresses the previous review comment that suggested using "pointCloud" instead of "original(Advanced)".vitest.setup.ts (1)
4-9: LGTM - Appropriate mock for WASM-dependent library.The mock for
@sparkjsdev/sparkwith an emptySplatMeshconstructor is appropriate for the unit test environment where WASM is not available. This allows the module to be imported and basic type checking to work without requiring the full WASM runtime.Based on learnings, this follows the repository's testing guidelines to mock external dependencies and keep module mocks contained.
src/extensions/core/load3d.ts (2)
202-212: LGTM - Well-structured setting with clear documentation.The new
Comfy.Load3D.PLYEnginesetting is well-designed:
- Clear tooltip explaining the three engine options
- Appropriate default value (
threejs) for backward compatibility- Correctly marked as experimental
- Consistent category structure
The setting properly aligns with the new PLY/splat support introduced in this PR and matches the schema definition in
src/schemas/apiSchema.tsline 511.
252-255: Extension list is correct; clarify that splat formats are not handled by all three PLY engines.The listed extensions (.ply, .spz, .splat, .ksplat) are accurate and complete—no missing standard formats like
.gsor.gsplatexist. However, the premise about engine support needs correction:
.spz,.splat, and.ksplatare handled exclusively by thesparkjsengine (SplatMesh from @sparkjsdev/spark)threejs(THREE.js PLYLoader) handles only standard.plyfilesfastply(FastPLYLoader) handles only ASCII.plyfilesThese are not interchangeable engines; they serve different purposes and do not all support the same formats.
Likely an incorrect or invalid review comment.
src/schemas/apiSchema.ts (1)
511-511: LGTM - Schema definition matches extension setting.The
'Comfy.Load3D.PLYEngine'entry correctly matches the extension setting definition insrc/extensions/core/load3d.tslines 202-212:
- Enum values are identical:
['threejs', 'fastply', 'sparkjs']- Positioned logically with other Load3D settings
- Uses Zod v3
z.enumsyntaxAs per coding guidelines, this properly expands the exported
Settingstype viaz.infer<typeof zSettings>.pnpm-workspace.yaml (1)
30-30: The addition of@sparkjsdev/sparkat version^0.1.10is valid. Version 0.1.10 is the current documented version and the package properly includes WebAssembly components in its build.src/components/load3d/Load3DControls.vue (1)
90-116: LGTM! Props and computed logic are correctly implemented.The Vue 3.5 style prop destructuring with defaults is correct, and the
availableCategoriescomputed properly filters out the 'light' category for splat models since 3DGS handles its own lighting internally.src/extensions/core/load3d/interfaces.ts (2)
10-15: LGTM! MaterialMode type extended correctly.The new
'pointCloud'mode is properly added to the union type for PLY point cloud rendering support.
189-199: LGTM! Supported extensions properly extended.The new file extensions (
.spz,.splat,.ply,.ksplat) are correctly added for PLY and Gaussian splatting format support.src/composables/useLoad3d.ts (1)
66-67: LGTM! New reactive flags properly declared and exposed.The
isSplatModelandisPlyModelrefs are correctly initialized and exposed in the composable's return object, enabling downstream components to reactively respond to model type changes.Also applies to: 568-569
src/components/load3d/controls/ModelControls.vue (3)
74-77: LGTM! Props correctly defined with Vue 3.5 style.The
hideMaterialModeandisPlyModelprops are properly declared with default values using Vue 3.5 style reactive destructuring.
95-109: LGTM! Conditional pointCloud mode insertion is correct.The computed property correctly inserts
'pointCloud'mode at index 1 (after 'original') only whenisPlyModelis true, providing the appropriate UI options for PLY file rendering.
31-60: LGTM! Conditional rendering for material mode section.The
v-if="!hideMaterialMode"correctly hides the material mode controls for splat models, which handle their own rendering internally.src/extensions/core/load3d/Load3d.ts (1)
574-580: LGTM! Model type detection methods correctly implemented.Both
isSplatModel()andisPlyModel()are properly implemented:
isSplatModel()delegates to the model manager'scontainsSplatMesh()methodisPlyModel()correctly identifies PLY models by checking iforiginalModelis an instance ofTHREE.BufferGeometrysrc/components/load3d/Load3D.vue (1)
25-26: LGTM! Props correctly bound and destructured.The
isSplatModelandisPlyModelrefs are properly destructured fromuseLoad3dand correctly bound toLoad3DControlsusing kebab-case prop syntax.Also applies to: 114-115
src/extensions/core/load3d/SceneModelManager.ts (4)
1-1: LGTM! SplatMesh import for 3DGS support.The
SplatMeshimport from@sparkjsdev/sparkenables 3D Gaussian Splatting model detection and handling.
102-239: Well-structured PLY mode switching logic.The
handlePLYModeSwitchmethod correctly handles the complexity of switching betweenpointCloud(THREE.Points) and mesh-based (THREE.Mesh) rendering modes for PLY geometries. The method properly:
- Clones the original geometry to preserve it
- Handles vertex colors when present
- Centers and scales point cloud geometry
- Applies appropriate materials per mode
One consideration from a past review: add defensive validation for the geometry before cloning to handle potentially malformed PLY data.
427-440: LGTM! SplatMesh models correctly bypass standard setup.The early return for SplatMesh-containing models is appropriate since 3DGS models handle their own rendering internally and don't need standard mesh fitting, material setup, or camera positioning calculations.
334-351: ThepointCloudcase fallthrough is correct and safe for the code architecture.The UI properly restricts
pointCloudmode to PLY models only (via theisPlyModelprop check in ModelControls.vue). For PLY models, the code entershandlePLYModeSwitch(line 250 check:instanceof THREE.BufferGeometry), which recreates the geometry as a THREE.Points object. For non-PLY models,handlePLYModeSwitchguards against execution and the normal switch/case logic applies, where thepointCloudcase falls through tooriginal, gracefully restoring the original material. This design is intentional and prevents runtime errors.src/scripts/metadata/ply.ts (2)
137-145: LGTM with a note on large file handling.The implementation decodes the entire buffer to a string and splits it into lines, which is straightforward but could be memory-intensive for very large ASCII PLY files. For the current use case this appears acceptable, especially since binary PLY files would use the standard Three.js loader.
If large ASCII PLY files become common, consider implementing streaming/chunked parsing. For now, verify the expected file sizes in your use cases.
150-153: Simple and effective format detection.Checking the first 500 bytes for the "format ascii" substring is a practical heuristic for PLY format detection. While theoretically this could match content in comments or data, PLY headers are well-structured and this should work reliably in practice.
src/extensions/core/load3d/LoaderManager.ts (3)
239-252: Well-structured engine selection logic.The format detection using
isPLYAsciiFormatcombined with the engine setting provides appropriate fallback behavior. The FastPLYLoader is only used for ASCII files when explicitly configured, with a sensible fallback to the standard Three.js PLYLoader.
257-281: Point cloud normalization and material setup looks good.The centering and scaling logic using the bounding sphere is appropriate for normalizing point clouds. The conditional material creation based on vertex color availability is well-handled.
294-315: Mesh rendering path is well-implemented.The mesh mode correctly handles vertex colors when available and falls back to cloning the standard material. Setting
DoubleSidefor PLY meshes is appropriate to avoid backface culling issues common with mesh-based point cloud data.
bed0d3f to
5e2ec32
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (13)
src/composables/useLoad3d.ts (1)
492-497: Reset model type flags at load start to prevent stale state.If a splat/PLY model loads successfully and then a subsequent model load fails,
isSplatModelandisPlyModelretain their previous values. Consider resetting both flags inmodelLoadingStartto ensure UI consistency.🔎 Suggested fix:
modelLoadingStart: () => { loadingMessage.value = t('load3d.loadingModel') loading.value = true + isSplatModel.value = false + isPlyModel.value = false },tests-ui/tests/composables/useLoad3d.test.ts (1)
108-109: Consider adding test coverage for splat and PLY model scenarios.The mocks currently return
falsefor bothisSplatModelandisPlyModel, which tests only the non-splat/non-PLY path. Consider adding test cases that verify behavior when these returntrueto ensure complete coverage.Example scenarios:
- Verify that
isSplatModelandisPlyModelflags are correctly populated in the composable's return value when models are loaded- Test that UI-related logic (e.g., material mode options) adjusts based on these flags
Based on learnings: Write tests for all changes, especially new features.
src/extensions/core/load3d/loader/FastPLYLoader.ts (1)
11-16: LGTM: Clean delegation to shared PLY parser.The FastPLYLoader correctly delegates parsing to
parseASCIIPLYfrom the metadata module, which addresses previous concerns about parsing logic separation.Optionally, consider making the error message more descriptive to aid debugging:
if (!plyData) { - throw new Error('Failed to parse PLY data') + throw new Error('Failed to parse PLY data: invalid format or missing required properties (x, y, z)') }src/services/load3dService.ts (1)
78-82: Silent no-op when splat model lacks originalURL.When
source.isSplatModel()is true butoriginalURLis missing, the function silently skips copying the model entirely without any warning. This could lead to confusing behavior where a user expects model state to be copied but nothing happens.This was flagged in a previous review. Consider adding a warning log:
🔎 Suggested enhancement
if (source.isSplatModel()) { const originalURL = source.modelManager.originalURL if (originalURL) { await target.loadModel(originalURL) + } else { + console.warn('Cannot copy splat model: originalURL is missing') } } else {src/scripts/metadata/ply.ts (2)
26-42: Missing PLY magic string validation and bounds checking.The parser doesn't validate that the file starts with the PLY magic string "ply", and line 42 accesses
line.split(/\s+/)[2]without verifying the array has at least 3 elements. If a malformed header containselement vertexwithout a count,parseInt(undefined)returnsNaN.These issues were flagged in previous reviews.
🔎 Suggested fixes
function parsePLYHeader(lines: string[]): PLYHeader | null { + // Validate PLY magic string + if (lines.length === 0 || lines[0].trim() !== 'ply') { + return null + } + let vertexCount = 0 let headerEndLine = 0 // ... existing code ... if (line.startsWith('element vertex')) { - vertexCount = parseInt(line.split(/\s+/)[2]) + const parts = line.split(/\s+/) + if (parts.length >= 3) { + vertexCount = parseInt(parts[2]) + } }
105-107: Missing NaN validation for parsed vertex positions.
parseFloatcan returnNaNfor malformed data, which would populate thepositionsarray with invalid values and potentially create corrupt geometry downstream.This was flagged in a previous review.
🔎 Suggested fix
const posIndex = vertexIndex * 3 - positions[posIndex] = parseFloat(parts[xIndex]) - positions[posIndex + 1] = parseFloat(parts[yIndex]) - positions[posIndex + 2] = parseFloat(parts[zIndex]) + const x = parseFloat(parts[xIndex]) + const y = parseFloat(parts[yIndex]) + const z = parseFloat(parts[zIndex]) + + if (Number.isNaN(x) || Number.isNaN(y) || Number.isNaN(z)) { + continue // Skip malformed vertex + } + + positions[posIndex] = x + positions[posIndex + 1] = y + positions[posIndex + 2] = zsrc/extensions/core/load3d/SceneModelManager.ts (3)
102-107: Add defensive validation before cloning PLY geometry.The
clone()call on line 107 could fail iforiginalModelis a malformed or corrupted BufferGeometry. Consider validating that the geometry has the required position attribute before attempting to clone.This was flagged in a previous review.
🔎 Suggested fix
private handlePLYModeSwitch(mode: MaterialMode): void { if (!(this.originalModel instanceof THREE.BufferGeometry)) { return } + + if (!this.originalModel.attributes.position) { + console.error('Invalid PLY geometry: missing position attribute') + return + } const plyGeometry = this.originalModel.clone()
471-480:containsSplatMeshcontinues traversal after finding a match.Once
foundis set totrue, the traversal continues unnecessarily through the entire scene graph. For models with large hierarchies, this is inefficient.This was flagged in a previous review.
🔎 Suggested optimization using early-exit recursion
containsSplatMesh(model?: THREE.Object3D | null): boolean { const target = model ?? this.currentModel if (!target) return false if (target instanceof SplatMesh) return true - let found = false - target.traverse((child) => { - if (child instanceof SplatMesh) found = true - }) - return found + // Use recursive helper that can short-circuit + function checkChildren(obj: THREE.Object3D): boolean { + for (const child of obj.children) { + if (child instanceof SplatMesh) return true + if (checkChildren(child)) return true + } + return false + } + return checkChildren(target) }
205-212: Redundant "Double check" traversal remains in the code.The comment "Double check: remove any remaining MainModel before adding new one" suggests uncertainty about the first cleanup (lines 111-131). If the first removal works correctly, this second traversal is wasteful. If there's a known race condition or edge case, it should be documented.
🔎 Consider consolidating or documenting
Either remove the redundant check if the first cleanup is reliable:
- // Double check: remove any remaining MainModel before adding new one - const remainingMainModels: THREE.Object3D[] = [] - this.scene.traverse((obj) => { - if (obj.name === 'MainModel') { - remainingMainModels.push(obj) - } - }) - remainingMainModels.forEach((obj) => this.scene.remove(obj)) - this.currentModel = newModel newModel.name = 'MainModel'Or add a comment explaining why the double-check is necessary.
src/extensions/core/load3d/LoaderManager.ts (4)
213-222: Wrap switch case declarations in a block to prevent scope leakage.Biome correctly identifies that
splatUrl,splatMesh, andsplatGroupdeclarations can leak to other switch clauses.This was flagged in a previous review and by static analysis.
🔎 Apply this fix
case 'spz': case 'splat': - case 'ksplat': - const splatUrl = path + encodeURIComponent(filename) - const splatMesh = new SplatMesh({ url: splatUrl }) - this.modelManager.setOriginalModel(splatMesh) - const splatGroup = new THREE.Group() - splatGroup.add(splatMesh) - model = splatGroup - break + case 'ksplat': { + const splatUrl = path + encodeURIComponent(filename) + const splatMesh = new SplatMesh({ url: splatUrl }) + this.modelManager.setOriginalModel(splatMesh) + const splatGroup = new THREE.Group() + splatGroup.add(splatMesh) + model = splatGroup + break + }
232-232: Avoidas stringtype assertion; use nullish coalescing instead.Per coding guidelines, avoid
astype assertions. The setting value could beundefinedor a different type, which this cast would hide.This was flagged in a previous review.
🔎 Suggested safer approach
- const plyEngine = useSettingStore().get('Comfy.Load3D.PLYEngine') as string + const plyEngine = useSettingStore().get('Comfy.Load3D.PLYEngine') ?? 'threejs'
244-246: Missingresponse.okcheck before reading the response body.If the fetch fails with a 4xx/5xx status,
response.arrayBuffer()will still execute but may return an error page or empty data, leading to confusing parsing errors downstream.This was flagged in a previous review.
🔎 Add response validation
// Use Three.js PLYLoader or FastPLYLoader for point cloud PLY files const fullUrl = path + filename const response = await fetch(fullUrl) + if (!response.ok) { + throw new Error(`Failed to load PLY file: ${response.status} ${response.statusText}`) + } const arrayBuffer = await response.arrayBuffer()
293-296: Unsafe type assertionas unknown as THREE.Meshviolates coding guidelines.Per coding guidelines: "Never use
as anytype assertions - fix the underlying type issue." Theas unknown as THREE.Meshpattern is similarly unsafe. The root cause is thatoriginalMaterialsWeakMap is typed forTHREE.Meshbut needs to storeTHREE.Pointsas well.🔎 Fix by widening the WeakMap type in SceneModelManager
In
SceneModelManager.ts, update the type:- originalMaterials: WeakMap<THREE.Mesh, THREE.Material | THREE.Material[]> = + originalMaterials: WeakMap<THREE.Mesh | THREE.Points, THREE.Material | THREE.Material[]> = new WeakMap()Then remove the unsafe cast here:
const plyPoints = new THREE.Points(plyGeometry, pointMaterial) - this.modelManager.originalMaterials.set( - plyPoints as unknown as THREE.Mesh, - pointMaterial - ) + this.modelManager.originalMaterials.set(plyPoints, pointMaterial)
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (22)
package.json(1 hunks)pnpm-workspace.yaml(1 hunks)src/components/load3d/Load3D.vue(2 hunks)src/components/load3d/Load3DControls.vue(3 hunks)src/components/load3d/Load3dViewerContent.vue(2 hunks)src/components/load3d/controls/ModelControls.vue(3 hunks)src/components/load3d/controls/viewer/ViewerModelControls.vue(3 hunks)src/composables/useLoad3d.ts(3 hunks)src/composables/useLoad3dViewer.ts(4 hunks)src/extensions/core/load3d.ts(4 hunks)src/extensions/core/load3d/Load3d.ts(1 hunks)src/extensions/core/load3d/LoaderManager.ts(4 hunks)src/extensions/core/load3d/SceneModelManager.ts(5 hunks)src/extensions/core/load3d/interfaces.ts(2 hunks)src/extensions/core/load3d/loader/FastPLYLoader.ts(1 hunks)src/extensions/core/saveMesh.ts(1 hunks)src/locales/en/main.json(1 hunks)src/schemas/apiSchema.ts(1 hunks)src/scripts/metadata/ply.ts(1 hunks)src/services/load3dService.ts(1 hunks)tests-ui/tests/composables/useLoad3d.test.ts(1 hunks)vitest.setup.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (17)
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
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
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
src/**/*.vue: Vue 3 SFCs must use Composition API only - no Options API
Use<script setup lang="ts">for component logic
Use Tailwind 4 utility classes for styling - avoid<style>blocks
Usecn()utility from@/utils/tailwindUtilto merge Tailwind class names - never use:class="[]"syntax
Never use thedark:Tailwind variant - use semantic values fromstyle.csstheme instead (e.g.,bg-node-component-surface)
Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - preferuseModelto prop/emit pairs, do not usewithDefaults
Do not import Vue macros unnecessarily
Use vue-i18n in composition API for string literals - place translation entries insrc/locales/en/main.json
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Avoid new usage of PrimeVue components
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
src/**/*.{vue,ts}: Avoid usingrefandwatchtogether - usecomputedinstead if possible
Do not addrefif a prop would suffice; do not addcomputedif the ref/prop directly would work; usewatchonly whencomputedwon't accomplish the goal
Leverage VueUse functions for performance-enhancing styles
Files:
src/components/load3d/Load3DControls.vuesrc/extensions/core/saveMesh.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/composables/useLoad3dViewer.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/services/load3dService.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/components/load3d/controls/ModelControls.vue
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
src/**/*.{ts,tsx,vue}: ESLint rules: Vue + TS rules, no floating promises, unused imports disallowed, i18n raw text restrictions in templates
Use es-toolkit for utility functions
Avoid mutable state - prefer immutability and assignment at point of declaration
Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
src/components/load3d/Load3DControls.vuesrc/extensions/core/saveMesh.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/composables/useLoad3dViewer.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/services/load3dService.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/components/load3d/controls/ModelControls.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/composables/useLoad3dViewer.tssrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vue
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/components/load3d/Load3DControls.vuesrc/extensions/core/saveMesh.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/composables/useLoad3dViewer.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/services/load3dService.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/components/load3d/controls/ModelControls.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/composables/useLoad3dViewer.tssrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vue
src/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue componentsVue components must be named in PascalCase (e.g.,
MenuHamburger.vue)
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
src/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
src/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings
Files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
src/**/*.{js,ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively - no new JavaScript files
Files:
src/components/load3d/Load3DControls.vuesrc/extensions/core/saveMesh.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/composables/useLoad3dViewer.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/services/load3dService.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/components/load3d/controls/ModelControls.vue
src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,tsx,vue,js}: Indent with 2 spaces, use single quotes, no trailing semicolons, line width 80 - see.prettierrc
Sort and group imports by plugin, runpnpm formatbefore committing
Files:
src/components/load3d/Load3DControls.vuesrc/extensions/core/saveMesh.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/composables/useLoad3dViewer.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/services/load3dService.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/components/load3d/controls/ModelControls.vue
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
src/**/*.ts: Extract complex type definitions that are inlined in multiple related places - name them for reuse
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones
Files:
src/extensions/core/saveMesh.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/composables/useLoad3dViewer.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/services/load3dService.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.ts
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use function expressions - use function declarations instead when possible
Files:
src/extensions/core/saveMesh.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/composables/useLoad3dViewer.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/services/load3dService.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/composables/useLoad3dViewer.tssrc/composables/useLoad3d.tssrc/services/load3dService.ts
src/composables/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Composables must follow the naming pattern
useXyz.ts
Files:
src/composables/useLoad3dViewer.tssrc/composables/useLoad3d.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)
tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks
Files:
tests-ui/tests/composables/useLoad3d.test.ts
tests-ui/**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
tests-ui/**/*.test.ts: Write tests for all changes, especially bug fixes to catch future regressions
Unit/Component test files must use pattern**/*.test.ts
Do not write change detector tests - do not just assert that defaults are certain values
Do not write tests dependent on non-behavioral features like utility classes or styles
Be parsimonious in testing - do not write redundant tests
Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
For mocking, leverage Vitest's utilities where possible
Keep module mocks contained - do not use global mutable state within test files, usevi.hoisted()if necessary
For Component testing, use Vue Test Utils and follow advice about making components easy to test
Aim for behavioral coverage of critical and new features
Files:
tests-ui/tests/composables/useLoad3d.test.ts
🧠 Learnings (40)
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.
Applied to files:
src/locales/en/main.json
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Avoid new usage of PrimeVue components
Applied to files:
package.jsonpnpm-workspace.yaml
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue TabMenu component with Tabs without panels
Applied to files:
package.json
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - prefer `useModel` to prop/emit pairs, do not use `withDefaults`
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/composables/useLoad3dViewer.tssrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Define proper props and emits definitions in Vue components
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use vue 3.5 style of default prop declaration
Applied to files:
src/components/load3d/Load3DControls.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/extensions/core/saveMesh.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tsvitest.setup.tssrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/composables/useLoad3dViewer.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/services/load3dService.tstests-ui/tests/composables/useLoad3d.test.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.
Applied to files:
src/components/load3d/Load3DControls.vuesrc/components/load3d/Load3dViewerContent.vuesrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vue
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
src/extensions/core/saveMesh.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tsvitest.setup.tssrc/composables/useLoad3dViewer.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/services/load3dService.tstests-ui/tests/composables/useLoad3d.test.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/extensions/core/saveMesh.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tsvitest.setup.tssrc/composables/useLoad3dViewer.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/services/load3dService.tstests-ui/tests/composables/useLoad3d.test.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/extensions/core/saveMesh.tssrc/extensions/core/load3d.tssrc/extensions/core/load3d/interfaces.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tsvitest.setup.tssrc/composables/useLoad3dViewer.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/services/load3dService.tstests-ui/tests/composables/useLoad3d.test.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : For mocking, leverage Vitest's utilities where possible
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Keep module mocks contained - do not use global mutable state within test files, use `vi.hoisted()` if necessary
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup
Applied to files:
vitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`
Applied to files:
vitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : For Component testing, use Vue Test Utils and follow advice about making components easy to test
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-18T20:39:30.137Z
Learnt from: jtydhr88
Repo: Comfy-Org/ComfyUI_frontend PR: 7621
File: src/components/load3d/Load3DScene.vue:4-4
Timestamp: 2025-12-18T20:39:30.137Z
Learning: In src/components/load3d/Load3DScene.vue, the scoped `<style>` block with `!important` declarations for the canvas element is necessary because Three.js dynamically creates the canvas with inline styles, preventing direct application of Tailwind classes. This is a valid exception to the Tailwind-only styling guideline.
Applied to files:
src/components/load3d/Load3dViewerContent.vuesrc/components/load3d/Load3D.vue
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `as any` type assertions - fix the underlying type issue
Applied to files:
src/extensions/core/load3d/LoaderManager.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Take advantage of `TypedArray` `subarray` when appropriate
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Destructure props using Vue 3.5 style in Vue components
Applied to files:
src/components/load3d/Load3D.vue
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Aim for behavioral coverage of critical and new features
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Be parsimonious in testing - do not write redundant tests
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
🧬 Code graph analysis (5)
src/extensions/core/load3d/SceneModelManager.ts (2)
src/extensions/core/load3d/interfaces.ts (1)
MaterialMode(10-15)src/extensions/core/load3d/Load3d.ts (1)
isSplatModel(580-582)
src/composables/useLoad3dViewer.ts (1)
src/extensions/core/load3d/Load3d.ts (2)
isSplatModel(580-582)isPlyModel(584-586)
src/extensions/core/load3d/LoaderManager.ts (3)
src/extensions/core/load3d/interfaces.ts (1)
LoaderManagerInterface(177-187)src/extensions/core/load3d/loader/FastPLYLoader.ts (1)
FastPLYLoader(10-33)src/scripts/metadata/ply.ts (1)
isPLYAsciiFormat(150-153)
src/extensions/core/load3d/loader/FastPLYLoader.ts (1)
src/scripts/metadata/ply.ts (1)
parseASCIIPLY(137-145)
src/composables/useLoad3d.ts (1)
src/extensions/core/load3d/Load3d.ts (2)
isSplatModel(580-582)isPlyModel(584-586)
🪛 Biome (2.1.2)
src/extensions/core/load3d/LoaderManager.ts
[error] 216-216: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 217-217: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 219-219: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: deploy-and-comment
- GitHub Check: collect
- GitHub Check: lint-and-format
- GitHub Check: setup
- GitHub Check: test
5e2ec32 to
775f784
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/extensions/core/load3d/SceneModelManager.ts (1)
334-351: Clarify thepointCloudfallthrough behavior.The
pointCloudcase falls through tooriginal, which works for non-PLY models but may be confusing. Consider adding a comment explaining this is intentional for mesh-based models.case 'original': - case 'pointCloud': + case 'pointCloud': // For non-PLY models, pointCloud behaves like original const originalMaterial = this.originalMaterials.get(child)
♻️ Duplicate comments (13)
src/services/load3dService.ts (2)
78-82: Add error handling for splat models without originalURL.When a splat model lacks an
originalURL, the method silently skips model copying entirely. This can lead to confusing behavior where the copy operation appears to succeed but the model isn't actually loaded.🔎 Recommended enhancement
if (source.isSplatModel()) { const originalURL = source.modelManager.originalURL if (originalURL) { await target.loadModel(originalURL) + } else { + console.warn('Cannot copy splat model: originalURL is missing') } } else {
95-102: Remove redundant property assignments.Lines 95-96 and 98-99 directly assign properties that are then immediately overwritten by setter calls on lines 101-102. The setters likely update the same internal properties, making the direct assignments redundant.
🔎 Proposed refactor
- target.getModelManager().materialMode = - source.getModelManager().materialMode - - target.getModelManager().currentUpDirection = - source.getModelManager().currentUpDirection - target.setMaterialMode(source.getModelManager().materialMode) target.setUpDirection(source.getModelManager().currentUpDirection)If the setters don't update internal state, keep the direct assignments and remove the setter calls instead.
src/composables/useLoad3d.ts (1)
488-497: Consider resetting both flags at the start of model loading.As noted in a previous review, if a splat model loads successfully and then a subsequent non-splat model fails to load,
isSplatModelretains a staletruevalue. The same concern applies toisPlyModel.🔎 Suggested improvement:
modelLoadingStart: () => { loadingMessage.value = t('load3d.loadingModel') loading.value = true + isSplatModel.value = false + isPlyModel.value = false },src/extensions/core/load3d/loader/FastPLYLoader.ts (1)
1-33: LGTM! Clean refactoring addresses previous concerns.The
FastPLYLoaderproperly delegates ASCII PLY parsing to the sharedparseASCIIPLYfunction from the metadata module, which addresses the previous review comment about separating concerns. The geometry construction is straightforward and correct.The error handling is minimal but acceptable, as the underlying
parseASCIIPLYfunction handles detailed validation (header checks, required properties, etc.).tests-ui/tests/composables/useLoad3d.test.ts (1)
108-109: Add test coverage for splat and PLY model scenarios.The mock methods
isSplatModelandisPlyModelalways returnfalse, which only tests the non-splat/non-PLY paths. Consider adding test cases that verify behavior when these methods returntrueto ensure complete coverage of the new model type detection logic.Based on learnings: Write tests for all changes, especially new features. Aim for behavioral coverage of critical and new features.
src/extensions/core/load3d/SceneModelManager.ts (3)
102-107: Add defensive validation before cloning geometry.The
clone()call on line 107 could throw if the geometry is malformed. Consider validating the presence of required attributes first.🔎 Add defensive check:
private handlePLYModeSwitch(mode: MaterialMode): void { if (!(this.originalModel instanceof THREE.BufferGeometry)) { return } + + if (!this.originalModel.attributes.position) { + console.error('Invalid PLY geometry: missing position attribute') + return + } const plyGeometry = this.originalModel.clone()
471-480:containsSplatMeshtraversal doesn't short-circuit.Once
foundis set totrue, traversal continues through the entire scene graph. For large models, consider a manual recursive check that can exit early.🔎 Short-circuiting alternative:
containsSplatMesh(model?: THREE.Object3D | null): boolean { const target = model ?? this.currentModel if (!target) return false if (target instanceof SplatMesh) return true - let found = false - target.traverse((child) => { - if (child instanceof SplatMesh) found = true - }) - return found + function checkChildren(obj: THREE.Object3D): boolean { + for (const child of obj.children) { + if (child instanceof SplatMesh) return true + if (checkChildren(child)) return true + } + return false + } + return checkChildren(target) }
205-212: Redundant "Double check" traversal still present.The scene is traversed twice to remove
MainModelobjects (first at lines 111-131, then again here). The first removal should be sufficient unless there's a specific race condition or re-entrancy concern that warrants documenting.🔎 If the first removal is reliable, remove the redundant check:
- // Double check: remove any remaining MainModel before adding new one - const remainingMainModels: THREE.Object3D[] = [] - this.scene.traverse((obj) => { - if (obj.name === 'MainModel') { - remainingMainModels.push(obj) - } - }) - remainingMainModels.forEach((obj) => this.scene.remove(obj)) - this.currentModel = newModel newModel.name = 'MainModel'If the double-check is actually needed due to a known issue, please add a comment explaining why.
src/scripts/metadata/ply.ts (3)
26-42: Add PLY magic string validation and bounds checking.The parser should validate that the first line is
plyper the PLY specification, and line 42 should verify the split array has sufficient elements before accessing index 2.🔎 Suggested fixes:
function parsePLYHeader(lines: string[]): PLYHeader | null { + // Validate PLY magic string + if (lines.length === 0 || lines[0].trim() !== 'ply') { + return null + } + let vertexCount = 0 let headerEndLine = 0 // ... existing code ... for (let i = 0; i < lines.length; i++) { const line = lines[i].trim() if (line.startsWith('element vertex')) { - vertexCount = parseInt(line.split(/\s+/)[2]) + const parts = line.split(/\s+/) + if (parts.length >= 3) { + vertexCount = parseInt(parts[2]) + } } else if (line.startsWith('property')) {
105-107: Add NaN validation for parsed vertex positions.
parseFloatreturnsNaNfor malformed input, which would corrupt the geometry. Consider validating parsed values.🔎 Suggested fix:
const posIndex = vertexIndex * 3 - positions[posIndex] = parseFloat(parts[xIndex]) - positions[posIndex + 1] = parseFloat(parts[yIndex]) - positions[posIndex + 2] = parseFloat(parts[zIndex]) + const x = parseFloat(parts[xIndex]) + const y = parseFloat(parts[yIndex]) + const z = parseFloat(parts[zIndex]) + + if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z)) { + console.warn(`Invalid vertex data at line ${i}, skipping`) + continue + } + + positions[posIndex] = x + positions[posIndex + 1] = y + positions[posIndex + 2] = z
117-119: Document the uchar color range assumption.The implementation assumes color values are in the 0-255 range (uchar in PLY spec). PLY files can also store colors as floats in 0.0-1.0 range, which would render incorrectly.
Consider adding a comment documenting this limitation, or detecting property types during header parsing:
+ // Note: Assumes uchar (0-255) color values per PLY spec. + // Float-based colors (0.0-1.0) are not currently supported. if (parts.length > Math.max(redIndex, greenIndex, blueIndex)) { colors[posIndex] = parseInt(parts[redIndex]) / 255src/extensions/core/load3d/LoaderManager.ts (2)
251-251: Consider safer setting retrieval.The
as stringcast could hide issues if the setting returnsundefined. Per coding guidelines, prefer proper TypeScript types over assertions.🔎 Suggested safer approach:
- const plyEngine = useSettingStore().get('Comfy.Load3D.PLYEngine') as string + const plyEngine = useSettingStore().get('Comfy.Load3D.PLYEngine') ?? 'threejs'
305-308: Type assertion issue withoriginalMaterialsWeakMap.The
as unknown as THREE.Meshcast is needed becauseoriginalMaterialsis typed forTHREE.Meshbut storesTHREE.Points. Consider widening the type definition inSceneModelManager.The proper fix is to update the
originalMaterialstype in SceneModelManager:originalMaterials: WeakMap<THREE.Mesh | THREE.Points, THREE.Material | THREE.Material[]>Then remove this cast.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (24)
package.json(1 hunks)pnpm-workspace.yaml(1 hunks)src/components/load3d/Load3D.vue(2 hunks)src/components/load3d/Load3DControls.vue(3 hunks)src/components/load3d/Load3dViewerContent.vue(2 hunks)src/components/load3d/controls/ModelControls.vue(3 hunks)src/components/load3d/controls/viewer/ViewerModelControls.vue(3 hunks)src/composables/useLoad3d.ts(3 hunks)src/composables/useLoad3dViewer.ts(4 hunks)src/extensions/core/load3d.ts(4 hunks)src/extensions/core/load3d/Load3d.ts(1 hunks)src/extensions/core/load3d/LoaderManager.ts(4 hunks)src/extensions/core/load3d/SceneModelManager.ts(5 hunks)src/extensions/core/load3d/interfaces.ts(2 hunks)src/extensions/core/load3d/loader/FastPLYLoader.ts(1 hunks)src/extensions/core/saveMesh.ts(1 hunks)src/locales/en/main.json(1 hunks)src/schemas/apiSchema.ts(1 hunks)src/scripts/metadata/ply.ts(1 hunks)src/services/load3dService.ts(1 hunks)tests-ui/tests/composables/useLoad3d.test.ts(1 hunks)tests-ui/tests/scripts/metadata/ply.test.ts(1 hunks)vite.config.mts(1 hunks)vitest.setup.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (17)
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
src/**/*.{vue,ts}: Avoid usingrefandwatchtogether - usecomputedinstead if possible
Do not addrefif a prop would suffice; do not addcomputedif the ref/prop directly would work; usewatchonly whencomputedwon't accomplish the goal
Leverage VueUse functions for performance-enhancing styles
Files:
src/extensions/core/saveMesh.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d.tssrc/composables/useLoad3dViewer.tssrc/services/load3dService.tssrc/components/load3d/Load3dViewerContent.vue
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
src/**/*.ts: Extract complex type definitions that are inlined in multiple related places - name them for reuse
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones
Files:
src/extensions/core/saveMesh.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d.tssrc/composables/useLoad3dViewer.tssrc/services/load3dService.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
src/**/*.{ts,tsx,vue}: ESLint rules: Vue + TS rules, no floating promises, unused imports disallowed, i18n raw text restrictions in templates
Use es-toolkit for utility functions
Avoid mutable state - prefer immutability and assignment at point of declaration
Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
src/extensions/core/saveMesh.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d.tssrc/composables/useLoad3dViewer.tssrc/services/load3dService.tssrc/components/load3d/Load3dViewerContent.vue
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/extensions/core/saveMesh.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d.tssrc/composables/useLoad3dViewer.tssrc/services/load3dService.tssrc/components/load3d/Load3dViewerContent.vue
src/**/*.{js,ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively - no new JavaScript files
Files:
src/extensions/core/saveMesh.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d.tssrc/composables/useLoad3dViewer.tssrc/services/load3dService.tssrc/components/load3d/Load3dViewerContent.vue
src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,tsx,vue,js}: Indent with 2 spaces, use single quotes, no trailing semicolons, line width 80 - see.prettierrc
Sort and group imports by plugin, runpnpm formatbefore committing
Files:
src/extensions/core/saveMesh.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d.tssrc/composables/useLoad3dViewer.tssrc/services/load3dService.tssrc/components/load3d/Load3dViewerContent.vue
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use function expressions - use function declarations instead when possible
Files:
src/extensions/core/saveMesh.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d.tssrc/composables/useLoad3dViewer.tssrc/services/load3dService.ts
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
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
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
src/**/*.vue: Vue 3 SFCs must use Composition API only - no Options API
Use<script setup lang="ts">for component logic
Use Tailwind 4 utility classes for styling - avoid<style>blocks
Usecn()utility from@/utils/tailwindUtilto merge Tailwind class names - never use:class="[]"syntax
Never use thedark:Tailwind variant - use semantic values fromstyle.csstheme instead (e.g.,bg-node-component-surface)
Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - preferuseModelto prop/emit pairs, do not usewithDefaults
Do not import Vue macros unnecessarily
Use vue-i18n in composition API for string literals - place translation entries insrc/locales/en/main.json
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Avoid new usage of PrimeVue components
Files:
src/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3dViewerContent.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/composables/useLoad3dViewer.tssrc/components/load3d/Load3dViewerContent.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tssrc/components/load3d/controls/ModelControls.vuesrc/composables/useLoad3dViewer.tssrc/components/load3d/Load3dViewerContent.vue
src/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue componentsVue components must be named in PascalCase (e.g.,
MenuHamburger.vue)
Files:
src/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3dViewerContent.vue
src/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package
Files:
src/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3dViewerContent.vue
src/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings
Files:
src/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3dViewerContent.vue
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/composables/useLoad3d.tssrc/composables/useLoad3dViewer.tssrc/services/load3dService.ts
src/composables/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Composables must follow the naming pattern
useXyz.ts
Files:
src/composables/useLoad3d.tssrc/composables/useLoad3dViewer.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)
tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks
Files:
tests-ui/tests/scripts/metadata/ply.test.tstests-ui/tests/composables/useLoad3d.test.ts
tests-ui/**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
tests-ui/**/*.test.ts: Write tests for all changes, especially bug fixes to catch future regressions
Unit/Component test files must use pattern**/*.test.ts
Do not write change detector tests - do not just assert that defaults are certain values
Do not write tests dependent on non-behavioral features like utility classes or styles
Be parsimonious in testing - do not write redundant tests
Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
For mocking, leverage Vitest's utilities where possible
Keep module mocks contained - do not use global mutable state within test files, usevi.hoisted()if necessary
For Component testing, use Vue Test Utils and follow advice about making components easy to test
Aim for behavioral coverage of critical and new features
Files:
tests-ui/tests/scripts/metadata/ply.test.tstests-ui/tests/composables/useLoad3d.test.ts
🧠 Learnings (42)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
src/extensions/core/saveMesh.tsvitest.setup.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tstests-ui/tests/scripts/metadata/ply.test.tstests-ui/tests/composables/useLoad3d.test.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d.tssrc/composables/useLoad3dViewer.tssrc/services/load3dService.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/extensions/core/saveMesh.tsvitest.setup.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tstests-ui/tests/scripts/metadata/ply.test.tstests-ui/tests/composables/useLoad3d.test.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d.tssrc/composables/useLoad3dViewer.tssrc/services/load3dService.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/extensions/core/saveMesh.tsvitest.setup.tssrc/extensions/core/load3d/interfaces.tssrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/composables/useLoad3d.tstests-ui/tests/scripts/metadata/ply.test.tstests-ui/tests/composables/useLoad3d.test.tssrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d.tssrc/composables/useLoad3dViewer.tssrc/services/load3dService.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/extensions/core/saveMesh.tsvitest.setup.tssrc/extensions/core/load3d/interfaces.tssrc/components/load3d/controls/viewer/ViewerModelControls.vuesrc/extensions/core/load3d/loader/FastPLYLoader.tssrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/composables/useLoad3d.tstests-ui/tests/scripts/metadata/ply.test.tstests-ui/tests/composables/useLoad3d.test.tssrc/components/load3d/controls/ModelControls.vuesrc/schemas/apiSchema.tssrc/extensions/core/load3d/SceneModelManager.tssrc/scripts/metadata/ply.tssrc/extensions/core/load3d/Load3d.tssrc/extensions/core/load3d/LoaderManager.tssrc/extensions/core/load3d.tssrc/composables/useLoad3dViewer.tssrc/services/load3dService.tssrc/components/load3d/Load3dViewerContent.vue
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : For mocking, leverage Vitest's utilities where possible
Applied to files:
vitest.setup.tstests-ui/tests/scripts/metadata/ply.test.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Keep module mocks contained - do not use global mutable state within test files, use `vi.hoisted()` if necessary
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project
Applied to files:
vitest.setup.tstests-ui/tests/scripts/metadata/ply.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
Applied to files:
vitest.setup.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`
Applied to files:
vitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Do not write tests dependent on non-behavioral features like utility classes or styles
Applied to files:
vitest.setup.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : For Component testing, use Vue Test Utils and follow advice about making components easy to test
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest
Applied to files:
vitest.setup.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor
Applied to files:
vitest.setup.tstests-ui/tests/scripts/metadata/ply.test.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features
Applied to files:
vitest.setup.tstests-ui/tests/scripts/metadata/ply.test.tstests-ui/tests/composables/useLoad3d.test.tssrc/scripts/metadata/ply.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - prefer `useModel` to prop/emit pairs, do not use `withDefaults`
Applied to files:
src/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vuesrc/composables/useLoad3dViewer.tssrc/components/load3d/Load3dViewerContent.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3dViewerContent.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.
Applied to files:
src/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3dViewerContent.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3dViewerContent.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3dViewerContent.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.
Applied to files:
src/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3dViewerContent.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.
Applied to files:
src/components/load3d/controls/viewer/ViewerModelControls.vuesrc/components/load3d/Load3DControls.vuesrc/components/load3d/Load3D.vuesrc/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3dViewerContent.vue
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Take advantage of `TypedArray` `subarray` when appropriate
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred
Applied to files:
src/extensions/core/load3d/loader/FastPLYLoader.tssrc/services/load3dService.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Define proper props and emits definitions in Vue components
Applied to files:
src/components/load3d/Load3DControls.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Destructure props using Vue 3.5 style in Vue components
Applied to files:
src/components/load3d/Load3D.vue
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions
Applied to files:
tests-ui/tests/scripts/metadata/ply.test.tstests-ui/tests/composables/useLoad3d.test.tssrc/scripts/metadata/ply.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Aim for behavioral coverage of critical and new features
Applied to files:
tests-ui/tests/scripts/metadata/ply.test.tstests-ui/tests/composables/useLoad3d.test.tssrc/scripts/metadata/ply.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.
Applied to files:
tests-ui/tests/scripts/metadata/ply.test.tstests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines
Applied to files:
tests-ui/tests/composables/useLoad3d.test.tssrc/scripts/metadata/ply.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase
Applied to files:
tests-ui/tests/composables/useLoad3d.test.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to tests-ui/**/*.test.ts : Be parsimonious in testing - do not write redundant tests
Applied to files:
tests-ui/tests/composables/useLoad3d.test.tssrc/scripts/metadata/ply.ts
📚 Learning: 2025-12-18T20:39:30.137Z
Learnt from: jtydhr88
Repo: Comfy-Org/ComfyUI_frontend PR: 7621
File: src/components/load3d/Load3DScene.vue:4-4
Timestamp: 2025-12-18T20:39:30.137Z
Learning: In src/components/load3d/Load3DScene.vue, the scoped `<style>` block with `!important` declarations for the canvas element is necessary because Three.js dynamically creates the canvas with inline styles, preventing direct application of Tailwind classes. This is a valid exception to the Tailwind-only styling guideline.
Applied to files:
src/components/load3d/controls/ModelControls.vuesrc/components/load3d/Load3dViewerContent.vue
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.
Applied to files:
src/locales/en/main.json
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Create browser tests as appropriate after code changes
Applied to files:
src/scripts/metadata/ply.ts
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.vue : Avoid new usage of PrimeVue components
Applied to files:
package.jsonpnpm-workspace.yaml
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue TabMenu component with Tabs without panels
Applied to files:
package.json
📚 Learning: 2025-12-17T01:01:03.609Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.609Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `as any` type assertions - fix the underlying type issue
Applied to files:
src/extensions/core/load3d/LoaderManager.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{services,composables}/**/*.{ts,tsx} : Use `api.apiURL()` for backend endpoints instead of constructing URLs directly
Applied to files:
src/extensions/core/load3d/LoaderManager.ts
🧬 Code graph analysis (6)
src/extensions/core/load3d/loader/FastPLYLoader.ts (1)
src/scripts/metadata/ply.ts (1)
parseASCIIPLY(137-145)
src/composables/useLoad3d.ts (1)
src/extensions/core/load3d/Load3d.ts (2)
isSplatModel(580-582)isPlyModel(584-586)
tests-ui/tests/scripts/metadata/ply.test.ts (1)
src/scripts/metadata/ply.ts (2)
isPLYAsciiFormat(150-153)parseASCIIPLY(137-145)
src/extensions/core/load3d/SceneModelManager.ts (2)
src/extensions/core/load3d/interfaces.ts (1)
MaterialMode(10-15)src/extensions/core/load3d/Load3d.ts (1)
isSplatModel(580-582)
src/extensions/core/load3d/LoaderManager.ts (4)
src/extensions/core/load3d/loader/FastPLYLoader.ts (1)
FastPLYLoader(10-33)src/scripts/api.ts (1)
api(1306-1306)src/platform/settings/settingStore.ts (1)
useSettingStore(46-252)src/scripts/metadata/ply.ts (1)
isPLYAsciiFormat(150-153)
src/composables/useLoad3dViewer.ts (1)
src/extensions/core/load3d/Load3d.ts (2)
isSplatModel(580-582)isPlyModel(584-586)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: setup
- GitHub Check: test
- GitHub Check: lint-and-format
- GitHub Check: collect
## Summary integrated sparkjs https://sparkjs.dev/, built by [world labs ](https://www.worldlabs.ai/) to support 3dgs. - Add 3D Gaussian Splatting (3DGS) support using @sparkjsdev/spark library - Add PLY file format support with multiple rendering engines - Support new file formats: `.ply`, `.spz`, `.splat`, `.ksplat` - Add PLY Engine setting with three options: `threejs` (mesh), `fastply` (optimized ASCII point clouds), `sparkjs` (3DGS) - Add `FastPLYLoader` for 4-5x faster ASCII PLY parsing - Add `original(Advanced)` material mode for point cloud rendering with THREE.Points 3dgs generated by https://marble.worldlabs.ai/ test ply file from: 1. made by https://github.com/PozzettiAndrea/ComfyUI-DepthAnythingV3 2. threejs offically repo ## Screenshots https://github.com/user-attachments/assets/44e64d3e-b58d-4341-9a70-a9aa64801220 https://github.com/user-attachments/assets/76b0dfba-0c12-4f64-91cb-bfc5d672294d https://github.com/user-attachments/assets/2a8bfe81-1fb2-44c4-8787-dff325369c61 https://github.com/user-attachments/assets/e4beecee-d7a2-40c9-97f7-79b09c60312d ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7602-3dgs-ply-support-2cd6d73d3650814098fcea86cfaf747d) by [Unito](https://www.unito.io)
Summary
integrated sparkjs https://sparkjs.dev/, built by world labs to support 3dgs.
.ply,.spz,.splat,.ksplatthreejs(mesh),fastply(optimized ASCII point clouds),sparkjs(3DGS)FastPLYLoaderfor 4-5x faster ASCII PLY parsingoriginal(Advanced)material mode for point cloud rendering with THREE.Points3dgs generated by https://marble.worldlabs.ai/
test ply file from:
Screenshots
2025-12-17.20-53-48.mp4
2025-12-17.20-54-45.mp4
2025-12-17.20-55-33.mp4
2025-12-17.20-56-28.mp4
┆Issue is synchronized with this Notion page by Unito