arkai2025 commited on
Commit
6e514bc
Β·
1 Parent(s): 9678e3b

docs(wiki): two-page splice flow + lazy-column reveal gotcha

Browse files
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
- - **AI tweak is NOT a bridge β€” it is a plain `gr.Textbox.submit`.** The Lab has
48
- one visible inline tweak box per staged slot (`tweak_a` / `tweak_b`); their
49
- `.submit` handlers reshape that creature server-side and re-render the slot +
50
- tree. The detail modal is **inspect-only** (no tweak form). The earlier design
51
- put the tweak inside the modal and refreshed it from JS via a hidden bridge on a
52
- fixed `setTimeout` β€” that timeout was too short for the slow real ZeroGPU model,
53
- so the modal closed/refreshed before the edit returned and the change appeared
54
- to vanish. Inline server-rendered submit has no timing dependency. (The old
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- - `src/buddy_fusion/fusion_ui.py` (hidden bridge textbox/button, `BROWSER_VOICE_JS`,
111
- `buddy-bridge-box`)
 
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 three-screen state machine
63
- (landing β†’ lab pedigree hub β†’ reveal) toggled by `gr.Column(visible=...)`,
64
- selection slots, the landing backdrop (`LANDING_BG_JS` + `_buddy_data_uris`),
65
- all CSS, and the hidden JS↔Python bridges. Exports `CSS, FUSION_HEAD, build_app`.
 
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. The family pedigree is the hub: tap two creatures (any nodes, children
73
- included) to stage them in the A/B slots; πŸ” opens a detail modal with a live
74
- 3D view + genome card + AI text-tweak (`interpret_genome_command`).
75
- 3. Splice: one LLM call recombines the two staged genomes β†’ child dict β†’
 
 
 
 
 
76
  `repair_genome` β†’ `Genome` (`do_fuse` reads the selection, not a fixed pair).
77
- 4. The reveal screen shows both parents + the newborn; the child enters the
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,