diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 83c3322..154840e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -131,180 +131,7 @@ importers: specifier: 5.9.3 version: 5.9.3 - videos/cuabench-launch: - dependencies: - '@launchpad/assets': - specifier: workspace:* - version: link:../../packages/assets - '@launchpad/shared': - specifier: workspace:* - version: link:../../packages/shared - '@remotion/bundler': - specifier: 4.0.407 - version: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@remotion/cli': - specifier: 4.0.407 - version: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@remotion/google-fonts': - specifier: 4.0.407 - version: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@remotion/paths': - specifier: 4.0.407 - version: 4.0.407 - '@remotion/player': - specifier: 4.0.407 - version: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@remotion/shapes': - specifier: 4.0.407 - version: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@remotion/tailwind-v4': - specifier: 4.0.407 - version: 4.0.407(@remotion/bundler@4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)(webpack@5.96.1) - clsx: - specifier: 2.1.1 - version: 2.1.1 - next: - specifier: 16.0.10 - version: 16.0.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: - specifier: 19.2.3 - version: 19.2.3 - react-dom: - specifier: 19.2.3 - version: 19.2.3(react@19.2.3) - remotion: - specifier: 4.0.407 - version: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - tailwind-merge: - specifier: 3.0.1 - version: 3.0.1 - zod: - specifier: 3.22.3 - version: 3.22.3 - devDependencies: - '@remotion/eslint-plugin': - specifier: 4.0.407 - version: 4.0.407(eslint@9.19.0(jiti@2.6.1))(typescript@5.9.3) - '@tailwindcss/postcss': - specifier: 4.1.1 - version: 4.1.1 - '@types/node': - specifier: 20.12.14 - version: 20.12.14 - '@types/react': - specifier: 19.2.3 - version: 19.2.3 - '@types/react-dom': - specifier: 19.2.3 - version: 19.2.3(@types/react@19.2.3) - autoprefixer: - specifier: 10.4.20 - version: 10.4.20(postcss@8.4.47) - eslint: - specifier: 9.19.0 - version: 9.19.0(jiti@2.6.1) - postcss: - specifier: 8.4.47 - version: 8.4.47 - prettier: - specifier: 3.6.0 - version: 3.6.0 - tailwindcss: - specifier: 4.0.3 - version: 4.0.3 - typescript: - specifier: 5.9.3 - version: 5.9.3 - - videos/cuabenchnew: - dependencies: - '@launchpad/assets': - specifier: workspace:* - version: link:../../packages/assets - '@launchpad/shared': - specifier: workspace:* - version: link:../../packages/shared - '@remotion/bundler': - specifier: 4.0.407 - version: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@remotion/cli': - specifier: 4.0.407 - version: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@remotion/google-fonts': - specifier: 4.0.407 - version: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@remotion/paths': - specifier: 4.0.407 - version: 4.0.407 - '@remotion/player': - specifier: 4.0.407 - version: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@remotion/shapes': - specifier: 4.0.407 - version: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@remotion/tailwind-v4': - specifier: 4.0.407 - version: 4.0.407(@remotion/bundler@4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)(webpack@5.96.1) - '@remotion/transitions': - specifier: 4.0.407 - version: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - clsx: - specifier: 2.1.1 - version: 2.1.1 - next: - specifier: 16.0.10 - version: 16.0.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: - specifier: 19.2.3 - version: 19.2.3 - react-dom: - specifier: 19.2.3 - version: 19.2.3(react@19.2.3) - remotion: - specifier: 4.0.407 - version: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - tailwind-merge: - specifier: 3.0.1 - version: 3.0.1 - zod: - specifier: 3.22.3 - version: 3.22.3 - devDependencies: - '@remotion/eslint-plugin': - specifier: 4.0.407 - version: 4.0.407(eslint@9.19.0(jiti@2.6.1))(typescript@5.9.3) - '@tailwindcss/postcss': - specifier: 4.1.1 - version: 4.1.1 - '@types/node': - specifier: 20.12.14 - version: 20.12.14 - '@types/react': - specifier: 19.2.7 - version: 19.2.7 - '@types/react-dom': - specifier: 19.2.3 - version: 19.2.3(@types/react@19.2.7) - autoprefixer: - specifier: 10.4.20 - version: 10.4.20(postcss@8.4.47) - eslint: - specifier: 9.19.0 - version: 9.19.0(jiti@2.6.1) - postcss: - specifier: 8.4.47 - version: 8.4.47 - prettier: - specifier: 3.6.0 - version: 3.6.0 - tailwindcss: - specifier: 4.0.3 - version: 4.0.3 - typescript: - specifier: 5.9.3 - version: 5.9.3 - - videos/skills-announcement: + videos/laudos-launch: dependencies: '@launchpad/assets': specifier: workspace:* @@ -1356,12 +1183,6 @@ packages: peerDependencies: '@remotion/bundler': 4.0.407 - '@remotion/transitions@4.0.407': - resolution: {integrity: sha512-XnRoBM/IEjQ3BHjTlJS/b3o8uxq9CH/s8qAC9n1PWkhoWx4I1/JaUqFbkunc6LQIAPC7286up2Edtx2zAOP1rA==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - '@remotion/web-renderer@4.0.407': resolution: {integrity: sha512-wO3IE+opVoT6mdcrZUzvD9urdglOr91qXO4uJqbTgzcVzRCpRp2iOPKQCjPmI/RxWQ6+fWN4VjZJP1E0iQIgGw==} peerDependencies: @@ -1481,9 +1302,6 @@ packages: peerDependencies: '@types/react': ^19.2.0 - '@types/react@19.2.3': - resolution: {integrity: sha512-k5dJVszUiNr1DSe8Cs+knKR6IrqhqdhpUwzqhkS8ecQTSf3THNtbfIp/umqHMpX2bv+9dkx3fwDv/86LcSfvSg==} - '@types/react@19.2.7': resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==} @@ -3508,14 +3326,14 @@ snapshots: '@remotion/media-parser': 4.0.407 '@remotion/studio': 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@remotion/studio-shared': 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - css-loader: 5.2.7(webpack@5.96.1) + css-loader: 5.2.7(webpack@5.96.1(esbuild@0.25.0)) esbuild: 0.25.0 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) react-refresh: 0.9.0 remotion: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) source-map: 0.7.3 - style-loader: 4.0.0(webpack@5.96.1) + style-loader: 4.0.0(webpack@5.96.1(esbuild@0.25.0)) webpack: 5.96.1(esbuild@0.25.0) transitivePeerDependencies: - '@swc/core' @@ -3692,25 +3510,17 @@ snapshots: dependencies: '@remotion/bundler': 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@tailwindcss/postcss': 4.1.1 - css-loader: 5.2.7(webpack@5.96.1) + css-loader: 5.2.7(webpack@5.96.1(esbuild@0.25.0)) postcss: 8.5.1 postcss-loader: 8.1.1(postcss@8.5.1)(typescript@5.9.3)(webpack@5.96.1) postcss-preset-env: 10.1.3(postcss@8.5.1) - style-loader: 4.0.0(webpack@5.96.1) + style-loader: 4.0.0(webpack@5.96.1(esbuild@0.25.0)) tailwindcss: 4.1.1 transitivePeerDependencies: - '@rspack/core' - typescript - webpack - '@remotion/transitions@4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@remotion/paths': 4.0.407 - '@remotion/shapes': 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - remotion: 4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@remotion/web-renderer@4.0.407(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@remotion/licensing': 4.0.407 @@ -3821,18 +3631,10 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/react-dom@19.2.3(@types/react@19.2.3)': - dependencies: - '@types/react': 19.2.3 - '@types/react-dom@19.2.3(@types/react@19.2.7)': dependencies: '@types/react': 19.2.7 - '@types/react@19.2.3': - dependencies: - csstype: 3.2.3 - '@types/react@19.2.7': dependencies: csstype: 3.2.3 @@ -4105,7 +3907,7 @@ snapshots: postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 - css-loader@5.2.7(webpack@5.96.1): + css-loader@5.2.7(webpack@5.96.1(esbuild@0.25.0)): dependencies: icss-utils: 5.1.0(postcss@8.4.47) loader-utils: 2.0.4 @@ -5102,7 +4904,7 @@ snapshots: strip-json-comments@3.1.1: {} - style-loader@4.0.0(webpack@5.96.1): + style-loader@4.0.0(webpack@5.96.1(esbuild@0.25.0)): dependencies: webpack: 5.96.1(esbuild@0.25.0) @@ -5127,7 +4929,7 @@ snapshots: tapable@2.3.0: {} - terser-webpack-plugin@5.3.16(esbuild@0.25.0)(webpack@5.96.1(esbuild@0.25.0)): + terser-webpack-plugin@5.3.16(esbuild@0.25.0)(webpack@5.96.1): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 @@ -5249,7 +5051,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(esbuild@0.25.0)(webpack@5.96.1(esbuild@0.25.0)) + terser-webpack-plugin: 5.3.16(esbuild@0.25.0)(webpack@5.96.1) watchpack: 2.5.1 webpack-sources: 3.3.3 transitivePeerDependencies: diff --git a/videos/laudos-launch/next.config.js b/videos/laudos-launch/next.config.js new file mode 100644 index 0000000..2b227a8 --- /dev/null +++ b/videos/laudos-launch/next.config.js @@ -0,0 +1,6 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + transpilePackages: ["@launchpad/shared", "@launchpad/assets"], +}; + +module.exports = nextConfig; diff --git a/videos/laudos-launch/package.json b/videos/laudos-launch/package.json new file mode 100644 index 0000000..333891e --- /dev/null +++ b/videos/laudos-launch/package.json @@ -0,0 +1,45 @@ +{ + "name": "@launchpad/LaudosLaunch", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint .", + "remotion": "remotion studio", + "render": "remotion render LaudosLaunchFull", + "render:preview": "remotion render LaudosLaunchFull --scale=0.5" + }, + "dependencies": { + "@launchpad/shared": "workspace:*", + "@launchpad/assets": "workspace:*", + "@remotion/bundler": "4.0.407", + "@remotion/cli": "4.0.407", + "@remotion/google-fonts": "4.0.407", + "@remotion/paths": "4.0.407", + "@remotion/player": "4.0.407", + "@remotion/shapes": "4.0.407", + "@remotion/tailwind-v4": "4.0.407", + "clsx": "2.1.1", + "next": "16.0.10", + "react": "19.2.3", + "react-dom": "19.2.3", + "remotion": "4.0.407", + "tailwind-merge": "3.0.1", + "zod": "3.22.3" + }, + "devDependencies": { + "@tailwindcss/postcss": "4.1.1", + "@remotion/eslint-plugin": "4.0.407", + "@types/node": "20.12.14", + "@types/react": "19.2.7", + "@types/react-dom": "19.2.3", + "autoprefixer": "10.4.20", + "eslint": "9.19.0", + "postcss": "8.4.47", + "prettier": "3.6.0", + "tailwindcss": "4.0.3", + "typescript": "5.9.3" + } +} diff --git a/videos/laudos-launch/postcss.config.mjs b/videos/laudos-launch/postcss.config.mjs new file mode 100644 index 0000000..d5c96e4 --- /dev/null +++ b/videos/laudos-launch/postcss.config.mjs @@ -0,0 +1,8 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + autoprefixer: {}, + }, +}; + +export default config; diff --git a/videos/laudos-launch/public/.gitkeep b/videos/laudos-launch/public/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/videos/laudos-launch/public/ascending-ticks.wav b/videos/laudos-launch/public/ascending-ticks.wav new file mode 100644 index 0000000..ce99e88 Binary files /dev/null and b/videos/laudos-launch/public/ascending-ticks.wav differ diff --git a/videos/laudos-launch/public/background-music.wav b/videos/laudos-launch/public/background-music.wav new file mode 100644 index 0000000..8f68e18 Binary files /dev/null and b/videos/laudos-launch/public/background-music.wav differ diff --git a/videos/laudos-launch/public/deep-whoosh.wav b/videos/laudos-launch/public/deep-whoosh.wav new file mode 100644 index 0000000..f6932a4 Binary files /dev/null and b/videos/laudos-launch/public/deep-whoosh.wav differ diff --git a/videos/laudos-launch/public/descending-ticks.wav b/videos/laudos-launch/public/descending-ticks.wav new file mode 100644 index 0000000..92dc2af Binary files /dev/null and b/videos/laudos-launch/public/descending-ticks.wav differ diff --git a/videos/laudos-launch/public/pop.wav b/videos/laudos-launch/public/pop.wav new file mode 100644 index 0000000..9f8fbe5 Binary files /dev/null and b/videos/laudos-launch/public/pop.wav differ diff --git a/videos/laudos-launch/public/selection-tap.wav b/videos/laudos-launch/public/selection-tap.wav new file mode 100644 index 0000000..9a4d6f3 Binary files /dev/null and b/videos/laudos-launch/public/selection-tap.wav differ diff --git a/videos/laudos-launch/public/typing.wav b/videos/laudos-launch/public/typing.wav new file mode 100644 index 0000000..12c3fe8 Binary files /dev/null and b/videos/laudos-launch/public/typing.wav differ diff --git a/videos/laudos-launch/public/unscramble.wav b/videos/laudos-launch/public/unscramble.wav new file mode 100644 index 0000000..14c075b Binary files /dev/null and b/videos/laudos-launch/public/unscramble.wav differ diff --git a/videos/laudos-launch/public/whoosh.wav b/videos/laudos-launch/public/whoosh.wav new file mode 100644 index 0000000..a927647 Binary files /dev/null and b/videos/laudos-launch/public/whoosh.wav differ diff --git a/videos/laudos-launch/remotion.config.ts b/videos/laudos-launch/remotion.config.ts new file mode 100644 index 0000000..07a9aa5 --- /dev/null +++ b/videos/laudos-launch/remotion.config.ts @@ -0,0 +1,5 @@ +import { Config } from "@remotion/cli/config"; +import { webpackOverride } from "./src/remotion/webpack-override.mjs"; + +Config.setVideoImageFormat("jpeg"); +Config.overrideWebpackConfig(webpackOverride); diff --git a/videos/laudos-launch/src/app/layout.tsx b/videos/laudos-launch/src/app/layout.tsx new file mode 100644 index 0000000..29e92ac --- /dev/null +++ b/videos/laudos-launch/src/app/layout.tsx @@ -0,0 +1,15 @@ +import type { Metadata } from "next"; +import "../styles/global.css"; + +export const metadata: Metadata = { + title: "Laudos.AI Launch Video Preview", + description: "Preview and render Remotion videos", +}; + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} diff --git a/videos/laudos-launch/src/app/page.tsx b/videos/laudos-launch/src/app/page.tsx new file mode 100644 index 0000000..bab85e1 --- /dev/null +++ b/videos/laudos-launch/src/app/page.tsx @@ -0,0 +1,32 @@ +"use client"; + +import { Player } from "@remotion/player"; +import { FullVideo, FULL_VIDEO_DURATION } from "../remotion/scenes/FullVideo"; +import { VIDEO_WIDTH, VIDEO_HEIGHT, VIDEO_FPS } from "../../types/constants"; + +export default function Home() { + return ( +
+

Laudos.AI Launch Video

+ +
+ +
+ +
+

Use Remotion Studio for full editing: pnpm remotion

+

Render video: pnpm render

+
+
+ ); +} diff --git a/videos/laudos-launch/src/remotion/Root.tsx b/videos/laudos-launch/src/remotion/Root.tsx new file mode 100644 index 0000000..8653149 --- /dev/null +++ b/videos/laudos-launch/src/remotion/Root.tsx @@ -0,0 +1,71 @@ +import React from "react"; +import { Composition } from "remotion"; +import { VIDEO_WIDTH, VIDEO_HEIGHT, VIDEO_FPS } from "../../types/constants"; +import { IntroScene, INTRO_SCENE_DURATION } from "./scenes/IntroScene"; +import { ProblemScene, PROBLEM_SCENE_DURATION } from "./scenes/ProblemScene"; +import { FeaturesScene, FEATURES_SCENE_DURATION } from "./scenes/FeaturesScene"; +import { DemoScene, DEMO_SCENE_DURATION } from "./scenes/DemoScene"; +import { OutroScene, OUTRO_SCENE_DURATION } from "./scenes/OutroScene"; +import { FullVideo, FULL_VIDEO_DURATION } from "./scenes/FullVideo"; + +export const RemotionRoot: React.FC = () => { + return ( + <> + {/* Full video composition */} + + + {/* Individual scene compositions for preview */} + + + + + + + + + + + ); +}; diff --git a/videos/laudos-launch/src/remotion/index.ts b/videos/laudos-launch/src/remotion/index.ts new file mode 100644 index 0000000..a4e987f --- /dev/null +++ b/videos/laudos-launch/src/remotion/index.ts @@ -0,0 +1,5 @@ +import { registerRoot } from "remotion"; +import { RemotionRoot } from "./Root"; +import "../styles/global.css"; + +registerRoot(RemotionRoot); diff --git a/videos/laudos-launch/src/remotion/scenes/DemoScene.tsx b/videos/laudos-launch/src/remotion/scenes/DemoScene.tsx new file mode 100644 index 0000000..6776691 --- /dev/null +++ b/videos/laudos-launch/src/remotion/scenes/DemoScene.tsx @@ -0,0 +1,396 @@ +import React from "react"; +import { + AbsoluteFill, + useCurrentFrame, + interpolate, + Easing, + Sequence, + Audio, + staticFile, +} from "remotion"; +import { loadFont, fontFamily } from "@remotion/google-fonts/Inter"; + +loadFont("normal", { + subsets: ["latin"], + weights: ["400", "500", "600", "700"], +}); + +const COLORS = { + bg: "#f8f8f8", + bgWhite: "#FFFFFF", + text: "#171717", + textMuted: "#737373", + textLight: "#a3a3a3", + accent: "#171717", + border: "#e5e5e5", + success: "#10B981", + recording: "#ef4444", +}; + +// Timing - Fluxo correto de ditado +const UI_APPEAR = 0; +const CLICK_MIC = 30; // Clica no Ditar +const RECORDING_START = 45; // Começa a gravar +const VOICE_WAVE_1 = 60; // Ondas de voz +const VOICE_WAVE_2 = 90; +const VOICE_WAVE_3 = 120; +const TRANSCRIPTION_START = 80; // IA começa a transcrever +const TRANSCRIPTION_END = 200; +const RECORDING_STOP = 210; +const SAVE_HIGHLIGHT = 240; + +const RECENT_LAUDOS = [ + { title: "Laudo TC Crânio - 24/01/2026", type: "TC de Crânio", category: "Radiologia", time: "há 2 horas" }, + { title: "Laudo ANGIOTOMOGRAFIA...", type: "Angiotomografia", category: "Radiologia", time: "há 3 horas" }, + { title: "Laudo por Voz - 24/01/2026", type: "", category: "Voz", time: "há 4 horas" }, +]; + +// O que o médico FALA e a IA transcreve +const SPOKEN_TEXT = `TÉCNICA: +Tomografia computadorizada de tórax sem contraste. + +ACHADOS: +Parênquima pulmonar com atenuação preservada. +Ausência de nódulos, massas ou consolidações. +Estruturas mediastinais sem alterações. +Ausência de derrame pleural. + +IMPRESSÃO: +Exame dentro dos limites da normalidade.`; + +export const DEMO_SCENE_DURATION = 270; + +export const DemoScene: React.FC = () => { + const frame = useCurrentFrame(); + + // UI appear + const uiOpacity = interpolate(frame, [UI_APPEAR, UI_APPEAR + 20], [0, 1], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + }); + + // Click animation on mic + const clickScale = frame >= CLICK_MIC && frame < CLICK_MIC + 10 + ? interpolate(frame, [CLICK_MIC, CLICK_MIC + 5, CLICK_MIC + 10], [1, 0.9, 1]) + : 1; + + // Recording state + const isRecording = frame >= RECORDING_START && frame < RECORDING_STOP; + const recordingPulse = isRecording ? Math.sin(frame * 0.15) * 0.5 + 0.5 : 0; + + // Voice wave animation + const getWaveHeight = (waveFrame: number, baseHeight: number) => { + if (frame < waveFrame || frame >= RECORDING_STOP) return baseHeight; + const t = (frame - waveFrame) * 0.2; + return baseHeight + Math.sin(t) * 15 + Math.random() * 5; + }; + + // Transcription progress + const transcriptionProgress = frame >= TRANSCRIPTION_START + ? interpolate(frame, [TRANSCRIPTION_START, TRANSCRIPTION_END], [0, 1], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + }) + : 0; + const charsToShow = Math.floor(transcriptionProgress * SPOKEN_TEXT.length); + + // Show transcribed text or empty state + const showTranscription = frame >= TRANSCRIPTION_START; + + // Save button highlight + const saveHighlight = frame >= SAVE_HIGHLIGHT + ? interpolate(frame, [SAVE_HIGHLIGHT, SAVE_HIGHLIGHT + 15], [0, 1], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + }) + : 0; + + // Cursor blink + const cursorVisible = frame % 16 < 8 && frame >= TRANSCRIPTION_START && frame < TRANSCRIPTION_END; + + return ( + + {/* Main UI */} +
+ {/* LEFT SIDEBAR */} +
+ {/* Header */} +
+ + + + + + Sugerir melhoria +
+ + {/* Search */} +
+
+ + + + + Buscar laudos... +
+ + K +
+
+
+ + {/* Laudos Recentes */} +
+ Laudos Recentes + Ver todos +
+ +
+ {RECENT_LAUDOS.map((laudo, idx) => ( +
+ + + + +
+
{laudo.title}
+ {laudo.type &&
{laudo.type}
} +
+ {laudo.category} +
+
{laudo.time}
+
+
+ ))} +
+
+ + {/* MAIN CONTENT */} +
+ {/* TOP BAR */} +
+ Novo Documento +
+
+ + + + + {frame < SAVE_HIGHLIGHT ? "Editando..." : "Salvo"} +
+
0 ? COLORS.success : COLORS.accent, + borderRadius: 8, + }} + > + + + + + + Salvar +
+
+
+ + {/* TOOLBAR */} +
+ {["B", "I", "U"].map((tool) => ( +
+ {tool} +
+ ))} +
+ {["H1", "H2"].map((tool) => ( +
{tool}
+ ))} +
+ + {/* SECONDARY TOOLBAR */} +
+
+ Buscar Artigos +
+ + + + Extrair Frases +
+
+
+ Crit + Copiar + Atalhos +
+
+ + {/* EDITOR CONTENT */} +
+ + {!showTranscription ? ( + /* ESTADO INICIAL - Botão Ditar */ +
+ {/* Mic Button - Clicável */} +
+ + + + + + +
+ + + {isRecording ? "Gravando..." : "Ditar laudo"} + + + {isRecording ? "Fale o exame e achados" : "Clique para iniciar"} + + + {/* Voice Waves - Aparecem durante gravação */} + {isRecording && ( +
+ {[0, 1, 2, 3, 4, 5, 6, 7].map((i) => ( +
+ ))} +
+ )} + + {/* Template selector */} +
+
+ + + + + Selecionar modelo (opcional) +
+ + + +
+
+ ) : ( + /* ESTADO TRANSCREVENDO - Mostra o laudo sendo escrito pela IA */ +
+ {/* Recording indicator */} + {isRecording && ( +
+
+ Transcrevendo sua voz... + {/* Voice waves inline */} +
+ {[0, 1, 2, 3, 4].map((i) => ( +
+ ))} +
+
+ )} + + {/* Transcribed text */} +
+ {SPOKEN_TEXT.slice(0, charsToShow)} + {cursorVisible && ( + + )} +
+
+ )} +
+ + {/* BOTTOM BAR */} +
+
+ {[ + { key: "Espaço", label: "Ditar" }, + { key: "S", label: "Salvar" }, + { key: "K", label: "Buscar" }, + ].map((s) => ( +
+ {s.key} + {s.label} +
+ ))} +
+
+ Formato: Arial 12 +
+
+
+
+ + {/* Audio */} + + + + + + + ); +}; diff --git a/videos/laudos-launch/src/remotion/scenes/FeaturesScene.tsx b/videos/laudos-launch/src/remotion/scenes/FeaturesScene.tsx new file mode 100644 index 0000000..d899e7d --- /dev/null +++ b/videos/laudos-launch/src/remotion/scenes/FeaturesScene.tsx @@ -0,0 +1,337 @@ +import React from "react"; +import { + AbsoluteFill, + useCurrentFrame, + interpolate, + Easing, + Sequence, + Audio, + staticFile, +} from "remotion"; +import { loadFont, fontFamily } from "@remotion/google-fonts/Inter"; + +loadFont("normal", { + subsets: ["latin"], + weights: ["400", "500", "600", "700", "800"], +}); + +// Clean white design system +const COLORS = { + bg: "#FFFFFF", + bgSubtle: "#F8FAFC", + text: "#0F172A", + textMuted: "#64748B", + accent: "#0066FF", + accentLight: "#E0EDFF", + border: "#E2E8F0", +}; + +// Title timing +const LOGO_APPEAR = 0; +const TAGLINE_START = 25; + +// Feature cards data - showcasing unique LaudAI features +const FEATURES = [ + { + icon: "brain", + title: "LaudAI", + subtitle: "Nossa IA treinada", + description: "IA proprietária treinada especificamente para radiologia brasileira. Entende contexto clínico e gera laudos com precisão.", + color: "#0066FF", + }, + { + icon: "agents", + title: "Agentic AI", + subtitle: "Multi-agent architecture", + description: "Múltiplos agentes de IA trabalhando juntos: validação, formatação, detecção de achados críticos em tempo real.", + color: "#8B5CF6", + }, + { + icon: "voice", + title: "Ditado Inteligente", + subtitle: "Voz para laudo estruturado", + description: "Fale naturalmente em português. A IA transcreve, estrutura e aplica seu estilo pessoal automaticamente.", + color: "#10B981", + }, + { + icon: "crit", + title: "Crit Enterprise", + subtitle: "Achados críticos", + description: "Detecção automática de achados urgentes. Alertas em tempo real para pneumotórax, AVC, embolia e mais.", + color: "#EF4444", + }, +]; + +// Feature cards timing +const CARDS_START = 60; +const CARD_STAGGER = 15; + +// Feature icons +const getIcon = (icon: string, color: string) => { + const iconSize = 32; + const icons: Record = { + brain: ( + + + + + + + ), + agents: ( + + + + + + + + + ), + voice: ( + + + + + ), + crit: ( + + + + + ), + }; + return icons[icon]; +}; + +export const FEATURES_SCENE_DURATION = 210; // 7 seconds + +export const FeaturesScene: React.FC = () => { + const frame = useCurrentFrame(); + + // Logo appear + const logoOpacity = interpolate(frame, [LOGO_APPEAR, LOGO_APPEAR + 15], [0, 1], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + }); + const logoScale = interpolate(frame, [LOGO_APPEAR, LOGO_APPEAR + 15], [0.9, 1], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + easing: Easing.out(Easing.cubic), + }); + + // Tagline appear + const taglineOpacity = frame >= TAGLINE_START + ? interpolate(frame, [TAGLINE_START, TAGLINE_START + 12], [0, 1], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + }) + : 0; + + return ( + + {/* Logo and tagline */} +
+ {/* Logo "laudos.ai" */} + + laudos.ai + + + {/* Tagline */} + + Assistente de laudos com IA agêntica + +
+ + {/* Feature cards grid */} +
+ {FEATURES.map((feature, idx) => { + const cardAppearFrame = CARDS_START + idx * CARD_STAGGER; + const isVisible = frame >= cardAppearFrame; + if (!isVisible) return null; + + const framesSinceAppear = frame - cardAppearFrame; + const slideProgress = interpolate( + framesSinceAppear, + [0, 18], + [0, 1], + { + extrapolateRight: "clamp", + easing: Easing.out(Easing.cubic), + } + ); + + const translateY = interpolate(slideProgress, [0, 1], [50, 0]); + const opacity = interpolate(framesSinceAppear, [0, 12], [0, 1], { + extrapolateRight: "clamp", + }); + + return ( +
+ {/* Icon and title row */} +
+ {/* Icon */} +
+ {getIcon(feature.icon, feature.color)} +
+ + {/* Title and subtitle */} +
+ + {feature.title} + + + {feature.subtitle} + +
+
+ + {/* Description */} + + {feature.description} + +
+ ); + })} +
+ + {/* Sound effects */} + + + + {FEATURES.map((_, idx) => ( + + + ))} +
+ ); +}; diff --git a/videos/laudos-launch/src/remotion/scenes/FullVideo.tsx b/videos/laudos-launch/src/remotion/scenes/FullVideo.tsx new file mode 100644 index 0000000..2f54fca --- /dev/null +++ b/videos/laudos-launch/src/remotion/scenes/FullVideo.tsx @@ -0,0 +1,60 @@ +import React from "react"; +import { Sequence, Audio, staticFile } from "remotion"; +import { IntroScene, INTRO_SCENE_DURATION } from "./IntroScene"; +import { ProblemScene, PROBLEM_SCENE_DURATION } from "./ProblemScene"; +import { FeaturesScene, FEATURES_SCENE_DURATION } from "./FeaturesScene"; +import { DemoScene, DEMO_SCENE_DURATION } from "./DemoScene"; +import { OutroScene, OUTRO_SCENE_DURATION } from "./OutroScene"; + +// Scene timing +const INTRO_START = 0; +const PROBLEM_START = INTRO_START + INTRO_SCENE_DURATION; +const FEATURES_START = PROBLEM_START + PROBLEM_SCENE_DURATION; +const DEMO_START = FEATURES_START + FEATURES_SCENE_DURATION; +const OUTRO_START = DEMO_START + DEMO_SCENE_DURATION; + +// Total duration +export const FULL_VIDEO_DURATION = + INTRO_SCENE_DURATION + + PROBLEM_SCENE_DURATION + + FEATURES_SCENE_DURATION + + DEMO_SCENE_DURATION + + OUTRO_SCENE_DURATION; + +export const FullVideo: React.FC = () => { + return ( + <> + {/* Background music */} +