"use client" import React, { MouseEventHandler, useEffect, useRef, useState } from "react" import { cn } from "@/lib/utils/cn" import { useLatentEngine } from "../store/useLatentEngine" import { PlayPauseButton } from "../components/play-pause-button" import { StreamTag } from "../../stream-tag" import { ContentLayer } from "../components/content-layer" import { MediaInfo } from "@/types/general" import { getMockClap } from "@/lib/clap/getMockClap" import { serializeClap } from "@/lib/clap/serializeClap" function LatentEngine({ media, width, height, className = "" }: { media: MediaInfo width?: number height?: number className?: string }) { const setContainerDimension = useLatentEngine(s => s.setContainerDimension) const isLoaded = useLatentEngine(s => s.isLoaded) const imagine = useLatentEngine(s => s.imagine) const open = useLatentEngine(s => s.open) const setImageElement = useLatentEngine(s => s.setImageElement) const setVideoElement = useLatentEngine(s => s.setVideoElement) const setSegmentationElement = useLatentEngine(s => s.setSegmentationElement) const simulationVideoPlaybackFPS = useLatentEngine(s => s.simulationVideoPlaybackFPS) const simulationRenderingTimeFPS = useLatentEngine(s => s.simulationRenderingTimeFPS) const streamType = useLatentEngine(s => s.streamType) const isStatic = useLatentEngine(s => s.isStatic) const isLive = useLatentEngine(s => s.isLive) const isInteractive = useLatentEngine(s => s.isInteractive) const isPlaying = useLatentEngine(s => s.isPlaying) const togglePlayPause = useLatentEngine(s => s.togglePlayPause) const videoLayer = useLatentEngine(s => s.videoLayer) const segmentationLayer = useLatentEngine(s => s.segmentationLayer) const interfaceLayer = useLatentEngine(s => s.interfaceLayer) const videoElement = useLatentEngine(s => s.videoElement) const imageElement = useLatentEngine(s => s.imageElement) const onClickOnSegmentationLayer = useLatentEngine(s => s.onClickOnSegmentationLayer) const stateRef = useRef({ isInitialized: false }) const [isOverlayVisible, setOverlayVisible] = useState(true) const overlayTimerRef = useRef() const videoLayerRef = useRef(null) const segmentationLayerRef = useRef(null) const mediaUrl = media.clapUrl || media.assetUrlHd || media.assetUrl useEffect(() => { if (!stateRef.current.isInitialized && mediaUrl) { stateRef.current.isInitialized = true const fn = async () => { // TODO julian // there is a bug, we can't unpack the .clap when it's from a data-uri :/ // open(mediaUrl) const mockClap = getMockClap() const mockArchive = await serializeClap(mockClap) // for some reason conversion to data uri doesn't work // const mockDataUri = await blobToDataUri(mockArchive, "application/x-gzip") // console.log("mockDataUri:", mockDataUri) open(mockArchive) } fn() } }, [mediaUrl]) const isPlayingRef = useRef(isPlaying) isPlayingRef.current = isPlaying const scheduleOverlayInvisibility = () => { clearTimeout(overlayTimerRef.current) overlayTimerRef.current = setTimeout(() => { if (isPlayingRef.current) { setOverlayVisible(!isPlayingRef.current) } clearTimeout(overlayTimerRef.current) }, 1000) } /* useEffect(() => { if (isPlaying) { scheduleOverlayInvisibility() } else { clearTimeout(overlayTimerRef.current) setOverlayVisible(true) } return () => { clearTimeout(overlayTimerRef.current) } }, [isPlaying]) */ useEffect(() => { if (!videoLayerRef.current) { return } // note how in both cases we are pulling from the videoLayerRef // that's because one day everything will be a video, but for now we // "fake it until we make it" const videoElements = Array.from( videoLayerRef.current.querySelectorAll('.latent-video') ) as HTMLVideoElement[] setVideoElement(videoElements.at(0)) // images are used for simpler or static experiences const imageElements = Array.from( videoLayerRef.current.querySelectorAll('.latent-image') ) as HTMLImageElement[] setImageElement(imageElements.at(0)) if (!segmentationLayerRef.current) { return } const segmentationElements = Array.from( segmentationLayerRef.current.querySelectorAll('.segmentation-canvas') ) as HTMLCanvasElement[] setSegmentationElement(segmentationElements.at(0)) }) useEffect(() => { setContainerDimension({ width: width || 256, height: height || 256 }) }, [width, height]) return (
{/* */} {/* main content container */} {videoLayer} {/* {interfaceLayer} */} {/* content overlay, with the gradient, buttons etc */}
{ setOverlayVisible(true) scheduleOverlayInvisibility() }} style={{ width, height, boxShadow: "rgba(0, 0, 0, 1) 0px -77px 100px 15px inset" }}> {/* bottom slider and button bar */}
{/* the (optional) timeline slider bar */}
{/* button bar */}
{/* left-side buttons */}
{/* right-side buttons */}
{/* TODO: put a fullscreen button (and mode) here */}
playback: {Math.round(simulationVideoPlaybackFPS * 100) / 100} FPS
rendering: {Math.round(simulationRenderingTimeFPS * 100) / 100} FPS
); } export default LatentEngine