Compare commits

..

1 Commits

Author SHA1 Message Date
aa19bcbc09 tmp media stream fix 2024-07-12 08:39:49 +10:00
33 changed files with 275 additions and 259 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "untitled-app", "name": "untitled-app",
"version": "0.24.1", "version": "0.24.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@codemirror/autocomplete": "^6.17.0", "@codemirror/autocomplete": "^6.17.0",

View File

@ -93,10 +93,23 @@ export class LanguageServerPlugin implements PluginValue {
private doSemanticTokens: boolean = false private doSemanticTokens: boolean = false
private doFoldingRanges: boolean = false private doFoldingRanges: boolean = false
// When a doc update needs to be sent to the server, this holds the private _defferer = deferExecution((code: string) => {
// timeout handle for it. When null, the server has the up-to-date try {
// document. // Update the state (not the editor) with the new code.
private sendScheduled: number | null = null this.client.textDocumentDidChange({
textDocument: {
uri: this.getDocUri(),
version: this.documentVersion++,
},
contentChanges: [{ text: code }],
})
this.requestSemanticTokens()
this.updateFoldingRanges()
} catch (e) {
console.error(e)
}
}, this.changesDelay)
constructor(options: LanguageServerOptions, private view: EditorView) { constructor(options: LanguageServerOptions, private view: EditorView) {
this.client = options.client this.client = options.client
@ -139,9 +152,14 @@ export class LanguageServerPlugin implements PluginValue {
} }
update(viewUpdate: ViewUpdate) { update(viewUpdate: ViewUpdate) {
if (viewUpdate.docChanged) { // If the doc didn't change we can return early.
this.scheduleSendDoc() if (!viewUpdate.docChanged) {
return
} }
this.sendChange({
documentText: viewUpdate.state.doc.toString(),
})
} }
destroy() { destroy() {
@ -166,6 +184,16 @@ export class LanguageServerPlugin implements PluginValue {
this.updateFoldingRanges() this.updateFoldingRanges()
} }
async sendChange({ documentText }: { documentText: string }) {
if (!this.client.ready) return
this._defferer(documentText)
}
requestDiagnostics() {
this.sendChange({ documentText: this.getDocText() })
}
async requestHoverTooltip( async requestHoverTooltip(
view: EditorView, view: EditorView,
{ line, character }: { line: number; character: number } { line, character }: { line: number; character: number }
@ -176,7 +204,7 @@ export class LanguageServerPlugin implements PluginValue {
) )
return null return null
this.ensureDocSent() this.sendChange({ documentText: this.getDocText() })
const result = await this.client.textDocumentHover({ const result = await this.client.textDocumentHover({
textDocument: { uri: this.getDocUri() }, textDocument: { uri: this.getDocUri() },
position: { line, character }, position: { line, character },
@ -199,42 +227,6 @@ export class LanguageServerPlugin implements PluginValue {
return { pos, end, create: (view) => ({ dom }), above: true } return { pos, end, create: (view) => ({ dom }), above: true }
} }
scheduleSendDoc() {
if (this.sendScheduled != null) window.clearTimeout(this.sendScheduled)
this.sendScheduled = window.setTimeout(
() => this.sendDoc(),
this.changesDelay
)
}
sendDoc() {
if (this.sendScheduled != null) {
window.clearTimeout(this.sendScheduled)
this.sendScheduled = null
}
if (!this.client.ready) return
try {
// Update the state (not the editor) with the new code.
this.client.textDocumentDidChange({
textDocument: {
uri: this.getDocUri(),
version: this.documentVersion++,
},
contentChanges: [{ text: this.view.state.doc.toString() }],
})
this.requestSemanticTokens()
this.updateFoldingRanges()
} catch (e) {
console.error(e)
}
}
ensureDocSent() {
if (this.sendScheduled != null) this.sendDoc()
}
async getFoldingRanges(): Promise<LSP.FoldingRange[] | null> { async getFoldingRanges(): Promise<LSP.FoldingRange[] | null> {
if ( if (
!this.doFoldingRanges || !this.doFoldingRanges ||
@ -292,7 +284,13 @@ export class LanguageServerPlugin implements PluginValue {
) )
return null return null
this.ensureDocSent() this.client.textDocumentDidChange({
textDocument: {
uri: this.getDocUri(),
version: this.documentVersion++,
},
contentChanges: [{ text: this.getDocText() }],
})
const result = await this.client.textDocumentFormatting({ const result = await this.client.textDocumentFormatting({
textDocument: { uri: this.getDocUri() }, textDocument: { uri: this.getDocUri() },
@ -332,7 +330,9 @@ export class LanguageServerPlugin implements PluginValue {
) )
return null return null
this.ensureDocSent() this.sendChange({
documentText: context.state.doc.toString(),
})
const result = await this.client.textDocumentCompletion({ const result = await this.client.textDocumentCompletion({
textDocument: { uri: this.getDocUri() }, textDocument: { uri: this.getDocUri() },

View File

@ -80,5 +80,5 @@
} }
}, },
"productName": "Zoo Modeling App", "productName": "Zoo Modeling App",
"version": "0.24.1" "version": "0.24.0"
} }

View File

@ -26,6 +26,7 @@ import useHotkeyWrapper from 'lib/hotkeyWrapper'
import Gizmo from 'components/Gizmo' import Gizmo from 'components/Gizmo'
import { CoreDumpManager } from 'lib/coredump' import { CoreDumpManager } from 'lib/coredump'
import { UnitsMenu } from 'components/UnitsMenu' import { UnitsMenu } from 'components/UnitsMenu'
import { useAppState } from 'AppState'
export function App() { export function App() {
useRefreshSettings(paths.FILE + 'SETTINGS') useRefreshSettings(paths.FILE + 'SETTINGS')
@ -45,6 +46,8 @@ export function App() {
useHotKeyListener() useHotKeyListener()
const { context } = useModelingContext() const { context } = useModelingContext()
const { streamDimensions, didDragInStream, buttonDownInStream } =
useAppState()
const { auth, settings } = useSettingsAuthContext() const { auth, settings } = useSettingsAuthContext()
const token = auth?.context?.token const token = auth?.context?.token
@ -74,7 +77,7 @@ export function App() {
(p) => p === onboardingStatus.current (p) => p === onboardingStatus.current
) )
? 'opacity-20' ? 'opacity-20'
: context.store?.didDragInStream : didDragInStream
? 'opacity-40' ? 'opacity-40'
: '' : ''
@ -92,11 +95,11 @@ export function App() {
clientX: e.clientX, clientX: e.clientX,
clientY: e.clientY, clientY: e.clientY,
el: e.currentTarget, el: e.currentTarget,
...context.store?.streamDimensions, ...streamDimensions,
}) })
const newCmdId = uuidv4() const newCmdId = uuidv4()
if (context.store?.buttonDownInStream === undefined) { if (buttonDownInStream === undefined) {
debounceSocketSend({ debounceSocketSend({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd: { cmd: {
@ -118,7 +121,7 @@ export function App() {
className={ className={
'transition-opacity transition-duration-75 ' + 'transition-opacity transition-duration-75 ' +
paneOpacity + paneOpacity +
(context.store?.buttonDownInStream ? ' pointer-events-none' : '') (buttonDownInStream ? ' pointer-events-none' : '')
} }
project={{ project, file }} project={{ project, file }}
enableMenu={true} enableMenu={true}

View File

@ -1,4 +1,10 @@
import { createContext, useContext, useState, ReactNode } from 'react' import {
createContext,
useContext,
useState,
ReactNode,
useEffect,
} from 'react'
/* /*
@ -11,11 +17,23 @@ Please do not fill this up with junk.
interface AppState { interface AppState {
isStreamReady: boolean isStreamReady: boolean
setAppState: (newAppState: Partial<AppState>) => void setAppState: (newAppState: Partial<AppState>) => void
mediaStream?: MediaStream
buttonDownInStream: number | undefined
didDragInStream: boolean
streamDimensions: { streamWidth: number; streamHeight: number }
// openPanes: SidebarType[]
} }
const AppStateContext = createContext<AppState>({ const AppStateContext = createContext<AppState>({
isStreamReady: false, isStreamReady: false,
setAppState: () => {}, setAppState: () => {},
buttonDownInStream: undefined,
didDragInStream: false,
streamDimensions: { streamWidth: 1280, streamHeight: 720 },
mediaStream: undefined,
// openPanes: persistedContext.openPanes || ['code'],
}) })
export const useAppState = () => useContext(AppStateContext) export const useAppState = () => useContext(AppStateContext)
@ -24,47 +42,38 @@ export const AppStateProvider = ({ children }: { children: ReactNode }) => {
const [appState, _setAppState] = useState<AppState>({ const [appState, _setAppState] = useState<AppState>({
isStreamReady: false, isStreamReady: false,
setAppState: () => {}, setAppState: () => {},
buttonDownInStream: undefined,
didDragInStream: false,
streamDimensions: { streamWidth: 1280, streamHeight: 720 },
mediaStream: undefined,
// openPanes: persistedContext.openPanes || ['code'],
}) })
const setAppState = (newAppState: Partial<AppState>) => useEffect(() => {
_setAppState({ ...appState, ...newAppState }) // console.log('appState change', appState)
}, [appState])
const setAppState = (newAppState: Partial<AppState>) => {
// console.log('appstate', newAppState)
_setAppState({
...appState,
...newAppState,
mediaStream: newAppState.mediaStream || appState.mediaStream,
})
}
return ( return (
<AppStateContext.Provider <AppStateContext.Provider
value={{ value={{
isStreamReady: appState.isStreamReady, isStreamReady: appState.isStreamReady,
setAppState, setAppState,
mediaStream: appState.mediaStream,
buttonDownInStream: appState.buttonDownInStream,
didDragInStream: appState.didDragInStream,
streamDimensions: appState.streamDimensions,
}} }}
> >
{children} {children}
</AppStateContext.Provider> </AppStateContext.Provider>
) )
} }
interface AppStream {
mediaStream: MediaStream
setMediaStream: (mediaStream: MediaStream) => void
}
const AppStreamContext = createContext<AppStream>({
mediaStream: undefined as unknown as MediaStream,
setMediaStream: () => {},
})
export const useAppStream = () => useContext(AppStreamContext)
export const AppStreamProvider = ({ children }: { children: ReactNode }) => {
const [mediaStream, setMediaStream] = useState<MediaStream>(
undefined as unknown as MediaStream
)
return (
<AppStreamContext.Provider
value={{
mediaStream,
setMediaStream,
}}
>
{children}
</AppStreamContext.Provider>
)
}

View File

@ -49,17 +49,17 @@ const router = createBrowserRouter([
/* Make sure auth is the outermost provider or else we will have /* Make sure auth is the outermost provider or else we will have
* inefficient re-renders, use the react profiler to see. */ * inefficient re-renders, use the react profiler to see. */
element: ( element: (
<AppStateProvider>
<CommandBarProvider> <CommandBarProvider>
<SettingsAuthProvider> <SettingsAuthProvider>
<LspProvider> <LspProvider>
<KclContextProvider> <KclContextProvider>
<AppStateProvider>
<Outlet /> <Outlet />
</AppStateProvider>
</KclContextProvider> </KclContextProvider>
</LspProvider> </LspProvider>
</SettingsAuthProvider> </SettingsAuthProvider>
</CommandBarProvider> </CommandBarProvider>
</AppStateProvider>
), ),
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
children: [ children: [

View File

@ -1,6 +1,7 @@
import styles from './ModelingPane.module.css' import styles from './ModelingPane.module.css'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { useAppState } from 'AppState'
export interface ModelingPaneProps export interface ModelingPaneProps
extends React.PropsWithChildren, extends React.PropsWithChildren,
@ -33,9 +34,10 @@ export const ModelingPane = ({
}: ModelingPaneProps) => { }: ModelingPaneProps) => {
const { settings } = useSettingsAuthContext() const { settings } = useSettingsAuthContext()
const onboardingStatus = settings.context.app.onboardingStatus const onboardingStatus = settings.context.app.onboardingStatus
const { context } = useModelingContext() // const { context } = useModelingContext()
const { buttonDownInStream } = useAppState()
const pointerEventsCssClass = const pointerEventsCssClass =
context.store?.buttonDownInStream || onboardingStatus.current === 'camera' buttonDownInStream || onboardingStatus.current === 'camera'
? 'pointer-events-none ' ? 'pointer-events-none '
: 'pointer-events-auto ' : 'pointer-events-auto '
return ( return (

View File

@ -15,6 +15,7 @@ import styles from './ModelingSidebar.module.css'
import { ModelingPane } from './ModelingPane' import { ModelingPane } from './ModelingPane'
import { isTauri } from 'lib/isTauri' import { isTauri } from 'lib/isTauri'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { useAppState } from 'AppState'
interface ModelingSidebarProps { interface ModelingSidebarProps {
paneOpacity: '' | 'opacity-20' | 'opacity-40' paneOpacity: '' | 'opacity-20' | 'opacity-40'
@ -24,8 +25,9 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
const { settings } = useSettingsAuthContext() const { settings } = useSettingsAuthContext()
const onboardingStatus = settings.context.app.onboardingStatus const onboardingStatus = settings.context.app.onboardingStatus
const { context } = useModelingContext() const { context } = useModelingContext()
const { buttonDownInStream } = useAppState()
const pointerEventsCssClass = const pointerEventsCssClass =
context.store?.buttonDownInStream || buttonDownInStream ||
onboardingStatus.current === 'camera' || onboardingStatus.current === 'camera' ||
context.store?.openPanes.length === 0 context.store?.openPanes.length === 0
? 'pointer-events-none ' ? 'pointer-events-none '

View File

@ -9,7 +9,7 @@ import { ClientSideScene } from 'clientSideScene/ClientSideSceneComp'
import { btnName } from 'lib/cameraControls' import { btnName } from 'lib/cameraControls'
import { sendSelectEventToEngine } from 'lib/selections' import { sendSelectEventToEngine } from 'lib/selections'
import { kclManager, engineCommandManager, sceneInfra } from 'lib/singletons' import { kclManager, engineCommandManager, sceneInfra } from 'lib/singletons'
import { useAppStream } from 'AppState' import { useAppState } from 'AppState'
export const Stream = () => { export const Stream = () => {
const [isLoading, setIsLoading] = useState(true) const [isLoading, setIsLoading] = useState(true)
@ -17,8 +17,10 @@ export const Stream = () => {
const [clickCoords, setClickCoords] = useState<{ x: number; y: number }>() const [clickCoords, setClickCoords] = useState<{ x: number; y: number }>()
const videoRef = useRef<HTMLVideoElement>(null) const videoRef = useRef<HTMLVideoElement>(null)
const { settings } = useSettingsAuthContext() const { settings } = useSettingsAuthContext()
const { state, send, context } = useModelingContext() const { state, send } = useModelingContext()
const { mediaStream } = useAppStream() const { mediaStream, streamDimensions, didDragInStream, setAppState } =
useAppState()
const { overallState } = useNetworkContext() const { overallState } = useNetworkContext()
const [isFreezeFrame, setIsFreezeFrame] = useState(false) const [isFreezeFrame, setIsFreezeFrame] = useState(false)
@ -126,12 +128,19 @@ export const Stream = () => {
) )
return return
if (!videoRef.current) return if (!videoRef.current) return
if (!mediaStream) return // console.log('setting mideastrema to vi2', mediaStream, (window as any).mediaStream)
const _mediaStream = mediaStream || (window as any).mediaStream
if (!_mediaStream) return
// console.log('setting mideastrema to vi')
// Do not immediately play the stream! // Do not immediately play the stream!
videoRef.current.srcObject = mediaStream videoRef.current.srcObject = _mediaStream
videoRef.current.pause() videoRef.current.pause()
// setAppState({
// mediaStream,
// })
send({ send({
type: 'Set context', type: 'Set context',
data: { data: {
@ -150,44 +159,49 @@ export const Stream = () => {
clientX: e.clientX, clientX: e.clientX,
clientY: e.clientY, clientY: e.clientY,
el: videoRef.current, el: videoRef.current,
...context.store?.streamDimensions, ...streamDimensions,
}) })
send({ setAppState({
type: 'Set context',
data: {
buttonDownInStream: e.button, buttonDownInStream: e.button,
},
}) })
// send({
// type: 'Set context',
// data: {
// buttonDownInStream: e.button,
// },
// })
setClickCoords({ x, y }) setClickCoords({ x, y })
} }
const handleMouseUp: MouseEventHandler<HTMLDivElement> = (e) => { const handleMouseUp: MouseEventHandler<HTMLDivElement> = (e) => {
if (!isNetworkOkay) return if (!isNetworkOkay) return
if (!videoRef.current) return if (!videoRef.current) return
send({ setAppState({
type: 'Set context',
data: {
buttonDownInStream: undefined, buttonDownInStream: undefined,
},
}) })
// send({
// type: 'Set context',
// data: {
// buttonDownInStream: undefined,
// },
// })
if (state.matches('Sketch')) return if (state.matches('Sketch')) return
if (state.matches('Sketch no face')) return if (state.matches('Sketch no face')) return
if (!context.store?.didDragInStream && btnName(e).left) { if (!didDragInStream && btnName(e).left) {
sendSelectEventToEngine( sendSelectEventToEngine(e, videoRef.current, streamDimensions)
e,
videoRef.current,
context.store?.streamDimensions
)
} }
send({ setAppState({
type: 'Set context',
data: {
didDragInStream: false, didDragInStream: false,
},
}) })
// send({
// type: 'Set context',
// data: {
// didDragInStream: false,
// },
// })
setClickCoords(undefined) setClickCoords(undefined)
} }
@ -201,13 +215,16 @@ export const Stream = () => {
((clickCoords.x - e.clientX) ** 2 + (clickCoords.y - e.clientY) ** 2) ** ((clickCoords.x - e.clientX) ** 2 + (clickCoords.y - e.clientY) ** 2) **
0.5 0.5
if (delta > 5 && !context.store?.didDragInStream) { if (delta > 5 && !didDragInStream) {
send({ setAppState({
type: 'Set context',
data: {
didDragInStream: true, didDragInStream: true,
},
}) })
// send({
// type: 'Set context',
// data: {
// didDragInStream: true,
// },
// })
} }
} }

View File

@ -195,15 +195,14 @@ export class CompletionRequester implements PluginValue {
private queuedUids: string[] = [] private queuedUids: string[] = []
private _deffererCodeUpdate = deferExecution(() => {
this.requestCompletions()
}, changesDelay)
private _deffererUserSelect = deferExecution(() => { private _deffererUserSelect = deferExecution(() => {
this.rejectSuggestionCommand() this.rejectSuggestionCommand()
}, changesDelay) }, changesDelay)
// When a doc update needs to be sent to the server, this holds the
// timeout handle for it. When null, the server has the up-to-date
// document.
private sendScheduledInput: number | null = null
constructor(readonly view: EditorView, client: LanguageServerClient) { constructor(readonly view: EditorView, client: LanguageServerClient) {
this.client = client this.client = client
} }
@ -246,34 +245,7 @@ export class CompletionRequester implements PluginValue {
} }
this.lastPos = this.view.state.selection.main.head this.lastPos = this.view.state.selection.main.head
if (viewUpdate.docChanged) this.scheduleUpdateDoc() if (viewUpdate.docChanged) this._deffererCodeUpdate(true)
}
scheduleUpdateDoc() {
if (this.sendScheduledInput != null)
window.clearTimeout(this.sendScheduledInput)
this.sendScheduledInput = window.setTimeout(
() => this.updateDoc(),
changesDelay
)
}
updateDoc() {
if (this.sendScheduledInput != null) {
window.clearTimeout(this.sendScheduledInput)
this.sendScheduledInput = null
}
if (!this.client.ready) return
try {
this.requestCompletions()
} catch (e) {
console.error(e)
}
}
ensureDocUpdated() {
if (this.sendScheduledInput != null) this.updateDoc()
} }
ghostText(): GhostText | null { ghostText(): GhostText | null {

View File

@ -27,10 +27,13 @@ export class KclPlugin implements PluginValue {
this.client = client this.client = client
} }
// When a doc update needs to be sent to the server, this holds the private _deffererCodeUpdate = deferExecution(() => {
// timeout handle for it. When null, the server has the up-to-date if (this.viewUpdate === null) {
// document. return
private sendScheduledInput: number | null = null }
kclManager.executeCode()
}, changesDelay)
private _deffererUserSelect = deferExecution(() => { private _deffererUserSelect = deferExecution(() => {
if (this.viewUpdate === null) { if (this.viewUpdate === null) {
@ -98,34 +101,7 @@ export class KclPlugin implements PluginValue {
codeManager.code = newCode codeManager.code = newCode
codeManager.writeToFile() codeManager.writeToFile()
this.scheduleUpdateDoc() this._deffererCodeUpdate(true)
}
scheduleUpdateDoc() {
if (this.sendScheduledInput != null)
window.clearTimeout(this.sendScheduledInput)
this.sendScheduledInput = window.setTimeout(
() => this.updateDoc(),
changesDelay
)
}
updateDoc() {
if (this.sendScheduledInput != null) {
window.clearTimeout(this.sendScheduledInput)
this.sendScheduledInput = null
}
if (!this.client.ready) return
try {
kclManager.executeCode()
} catch (e) {
console.error(e)
}
}
ensureDocUpdated() {
if (this.sendScheduledInput != null) this.updateDoc()
} }
async updateUnits( async updateUnits(

View File

@ -1,10 +1,10 @@
import { useLayoutEffect, useEffect, useRef } from 'react' import { useLayoutEffect, useEffect, useRef } from 'react'
import { engineCommandManager, kclManager } from 'lib/singletons' import { engineCommandManager, kclManager, sceneInfra } from 'lib/singletons'
import { deferExecution } from 'lib/utils' import { deferExecution } from 'lib/utils'
import { Themes } from 'lib/theme' import { Themes } from 'lib/theme'
import { makeDefaultPlanes, modifyGrid } from 'lang/wasm' import { makeDefaultPlanes, modifyGrid } from 'lang/wasm'
import { useModelingContext } from './useModelingContext' import { useModelingContext } from './useModelingContext'
import { useAppState, useAppStream } from 'AppState' import { useAppState } from 'AppState'
export function useSetupEngineManager( export function useSetupEngineManager(
streamRef: React.RefObject<HTMLDivElement>, streamRef: React.RefObject<HTMLDivElement>,
@ -27,8 +27,7 @@ export function useSetupEngineManager(
showScaleGrid: boolean showScaleGrid: boolean
} }
) { ) {
const { setAppState } = useAppState() const { setAppState, streamDimensions } = useAppState()
const { setMediaStream } = useAppStream()
const streamWidth = streamRef?.current?.offsetWidth const streamWidth = streamRef?.current?.offsetWidth
const streamHeight = streamRef?.current?.offsetHeight const streamHeight = streamRef?.current?.offsetHeight
@ -48,14 +47,17 @@ export function useSetupEngineManager(
streamWidth, streamWidth,
streamHeight streamHeight
) )
if ( if (!hasSetNonZeroDimensions.current && quadHeight && quadWidth) {
!hasSetNonZeroDimensions.current &&
quadHeight &&
quadWidth &&
settings.modelingSend
) {
engineCommandManager.start({ engineCommandManager.start({
setMediaStream: setMediaStream, // setMediaStream: (mediaStream) =>
// settings.modelingSend({
// type: 'Set context',
// data: { mediaStream },
// }),
setMediaStream: (mediaStream) => {
;(window as any).mediaStream = mediaStream
setAppState({ mediaStream })
},
setIsStreamReady: (isStreamReady) => setAppState({ isStreamReady }), setIsStreamReady: (isStreamReady) => setAppState({ isStreamReady }),
width: quadWidth, width: quadWidth,
height: quadHeight, height: quadHeight,
@ -76,15 +78,22 @@ export function useSetupEngineManager(
return modifyGrid(kclManager.engineCommandManager, hidden) return modifyGrid(kclManager.engineCommandManager, hidden)
}, },
}) })
settings.modelingSend({ setAppState({
type: 'Set context', streamDimensions: { streamWidth: quadWidth, streamHeight: quadHeight },
data: { })
streamDimensions: { sceneInfra._streamDimensions = {
streamWidth: quadWidth, streamWidth: quadWidth,
streamHeight: quadHeight, streamHeight: quadHeight,
}, }
}, // settings.modelingSend({
}) // type: 'Set context',
// data: {
// streamDimensions: {
// streamWidth: quadWidth,
// streamHeight: quadHeight,
// },
// },
// })
hasSetNonZeroDimensions.current = true hasSetNonZeroDimensions.current = true
} }
} }
@ -93,6 +102,7 @@ export function useSetupEngineManager(
streamRef?.current?.offsetWidth, streamRef?.current?.offsetWidth,
streamRef?.current?.offsetHeight, streamRef?.current?.offsetHeight,
settings.modelingSend, settings.modelingSend,
setAppState,
]) ])
useEffect(() => { useEffect(() => {
@ -102,22 +112,29 @@ export function useSetupEngineManager(
streamRef?.current?.offsetHeight streamRef?.current?.offsetHeight
) )
if ( if (
settings.modelingContext.store.streamDimensions.streamWidth !== width || streamDimensions.streamWidth !== width ||
settings.modelingContext.store.streamDimensions.streamHeight !== height streamDimensions.streamHeight !== height
) { ) {
engineCommandManager.handleResize({ engineCommandManager.handleResize({
streamWidth: width, streamWidth: width,
streamHeight: height, streamHeight: height,
}) })
settings.modelingSend({ setAppState({
type: 'Set context', streamDimensions: { streamWidth: width, streamHeight: height },
data: { })
streamDimensions: { sceneInfra._streamDimensions = {
streamWidth: width, streamWidth: width,
streamHeight: height, streamHeight: height,
}, }
}, // settings.modelingSend({
}) // type: 'Set context',
// data: {
// streamDimensions: {
// streamWidth: width,
// streamHeight: height,
// },
// },
// })
} }
}, 500) }, 500)

View File

@ -13,7 +13,6 @@ import {
UpdaterRestartModal, UpdaterRestartModal,
createUpdaterRestartModal, createUpdaterRestartModal,
} from 'components/UpdaterRestartModal' } from 'components/UpdaterRestartModal'
import { AppStreamProvider } from 'AppState'
// uncomment for xstate inspector // uncomment for xstate inspector
// import { DEV } from 'env' // import { DEV } from 'env'
@ -27,7 +26,6 @@ const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
root.render( root.render(
<HotkeysProvider> <HotkeysProvider>
<AppStreamProvider>
<Router /> <Router />
<Toaster <Toaster
position="bottom-center" position="bottom-center"
@ -50,7 +48,6 @@ root.render(
}} }}
/> />
<ModalContainer /> <ModalContainer />
</AppStreamProvider>
</HotkeysProvider> </HotkeysProvider>
) )

View File

@ -138,6 +138,7 @@ export type SegmentOverlayPayload =
} }
interface Store { interface Store {
mediaStream?: MediaStream
videoElement?: HTMLVideoElement videoElement?: HTMLVideoElement
buttonDownInStream: number | undefined buttonDownInStream: number | undefined
didDragInStream: boolean didDragInStream: boolean

View File

@ -8,9 +8,11 @@ import {
} from 'lib/cameraControls' } from 'lib/cameraControls'
import { SettingsSection } from 'components/Settings/SettingsSection' import { SettingsSection } from 'components/Settings/SettingsSection'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { useAppState } from 'AppState'
export default function Units() { export default function Units() {
const { context } = useModelingContext() const { context } = useModelingContext()
const { buttonDownInStream } = useAppState()
const dismiss = useDismiss() const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.STREAMING) const next = useNextClick(onboardingPaths.STREAMING)
const { const {
@ -29,7 +31,7 @@ export default function Units() {
<div <div
className={ className={
'max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' + 'max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto') (buttonDownInStream ? '' : ' pointer-events-auto')
} }
> >
<SettingsSection <SettingsSection

View File

@ -2,9 +2,11 @@ import usePlatform from 'hooks/usePlatform'
import { OnboardingButtons, kbdClasses, useDismiss, useNextClick } from '.' import { OnboardingButtons, kbdClasses, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths' import { onboardingPaths } from 'routes/Onboarding/paths'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { useAppState } from 'AppState'
export default function CmdK() { export default function CmdK() {
const { context } = useModelingContext() // const { context } = useModelingContext()
const { buttonDownInStream } = useAppState()
const dismiss = useDismiss() const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.USER_MENU) const next = useNextClick(onboardingPaths.USER_MENU)
const platformName = usePlatform() const platformName = usePlatform()
@ -14,7 +16,7 @@ export default function CmdK() {
<div <div
className={ className={
'max-w-full xl:max-w-4xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' + 'max-w-full xl:max-w-4xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto') (buttonDownInStream ? '' : ' pointer-events-auto')
} }
> >
<h2 className="text-2xl font-bold">Command Bar</h2> <h2 className="text-2xl font-bold">Command Bar</h2>

View File

@ -1,10 +1,12 @@
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.' import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths' import { onboardingPaths } from 'routes/Onboarding/paths'
import { useAppState } from 'AppState'
export default function OnboardingCodeEditor() { export default function OnboardingCodeEditor() {
useDemoCode() useDemoCode()
const { context } = useModelingContext() const { context } = useModelingContext()
const { buttonDownInStream } = useAppState()
const dismiss = useDismiss() const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.PARAMETRIC_MODELING) const next = useNextClick(onboardingPaths.PARAMETRIC_MODELING)
@ -13,7 +15,7 @@ export default function OnboardingCodeEditor() {
<div <div
className={ className={
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' + 'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto') (buttonDownInStream ? '' : ' pointer-events-auto')
} }
> >
<section className="flex-1 overflow-y-auto"> <section className="flex-1 overflow-y-auto">

View File

@ -2,9 +2,11 @@ import { APP_NAME } from 'lib/constants'
import { OnboardingButtons, useDismiss, useNextClick } from '.' import { OnboardingButtons, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths' import { onboardingPaths } from 'routes/Onboarding/paths'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { useAppState } from 'AppState'
export default function Export() { export default function Export() {
const { context } = useModelingContext() const { context } = useModelingContext()
const { buttonDownInStream } = useAppState()
const dismiss = useDismiss() const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.SKETCHING) const next = useNextClick(onboardingPaths.SKETCHING)
@ -13,7 +15,7 @@ export default function Export() {
<div <div
className={ className={
'max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' + 'max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto') (buttonDownInStream ? '' : ' pointer-events-auto')
} }
> >
<section className="flex-1"> <section className="flex-1">

View File

@ -8,10 +8,12 @@ import {
import { onboardingPaths } from 'routes/Onboarding/paths' import { onboardingPaths } from 'routes/Onboarding/paths'
import { bracketWidthConstantLine } from 'lib/exampleKcl' import { bracketWidthConstantLine } from 'lib/exampleKcl'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { useAppState } from 'AppState'
export default function OnboardingInteractiveNumbers() { export default function OnboardingInteractiveNumbers() {
useDemoCode() useDemoCode()
const { context } = useModelingContext() const { context } = useModelingContext()
const { buttonDownInStream } = useAppState()
const dismiss = useDismiss() const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.COMMAND_K) const next = useNextClick(onboardingPaths.COMMAND_K)
@ -20,7 +22,7 @@ export default function OnboardingInteractiveNumbers() {
<div <div
className={ className={
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' + 'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto') (buttonDownInStream ? '' : ' pointer-events-auto')
} }
> >
<section className="flex-1 overflow-y-auto mb-6"> <section className="flex-1 overflow-y-auto mb-6">

View File

@ -4,10 +4,12 @@ import { Themes, getSystemTheme } from 'lib/theme'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { bracketThicknessCalculationLine } from 'lib/exampleKcl' import { bracketThicknessCalculationLine } from 'lib/exampleKcl'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { useAppState } from 'AppState'
export default function OnboardingParametricModeling() { export default function OnboardingParametricModeling() {
useDemoCode() useDemoCode()
const { context } = useModelingContext() const { context } = useModelingContext()
const { buttonDownInStream } = useAppState()
const { const {
settings: { settings: {
context: { context: {
@ -30,7 +32,7 @@ export default function OnboardingParametricModeling() {
<div <div
className={ className={
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' + 'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto') (buttonDownInStream ? '' : ' pointer-events-auto')
} }
> >
<section className="flex-1 overflow-y-auto mb-6"> <section className="flex-1 overflow-y-auto mb-6">

View File

@ -2,9 +2,11 @@ import { OnboardingButtons, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths' import { onboardingPaths } from 'routes/Onboarding/paths'
import { isTauri } from 'lib/isTauri' import { isTauri } from 'lib/isTauri'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { useAppState } from 'AppState'
export default function ProjectMenu() { export default function ProjectMenu() {
const { context } = useModelingContext() const { context } = useModelingContext()
const { buttonDownInStream } = useAppState()
const dismiss = useDismiss() const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.EXPORT) const next = useNextClick(onboardingPaths.EXPORT)
const tauri = isTauri() const tauri = isTauri()
@ -14,7 +16,7 @@ export default function ProjectMenu() {
<div <div
className={ className={
'max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' + 'max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto') (buttonDownInStream ? '' : ' pointer-events-auto')
} }
> >
<section className="flex-1"> <section className="flex-1">

View File

@ -3,9 +3,11 @@ import { onboardingPaths } from 'routes/Onboarding/paths'
import { useEffect } from 'react' import { useEffect } from 'react'
import { codeManager, kclManager } from 'lib/singletons' import { codeManager, kclManager } from 'lib/singletons'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { useAppState } from 'AppState'
export default function Sketching() { export default function Sketching() {
const { context } = useModelingContext() const { context } = useModelingContext()
const { buttonDownInStream } = useAppState()
const dismiss = useDismiss() const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.FUTURE_WORK) const next = useNextClick(onboardingPaths.FUTURE_WORK)
@ -23,7 +25,7 @@ export default function Sketching() {
<div <div
className={ className={
'max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' + 'max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto') (buttonDownInStream ? '' : ' pointer-events-auto')
} }
> >
<h1 className="text-2xl font-bold">Sketching</h1> <h1 className="text-2xl font-bold">Sketching</h1>

View File

@ -1,9 +1,11 @@
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { OnboardingButtons, useDismiss, useNextClick } from '.' import { OnboardingButtons, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths' import { onboardingPaths } from 'routes/Onboarding/paths'
import { useAppState } from 'AppState'
export default function Streaming() { export default function Streaming() {
const { context } = useModelingContext() const { context } = useModelingContext()
const { buttonDownInStream } = useAppState()
const dismiss = useDismiss() const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.EDITOR) const next = useNextClick(onboardingPaths.EDITOR)
@ -12,7 +14,7 @@ export default function Streaming() {
<div <div
className={ className={
'max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' + 'max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto') (buttonDownInStream ? '' : ' pointer-events-auto')
} }
> >
<section className="flex-1 overflow-y-auto"> <section className="flex-1 overflow-y-auto">

View File

@ -3,9 +3,11 @@ import { onboardingPaths } from 'routes/Onboarding/paths'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { useAppState } from 'AppState'
export default function UserMenu() { export default function UserMenu() {
const { context } = useModelingContext() const { context } = useModelingContext()
const { buttonDownInStream } = useAppState()
const { auth } = useSettingsAuthContext() const { auth } = useSettingsAuthContext()
const dismiss = useDismiss() const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.PROJECT_MENU) const next = useNextClick(onboardingPaths.PROJECT_MENU)
@ -36,7 +38,7 @@ export default function UserMenu() {
<div <div
className={ className={
'max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' + 'max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto') (buttonDownInStream ? '' : ' pointer-events-auto')
} }
> >
<section className="flex-1"> <section className="flex-1">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 KiB

After

Width:  |  Height:  |  Size: 333 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 KiB

After

Width:  |  Height:  |  Size: 333 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB