Repository navigation
Conversation
The 3D view showed whatever model.gltf was last exported, even after the slices, camera or displacement changed - a project could show a scene missing slices it has since gained. Exports now record a fingerprint of the scene they were built from (model_source.json); the project view reports exports.gltfStale, and the 3D view rebuilds a missing or stale export before showing it (Export dialog's DOF choice kept, no toast). A failed rebuild offers "Try again" instead of looping. The viewer also opens at the reference camera (target, orbit and field of view from the scene profile) instead of Dash's fixed zoomed-in orbit, which cropped much of the scene, and no longer auto-rotates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The changes are cohesive across backend/API/frontend, and the new behavior is covered by targeted pytest, vitest, and e2e tests with no confirmed correctness issues found in review.
Review effort: Lite
Findings: None
What changed in this PR
This PR ensures the 3D view always displays a glTF export that matches the current project scene by adding a backend “scene fingerprint” sidecar and teaching the frontend 3D viewer to automatically rebuild missing/stale exports before rendering, while also improving initial camera framing based on sceneProfile.
Changes:
- Backend: write and validate a
model_source.jsonfingerprint sidecar to detect stale glTF exports, and exposeexports.gltfStalevia the project view. - Frontend: auto-rebuild glTF on entering the 3D view when missing/stale (with retry/pending guards) and update viewer framing from
sceneProfile. - Tests: add/extend pytest, vitest, and e2e coverage for fingerprint staleness, auto-rebuild behavior, and framing.
| File | Description |
|---|---|
| parallax_maker/export_services.py | Adds glTF scene fingerprinting + sidecar write and a staleness check helper. |
| parallax_maker/api/projects.py | Surfaces exports.gltfStale in the project view based on fingerprint comparison. |
| parallax_maker/api/schemas.py | Extends the API schema with gltf_stale on ProjectExportsView. |
| parallax_maker/test_export_services.py | Adds unit tests for fingerprint generation and staleness detection. |
| parallax_maker/test_api_project_export.py | Adds API-level tests for gltfStale and sidecar recording behavior. |
| frontend/src/lib/workflow.ts | Changes startGltfExport to support “preview” rebuild mode and return success/failure. |
| frontend/src/lib/workflow.test.ts | Adds tests validating preview vs non-preview export behavior and return value. |
| frontend/src/lib/state/ui.svelte.ts | Persists export DOF choice in uiStore.exportDof for reuse by auto-rebuild. |
| frontend/src/lib/components/viewer/Model3DViewer.svelte | Implements auto-rebuild/retry UX and derives framing attributes from sceneProfile. |
| frontend/src/lib/components/viewer/Model3DViewer.test.ts | Adds tests for auto-rebuild guards, retry flow, and framing attribute computation. |
| frontend/src/lib/components/dialogs/ExportDialog.svelte | Hides “Scene ready” while stale, and avoids downloading when export fails. |
| frontend/src/lib/components/dialogs/ExportDialog.test.ts | Adds tests for stale-aware “Scene ready” and DOF persistence through uiStore. |
| frontend/src/lib/api/schema.json | Updates generated schema to include gltfStale. |
| frontend/src/lib/api/generated.ts | Regenerates API types for gltfStale. |
| e2e/project-export.spec.ts | Adds an e2e scenario asserting 3D view rebuilds after slice changes. |
| e2e/drivers/types.ts | Extends UiDriver with view3dScene() for frontend-neutral 3D assertions. |
| e2e/drivers/svelte.ts | Implements view3dScene() by waiting for <model-viewer> to load and exposing URL/material count. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The 3D view rendered whatever
model.gltfexisted on disk. Inappstate-DMcExmtrthat file dated from before slices 2–4 were created, soimage_slice_2was simply absent from the 3D preview. Nothing marked the export as outdated.Separately, the viewer's fixed Dash orbit (
camera-target 0 0 0, 50 m, 8° FOV, auto-rotate) showed a zoomed, off-centre crop of the scene, so even a fresh export didn't show slice 2 in the default view.Fix
ExportService.export_gltfwritesmodel_source.jsonwith a fingerprint of everything the export depends on: slice files, depths, ground flag, upscaled textures, depth maps when displaced, camera and displacement.ProjectView.exports.gltfStalecompares that fingerprint with the current state. An export without the file counts as stale.uiStore.exportDof, and gives no toast and no Export step tick. A failed rebuild shows "Try again" rather than retrying in a loop; apendingguard covers the gap between the job ending and the export call settling.sceneProfile, it orbits around the middle of the card stack, and auto-rotate is off.Verification
appstate-DMcExmtr, entering 3D rebuilt the stale export in about 2.7 s. The view then matches the image, and hiding slice 2's material changes about 1.4k pixels, so it is visible.pendingguard.Not addressed: cards below the ground plane
With a ground plane, a card whose depth lies behind its ground contact ends up below the ground. That's slice 2 here: its card is at z 176, but the ground at its bottom row is at z 64. The default BLEND export still shows it, because three.js draws transparent layers back to front. Depth-writing renders (DOF/MASK exports, and most 3D tools) hide it behind the opaque inpainted ground. How to fix that geometry is a separate design decision.
🤖 Generated with Claude Code