+
+ setShowStickerWallModal(false)}
+ imageUrl={stickerWallUrl}
+ />
+```
+
+- [ ] **Step 4: Verify the app builds without errors**
+
+Run: `cd frontend && npx vite build 2>&1 | tail -5`
+Expected: Build succeeds
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add frontend/src/pages/SessionDetail.jsx
+git commit -m "feat: add sticker wall section to SessionDetail view"
+```
diff --git a/docs/superpowers/specs/2026-08-24-sticker-wall-preview-design.md b/docs/superpowers/specs/2026-08-24-sticker-wall-preview-design.md
new file mode 100644
index 0000000..62a620f
--- /dev/null
+++ b/docs/superpowers/specs/2026-08-24-sticker-wall-preview-design.md
@@ -0,0 +1,158 @@
+# Sticker Wall Preview — Design Spec
+
+Display sticker wall images in two places: as a live preview in the Picker's sticker toggle card, and as a historical record in the SessionDetail view.
+
+## Backend — Proxy Endpoints
+
+Two new Express routes in `backend/routes/stickerwalls.js`, both behind JWT auth middleware.
+
+### `GET /api/stickerwalls/:sessionId`
+
+Proxies to the vote-app's `GET /stickerwalls/{sessionID}.png`.
+
+- Streams the PNG response through to the client.
+- Passes through status codes: 200 with `image/png` body, 404 if no render exists.
+- Passes through `Cache-Control` header from upstream.
+
+### `POST /api/stickerwalls/:sessionId/render`
+
+Proxies to the vote-app's `POST /api/stickerwalls/{sessionID}/render`.
+
+- Injects the `X-API-Key` header server-side (from env var).
+- Streams back the PNG response.
+- Forwards the `X-Sticker-Wall-Rendered` response header (indicates fresh render vs cached).
+- Passes through status codes: 200 with image, 404 if session has no placed stickers.
+
+### Configuration
+
+Two new environment variables:
+
+- `VOTE_APP_URL` — base URL of the vote-app (e.g. `https://vote-app.example.com`)
+- `VOTE_APP_API_KEY` — API key for the render endpoint
+
+## Frontend — Shared Components
+
+### `StickerWallThumbnail` (`frontend/src/components/StickerWallThumbnail.jsx`)
+
+Clickable image thumbnail for sticker walls. Used in both Picker and SessionDetail.
+
+**Props:**
+
+- `imageUrl` — blob URL or null. When set, displays this image.
+- `loading` — boolean, shows a spinner overlay while fetching.
+- `error` — boolean, shows placeholder state ("No sticker wall").
+- `onClick` — callback for enlarging (opens modal).
+
+**Rendering:**
+
+- Fixed small size, 16:9 aspect ratio. Scaled-down from 1920×1080.
+- Rounded corners, subtle border matching surrounding card style.
+- Three visual states: loading (spinner), error/empty (muted placeholder), loaded (image).
+
+### `StickerWallModal` (`frontend/src/components/StickerWallModal.jsx`)
+
+Full-size image viewer modal. Used in both Picker and SessionDetail.
+
+**Props:**
+
+- `isOpen` — boolean controlling visibility.
+- `onClose` — callback to close.
+- `imageUrl` — blob URL of the sticker wall image.
+
+**Behavior:**
+
+- Displays the sticker wall image at full/large size, constrained to viewport (`max-w-screen`, `max-h-screen`, `object-contain`).
+- PNG with transparent background rendered over a dark backdrop so stickers are visible.
+- Closes on: Escape key, overlay click, explicit close button (top-right ×).
+- Follows existing Tailwind modal pattern (`fixed inset-0`, `z-50`), built as a reusable component like `RoomCodeModal`.
+
+## Shared Fetch Logic — `useStickerWall` Hook
+
+`frontend/src/hooks/useStickerWall.js` — custom hook used by both Picker and SessionDetail.
+
+**Input:** `sessionId` (triggers fetch when set/changed).
+
+**Returns:** `{ imageUrl, loading, error, refresh }` where `refresh()` manually calls the render endpoint.
+
+**Fetch sequence (runs on mount / sessionId change):**
+
+1. `GET /api/stickerwalls/:sessionId` — try the cached image.
+2. If 404 → `POST /api/stickerwalls/:sessionId/render` — attempt to generate one.
+3. If that also 404s (no stickers exist) → set error state.
+
+Both endpoints return image bytes. The hook fetches as blob, creates a blob URL via `URL.createObjectURL`, and revokes the previous URL to prevent memory leaks. Cleanup on unmount revokes the current URL.
+
+**`refresh()` method:** Calls `POST /api/stickerwalls/:sessionId/render` directly (skipping the GET), updates `imageUrl` with the result. Used only by the Picker's refresh button.
+
+This catches three cases:
+- Sessions with a final rendered image (normal post-feature sessions) — served from step 1.
+- Sessions with sticker data but no render yet (played between wall archival and retrieval deployment) — rendered in step 2.
+- Sessions with no stickers at all — error state after step 2 fails.
+
+## Frontend — Picker (Live Session Sticker Card)
+
+The existing sticker toggle card in `Picker.jsx` (~line 892) is expanded to include the sticker wall preview.
+
+### Layout (left to right)
+
+1. **Thumbnail** — `StickerWallThumbnail` on the left side. Sized to fit the card height (~80–90px tall, ~142–160px wide at 16:9). Rounded corners, subtle border.
+2. **Refresh button** — Immediately right of the thumbnail. Small, subtle icon button (refresh/sync icon). Muted styling (`text-gray-400 hover:text-indigo-500`) so it doesn't compete with the mode toggle. Visually separated from the segmented control.
+3. **Flex spacer** — Pushes the toggle control to the right edge.
+4. **"Stickers" label + auto/show/hide segmented control** — Unchanged, stays on the right.
+
+### Fetch behavior
+
+- On session load (when `sessionId` is available), run the shared fetch logic.
+- The refresh button calls `POST /api/stickerwalls/:sessionId/render` and updates the thumbnail with the response. Shows a spinner on the button while rendering.
+
+### Click to enlarge
+
+Clicking the thumbnail opens `StickerWallModal` with the current image.
+
+### State
+
+Managed by the `useStickerWall(sessionId)` hook. Picker destructures `{ imageUrl, loading, error, refresh }` — no additional local state needed beyond the modal open/close boolean.
+
+## Frontend — SessionDetail (History View)
+
+A new "Sticker Wall" section in `SessionDetail.jsx`, positioned after the notes section and before the games list.
+
+### Card layout
+
+- Section heading "Sticker Wall" matching existing heading style (Notes, Games, etc.).
+- Contains `StickerWallThumbnail`, slightly larger than in Picker (~120px tall).
+- No refresh button — historical sessions have immutable final images; the one-time render-on-404 from the shared fetch logic handles the edge case of pre-existing sessions.
+
+### Fetch behavior
+
+On load, run the shared fetch logic (GET, then POST on 404, then placeholder on second 404).
+
+### Placeholder state
+
+If no sticker wall exists (both GET and POST return 404), the card displays "No sticker wall for this session" in muted text.
+
+### Click to enlarge
+
+Clicking the thumbnail opens `StickerWallModal`.
+
+### Active sessions in SessionDetail
+
+If the session is still active (`is_active === 1`), the sticker wall section still appears with read-only fetch-on-load behavior. No refresh button — the Picker is the intended live interface.
+
+## Error Handling
+
+- **Network errors on proxy requests:** Show a brief toast or inline error state in the thumbnail. Don't block the rest of the page.
+- **Render endpoint returns cached (X-Sticker-Wall-Rendered: false):** No special UI treatment — just display the image. The admin can infer from visual inspection whether anything changed.
+- **Blob URL cleanup:** Revoke object URLs on unmount and when replaced by a new fetch, to avoid memory leaks.
+
+## Files Changed
+
+| File | Change |
+|------|--------|
+| `backend/routes/stickerwalls.js` | New file — proxy endpoints |
+| `backend/server.js` (or wherever routes mount) | Register stickerwalls routes |
+| `frontend/src/hooks/useStickerWall.js` | New file — shared fetch/render hook |
+| `frontend/src/components/StickerWallThumbnail.jsx` | New file — reusable thumbnail |
+| `frontend/src/components/StickerWallModal.jsx` | New file — reusable full-size modal |
+| `frontend/src/pages/Picker.jsx` | Expand sticker card with thumbnail, refresh button, modal |
+| `frontend/src/pages/SessionDetail.jsx` | Add sticker wall section after notes |
diff --git a/frontend/src/config/branding.js b/frontend/src/config/branding.js
index e237eb3..585651b 100644
--- a/frontend/src/config/branding.js
+++ b/frontend/src/config/branding.js
@@ -2,7 +2,7 @@ export const branding = {
app: {
name: 'HSO Jackbox Game Picker',
shortName: 'Jackbox Game Picker',
- version: '0.8.1.1 - Stickers That Stick Edition',
+ version: '8.1.2 - Stickers That Stick Edition',
description: 'Spicing up Hyper Spaceout game nights!',
},
meta: {