Skip to content

fix(3d): rebuild a stale glTF scene when entering the 3D view - #34

Open
provos wants to merge 1 commit into
mainfrom
fix/3d-view-stale-export
Open

provos wants to merge 1 commit into
mainfrom
fix/3d-view-stale-export

Conversation

@provos

@provos provos commented Sep 27, 2026

Copy link
Copy Markdown
Owner

Problem

The 3D view rendered whatever model.gltf existed on disk. In appstate-DMcExmtr that file dated from before slices 2–4 were created, so image_slice_2 was 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

  • Backend: ExportService.export_gltf writes model_source.json with a fingerprint of everything the export depends on: slice files, depths, ground flag, upscaled textures, depth maps when displaced, camera and displacement. ProjectView.exports.gltfStale compares that fingerprint with the current state. An export without the file counts as stale.
  • 3D view: when a project with slices has a missing or stale export, the view rebuilds it before showing it. The rebuild uses the Export dialog's DOF choice, now kept in uiStore.exportDof, and gives no toast and no Export step tick. A failed rebuild shows "Try again" rather than retrying in a loop; a pending guard covers the gap between the job ending and the export call settling.
  • Framing: the viewer opens at the reference camera. Target, orbit and FOV come from sceneProfile, it orbits around the middle of the card stack, and auto-rotate is off.
  • Export dialog: "Scene ready" is hidden while the export is stale, and "Download glTF" no longer downloads the old file when the export fails.

Verification

  • On a copy of 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.
  • New e2e: entering 3D builds the scene, and after a slice depth edit the viewer loads a rebuilt URL.
  • New pytest cases for the fingerprint and stale reporting, and vitest cases for auto-rebuild, busy, failure/retry and framing. The two tightened failure tests fail without the pending guard.
  • pytest 495, vitest 436, svelte-check clean, e2e 47/47. One slice-editing upload scenario flaked once and passed on rerun.

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

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>
Copilot AI lite review requested due to automatic review settings September 27, 2026 23:40

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.json fingerprint sidecar to detect stale glTF exports, and expose exports.gltfStale via 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants