Skip to content

Add live translation demo#72

Open
Karolk99 wants to merge 1 commit into
mainfrom
live-translations
Open

Add live translation demo#72
Karolk99 wants to merge 1 commit into
mainfrom
live-translations

Conversation

@Karolk99

@Karolk99 Karolk99 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Open source the live translation demo.
The source code will probably be updated in the near future.

@Karolk99 Karolk99 requested review from Copilot and czerwiukk June 9, 2026 17:14
@vercel

vercel Bot commented Jun 9, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
moq-demo Ready Ready Preview, Comment Jun 9, 2026 5:14pm

Request Review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new live-translation Vite + React application that open-sources a live streaming demo where a publisher streams camera/mic and viewers can watch with selectable AI-translated audio tracks over Media over QUIC (MoQ).

Changes:

  • Adds a complete Vite/React app scaffold (Vite config, TS config, Tailwind, PostCSS, routing, assets).
  • Implements MoQ publishing + viewing with translation discovery, quality selection, and synced A/V playback when switching translations.
  • Adds basic UI components and pages for publishing (QR/link sharing) and watching (play-gated viewer).

Reviewed changes

Copilot reviewed 41 out of 47 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
live-translation/vite.config.ts Vite dev server + alias configuration
live-translation/tsconfig.json TypeScript compiler configuration
live-translation/tailwind.config.cjs Tailwind theme/content configuration
live-translation/src/vite-env.d.ts Vite env var typings
live-translation/src/pages/watch.tsx Viewer route/page (play-gated)
live-translation/src/pages/publish.tsx Publisher route/page wrapper
live-translation/src/main.tsx App bootstrap, Fishjam provider, routes
live-translation/src/lib/utils.ts Shared cn() utility
live-translation/src/layout.tsx App layout + toaster mount
live-translation/src/index.css Global styles (Tailwind + custom layout CSS)
live-translation/src/hooks/useWakeLock.ts Wake lock hook for viewer/publisher sessions
live-translation/src/components/VideoPlayer.tsx MediaStream-backed <video> helper
live-translation/src/components/ui/sonner.tsx Toast toaster wrapper
live-translation/src/components/ui/select.tsx Radix select wrapper UI
live-translation/src/components/ui/label.tsx Label UI component
live-translation/src/components/ui/card.tsx Card UI components
live-translation/src/components/ui/button.tsx Button UI component
live-translation/src/components/ui/badge.tsx Badge UI component
live-translation/src/components/moq/VideoTile.tsx Tile rendering + quality/translation selectors
live-translation/src/components/moq/VideoSurface.tsx Video/canvas surface + backend attachment
live-translation/src/components/moq/utils.ts URL building, naming, translation parsing, persistence helpers
live-translation/src/components/moq/useSyncedPlayback.ts Hook managing persistent synced playback instance
live-translation/src/components/moq/useSignalValue.ts React hook adapter for MoQ signals
live-translation/src/components/moq/usePublisher.ts Publisher session + device selection + broadcast setup
live-translation/src/components/moq/useMoqStreamViewer.ts Connect-to-single-stream viewer hook
live-translation/src/components/moq/useMoqConnection.ts Core connection + discovery + tile model
live-translation/src/components/moq/types.ts Shared MoQ/publisher/viewer types
live-translation/src/components/moq/syncedPlayback.ts Cross-broadcast A/V clocking for translation audio
live-translation/src/components/moq/RoomView.tsx Main viewer UI frame (single-stream)
live-translation/src/components/moq/quality.ts Quality preference + rendition selection
live-translation/src/components/moq/PublisherPanel.tsx Publisher UI incl. QR/link + start/stop
live-translation/src/components/moq/generateStreamName.ts Stream name generator
live-translation/src/components/moq/CallToolbar.tsx Disconnect toolbar/footer
live-translation/src/components/moq/BrandHeader.tsx Header lockup + tagline
live-translation/src/components/DeviceSelect.tsx Camera/microphone device selector
live-translation/README.md Demo documentation + setup steps
live-translation/public/gemini-logo.svg Public asset
live-translation/public/fishjam-logo.svg Public asset
live-translation/public/favicon.svg Public asset
live-translation/public/avatar.svg Public asset
live-translation/postcss.config.cjs PostCSS configuration
live-translation/package.json App dependencies/scripts
live-translation/index.html Vite HTML entry
live-translation/.yarnrc.yml Yarn config
live-translation/.gitignore Demo-local gitignore
live-translation/.env.example Example env vars

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +3
/** @type {import('tailwindcss').Config} */
export default {
darkMode: ['class'],
Comment on lines +1 to +11
import { useTheme } from 'next-themes';
import { Toaster as Sonner } from 'sonner';

type ToasterProps = React.ComponentProps<typeof Sonner>;

const Toaster = ({ ...props }: ToasterProps) => {
const { theme = 'system' } = useTheme();

return (
<Sonner
theme={theme as ToasterProps['theme']}
Comment on lines +4 to +14
useEffect(() => {
const wakeLockAvailable = 'wakeLock' in navigator;
if (!wakeLockAvailable) {
return;
}

const wakeLock = navigator.wakeLock.request('screen');

return () => {
wakeLock.then((sentinel) => sentinel.release());
};
Comment on lines +159 to +162
className={cn(
'relative flex items-center justify-center overflow-hidden rounded-lg bg-stone-200',
isTileWithoutVideo && "bg-[url('./avatar.svg')] bg-center bg-no-repeat bg-[length:33%]",
isScreenshareTile && 'bg-black',
Comment on lines +170 to +176
export const prettyPeerName = (path: string) => {
const lastSegment =
path
.split('/')
.at(-1)
?.replace(new RegExp(`${SCREENSHARE_PATH_SUFFIX}$`), '') ?? 'peer';
const strippedSuffix = lastSegment.replace(/-[a-f0-9]{8}$/i, '');
Comment on lines +8 to +11
server: {
allowedHosts: true,
port: 5170,
},
Comment on lines +71 to +78
<Button
variant="outline"
size="icon"
title="Copy link"
onClick={() => {
navigator.clipboard.writeText(shareUrl);
toast('Viewer link copied to clipboard', { position: 'top-center', duration: 1500 });
}}>

@czerwiukk czerwiukk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

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.

3 participants