Skip to content

Redesign audience reaction UI with FAB and popup grid - #9

Merged
jackson-jpeg merged 2 commits into
v2from
claude/redesign-voting-ui-H4pCz
Feb 21, 2026
Merged

jackson-jpeg merged 2 commits into
v2from
claude/redesign-voting-ui-H4pCz

Conversation

@jackson-jpeg

Copy link
Copy Markdown
Owner

Summary

Redesigned the audience reaction interface from a horizontal button bar to a modern floating action button (FAB) with an expandable popup grid. This improves mobile UX by reducing screen clutter and providing better visual feedback. Also added solo mode support for plot twist voting.

Key Changes

Audience Reaction UI Redesign

  • Replaced horizontal button bar with a floating action button (FAB) positioned at bottom-right that toggles a 4-column reaction grid popup
  • Added floating emoji animations that rise from the FAB when reactions are received, providing visual feedback without cluttering the screen
  • Implemented popup menu with glassmorphic design (backdrop blur, semi-transparent background) that animates in/out smoothly
  • Enhanced FAB styling with dynamic colors (orange when open, dark when closed) and a cooldown ring SVG indicator around the button
  • Added last reaction memory - FAB displays the emoji of the last reaction sent, defaulting to a lightning bolt
  • Improved labels - Updated reaction labels ("Applause" → "Clap", "Mind Blown" → "Wow") for brevity in the compact grid layout
  • Added outside-click detection to close the popup menu when tapping elsewhere
  • Removed old CSS - Deleted 100+ lines of gradient button styles and conic-gradient cooldown sweep animations that are no longer needed

Host View (Unchanged)

  • Host view continues to display floating reactions and compact count badges at the top-right
  • No changes to host-side functionality

Solo Mode Plot Twist Support

  • Added auto-apply logic for plot twists in solo mode (skips audience voting)
  • Randomly selects a twist and immediately injects it into the script
  • Generates AI dialogue in the background without blocking the performance
  • Falls back gracefully if injection fails

Code Quality

  • Imported MOTION animation presets from @/lib/animations for consistent spring/easing
  • Removed redundant comments and cleaned up code formatting
  • Consolidated state initialization (single-line object literals)
  • Added isSoloMode prop to HostPerforming component for mode detection

Implementation Details

  • Uses Framer Motion's AnimatePresence for smooth enter/exit animations
  • Popup grid items stagger in with delay: i * 0.03 for a cascading effect
  • Cooldown progress visualized via SVG circle with strokeDasharray for smooth ring animation
  • Floating emojis use randomized rotation and scale for organic feel
  • Backdrop blur applied via CSS backdrop-filter with webkit fallback for iOS support

https://claude.ai/code/session_014T4yzapvSSZdPBJCJgsRkP

Replace the cramped 8-emoji horizontal pill bar (which overflowed on
small phones) with a clean FAB + popup grid pattern:

- Single floating action button on bottom-right, above nav controls
- Tap to expand a frosted-glass popup with 4x2 emoji grid
- Each reaction has proper touch targets with labels
- Cooldown shown as an SVG ring around the FAB
- Floating emoji rise from FAB when reactions come in
- Auto-dismiss on selection or tap outside
- Host view unchanged (count badges + floating emojis)

Removes all old .reaction-btn CSS (including duplicate block) since
mobile reactions are now fully inline-styled in the component.

https://claude.ai/code/session_014T4yzapvSSZdPBJCJgsRkP
Solo mode changes:
- Server: when host triggers CHAOS in solo mode, immediately pick a
  random twist and inject it instead of starting a 15s vote timer
  with no audience to vote
- Host UI: hide AudienceReactionBar and PlotTwistVoting in solo mode
  (no audience to show reactions from or voting UI to)
- Rename CHAOS button to TWIST in solo mode
- Update toast message for solo ("PLOT TWIST incoming!" vs audience voting)

Voting phase was already skipped server-side for solo mode
(teleprompter.service.ts goes straight to RESULTS).

https://claude.ai/code/session_014T4yzapvSSZdPBJCJgsRkP
@vercel

vercel Bot commented Feb 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
plot-twists Ready Ready Preview, Comment Feb 21, 2026 5:22pm

