# Gradio Layout Gym

**Status**: Active — compliance checker implemented, layout patterns documented

Self-learning loop for Gradio UI layouts + compliance checking:

```
Generate layout code → Screenshot → Score visually → Learn patterns → Repeat
```

## Contents

```
gradio_layout_gym/
├── compliance.py              Gradio 6.0 compliance scanner
├── patterns/                  CSS layout experiments & findings
│   ├── EXPERIMENTS.md         6 experiments: viewport, flex, overflow, footer
│   ├── app.py                 Test app: baseline vs CSS_FLEX_VIEWPORT
│   ├── capture.py             Playwright screenshot automation
│   ├── capture_tab.py         Tab-based capture variant
│   └── snapshots/             45 PNGs documenting layout experiments
├── tables/                    Interactive table/grid patterns
│   ├── dataframe_selection.py gr.DataFrame + SelectData event approach
│   └── custom_grid.py         Custom HTML/CSS Grid + JS bridge approach
├── screenshots/               78 PNGs from systematic responsive testing
└── reports/                   Batch evaluation reports
```

## Key Findings

### CSS Layout Patterns (`patterns/`)

- **CSS_FLEX_VIEWPORT is essential** for HTML components without built-in scrolling
  - Without it: footer pushed off-screen, page grows unbounded
  - With it: content contained, footer stays visible
- Code components (with built-in scrolling) work fine without flex CSS
- Tested at viewports: 1400x900, 1400x600

### Table Interactions (`tables/`)

- **DataFrame approach**: `gr.DataFrame` + `SelectData` event — simple, limited
- **Custom Grid approach**: HTML table + CSS Grid + JS bridge via `window.selectedRowIdx` — more control, more code
- Status badges with color coding work well in custom grids

## Compliance Checker

**Tool**: `compliance.py` — scans all Gradio apps for Gradio 6.0 compliance

```bash
python explorations/gradio_layout_gym/compliance.py
```

**Checks**:
- ✗ **ERROR**: `css`/`theme`/`head` in `Blocks()` constructor (Gradio 6.0 warning)
- ⚠ **WARNING**: Inline CSS via `gr.HTML("<style>...")` (prefer `launch(css=...)`)
- ℹ **INFO**: Missing `fill_width=True` for full-width layouts

**Standard Pattern**:
```python
CUSTOM_CSS = "..."

with gr.Blocks(title="App", fill_width=True) as app:
    # UI

app.launch(css=CUSTOM_CSS, theme=gr.themes.Soft())
```

**Learnings** (Feb 2026):
- Gradio 6.0 moved `css`/`theme`/`head` from Blocks to launch
- All rivus apps now use consistent `launch(css=...)` pattern
- `fill_width=True` removes container padding for full-width layouts
- Auto-reload: use `gradio app.py` CLI instead of `python app.py`

## The Gym Loop (planned)

1. **Generate**: LLMs produce `gr.Blocks()` code for a given task (chat UI, dashboard, etc.)
2. **Run**: Spin up each layout on a temp port
3. **Screenshot**: Capture at multiple viewport sizes
4. **Evaluate**: LLM scores visual appeal, usability, responsiveness
5. **Learn**: Track which patterns score well, feed back into generation

## TODO

- [ ] **Layout review skill** — `~/.claude/skills/layout-review/`: screenshot → identify issues → propose → implement → verify
- [ ] **Integrate compliance checker** into layout review skill as pre-check

## See also

- `~/.myconf/claude_global/howto/gradio.md` — Gradio 6.0 breaking changes
- `~/.myconf/claude_global/skills/gradio-layout/` — Layout patterns & CSS gotchas
