mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-05 13:41:59 +00:00
## Summary Add Gizmo transform controls to load3d - Remove automatic model normalization (scale + center) on load; models now appear at their original transform. The previous auto-normalization conflicted with gizmo controls — applying scale/position on load made it impossible to track and reset the user's intentional transform edits vs. the system's normalization - Add a manual Fit to Viewer button that performs the same normalization on demand, giving users explicit control - Add Gizmo Controls (translate/rotate) for interactive model manipulation with full state persistence across node properties, viewer dialog, and model reloads - Gizmo transform state is excluded from scene capture and recording to keep outputs clean ## Motivation The gizmo system is a prerequisite for these potential features: - Custom cameras — user-placed cameras in the scene need transform gizmos for precise positioning and orientation - Custom lights — scene lighting setup requires the ability to interactively position and aim light sources - Multi-object scene composition — positioning multiple models relative to each other requires per-object transform controls - Pose editor — skeletal pose editing depends on the same transform infrastructure to manipulate individual bones/joints Auto-normalization was removed because it silently mutated model transforms on load, making it impossible to distinguish between the original model pose and user edits. This broke gizmo reset (which needs to know the "clean" state) and would corrupt round-trip transform persistence. ## Screenshots (if applicable) https://github.com/user-attachments/assets/621ea559-d7c8-4c5a-a727-98e6a4130b66 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11274-gizmo-controls-3436d73d365081c38357c2d58e49c558) by [Unito](https://www.unito.io)
79 lines
2.0 KiB
TypeScript
79 lines
2.0 KiB
TypeScript
import { expect } from '@playwright/test'
|
|
import type { Locator } from '@playwright/test'
|
|
|
|
import { TestIds } from '@e2e/fixtures/selectors'
|
|
|
|
export class Load3DHelper {
|
|
constructor(readonly node: Locator) {}
|
|
|
|
get canvas(): Locator {
|
|
return this.node.locator('canvas')
|
|
}
|
|
|
|
get menuButton(): Locator {
|
|
return this.node.getByRole('button', { name: /show menu/i })
|
|
}
|
|
|
|
get recordingButton(): Locator {
|
|
return this.node.getByRole('button', { name: /start recording/i })
|
|
}
|
|
|
|
get colorInput(): Locator {
|
|
return this.node.locator('input[type="color"]')
|
|
}
|
|
|
|
get openViewerButton(): Locator {
|
|
return this.node.getByRole('button', { name: /open in 3d viewer/i })
|
|
}
|
|
|
|
getUploadButton(label: string): Locator {
|
|
return this.node.getByText(label)
|
|
}
|
|
|
|
getMenuCategory(name: string): Locator {
|
|
return this.node.getByText(name, { exact: true })
|
|
}
|
|
|
|
get gizmoToggleButton(): Locator {
|
|
return this.node.getByRole('button', { name: 'Gizmo' })
|
|
}
|
|
|
|
get gizmoTranslateButton(): Locator {
|
|
return this.node.getByRole('button', { name: 'Translate' })
|
|
}
|
|
|
|
get gizmoRotateButton(): Locator {
|
|
return this.node.getByRole('button', { name: 'Rotate' })
|
|
}
|
|
|
|
get gizmoScaleButton(): Locator {
|
|
return this.node.getByRole('button', { name: 'Scale' })
|
|
}
|
|
|
|
get gizmoResetButton(): Locator {
|
|
return this.node.getByRole('button', { name: 'Reset Transform' })
|
|
}
|
|
|
|
async openMenu(): Promise<void> {
|
|
await this.menuButton.click()
|
|
}
|
|
|
|
async openGizmoCategory(): Promise<void> {
|
|
await this.openMenu()
|
|
await this.getMenuCategory('Gizmo').click()
|
|
}
|
|
|
|
async setBackgroundColor(hex: string): Promise<void> {
|
|
await this.colorInput.evaluate((el, value) => {
|
|
;(el as HTMLInputElement).value = value
|
|
el.dispatchEvent(new Event('input', { bubbles: true }))
|
|
}, hex)
|
|
}
|
|
|
|
async waitForModelLoaded(): Promise<void> {
|
|
await expect(this.node.getByTestId(TestIds.loading.overlay)).toBeHidden({
|
|
timeout: 30000
|
|
})
|
|
}
|
|
}
|