@jackson-jpeg
jackson-jpeg merged commit 3626b58 into v2 Feb 21, 2026
3 checks passed
jackson-jpeg added a commit that referenced this pull request Jul 29, 2026
…ount

The cost section now carries the credit-tier table it was missing. One credit is
one round (deductCreditOrReject), lib/credits.ts prices four tiers, so #9 is
answerable on data for the first time: every tier covers the $0.053 inference
cost, and the original "$0.05-$0.07 per round" estimate was right at the low end.

The thin cell is Studio Head sold through Apple IAP — $0.070 a script against
$0.053, about a 24% gross margin before hosting. It goes negative around 4000
output tokens, and scripts are ALREADY running 50-80% over their requested line
count, so that is not a hypothetical. Web-first materially helps here: Stripe's
~3% against Apple's 30% is the difference between a 1.8x and a 1.3x margin on the
tier a heavy host is most likely to buy.

Also fixes a stale figure. The packet claimed scripts "came back at 45-64 lines"
— carried over from an earlier run, when the current one produced 59-73. A
hardcoded number went wrong inside a single regeneration, so the range is now
computed from the data it describes. Same class of mistake as the ordering gate
earlier today: a number written down beside the thing it measures instead of
derived from it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jackson-jpeg added a commit that referenced this pull request Jul 29, 2026
…aight man

Jackson's rulings, Q1-Q4.

Q1 — length. Target 30-38 lines, ceiling 2,600 tokens, over my proposed 35-45.
Applied to BOTH branches of generateScript: the host UI sends
scriptLength:'standard', so a real game takes the customization path, and
capping only the default would have measured clean and shipped inert. The
ENSEMBLE x1.25 multiplier is gone with it — it re-inflated standard to 3,250
on exactly the mode being capped, and cast size does not change tokens per
line. Three fresh 8-player generations: 38/38/38 lines, none truncated. Output
fell 39%; a round went $0.0531 -> $0.0407, and output's share of it 83% -> 56%.
SOLO measured too rather than assumed, since every number behind 2,600 was
ENSEMBLE.

A ceiling reached mid-JSON is a parse failure, not a short script, so
stop_reason === 'max_tokens' now throws with a message naming the ceiling
instead of surfacing "Unexpected end of JSON input" from the parser.

Q2 — DECISIONS #9 closed on measured margins. No repricing. Studio Head is
web/Stripe only and gets re-run if it ever ships through Apple IAP; 1.7x on
observed mean is not a business. Stripe modelled at 2.9% + $0.30, not a flat
3% — the fixed fee is 6% of a $5 purchase.

Q3 — the straight man is no longer characters[0]. The prompt picks it.

Q4 — logging kept.

Two things found while doing the above, both caught by cross-checking a change
against its instrument rather than either against itself:

- A FIFTH franchise leak, in the live SOLO prompt: "If the setting is from a
  known show/universe, USE THOSE CHARACTERS". Every layer passed it — the
  source audit looks for franchise names and there is no name in that sentence,
  and layer 3 screens output that the instruction had asked for. A leak does
  not need a proper noun, it needs permission. New gate reads prompt text for
  permission-shaped instructions; verified by reintroducing this line and the
  old "Yoda talks like Yoda" and watching it go red on both.

- The harness's script counter keyed on max_tokens >= 5000, calibrated to
  ENSEMBLE's old 10,000. At 2,600 it counted zero and failed three checks on a
  working product. Already latent: lightning asks for 2,048. The floor now sits
  between the populations and asserts its own separation at startup.

Also: disable Vercel preview deploys for this branch. The builds fail on the
missing Clerk publishable key, and the project cannot serve this product
anyway — start is a custom Socket.IO server that Vercel's preset never runs.

Suite 450/450, harness 49/49, tsc clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jackson-jpeg added a commit that referenced this pull request Jul 30, 2026
plotupdate.md is written for an outsider with no context — what the product
is, where it stands, what this session did, and the honest list of what is
unverified.

Writing it surfaced a real finding: DECISIONS #9's margin table still assumes
$0.0407 per round. #14 raised the line budget the same week, recorded the new
cost, and never recomputed the tiers. Re-measured at $0.0560; every tier still
clears on the web, but Studio Head via Apple IAP is 1.25x. The entry's own
tripwire was set to fire on a payment-rail change while the thing that moved
was cost — a guard watching one input while the other moves is not a guard.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants