Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 1 addition & 196 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -1389,86 +1389,7 @@ p {
}
}

/* Audience Reaction Buttons */
.reaction-btn {
width: 48px;
height: 48px;
border-radius: var(--radius-full);
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
cursor: pointer;
border: none;
position: relative;
overflow: hidden;
transition: transform var(--duration-fast) var(--easing-spring);
}

.reaction-btn:active {
transform: scale(0.9);
}

.reaction-btn-laugh {
background: radial-gradient(circle at 30% 30%, #FFD700, #FFA500);
}

.reaction-btn-cheer {
background: radial-gradient(circle at 30% 30%, #FF69B4, #FF1493);
}

.reaction-btn-gasp {
background: radial-gradient(circle at 30% 30%, #87CEEB, #4169E1);
}

.reaction-btn-boo {
background: radial-gradient(circle at 30% 30%, #9370DB, #6A0DAD);
}

.reaction-btn-applause {
background: radial-gradient(circle at 30% 30%, #50C878, #228B22);
}

.reaction-btn::after {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
opacity: 0;
transition: opacity var(--duration-fast);
}

.reaction-btn:hover::after {
background: rgba(255, 255, 255, 0.15);
opacity: 1;
}

@keyframes ring-burst {
0% {
box-shadow: 0 0 0 0 currentColor;
opacity: 0.6;
}
100% {
box-shadow: 0 0 0 20px transparent;
opacity: 0;
}
}

.reaction-btn-burst {
animation: ring-burst 0.4s var(--easing-out) forwards;
}

.reaction-cooldown-sweep {
position: absolute;
inset: 0;
border-radius: inherit;
background: conic-gradient(
transparent var(--sweep-progress, 0%),
rgba(0, 0, 0, 0.4) var(--sweep-progress, 0%)
);
pointer-events: none;
}

/* Audience Reaction - Host Count Badges */
.reaction-count-badge {
font-size: 12px;
font-weight: 600;
Expand All @@ -1486,14 +1407,6 @@ p {
animation: count-bounce 0.3s var(--easing-spring);
}

@media (min-width: 640px) {
.reaction-btn {
width: 56px;
height: 56px;
font-size: 28px;
}
}

/* Settings Panel */
.settings-panel {
background: var(--color-surface-alt);
Expand Down Expand Up @@ -4057,114 +3970,6 @@ textarea:focus-visible {
}
}

/* ==========================================================================
Audience Reaction Buttons
========================================================================== */

.reaction-btn {
width: 48px;
height: 48px;
border-radius: var(--radius-full);
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
cursor: pointer;
border: none;
position: relative;
overflow: hidden;
transition: transform var(--duration-fast) var(--easing-spring);
}

.reaction-btn:active {
transform: scale(0.9);
}

.reaction-btn-laugh {
background: radial-gradient(circle at 30% 30%, #FFD700, #FFA500);
}

.reaction-btn-cheer {
background: radial-gradient(circle at 30% 30%, #FF69B4, #FF1493);
}

.reaction-btn-gasp {
background: radial-gradient(circle at 30% 30%, #87CEEB, #4169E1);
}

.reaction-btn-boo {
background: radial-gradient(circle at 30% 30%, #9370DB, #6A0DAD);
}

.reaction-btn-applause {
background: radial-gradient(circle at 30% 30%, #50C878, #228B22);
}

.reaction-btn::after {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
opacity: 0;
transition: opacity var(--duration-fast);
}

.reaction-btn:hover::after {
background: rgba(255, 255, 255, 0.15);
opacity: 1;
}

@keyframes ring-burst {
0% {
box-shadow: 0 0 0 0 currentColor;
opacity: 0.6;
}
100% {
box-shadow: 0 0 0 20px transparent;
opacity: 0;
}
}

.reaction-btn-burst {
animation: ring-burst 0.4s var(--easing-out) forwards;
}

.reaction-cooldown-sweep {
position: absolute;
inset: 0;
border-radius: inherit;
background: conic-gradient(
transparent var(--sweep-progress, 0%),
rgba(0, 0, 0, 0.4) var(--sweep-progress, 0%)
);
pointer-events: none;
}

.reaction-count-badge {
font-size: 12px;
font-weight: 600;
color: rgba(255, 255, 255, 0.8);
min-width: 20px;
text-align: center;
}

@keyframes count-bounce {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.3); }
}

.reaction-count-bounce {
animation: count-bounce 0.3s var(--easing-spring);
}

@media (min-width: 640px) {
.reaction-btn {
width: 56px;
height: 56px;
font-size: 28px;
}
}

/* ==========================================================================
Movie Poster Frame
========================================================================== */
Expand Down
9 changes: 5 additions & 4 deletions app/host/components/HostPerforming.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface HostPerformingProps {
chaosCooldown: boolean
chaosCooldownRemaining: number
chaosShaking: boolean
isSoloMode?: boolean
teleprompterSettings: TeleprompterSettingsType
teleprompterSettingsLoading: boolean
onNextLine: () => void
Expand All @@ -40,7 +41,7 @@ export interface HostPerformingProps {
export function HostPerforming({
script, currentLineIndex, isPlaying, roomCode,
networkLatency, spectatorMessages, scriptImageUrl, isGeneratingImage,
chaosCooldown, chaosCooldownRemaining, chaosShaking,
chaosCooldown, chaosCooldownRemaining, chaosShaking, isSoloMode = false,
teleprompterSettings, teleprompterSettingsLoading,
onNextLine, onPreviousLine, onTogglePlayPause, onTriggerChaos,
onSetTeleprompterPreset, onSetTeleprompterCustom, onToggleTeleprompterAutoScroll,
Expand Down Expand Up @@ -69,8 +70,8 @@ export function HostPerforming({
return (
<motion.div key="performing" variants={VARIANTS.pageTransition} initial="initial" animate="animate" exit="exit" className="container max-w-5xl">
<SpectatorTicker messages={spectatorMessages} />
<AudienceReactionBar roomCode={roomCode} isPerforming={true} isHost={true} />
<PlotTwistVoting roomCode={roomCode} isHost={true} />
{!isSoloMode && <AudienceReactionBar roomCode={roomCode} isPerforming={true} isHost={true} />}
{!isSoloMode && <PlotTwistVoting roomCode={roomCode} isHost={true} />}

{/* Poster */}
<AnimatePresence mode="wait">
Expand Down Expand Up @@ -172,7 +173,7 @@ export function HostPerforming({
{chaosCooldown ? (
<span className="flex items-center gap-2">🌀 {Math.ceil(chaosCooldownRemaining)}s</span>
) : (
<span className="flex items-center gap-2"><motion.span animate={{ rotate: 360 }} transition={{ duration: 3, repeat: Infinity, ease: 'linear' }}>🌀</motion.span>CHAOS</span>
<span className="flex items-center gap-2"><motion.span animate={{ rotate: 360 }} transition={{ duration: 3, repeat: Infinity, ease: 'linear' }}>🌀</motion.span>{isSoloMode ? 'TWIST' : 'CHAOS'}</span>
)}
{chaosCooldown && (
<div className="absolute bottom-0 left-0 h-1 rounded-full" style={{ width: `${(chaosCooldownRemaining / 30) * 100}%`, background: 'linear-gradient(90deg, #a855f7, #ec4899)', transition: 'width 0.1s linear' }} />
Expand Down
3 changes: 2 additions & 1 deletion app/host/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export default function HostPage() {
setTimeout(() => setChaosShaking(false), 500)
successHaptic() // native haptics on iOS; no-op on web
if (navigator.vibrate) navigator.vibrate([100, 50, 100, 50, 200]) // Android web fallback
toast.info('CHAOS unleashed! Audience is voting on a plot twist...')
toast.info(settings.gameMode === 'SOLO' ? 'PLOT TWIST incoming!' : 'CHAOS unleashed! Audience is voting on a plot twist...')
}, [socket, roomCode, chaosCooldown, toast, setChaosCooldown])

const handleSetupModeChange = (mode: 'quick' | 'custom') => {
Expand Down Expand Up @@ -379,6 +379,7 @@ export default function HostPage() {
chaosCooldown={chaosCooldown}
chaosCooldownRemaining={chaosCooldownRemaining}
chaosShaking={chaosShaking}
isSoloMode={settings.gameMode === 'SOLO'}
teleprompterSettings={teleprompterSettings}
teleprompterSettingsLoading={teleprompterSettingsLoading}
onNextLine={nextLine} onPreviousLine={previousLine}
Expand Down
Loading