"use client"; import { motion } from "framer-motion"; import { COLORS, VizFrame } from "./common"; type ModalityKey = "tabular" | "image" | "text" | "audio" | "video"; const W_DEFAULT = 1040; const H_DEFAULT = 460; const MODS: { key: ModalityKey; title: string; shape: string; example: string }[] = [ { key: "tabular", title: "Tabular", shape: "(N, F)", example: "rows × features · sensor logs, telemetry" }, { key: "image", title: "Image", shape: "(H, W, C)", example: "pixels × channels · drone camera frame" }, { key: "text", title: "Text", shape: "(T,)", example: "sequence of tokens · radio chatter" }, { key: "audio", title: "Audio", shape: "(T,) · (F, T)", example: "waveform → spectrogram · motor sounds" }, { key: "video", title: "Video", shape: "(T, H, W, C)", example: "frames over time · flight footage" }, ]; function Tabular({ w, h }: { w: number; h: number }) { const rows = 5; const cols = 4; const cellW = (w - 24) / cols; const cellH = (h - 30) / rows; return ( {Array.from({ length: rows * cols }, (_, i) => { const r = Math.floor(i / cols); const c = i % cols; const v = ((c * 31 + r * 17) % 9) / 9; return ( {v.toFixed(2)} ); })} ); } function ImageMod({ w, h }: { w: number; h: number }) { const N = 10; const cellW = (w - 24) / N; const cellH = (h - 30) / N; return ( {Array.from({ length: N * N }, (_, i) => { const r = Math.floor(i / N); const c = i % N; const cx = N / 2; const cy = N / 2; const dist = Math.sqrt((c - cx) ** 2 + (r - cy) ** 2); const v = Math.max(0, 1 - dist / (N * 0.6)); return ( ); })} ); } function TextMod({ w }: { w: number; h: number }) { const tokens = ["the", "drone", "approaches", "a", "yellow", "gate"]; const ids = [102, 451, 9882, 19, 6022, 309]; return ( {tokens.map((t, i) => { const px = (i % 3) * ((w - 24) / 3); const py = Math.floor(i / 3) * 40; return ( {t} id {ids[i]} ); })} ); } function AudioMod({ w, h }: { w: number; h: number }) { const N = 36; const innerW = w - 24; const innerH = h - 30; const cy = 22 + innerH / 2; return ( {Array.from({ length: N }, (_, i) => { const phase = (i / N) * Math.PI * 4; const env = 1 - Math.abs(i / N - 0.5) * 1.4; const a = Math.sin(phase) * 0.6 * Math.max(0.1, env); const x = 12 + (i / (N - 1)) * innerW; const len = a * (innerH * 0.4); return ( ); })} ); } function VideoMod({ w, h }: { w: number; h: number }) { const frames = 4; const innerW = w - 24; const fw = innerW / frames - 6; const fh = h - 36; return ( {Array.from({ length: frames }, (_, i) => ( {/* Sky */} {/* Ground */} {/* Moving target */} t={i} ))} ); } export function DataModalities({ width = W_DEFAULT, height = H_DEFAULT, }: { width?: number; height?: number; }) { // 5 modalities — render a 3×2 grid (last cell empty) const cols = 3; const rows = 2; const padX = 16; const padY = 16; const gap = 14; const innerW = width - padX * 2; const innerH = height - padY * 2; const cellW = (innerW - gap * (cols - 1)) / cols; const cellH = (innerH - gap * (rows - 1)) / rows; return ( {MODS.map((m, i) => { const c = i % cols; const r = Math.floor(i / cols); const x = padX + c * (cellW + gap); const y = padY + r * (cellH + gap); return ( // Static positioning wrapper; motion lives inside so it cannot // overwrite the translate with its own transform. {m.title} {m.shape} {m.key === "tabular" && } {m.key === "image" && } {m.key === "text" && } {m.key === "audio" && } {m.key === "video" && } {m.example} ); })} ); }