Spaces:
Running on Zero
Running on Zero
docs: spec for Topaz Cinema Slate palette + drawer layout
Browse files
docs/superpowers/specs/2026-05-01-topaz-drawer-redesign-design.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Visual redesign β Topaz Cinema Slate + Drawer layout
|
| 2 |
+
|
| 3 |
+
**Date:** 2026-05-01
|
| 4 |
+
**Status:** Draft, awaiting user review
|
| 5 |
+
**Related:** `2026-04-30-ltx23-aio-generator-design.md` (original spec)
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## Goal
|
| 10 |
+
|
| 11 |
+
Replace the current `gr.themes.Soft()` cream + purple palette with a dark slate-and-amber palette (**Topaz Cinema Slate**), and replace the always-visible left sidebar with a **hamburger drawer** that opens by default on desktop and is hidden by default on tablet/phone. Both changes are surface-level β no logic or backend changes.
|
| 12 |
+
|
| 13 |
+
## Why
|
| 14 |
+
|
| 15 |
+
The current palette reads as a hobby AI demo, not a creative-pro tool. Slate-on-slate is gentlest on the eye when judging color-graded video output, and an amber CTA reads "render," not "alert." The drawer pattern gives the form panel full screen real estate on phones (the sidebar currently stacks above the form on `<700px`, eating half the viewport for nav), while still keeping the sidebar always-visible at desktop widths where it costs nothing.
|
| 16 |
+
|
| 17 |
+
## Theme tokens
|
| 18 |
+
|
| 19 |
+
Applied via `gr.themes.Base().set(...)` overrides on the Blocks theme:
|
| 20 |
+
|
| 21 |
+
| Token | Value | Used for |
|
| 22 |
+
|---|---|---|
|
| 23 |
+
| `body_background_fill` | `#12161B` | App background |
|
| 24 |
+
| `background_fill_primary` | `#12161B` | Form/page background |
|
| 25 |
+
| `background_fill_secondary` | `#1A1F26` | Card / panel surface |
|
| 26 |
+
| `block_background_fill` | `#1A1F26` | Component (input, slider) surface |
|
| 27 |
+
| `body_text_color` | `#E6E8EB` | Primary text |
|
| 28 |
+
| `body_text_color_subdued` | `#7C8693` | Secondary / hint text |
|
| 29 |
+
| `border_color_primary` | `#262C35` | Card / input border |
|
| 30 |
+
| `border_color_accent` | `#E0A458` | Focused input ring |
|
| 31 |
+
| `button_primary_background_fill` | `#E0A458` | Generate button |
|
| 32 |
+
| `button_primary_text_color` | `#12161B` | Generate button label |
|
| 33 |
+
| `error_background_fill` | `#3A1E20` | Error banner background |
|
| 34 |
+
| `error_text_color` | `#F4A6A8` | Error banner text |
|
| 35 |
+
|
| 36 |
+
Fonts: `IBM Plex Sans` (UI 14 px) + `IBM Plex Mono` (mono 13 px), loaded from Google Fonts in the page `<head>` (Gradio's `head` parameter on `Blocks`, or via `_CUSTOM_CSS` `@import`).
|
| 37 |
+
|
| 38 |
+
## Layout: hamburger drawer
|
| 39 |
+
|
| 40 |
+
### Markup structure (logical, Gradio components)
|
| 41 |
+
|
| 42 |
+
```
|
| 43 |
+
gr.Row() # header
|
| 44 |
+
βββ HamburgerButton (gr.Button, β‘ icon) # toggles drawer
|
| 45 |
+
βββ gr.Markdown("LTX 2.3 Studio") # title
|
| 46 |
+
βββ ActiveModeTag (gr.Markdown, amber pill) # shows current mode
|
| 47 |
+
|
| 48 |
+
gr.Row(elem_classes="layer")
|
| 49 |
+
βββ gr.Column(elem_classes="drawer", visible=...) # 220 px wide
|
| 50 |
+
β βββ 6 mode buttons (existing)
|
| 51 |
+
βββ gr.Column(elem_classes="body-pane")
|
| 52 |
+
βββ gr.Tabs(elem_classes="hidden-tabs") # current 6 mode tabs
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
### Open / closed behavior
|
| 56 |
+
|
| 57 |
+
- **Desktop (β₯1024 px):** drawer open by default, occupies the left 220 px of the viewport. Hamburger still works as a toggle but most users leave it open.
|
| 58 |
+
- **Tablet (700β1023 px):** drawer closed by default; opening it slides over content with a translucent overlay (`background: rgba(0,0,0,0.5)`). Tapping outside closes.
|
| 59 |
+
- **Phone (<700 px):** same as tablet, but drawer takes 80 % of viewport width when open.
|
| 60 |
+
|
| 61 |
+
State persists in `localStorage` (`ltx-drawer-open` key) so a user who closes the drawer on desktop stays closed across reloads.
|
| 62 |
+
|
| 63 |
+
### Active mode header tag
|
| 64 |
+
|
| 65 |
+
A small amber-bordered pill in the header (e.g., `T2V`, `A2V`, `LIPSYNC`) showing the currently selected mode. Updates whenever a mode button is clicked. Uses `IBM Plex Mono` 11 px so it reads as a label, not a button.
|
| 66 |
+
|
| 67 |
+
### CSS approach
|
| 68 |
+
|
| 69 |
+
Pure CSS, no JS framework. Use `:has()` and `<input type="checkbox">` hidden control for drawer toggle, OR a tiny inline `<script>` block that toggles a class on the body. Gradio doesn't sandbox custom scripts in `_CUSTOM_CSS`, but it does support the `head` parameter on `gr.Blocks` for inline `<script>`.
|
| 70 |
+
|
| 71 |
+
Existing media queries (`@max-width: 700px`, `@max-width: 1024px`) collapse to a single `@max-width: 1023px` block since drawer behavior only differs at the desktop boundary.
|
| 72 |
+
|
| 73 |
+
## Files touched
|
| 74 |
+
|
| 75 |
+
- `app.py` β Blocks `theme=`, `head=` (fonts + drawer toggle script), `_CUSTOM_CSS` rewrite, header markup, drawer column wrapping the existing mode buttons
|
| 76 |
+
- `README.md` β update screenshot if any (defer; we don't have one yet)
|
| 77 |
+
|
| 78 |
+
No changes to `backend.py`, `models.py`, `modes.py`, `workflow.py`, `ui.py`.
|
| 79 |
+
|
| 80 |
+
## Out of scope (do not touch)
|
| 81 |
+
|
| 82 |
+
- Form layout inside each mode tab (prompt input, parameter sliders) β typography updates only via theme token cascade
|
| 83 |
+
- Model status / settings panel content β these display the same info, just on the new palette
|
| 84 |
+
- Mode set, generate flow, progress events β backend unchanged
|
| 85 |
+
- Any CUDA / MPS / Spaces logic
|
| 86 |
+
- Custom LoRA UI (still v1.1+)
|
| 87 |
+
|
| 88 |
+
## Testing plan
|
| 89 |
+
|
| 90 |
+
1. `python app.py` locally on macOS, browse `http://127.0.0.1:7860`
|
| 91 |
+
2. Resize Chrome window: full width β 1024 px β 700 px β 380 px. Drawer should:
|
| 92 |
+
- stay open β₯1024 px
|
| 93 |
+
- hide & become overlay-on-hamburger <1024 px
|
| 94 |
+
3. Click each of 6 mode buttons; confirm:
|
| 95 |
+
- active mode tag in header updates
|
| 96 |
+
- drawer auto-closes on phone after click (open-on-tap β click-to-pick β close)
|
| 97 |
+
4. Click Generate on T2V (with Balanced preset, 320Γ480, 5 s). Confirm progress + output render correctly on the new palette.
|
| 98 |
+
5. Trigger an error (e.g., empty prompt) and confirm error banner uses `#3A1E20` / `#F4A6A8`.
|
| 99 |
+
|
| 100 |
+
## Risks
|
| 101 |
+
|
| 102 |
+
- Gradio's `head` parameter is on `gr.Blocks` since 4.x β confirm it accepts a multi-line string with `<script>`.
|
| 103 |
+
- `gr.themes.Base().set(...)` may not cover every component (e.g., `gr.Slider`'s track). If we hit a gap we add an `elem_classes` override and target it in `_CUSTOM_CSS` β incremental, low-risk.
|
| 104 |
+
- The hidden-checkbox-and-`:has()` toggle pattern has Safari β₯15.4 compatibility, fine for our audience.
|