docs(wiki): two-page splice flow + lazy-column reveal gotcha
Browse files- wiki/gradio-embed-integration.md +47 -12
- wiki/log.md +12 -0
- wiki/system-overview.md +21 -10
wiki/gradio-embed-integration.md
CHANGED
|
@@ -43,15 +43,33 @@ Two bridges are in play, both proven patterns (see `fusion_ui.py` /
|
|
| 43 |
`#buddy-select-submit` to stage it in slot A/B. The bridge elements carry
|
| 44 |
`elem_classes=["buddy-bridge-box"]` (CSS-hidden, kept in the DOM); the
|
| 45 |
`buddyBridgeSet` helper uses the native value setter + `input` event before the
|
| 46 |
-
click, exactly like the voice bridge.
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
`#buddy-tweak-in` / `#buddy-tweak-submit` bridge and `buddyTweak` JS were
|
| 56 |
removed.)
|
| 57 |
|
|
@@ -79,6 +97,22 @@ Two bridges are in play, both proven patterns (see `fusion_ui.py` /
|
|
| 79 |
visibility (mounts the component), then `.then(populate)` that writes the value
|
| 80 |
once it is mounted. In `fusion_ui.py` the Splice click shows the reveal screen
|
| 81 |
first, then `.then(do_fuse)` fills `reveal_view` / `card_view`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
- **Dispatching an `input` event at a Gradio textbox does not reliably fire its
|
| 83 |
Python handler.** The JSβPython bridge via a hidden textbox alone silently
|
| 84 |
no-ops. A programmatic real `.click()` on a hidden Gradio **button** *does*
|
|
@@ -106,9 +140,10 @@ Two bridges are in play, both proven patterns (see `fusion_ui.py` /
|
|
| 106 |
## Sources
|
| 107 |
|
| 108 |
- `src/buddy_fusion/voxel_embed.py` (voxelizer, `VOXEL_JS_ON_LOAD`,
|
| 109 |
-
MutationObserver + poll, shared offscreen thumbnail renderer
|
| 110 |
-
|
| 111 |
-
|
|
|
|
| 112 |
|
| 113 |
## Related Pages
|
| 114 |
|
|
|
|
| 43 |
`#buddy-select-submit` to stage it in slot A/B. The bridge elements carry
|
| 44 |
`elem_classes=["buddy-bridge-box"]` (CSS-hidden, kept in the DOM); the
|
| 45 |
`buddyBridgeSet` helper uses the native value setter + `input` event before the
|
| 46 |
+
click, exactly like the voice bridge. `on_select` updates ONLY state + the Pick
|
| 47 |
+
screen's slots/tree β it does NOT toggle screens (see the auto-advance bridge).
|
| 48 |
+
- **Auto-advance bridge (JS β Python).** Staging the second creature opens the
|
| 49 |
+
Splice Bench. `_slots_html` marks `.buddy-slots[data-ready="1"]` when both slots
|
| 50 |
+
are filled; the 400ms voxel poll runs `buddyAutoAdvance`, which `.click()`s the
|
| 51 |
+
hidden `#buddy-adv-submit` button once (guarded by `window.__buddyAdvancing`).
|
| 52 |
+
That button's handler (`adv_open`) is a **clean, screens-only** response, with
|
| 53 |
+
the bench previews filled by a chained `.then(adv_fill)`. The guard is only
|
| 54 |
+
re-armed on a genuine deselect (slots present AND `data-ready="0"`), never when
|
| 55 |
+
the slots simply unmount β otherwise `β Back` re-shows the still-ready slots and
|
| 56 |
+
the poll bounces straight back to the bench. The reveal MUST be isolated this way
|
| 57 |
+
(see Failure Modes: lazy-mounted column reveal).
|
| 58 |
+
- **Chip bridge (JS β Python).** Each suggestion chip on the bench carries
|
| 59 |
+
`data-side`/`data-prompt`; a delegated click handler calls `buddyChip`, which
|
| 60 |
+
writes `{side, prompt}` JSON into `#buddy-chip-in` and `.click()`s
|
| 61 |
+
`#buddy-chip-submit`. `on_chip` parses it and runs the AI tweak on that side β
|
| 62 |
+
one tap, no Enter.
|
| 63 |
+
- **AI tweak is NOT a bridge β it is a plain `gr.Textbox.submit` (+ Apply button).**
|
| 64 |
+
The Splice Bench has one inline tweak box per side (`tweak_a` / `tweak_b`), each
|
| 65 |
+
with an explicit `Apply` button (`tweak_a_btn` / `tweak_b_btn`) bound to the same
|
| 66 |
+
handler as `.submit` (Enter still works). Handlers reshape that creature
|
| 67 |
+
server-side and re-render that bench side + the tree. The detail modal is
|
| 68 |
+
**inspect-only** (no tweak form). The earlier design put the tweak inside the
|
| 69 |
+
modal and refreshed it from JS via a hidden bridge on a fixed `setTimeout` β that
|
| 70 |
+
timeout was too short for the slow real ZeroGPU model, so the modal
|
| 71 |
+
closed/refreshed before the edit returned and the change appeared to vanish.
|
| 72 |
+
Inline server-rendered submit has no timing dependency. (The old
|
| 73 |
`#buddy-tweak-in` / `#buddy-tweak-submit` bridge and `buddyTweak` JS were
|
| 74 |
removed.)
|
| 75 |
|
|
|
|
| 97 |
visibility (mounts the component), then `.then(populate)` that writes the value
|
| 98 |
once it is mounted. In `fusion_ui.py` the Splice click shows the reveal screen
|
| 99 |
first, then `.then(do_fuse)` fills `reveal_view` / `card_view`.
|
| 100 |
+
- **Revealing a NEVER-yet-mounted `visible=False` column is stricter still: the
|
| 101 |
+
`visible=True` is silently dropped unless the response touches ONLY the screen
|
| 102 |
+
columns.** Gradio lazily mounts a `visible=False` column (it is absent from the
|
| 103 |
+
DOM until first shown). Flipping it to visible works *only* from a handler whose
|
| 104 |
+
outputs are just the screen column(s). If the same response also writes another
|
| 105 |
+
screen's HTML children (e.g. the Pick screen's slots/tree) **or** the toggle is
|
| 106 |
+
deferred to a chained `.then`, the column mounts but stays `hide` (display:none)
|
| 107 |
+
β content present, screen invisible. Verified empirically by bisecting ~6 wiring
|
| 108 |
+
variants: a pure columns-only handler reveals it; adding state/HTML-child outputs
|
| 109 |
+
or a `.then` before it does not; a *real* button vs a programmatic `.click()`
|
| 110 |
+
makes no difference. Fix for the bench auto-advance: a dedicated bridge
|
| 111 |
+
(`#buddy-adv-submit`) whose handler `adv_open` returns only `[screen_lab,
|
| 112 |
+
screen_bench]`, with `.then(adv_fill)` writing the bench previews afterward; the
|
| 113 |
+
selection handler (`on_select`) stays separate and never touches the columns.
|
| 114 |
+
This is why the bench could not simply reuse `on_select`'s outputs or a
|
| 115 |
+
`select_btn` `.then`.
|
| 116 |
- **Dispatching an `input` event at a Gradio textbox does not reliably fire its
|
| 117 |
Python handler.** The JSβPython bridge via a hidden textbox alone silently
|
| 118 |
no-ops. A programmatic real `.click()` on a hidden Gradio **button** *does*
|
|
|
|
| 140 |
## Sources
|
| 141 |
|
| 142 |
- `src/buddy_fusion/voxel_embed.py` (voxelizer, `VOXEL_JS_ON_LOAD`,
|
| 143 |
+
MutationObserver + poll, shared offscreen thumbnail renderer, `buddyChip` +
|
| 144 |
+
`buddyAutoAdvance` bridges)
|
| 145 |
+
- `src/buddy_fusion/fusion_ui.py` (hidden bridge textbox/button, `buddy-bridge-box`,
|
| 146 |
+
`on_select` / `adv_open` / `adv_fill` / `on_chip`, the Splice Bench layout)
|
| 147 |
|
| 148 |
## Related Pages
|
| 149 |
|
wiki/log.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
| 2 |
|
| 3 |
## 2026-06-14
|
| 4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
### deployment-strategy: response_format bug, Qwen2.5-3B default, ZeroGPU quota
|
| 6 |
|
| 7 |
- Recorded the root-cause fix: `response_format` must be
|
|
|
|
| 2 |
|
| 3 |
## 2026-06-14
|
| 4 |
|
| 5 |
+
### gradio-embed-integration + system-overview: two-page splice flow & lazy-column reveal
|
| 6 |
+
|
| 7 |
+
- Recorded the lazy-mounted `visible=False` column gotcha: a never-yet-mounted
|
| 8 |
+
column's `visible=True` is dropped unless the response touches only the screen
|
| 9 |
+
columns (no other screen's HTML children, not via `.then`). Documented the
|
| 10 |
+
dedicated `#buddy-adv-submit` bridge (`adv_open` + `.then(adv_fill)`) and the
|
| 11 |
+
`data-ready` / `buddyAutoAdvance` client trigger that work around it.
|
| 12 |
+
- Added the chip bridge (`buddyChip` / `on_chip`) and moved the AI tweak boxes
|
| 13 |
+
(now + Apply buttons) onto the new Splice Bench in the bridges section.
|
| 14 |
+
- Updated `system-overview.md` to a four-screen flow (landing β pick β bench β
|
| 15 |
+
reveal) with matching data-flow steps and a new gotcha bullet.
|
| 16 |
+
|
| 17 |
### deployment-strategy: response_format bug, Qwen2.5-3B default, ZeroGPU quota
|
| 18 |
|
| 19 |
- Recorded the root-cause fix: `response_format` must be
|
wiki/system-overview.md
CHANGED
|
@@ -59,22 +59,28 @@ reliable envelope.
|
|
| 59 |
bridges, the SVG pedigree connectors, and `window` export hooks. Renders each
|
| 60 |
voxel as an `InstancedMesh` cube.
|
| 61 |
- `formatter.py` β genome-card HTML + share text.
|
| 62 |
-
- `fusion_ui.py` β the Gradio Blocks game flow: a
|
| 63 |
-
(landing β lab pedigree hub β reveal) toggled by
|
| 64 |
-
selection slots,
|
| 65 |
-
|
|
|
|
| 66 |
- `json_utils.py` β JSON extraction helpers. (Command input is a text box now;
|
| 67 |
the old `asr.py` voice wrapper was deleted β see voice-input-asr.md.)
|
| 68 |
|
| 69 |
## Data flow
|
| 70 |
|
| 71 |
-
1. Landing screen β `Start` reveals the Lab.
|
| 72 |
-
2.
|
| 73 |
-
included) to stage them in the A/B slots; π opens
|
| 74 |
-
|
| 75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
`repair_genome` β `Genome` (`do_fuse` reads the selection, not a fixed pair).
|
| 77 |
-
|
| 78 |
`Lineage` and appears in the pedigree, ready to be staged again.
|
| 79 |
|
| 80 |
## Deployment
|
|
@@ -98,6 +104,11 @@ reliable envelope.
|
|
| 98 |
- Toggling a screen visible AND writing one of its components in the same response
|
| 99 |
leaves that component stuck in `pending`; split into a visibility event then
|
| 100 |
`.then(populate)` β see gradio-embed-integration.md.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
- Binary assets (the landing buddy PNGs, etc.) are tracked via Git LFS
|
| 102 |
(`.gitattributes`); pushing uploads LFS objects to the Space.
|
| 103 |
- **AI tweak silently did nothing on the real model (fixed 2026-06-14,
|
|
|
|
| 59 |
bridges, the SVG pedigree connectors, and `window` export hooks. Renders each
|
| 60 |
voxel as an `InstancedMesh` cube.
|
| 61 |
- `formatter.py` β genome-card HTML + share text.
|
| 62 |
+
- `fusion_ui.py` β the Gradio Blocks game flow: a four-screen state machine
|
| 63 |
+
(landing β lab/pick pedigree hub β splice bench β reveal) toggled by
|
| 64 |
+
`gr.Column(visible=...)`, selection slots, per-side AI tweak + quick chips on the
|
| 65 |
+
bench, the landing backdrop (`LANDING_BG_JS` + `_buddy_data_uris`), all CSS, and
|
| 66 |
+
the hidden JSβPython bridges. Exports `CSS, FUSION_HEAD, build_app`.
|
| 67 |
- `json_utils.py` β JSON extraction helpers. (Command input is a text box now;
|
| 68 |
the old `asr.py` voice wrapper was deleted β see voice-input-asr.md.)
|
| 69 |
|
| 70 |
## Data flow
|
| 71 |
|
| 72 |
+
1. Landing screen β `Start` reveals the Lab (Pick screen).
|
| 73 |
+
2. Pick: the family pedigree is the hub and fills the screen β tap two creatures
|
| 74 |
+
(any nodes, children included) to stage them in the A/B slots; π opens an
|
| 75 |
+
inspect-only detail modal (live 3D + genome card). Staging the second creature
|
| 76 |
+
auto-advances to the Splice Bench.
|
| 77 |
+
3. Splice Bench: the two staged creatures shown A-left / B-right with live
|
| 78 |
+
previews + genome cards; each side has an AI tweak box + Apply button + quick
|
| 79 |
+
suggestion chips (one-tap `interpret_genome_command`). `β Back` returns to Pick
|
| 80 |
+
with the picks retained.
|
| 81 |
+
4. Splice: one LLM call recombines the two staged genomes β child dict β
|
| 82 |
`repair_genome` β `Genome` (`do_fuse` reads the selection, not a fixed pair).
|
| 83 |
+
5. The reveal screen shows both parents + the newborn; the child enters the
|
| 84 |
`Lineage` and appears in the pedigree, ready to be staged again.
|
| 85 |
|
| 86 |
## Deployment
|
|
|
|
| 104 |
- Toggling a screen visible AND writing one of its components in the same response
|
| 105 |
leaves that component stuck in `pending`; split into a visibility event then
|
| 106 |
`.then(populate)` β see gradio-embed-integration.md.
|
| 107 |
+
- Revealing a *never-yet-mounted* `visible=False` screen is even stricter: the
|
| 108 |
+
`visible=True` is silently dropped unless the triggering response touches ONLY
|
| 109 |
+
the screen columns (no other screen's HTML children, and not via a chained
|
| 110 |
+
`.then`). The bench auto-advance uses a dedicated clean bridge for exactly this
|
| 111 |
+
β see gradio-embed-integration.md.
|
| 112 |
- Binary assets (the landing buddy PNGs, etc.) are tracked via Git LFS
|
| 113 |
(`.gitattributes`); pushing uploads LFS objects to the Space.
|
| 114 |
- **AI tweak silently did nothing on the real model (fixed 2026-06-14,
|