No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Parley Hatch 521a139768 Handoff for next session
docs/HANDOFF.md: current state, the one unblocked first task (midtone
starvation -- allocate levels inside the subject mask, background pinned open),
seven ranked questions, and the traps not to re-derive. AGENTS.md now points at
it as the entry point for a fresh session.

Highest-value question by a distance is whether the hand-made barbarian masks
can be shared. They are ground truth: a real fitness target instead of a proxy,
the actual level-area allocation that is currently the blocker, whether the
three masks are nested, and the vertex density that sets the tracing epsilon.

Also asks the question that should have come first last session -- what the
product actually is. Full automation has been the default assumption and was
never checked; "tool produces masks, human refines" may be most of the value
for a fraction of the difficulty.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 12:31:42 -06:00
docs Handoff for next session 2026-08-09 12:31:42 -06:00
scripts Bench the two missing stages: the barbarian reads 2026-08-09 12:16:53 -06:00
src/shadowbox Spec v2: model the light before solving for sheets; stop the preview lying 2026-08-09 11:41:50 -06:00
.gitignore Initial shadowbox toolkit: depth+form laser layer pipeline 2026-08-09 01:22:36 -06:00
AGENTS.md Handoff for next session 2026-08-09 12:31:42 -06:00
pyproject.toml Initial shadowbox toolkit: depth+form laser layer pipeline 2026-08-09 01:22:36 -06:00
README.md Flow engine, relief stack mode, cuttability audit 2026-08-09 10:30:32 -06:00

shadowbox

Any image → three laser-cut layers for backlit shadowbox panels (xTool S1, 3mm ply, etc.).

Not a paper-cut-only tool and not an engraving optimizer. Structure comes from scene geometry (depth) so photos, painterly art, graphic gens, and mixed styles can all feed the same pipeline.

Stack modes

relief (default) — reverse-nested, every tonal band gets a distinct physical depth. Dark-room physics of an opaque backlit stack: front face is darkest, each revealed deeper sheet catches more rim glow, full open is brightest.

Band (dark → bright) Physical identity
darkest solid on L3 (front silhouette)
next open on L3, solid on L2 (revealed, rim-lit)
next open on L3+L2, solid on L1 (deep, glowing)
lightest + background open through all three (full bright)

Invariant (relief): open(L1) ⊆ open(L2) ⊆ open(L3)

nested — the classic convention: L1 most open, L3 least open, open(L3) ⊆ open(L2) ⊆ open(L1), every L3 hole full-bright. Two tones only — kept for pumpkin-style pierced looks.

Either way: solid islands are dropped or bridged (material must connect to the panel frame).

Setup

cd shadowbox
python3 -m venv .venv
source .venv/bin/activate
pip install -e .

ComfyUI must be running with API on 0.0.0.0:8188 (or pass --comfy).

Needs:

  • Depth Anything 3: geometry_estimation/depth_anything_3_mono_large.safetensors
  • Z-Image-Turbo (optional, for generate): z_image_turbo_bf16.safetensors, qwen_3_4b.safetensors, ae.safetensors

Usage

shadowbox health

# Any image (photo, paint, gen, screenshot…)
shadowbox layers whatever.png -o out/run1 --width-mm 100 --height-mm 100

# Optional: generate a source first, then same depth path
shadowbox generate "oil painting of a foggy pier at dusk, rich brushwork" \
  -o out/pier --seed 7 --width-mm 100 --height-mm 100

# Offline fallback only (no depth model) — brightness-driven, style-sensitive
shadowbox layers photo.png -o out/run_lum --mode luminance

Outputs

File Meaning
source.png Input / generated image
depth.png DA3 depth (bright ≈ near)
open_score.png Field that was thresholded into layers
L1_open.png … L3_open.png White = cut away
L1_cut.svg … L3_cut.svg Vector cut paths (+ red frame)
preview_backlit.png Simulated interior light
contact_sheet.png Overview
meta.json Thresholds, open fractions, nesting check

Blue strokes in SVG = cut. Red = panel frame. Import into XCS / LightBurn and scale as needed.

Design

Default path is depth + form (flow engine) in relief mode:

  1. Depth (DA3) — subject vs background. BG open on every layer.
  2. Flow abstraction — iterated bilateral (edge-preserving flatten) → subject-masked k-means (tonal budget spent on the figure, not the wall) → edge-aware small-region absorption (small regions join across their weakest boundary). Boundaries hug real image edges — no label-median mush.
  3. Score linework (XDoG) — eyelashes / straps / feather shafts extracted as strokes, exported as a green engrave group on L3 and simulated in the preview. Detail returns as line, never as sub-kerf cut voids.
  4. Relief mapping — bands → distinct depths (see stack modes above).
  5. Fabrication cleanup — morph, min-web, island drop/bridge (relief-aware nesting).

Structure / engine knobs

Flag Default Effect
--structure form form / hybrid / edges / depth
--form-engine flow flow (edge-aware + score lines) / classic (old posterize)
--stack-mode relief relief (tonal depth bands) / nested (full-bright holes)
--levels 5 Posterize grey count (4–6 for relief; 3–4 for nested).
--min-blob 400 Min region area in px² (also see --min-blob-mm).
--min-blob-mm 1.5 Min form region size in mm at export scale.
--bridge / --no-bridge on Connect solid islands to the panel frame.
--bridge-mm 1.2 Bridge web width (mm).
--min-web-mm 0.5 Minimum solid web after morph (mm). Large values blob the design.
--curve 1.4 Contrast before quantize.
--backend krea2 Gen backend for generate.

Outputs (cut-ready)

Per run directory:

  • L1_cut.svg … L3_cut.svg — blue cut, red frame, green registration
  • all_layers.svg — overlay of all three for inspection
  • preview_backlit.png / contact_sheet.png
  • meta.json — includes nesting_ok, frame_connected, bridge reports

Not for cut-through (yet)

Floyd–Steinberg / fine halftone → speckles smaller than kerf. Keep those for a later engrave fill on a solid plate, not as cut voids.

Generation is optional source material. The layer engine takes any image.

Design notes

  • Depth prep: robust stretch + bilateral smooth so soft/painterly depth maps still band cleanly.
  • Layout / sheet nesting on plywood is left to you.
  • Island removal is manufacturability (floating wood falls out), not a style choice.