Canvas placeholder overlay persists after digitize, hiding stitched output #42
Labels
No labels
blocked:commit-ready-failed
blocked:gate-fetch
blocked:gate-lint
blocked:gate-plan
blocked:gate-research
blocked:needs-attention
blocked:needs-decision
blocked:needs-human
blocked:no-changes
blocked:verify-failed
bug
deferred
feature-request
in-progress
needs-decompose
needs-triage
quickfix
security/medium
triage-approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Mark/Kimi_Agent_Brother_10_Digitizing_App#42
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Bug — "Drop your image here" placeholder overlay persists after digitize
Severity: P3 (visual/UX — stitches are rendered underneath but hidden by the placeholder overlay).
Description: The "Drop your image here" heading + "or click to browse" paragraph in the canvas upload zone is always rendered on top of the canvas regardless of appState. After uploading an SVG and clicking Auto-Digitize, the digitize succeeds (stitch objects are created, bottom bar shows "Total: X stops | X.X yards", success toast is shown), but the canvas still displays the "Drop your image here" placeholder as if no design is loaded. The stitches are rendered underneath the overlay but not visible to the user.
Repro (verified in live browser, 2026-07-24):
Expected: The placeholder should hide when
appStateis not'idle'and digitized content exists. Once stitches are rendered, the user should see them — not the upload prompt.Fix: The upload-zone component should be gated behind
appState === 'idle'(or whichever state means "no design loaded"). It currently renders unconditionally on top of the canvas.Related: #28 was the FAB auto-advance fix that landed in
8da6c17. The placeholder visibility was not part of that fix.Verification — closed
Fix commit:
ca0c025(onmain). Resolves the overlay-after-digitize bug.Root cause (rooted in React fiber inspection of the running bundle):
The placeholder overlay was wrapped in
<AnimatePresence>with twonested
<motion.div>s. The outer hadexit={{ opacity: 0, scale: 0.95 }} transition={{ duration: 300 }}. The inner had its own entrancetransition={{ duration: 400 }}and no exit. Framer-motion v12 withReact 18 concurrent rendering failed to coordinate the exit cleanly —
the H2 hung in the DOM with opacity decaying over several seconds
(observed: 0.38 at t=2s, 0.30 at t=3s, 0.22 at t=5s, slowly toward
zero but never reaching unmount within typical user attention spans).
The condition
appState === 'empty'alone was correctly toggling, butthe rendered overlay kept stamping on top of the canvas, hiding the
stitched output.
Fix: Drop the
<AnimatePresence>wrapper and the outer<motion.div>. Render the conditional<div>directly. Exit unmountson the same React tick that flips appState. Tightened the condition
to also require
colorRegions.length === 0 && stitchObjects.length === 0(defensive).Verified live (browser snapshot after Auto-Digitize completes):
digitizeddocument.querySelectorAll('h2').length= 0 (was 1 before fix)Confirm & Edit) visible and unobstructed
Total: X stops | X.X yardsBuild status:
npm run buildexit 0, 198/198 tests pass.Closes #42.