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
3 changes: 3 additions & 0 deletions deep-sea-stories/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FISHJAM_ID=
FISHJAM_MANAGEMENT_TOKEN=
ELEVENLABS_API_KEY=
2 changes: 1 addition & 1 deletion deep-sea-stories/packages/web/src/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Toaster } from '@/components/ui/sonner';

const Layout: FC<PropsWithChildren> = (props) => {
return (
<main className="flex flex-col h-screen w-screen">
<main className="flex flex-col h-screen w-screen px-4 md:px-8">
{props.children}
<Toaster />
</main>
Expand Down
16 changes: 13 additions & 3 deletions deep-sea-stories/packages/web/src/assets/elevenlabs.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 11 additions & 11 deletions deep-sea-stories/packages/web/src/components/AgentPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ const PanelEvent: FC<PropsWithChildren<PanelEventProps>> = ({
}) => (
<div key={timestamp} className="flex gap-3 py-1 items-start">
<Icon size={24} className="flex-none" />
<div className="grow flex flex-col text-lg">{children}</div>
<div className="text-right flex-none text-sm text-muted">
<div className="grow flex flex-col text-sm md:text-lg">{children}</div>
<div className="text-right flex-none text-xs md:text-sm text-muted">
{new Date(timestamp).toLocaleTimeString()}
</div>
</div>
Expand All @@ -44,7 +44,7 @@ const renderEvent = (event: AgentEvent, index: number) => {
icon={LogIn}
timestamp={event.timestamp}
>
<div className="text-lg">
<div className="text-sm md:text-lg">
<span className="font-bold">{event.name}</span>
<span className="text-muted-foreground"> has joined the game</span>
</div>
Expand All @@ -57,7 +57,7 @@ const renderEvent = (event: AgentEvent, index: number) => {
icon={LogOut}
timestamp={event.timestamp}
>
<div className="text-lg">
<div className="text-sm md:text-lg">
<span className="font-bold">{event.name}</span>
<span className="text-muted-foreground"> has left the game</span>
</div>
Expand All @@ -70,7 +70,7 @@ const renderEvent = (event: AgentEvent, index: number) => {
icon={BookCheck}
timestamp={event.timestamp}
>
<div className="text-lg">
<div className="text-sm md:text-lg">
<span className="text-muted-foreground">Game Started</span>
</div>
</PanelEvent>
Expand All @@ -82,7 +82,7 @@ const renderEvent = (event: AgentEvent, index: number) => {
icon={OctagonMinus}
timestamp={event.timestamp}
>
<div className="text-lg">
<div className="text-sm md:text-lg">
<span className="text-muted-foreground">Game Ended</span>
</div>
</PanelEvent>
Expand All @@ -94,8 +94,8 @@ const renderEvent = (event: AgentEvent, index: number) => {
icon={MessageSquare}
timestamp={event.timestamp}
>
<div className="text-lg font-bold grow">Storyteller</div>
<div className="text-lg">
<div className="text-sm md:text-lg font-bold grow">Storyteller</div>
<div className="text-sm md:text-lg">
<p>{event.text}</p>
</div>
</PanelEvent>
Expand All @@ -107,13 +107,13 @@ const AgentPanel: FC<AgentPanelProps> = ({ roomId }) => {
const events = useAgentEvents(roomId);

return (
<div className="grid grid-cols-3 p-8 border rounded-xl">
<div className="md:grid grid-cols-3 flex flex-col md:p-8 md:border rounded-xl overflow-y-auto">
<img
src={blob}
alt="agent-visualizer"
className="object-contain h-full"
className="object-contain hidden md:block h-24 md:h-full flex-none"
/>
<ScrollArea className="grow col-span-2 border rounded-xl p-6">
<ScrollArea className="grow col-span-2 border rounded-xl p-3 md:p-6 md:mt-0 md:ml-4">
{events.map((event, index) => renderEvent(event, index))}
</ScrollArea>
</div>
Expand Down
16 changes: 16 additions & 0 deletions deep-sea-stories/packages/web/src/components/DeepSeaLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { cn } from '@/lib/utils';
import type { FC, HTMLAttributes } from 'react';

type DeepSeaLogoProps = HTMLAttributes<HTMLHeadingElement>;

export const DeepSeaLogo: FC<DeepSeaLogoProps> = (props) => (
<h1
{...props}
className={cn(
'font-title text-xl md:text-2xl text-center',
props.className,
)}
>
Deep Sea Stories
</h1>
);
30 changes: 16 additions & 14 deletions deep-sea-stories/packages/web/src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,29 @@ import elevenlabs from '@/assets/elevenlabs.svg';
import fishjam from '@/assets/fishjam.svg';
import HowItWorks from './HowItWorks';
import HowToPlay from './HowToPlay';
import Icon from './Icon';
import LinkButton from './LinkButton';

const Footer: FC = () => {
return (
<div className="flex pb-20 px-16 w-full flex-col items-center justify-between gap-4 md:flex-row">
<div className="flex items-center gap-4">
<p className="shrink-0 text-lg">Created with</p>
<LinkButton to="https://fishjam.io" variant="outline" newTab>
Fishjam
<Icon img={fishjam} alt="fishjam logo" />
</LinkButton>
<LinkButton to="https://elevenlabs.io" variant="outline" newTab>
ElevenLabs
<Icon img={elevenlabs} alt="elevenlabs logo" />
</LinkButton>
</div>
<div className="flex items-center gap-4">
<div className="flex w-full flex-col items-center md:flex-row-reverse justify-between gap-16 md:gap-4">
<div className="flex flex-col lg:flex-row items-center justify-between gap-4">
<HowToPlay />
<HowItWorks />
</div>

<div className="flex items-center flex-col md:flex-row gap-4">
<p className="shrink-0 text-lg">Created with</p>
<div className="flex gap-2 items-center flex-col lg:flex-row">
<LinkButton to="https://fishjam.io" variant="outline" newTab>
Fishjam
<img src={fishjam} alt="Fishjam logo" className="size-6 block" />
</LinkButton>

<LinkButton to="https://elevenlabs.io" variant="outline" newTab>
<img src={elevenlabs} alt="Elevenlabs logo" className="h-4 block" />
</LinkButton>
</div>
</div>
</div>
);
};
Expand Down
4 changes: 2 additions & 2 deletions deep-sea-stories/packages/web/src/components/HowItWorks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ const HowItWorks: FC<ButtonProps> = ({ variant, ...props }) => (
How does it work?
</Button>
</DialogTrigger>
<DialogContent className="bg-accent p-12 w-4xl rounded-4xl">
<DialogContent className="bg-accent p-12 max-w-4xl rounded-4xl">
<DialogHeader className="font-display text-2xl pb-4">
How to play Deep Sea Stories?
</DialogHeader>
<DialogDescription className="text-lg text-primary flex flex-col gap-4">
<DialogDescription className="text-lg text-primary flex flex-col gap-4 overflow-auto max-h-[50vh]">
<p>
“Deep Sea Stories” are a loose adaptation of the well-known game
called “Dark Stories”. With the help of an AI agent and room you can
Expand Down
6 changes: 3 additions & 3 deletions deep-sea-stories/packages/web/src/components/HowToPlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ const HowToPlay: FC<ButtonProps> = ({ variant, ...props }) => (
<Dialog>
<DialogTrigger asChild>
<Button variant={variant ?? 'outline'} {...props}>
How to play?
Help
</Button>
</DialogTrigger>
<DialogContent className="bg-accent p-12 w-4xl rounded-4xl">
<DialogContent className="bg-accent p-12 max-w-4xl rounded-4xl">
<DialogHeader className="font-display text-2xl pb-4">
How to play Deep Sea Stories?
</DialogHeader>
<DialogDescription className="text-lg text-primary flex flex-col gap-4">
<DialogDescription className="text-lg text-primary flex flex-col gap-4 overflow-auto max-h-[50vh]">
<p>
“Deep Sea Stories” are a loose adaptation of the well-known game
called “Dark Stories”. With the help of an AI agent and room you can
Expand Down
8 changes: 5 additions & 3 deletions deep-sea-stories/packages/web/src/components/PeerTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,24 @@ export const PeerTile: FC<PeerTileProps> = ({
return (
<div
className={cn(
'h-full w-full grid place-items-center border rounded-xl',
'h-full w-full flex border items-center max-w-xl justify-center rounded-xl overflow-hidden',
className,
)}
{...props}
>
{stream ? (
<video
className="h-full w-full rounded-xl object-cover"
className="h-full rounded-xl max-w-full object-cover"
autoPlay
muted
disablePictureInPicture
playsInline
ref={videoRef}
></video>
) : (
<div className="text-xl font-display">{name}</div>
<div className="text-sm md:text-xl font-display text-center p-2">
{name}
</div>
)}
{/* biome-ignore lint/a11y/useMediaCaption: Peer audio feed from WebRTC doesn't have captions */}
<audio ref={audioRef} autoPlay playsInline title={`Audio from ${name}`} />
Expand Down
23 changes: 12 additions & 11 deletions deep-sea-stories/packages/web/src/components/RoomControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import StorySelectionPanel from './StorySelectionPanel';
import { Button } from './ui/button';
import { toast } from './ui/sonner';
import { useTRPCClient } from '@/contexts/trpc';
import { DeepSeaLogo } from './DeepSeaLogo';

export type RoomControlsProps = {
roomId: string;
Expand All @@ -23,30 +24,30 @@ const RoomControls: FC<RoomControlsProps> = ({ roomId }) => {
}, [trpc]);

return (
<div className="flex flex-col py-6 gap-8">
<section className="font-title text-2xl text-center">
Deep Sea Stories
</section>
<section className="w-full grow">
<div className="flex flex-col py-2 md:py-6 gap-4 md:gap-8">
<DeepSeaLogo className="hidden md:block" />

<section className="w-full flex-none grid grid-cols-2 md:flex md:flex-col gap-4">
<Button
size="large"
className="w-full"
className="col-span-2 md:w-full text-sm md:text-base"
onClick={() => setIsStoryPanelOpen(true)}
>
Choose a story
</Button>
</section>
<section className="w-full flex-none flex flex-col gap-4">
<HowToPlay className="w-full" />
<HowItWorks className="w-full" />

<HowToPlay className="w-full text-sm md:text-base" />
<HowItWorks className="w-full text-sm md:text-base" />
<CopyButton
variant="outline"
className="col-span-2 md:col-span-1 text-sm md:text-base"
onCopy={() => toast('Gameroom link copied to clipboard', Check)}
value={url}
>
{url.length > 40 ? `${url.substring(0, 37)}...` : url}
Copy room link
</CopyButton>
</section>

<StorySelectionPanel
isOpen={isStoryPanelOpen}
onClose={() => setIsStoryPanelOpen(false)}
Expand Down
8 changes: 5 additions & 3 deletions deep-sea-stories/packages/web/src/components/TitleBar.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import type { FC } from 'react';
import { DeepSeaLogo } from './DeepSeaLogo';

const TitleBar: FC = () => {
return (
<div className="flex w-full pt-16 flex-col items-center justify-between gap-10">
<h1 className="font-title text-8xl">Deep Sea Stories</h1>
<h2 className="font-display text-3xl">
<div className="w-full space-y-4 text-center">
<DeepSeaLogo className="text-6xl xl:text-8xl" />

<h2 className="font-display text-xl lg:text-3xl">
Hear the most mysterious stories and try to deduce how they happened.
</h2>
</div>
Expand Down
3 changes: 3 additions & 0 deletions deep-sea-stories/packages/web/src/contexts/trpc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ export const TRPCClientProvider: FC<TRPCClientProviderProps> = ({
queryClient,
children,
}) => {
if (!import.meta.env.VITE_BACKEND_URL) {
throw new Error('VITE_BACKEND_URL is not set');
}
const [trpcClient] = useState(() =>
createTRPCClient<AppRouter>({
links: [
Expand Down
32 changes: 18 additions & 14 deletions deep-sea-stories/packages/web/src/views/GameView.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { usePeers } from '@fishjam-cloud/react-client';
import {
useCamera,
useInitializeDevices,
usePeers,
} from '@fishjam-cloud/react-client';
import type { FC } from 'react';
import { useMemo, useEffect, useRef } from 'react';
import { useQuery } from '@tanstack/react-query';
import AgentPanel from '@/components/AgentPanel';
import { PeerTile } from '@/components/PeerTile';
import RoomControls from '@/components/RoomControls';
import { useTRPCClient } from '@/contexts/trpc';
import { cn } from '@/lib/utils';

export type GameViewProps = {
roomId: string;
Expand Down Expand Up @@ -49,28 +54,27 @@ const GameView: FC<GameViewProps> = ({ roomId }) => {
agentAudioRef.current.srcObject = audioStream ?? null;
}, [agentPeer?.tracks[0]?.stream]);

const gridColumns = displayedPeers.length + 1;

return (
<>
<section className="w-full h-1/2 flex gap-8 pt-10 px-10">
<section className="w-full h-1/2 flex flex-col md:flex-row gap-8 pt-10 px-10">
<AgentPanel roomId={roomId} />
<RoomControls roomId={roomId} />
</section>

<section
className="w-full h-1/2 grid place-items-center gap-4 py-10 px-10"
style={{
gridTemplateColumns: `repeat(${gridColumns}, minmax(0, 1fr))`,
}}
className={cn(
'h-1/2 items-center w-full justify-items-center grid gap-4 py-10 overflow-hidden grid-cols-2 grid-rows-2 xl:grid-cols-4 xl:grid-rows-1',
{
'grid-cols-1 grid-rows-1 xl:grid-cols-1 md:grid-rows-1':
displayedPeers.length === 0,
'grid-rows-2 grid-cols-1 md:grid-cols-2 md:grid-rows-1 xl:grid-rows-1 xl:grid-cols-2':
displayedPeers.length === 1,
},
)}
>
<PeerTile
className="max-w-2xl"
name="You"
stream={localPeer?.cameraTrack?.stream}
/>
<PeerTile name="You" stream={localPeer?.cameraTrack?.stream} />
{displayedPeers.map((peer) => (
<PeerTile
className="max-w-2xl"
name={peer.metadata?.peer?.name ?? peer.id}
key={peer.id}
stream={
Expand Down
4 changes: 2 additions & 2 deletions deep-sea-stories/packages/web/src/views/HomeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default function HomeView() {
};

return (
<>
<section className="h-full w-full flex justify-between flex-col py-16 px-4 lg:px-16">
<TitleBar />
<section className="flex-1 py-16 grid place-items-center">
<Button
Expand All @@ -36,6 +36,6 @@ export default function HomeView() {
</Button>
</section>
<Footer />
</>
</section>
);
}
Loading