tsc lint fmt

This commit is contained in:
49lf
2025-02-17 10:38:15 -05:00
committed by lee-at-zoo-corp
parent e3705bf7df
commit deb83cf62c
5 changed files with 156 additions and 58 deletions

View File

@ -163,7 +163,7 @@ export function App() {
videoRef, videoRef,
canvasRef, canvasRef,
mediaStream: null, mediaStream: null,
authToken: token ?? null, authToken: token,
pool, pool,
zoomToFit: true, zoomToFit: true,
}, },

View File

@ -280,6 +280,11 @@ export class CameraControls {
>[0] >[0]
const cb = ({ data, type }: CallBackParam) => { const cb = ({ data, type }: CallBackParam) => {
// We're reconnecting, so ignore this init proces.
if (this.old) {
return
}
const camSettings = data.settings const camSettings = data.settings
this.camera.position.set( this.camera.position.set(
camSettings.pos.x, camSettings.pos.x,
@ -291,6 +296,7 @@ export class CameraControls {
camSettings.center.y, camSettings.center.y,
camSettings.center.z camSettings.center.z
) )
const orientation = new Quaternion( const orientation = new Quaternion(
camSettings.orientation.x, camSettings.orientation.x,
camSettings.orientation.y, camSettings.orientation.y,

View File

@ -14,6 +14,7 @@ import { PATHS } from 'lib/paths'
import { IndexLoaderData } from 'lib/types' import { IndexLoaderData } from 'lib/types'
import { err, reportRejection, trap } from 'lib/trap' import { err, reportRejection, trap } from 'lib/trap'
import { getArtifactOfTypes } from 'lang/std/artifactGraph' import { getArtifactOfTypes } from 'lang/std/artifactGraph'
import { clearSceneAndBustCache } from 'lang/wasm'
import { ViewControlContextMenu } from './ViewControlMenu' import { ViewControlContextMenu } from './ViewControlMenu'
import { commandBarActor, useCommandBarState } from 'machines/commandBarMachine' import { commandBarActor, useCommandBarState } from 'machines/commandBarMachine'
import { useSelector } from '@xstate/react' import { useSelector } from '@xstate/react'
@ -67,18 +68,20 @@ export const EngineStream = () => {
}) })
} }
useEffect(() => {
const play = () => { const play = () => {
engineStreamActor.send({ engineStreamActor.send({
type: EngineStreamTransition.Play, type: EngineStreamTransition.Play,
}) })
} }
useEffect(() => {
engineCommandManager.addEventListener( engineCommandManager.addEventListener(
EngineCommandManagerEvents.SceneReady, EngineCommandManagerEvents.SceneReady,
play play
) )
return () => { return () => {
engineCommandManager.tearDown()
engineCommandManager.removeEventListener( engineCommandManager.removeEventListener(
EngineCommandManagerEvents.SceneReady, EngineCommandManagerEvents.SceneReady,
play play
@ -87,6 +90,7 @@ export const EngineStream = () => {
}, []) }, [])
useEffect(() => { useEffect(() => {
if (engineStreamState.value === EngineStreamState.Reconfiguring) return
const video = engineStreamState.context.videoRef?.current const video = engineStreamState.context.videoRef?.current
if (!video) return if (!video) return
const canvas = engineStreamState.context.canvasRef?.current const canvas = engineStreamState.context.canvasRef?.current
@ -123,10 +127,8 @@ export const EngineStream = () => {
// On settings change, reconfigure the engine. When paused this gets really tricky, // On settings change, reconfigure the engine. When paused this gets really tricky,
// and also requires onMediaStream to be set! // and also requires onMediaStream to be set!
useEffect(() => { useEffect(() => {
if (engineStreamState.value === EngineStreamState.Playing) {
startOrReconfigureEngine() startOrReconfigureEngine()
} }, Object.values(settingsEngine))
}, [settings.context, engineStreamState.value])
/** /**
* Subscribe to execute code when the file changes * Subscribe to execute code when the file changes
@ -135,8 +137,8 @@ export const EngineStream = () => {
*/ */
useEffect(() => { useEffect(() => {
if (engineCommandManager.engineConnection?.isReady() && file?.path) { if (engineCommandManager.engineConnection?.isReady() && file?.path) {
console.log('execute on file change') console.log('file changed, executing code')
void kclManager.executeCode(true).catch(trap) kclManager.executeCode(true).catch(trap)
} }
}, [file?.path, engineCommandManager.engineConnection]) }, [file?.path, engineCommandManager.engineConnection])

View File

@ -1,15 +1,18 @@
import { uuidv4 } from 'lib/utils'
import { makeDefaultPlanes, clearSceneAndBustCache } from 'lang/wasm' import { makeDefaultPlanes, clearSceneAndBustCache } from 'lang/wasm'
import { MutableRefObject } from 'react' import { MutableRefObject } from 'react'
import { setup, assign, fromPromise } from 'xstate' import { setup, assign, fromPromise } from 'xstate'
import { createActorContext } from '@xstate/react' import { createActorContext } from '@xstate/react'
import { kclManager, sceneInfra, engineCommandManager } from 'lib/singletons' import { kclManager, sceneInfra, engineCommandManager } from 'lib/singletons'
import { trap } from 'lib/trap' import { trap } from 'lib/trap'
import { Vector3, Vector4 } from 'three'
export enum EngineStreamState { export enum EngineStreamState {
Off = 'off', Off = 'off',
On = 'on', On = 'on',
WaitForMediaStream = 'wait-for-media-stream', WaitForMediaStream = 'wait-for-media-stream',
Playing = 'playing', Playing = 'playing',
Reconfiguring = 'reconfiguring',
Paused = 'paused', Paused = 'paused',
// The is the state in-between Paused and Playing *specifically that order*. // The is the state in-between Paused and Playing *specifically that order*.
Resuming = 'resuming', Resuming = 'resuming',
@ -25,7 +28,7 @@ export enum EngineStreamTransition {
export interface EngineStreamContext { export interface EngineStreamContext {
pool: string | null pool: string | null
authToken: string | null authToken: string | undefined
mediaStream: MediaStream | null mediaStream: MediaStream | null
videoRef: MutableRefObject<HTMLVideoElement | null> videoRef: MutableRefObject<HTMLVideoElement | null>
canvasRef: MutableRefObject<HTMLCanvasElement | null> canvasRef: MutableRefObject<HTMLCanvasElement | null>
@ -44,6 +47,23 @@ export function getDimensions(streamWidth: number, streamHeight: number) {
return { width: quadWidth, height: quadHeight } return { width: quadWidth, height: quadHeight }
} }
export function holdOntoVideoFrameInCanvas(
video: HTMLVideoElement,
canvas: HTMLCanvasElement
) {
video.pause()
canvas.width = video.videoWidth
canvas.height = video.videoHeight
canvas.style.width = video.videoWidth + 'px'
canvas.style.height = video.videoHeight + 'px'
canvas.style.display = 'block'
const ctx = canvas.getContext('2d')
if (!ctx) return
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
}
const engineStreamMachine = setup({ const engineStreamMachine = setup({
types: { types: {
context: {} as EngineStreamContext, context: {} as EngineStreamContext,
@ -69,7 +89,6 @@ const engineStreamMachine = setup({
canvas.style.display = 'none' canvas.style.display = 'none'
await sceneInfra.camControls.restoreCameraPosition() await sceneInfra.camControls.restoreCameraPosition()
await clearSceneAndBustCache(kclManager.engineCommandManager)
video.srcObject = mediaStream video.srcObject = mediaStream
await video.play() await video.play()
@ -91,36 +110,76 @@ const engineStreamMachine = setup({
const canvas = context.canvasRef.current const canvas = context.canvasRef.current
if (!canvas) return if (!canvas) return
canvas.width = video.videoWidth holdOntoVideoFrameInCanvas(video, canvas)
canvas.height = video.videoHeight
canvas.style.width = video.videoWidth + 'px'
canvas.style.height = video.videoHeight + 'px'
canvas.style.display = 'block'
const ctx = canvas.getContext('2d')
if (!ctx) return
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
// Make sure we're on the next frame for no flickering between canvas // Make sure we're on the next frame for no flickering between canvas
// and the video elements. // and the video elements.
window.requestAnimationFrame(() => { window.requestAnimationFrame(
() =>
void (async () => {
video.style.display = 'none' video.style.display = 'none'
// Destroy the media stream only. We will re-establish it. We could // Destroy the media stream. We will re-establish it. We could
// leave everything at pausing, preventing video decoders from running // leave everything at pausing, preventing video decoders from running
// but we can do even better by significantly reducing network // but we can do even better by significantly reducing network
// cards also. // cards also.
context.mediaStream?.getVideoTracks()[0].stop() context.mediaStream?.getVideoTracks()[0].stop()
video.srcObject = null video.srcObject = null
const reqDefaultCameraGetSettings =
await engineCommandManager.sendSceneCommand({
// CameraControls subscribes to default_camera_get_settings response events
// firing this at connection ensure the camera's are synced initially
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_get_settings',
},
})
if (
reqDefaultCameraGetSettings === null ||
!reqDefaultCameraGetSettings.success
)
return
if (
!('modeling_response' in reqDefaultCameraGetSettings.resp.data)
)
return
if (
reqDefaultCameraGetSettings.resp.data.modeling_response.type ===
'empty'
)
return
if (
!(
'settings' in
reqDefaultCameraGetSettings.resp.data.modeling_response.data
)
)
return
const center =
reqDefaultCameraGetSettings.resp.data.modeling_response.data
.settings.center
const pos =
reqDefaultCameraGetSettings.resp.data.modeling_response.data
.settings.pos
sceneInfra.camControls.old = { sceneInfra.camControls.old = {
camera: sceneInfra.camControls.camera.clone(), camera: sceneInfra.camControls.camera.clone(),
target: sceneInfra.camControls.target.clone(), target: new Vector3(center.x, center.y, center.z),
} }
sceneInfra.camControls.old.camera.position.set(
pos.x,
pos.y,
pos.z
)
engineCommandManager.tearDown({ idleMode: true }) engineCommandManager.tearDown({ idleMode: true })
}) })()
)
} }
), ),
[EngineStreamTransition.StartOrReconfigureEngine]: fromPromise( [EngineStreamTransition.StartOrReconfigureEngine]: fromPromise(
@ -134,6 +193,9 @@ const engineStreamMachine = setup({
const video = context.videoRef.current const video = context.videoRef.current
if (!video) return if (!video) return
const canvas = context.canvasRef.current
if (!canvas) return
const { width, height } = getDimensions( const { width, height } = getDimensions(
window.innerWidth, window.innerWidth,
window.innerHeight window.innerHeight
@ -151,10 +213,20 @@ const engineStreamMachine = setup({
engineCommandManager.settings = settingsNext engineCommandManager.settings = settingsNext
// If we don't pause there could be a really bad flicker
// on reconfiguration (resize, for example)
holdOntoVideoFrameInCanvas(video, canvas)
canvas.style.display = 'block'
window.requestAnimationFrame(() => {
video.style.display = 'none'
engineCommandManager.start({ engineCommandManager.start({
setMediaStream: event.onMediaStream, setMediaStream: event.onMediaStream,
setIsStreamReady: (isStreamReady) => setIsStreamReady: (isStreamReady) => {
event.setAppState({ isStreamReady }), video.style.display = 'block'
canvas.style.display = 'none'
event.setAppState({ isStreamReady })
},
width, width,
height, height,
token: context.authToken, token: context.authToken,
@ -173,6 +245,7 @@ const engineStreamMachine = setup({
}, },
}, },
}) })
})
} }
), ),
}, },
@ -215,11 +288,23 @@ const engineStreamMachine = setup({
}), }),
}, },
on: { on: {
[EngineStreamTransition.StartOrReconfigureEngine]: {
target: EngineStreamState.Reconfiguring,
},
[EngineStreamTransition.Pause]: { [EngineStreamTransition.Pause]: {
target: EngineStreamState.Paused, target: EngineStreamState.Paused,
}, },
}, },
}, },
[EngineStreamState.Reconfiguring]: {
invoke: {
src: EngineStreamTransition.StartOrReconfigureEngine,
input: (args) => args,
onDone: {
target: EngineStreamState.Playing,
},
},
},
[EngineStreamState.Paused]: { [EngineStreamState.Paused]: {
invoke: { invoke: {
src: EngineStreamTransition.Pause, src: EngineStreamTransition.Pause,

View File

@ -839,6 +839,11 @@ class EngineConnection extends EventTarget {
this.engineCommandManager.inSequence = 1 this.engineCommandManager.inSequence = 1
// Bust the cache before anything
;(async () => {
await clearSceneAndBustCache(kclManager.engineCommandManager)
})().catch(reportRejection)
this.dispatchEvent( this.dispatchEvent(
new CustomEvent(EngineConnectionEvents.Opened, { detail: this }) new CustomEvent(EngineConnectionEvents.Opened, { detail: this })
) )
@ -1801,7 +1806,6 @@ export class EngineCommandManager extends EventTarget {
) )
this.engineConnection?.tearDown(opts) this.engineConnection?.tearDown(opts)
this.engineConnection = undefined
// Our window.engineCommandManager.tearDown assignment causes this case to happen which is // Our window.engineCommandManager.tearDown assignment causes this case to happen which is
// only really for tests. // only really for tests.
@ -1812,6 +1816,7 @@ export class EngineCommandManager extends EventTarget {
// @ts-ignore // @ts-ignore
this.engineCommandManager.engineConnection = null this.engineCommandManager.engineConnection = null
} }
this.engineConnection = undefined
} }
async startNewSession() { async startNewSession() {
this.responseMap = {} this.responseMap = {}