rename scene classes for clarity (#1409)

* rename for clarity

* typo

* make coverage happ+
somewhat pointless since we don't use coverage because its not complete with both vitest and playwright

* local storage issue

* fmt

* fix
This commit is contained in:
Kurt Hutten
2024-02-14 08:03:20 +11:00
committed by GitHub
parent e1af4b4219
commit 19925d22c1
15 changed files with 376 additions and 349 deletions

View File

@ -0,0 +1,252 @@
import { useRef, useEffect, useState } from 'react'
import { useModelingContext } from 'hooks/useModelingContext'
import { cameraMouseDragGuards } from 'lib/cameraControls'
import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
import { useStore } from 'useStore'
import {
DEBUG_SHOW_BOTH_SCENES,
ReactCameraProperties,
sceneInfra,
} from './sceneInfra'
import { throttle } from 'lib/utils'
function useShouldHideScene(): { hideClient: boolean; hideServer: boolean } {
const [isCamMoving, setIsCamMoving] = useState(false)
const [isTween, setIsTween] = useState(false)
const { state } = useModelingContext()
useEffect(() => {
sceneInfra.setIsCamMovingCallback((isMoving, isTween) => {
setIsCamMoving(isMoving)
setIsTween(isTween)
})
}, [])
if (DEBUG_SHOW_BOTH_SCENES || !isCamMoving)
return { hideClient: false, hideServer: false }
let hideServer = state.matches('Sketch') || state.matches('Sketch no face')
if (isTween) {
hideServer = false
}
return { hideClient: !hideServer, hideServer }
}
export const ClientSideScene = ({
cameraControls,
}: {
cameraControls: ReturnType<
typeof useGlobalStateContext
>['settings']['context']['cameraControls']
}) => {
const canvasRef = useRef<HTMLDivElement>(null)
const { state, send } = useModelingContext()
const { hideClient, hideServer } = useShouldHideScene()
const { setHighlightRange } = useStore((s) => ({
setHighlightRange: s.setHighlightRange,
highlightRange: s.highlightRange,
}))
// Listen for changes to the camera controls setting
// and update the client-side scene's controls accordingly.
useEffect(() => {
sceneInfra.setInteractionGuards(cameraMouseDragGuards[cameraControls])
}, [cameraControls])
useEffect(() => {
sceneInfra.updateOtherSelectionColors(
state?.context?.selectionRanges?.otherSelections || []
)
}, [state?.context?.selectionRanges?.otherSelections])
useEffect(() => {
if (!canvasRef.current) return
const canvas = canvasRef.current
canvas.appendChild(sceneInfra.renderer.domElement)
sceneInfra.animate()
sceneInfra.setHighlightCallback(setHighlightRange)
canvas.addEventListener('mousemove', sceneInfra.onMouseMove, false)
canvas.addEventListener('mousedown', sceneInfra.onMouseDown, false)
canvas.addEventListener('mouseup', sceneInfra.onMouseUp, false)
sceneInfra.setSend(send)
return () => {
canvas?.removeEventListener('mousemove', sceneInfra.onMouseMove)
canvas?.removeEventListener('mousedown', sceneInfra.onMouseDown)
canvas?.removeEventListener('mouseup', sceneInfra.onMouseUp)
}
}, [])
return (
<div
ref={canvasRef}
className={`absolute inset-0 h-full w-full transition-all duration-300 ${
hideClient ? 'opacity-0' : 'opacity-100'
} ${hideServer ? 'bg-black' : ''} ${
!hideClient && !hideServer && state.matches('Sketch')
? 'bg-black/80'
: ''
}`}
></div>
)
}
const throttled = throttle((a: ReactCameraProperties) => {
if (a.type === 'perspective' && a.fov) {
sceneInfra.dollyZoom(a.fov)
}
}, 1000 / 15)
export const CamDebugSettings = () => {
const [camSettings, setCamSettings] = useState<ReactCameraProperties>({
type: 'perspective',
fov: 12,
position: [0, 0, 0],
quaternion: [0, 0, 0, 1],
})
const [fov, setFov] = useState(12)
useEffect(() => {
sceneInfra.setReactCameraPropertiesCallback(setCamSettings)
}, [sceneInfra])
useEffect(() => {
if (camSettings.type === 'perspective' && camSettings.fov) {
setFov(camSettings.fov)
}
}, [(camSettings as any)?.fov])
return (
<div>
<h3>cam settings</h3>
perspective cam
<input
type="checkbox"
checked={camSettings.type === 'perspective'}
onChange={(e) => {
if (camSettings.type === 'perspective') {
sceneInfra.useOrthographicCamera()
} else {
sceneInfra.usePerspectiveCamera()
}
}}
/>
{camSettings.type === 'perspective' && (
<input
type="range"
min="4"
max="90"
step={0.5}
value={fov}
onChange={(e) => {
setFov(parseFloat(e.target.value))
throttled({
...camSettings,
fov: parseFloat(e.target.value),
})
}}
className="w-full cursor-pointer pointer-events-auto"
/>
)}
{camSettings.type === 'perspective' && (
<div>
<span>fov</span>
<input
type="number"
value={camSettings.fov}
className="text-black w-16"
onChange={(e) => {
sceneInfra.setCam({
...camSettings,
fov: parseFloat(e.target.value),
})
}}
/>
</div>
)}
{camSettings.type === 'orthographic' && (
<>
<div>
<span>fov</span>
<input
type="number"
value={camSettings.zoom}
className="text-black w-16"
onChange={(e) => {
sceneInfra.setCam({
...camSettings,
zoom: parseFloat(e.target.value),
})
}}
/>
</div>
</>
)}
<div>
Position
<ul className="flex">
<li>
<span className="pl-2 pr-1">x:</span>
<input
type="number"
step={5}
data-testid="cam-x-position"
value={camSettings.position[0]}
className="text-black w-16"
onChange={(e) => {
sceneInfra.setCam({
...camSettings,
position: [
parseFloat(e.target.value),
camSettings.position[1],
camSettings.position[2],
],
})
}}
/>
</li>
<li>
<span className="pl-2 pr-1">y:</span>
<input
type="number"
step={5}
data-testid="cam-y-position"
value={camSettings.position[1]}
className="text-black w-16"
onChange={(e) => {
sceneInfra.setCam({
...camSettings,
position: [
camSettings.position[0],
parseFloat(e.target.value),
camSettings.position[2],
],
})
}}
/>
</li>
<li>
<span className="pl-2 pr-1">z:</span>
<input
type="number"
step={5}
data-testid="cam-z-position"
value={camSettings.position[2]}
className="text-black w-16"
onChange={(e) => {
sceneInfra.setCam({
...camSettings,
position: [
camSettings.position[0],
camSettings.position[1],
parseFloat(e.target.value),
],
})
}}
/>
</li>
</ul>
</div>
</div>
)
}

View File

@ -25,14 +25,14 @@ import {
INTERSECTION_PLANE_LAYER,
isQuaternionVertical,
RAYCASTABLE_PLANE,
setupSingleton,
sceneInfra,
SKETCH_GROUP_SEGMENTS,
SKETCH_LAYER,
X_AXIS,
XZ_PLANE,
Y_AXIS,
YZ_PLANE,
} from './setup'
} from './sceneInfra'
import {
CallExpression,
getTangentialArcToInfo,
@ -85,7 +85,10 @@ export const TANGENTIAL_ARC_TO_SEGMENT_BODY = 'tangential-arc-to-segment-body'
export const TANGENTIAL_ARC_TO__SEGMENT_DASH =
'tangential-arc-to-segment-body-dashed'
class ClientSideScene {
// This singleton Class is responsible for all of the things the user sees and interacts with.
// That mostly mean sketch elements.
// Cameras, controls, raycasters, etc are handled by sceneInfra
class SceneEntities {
scene: Scene
sceneProgramMemory: ProgramMemory = { root: {}, return: null }
activeSegments: { [key: string]: Group } = {}
@ -93,18 +96,18 @@ class ClientSideScene {
axisGroup: Group | null = null
currentSketchQuaternion: Quaternion | null = null
constructor() {
this.scene = setupSingleton?.scene
setupSingleton?.setOnCamChange(this.onCamChange)
this.scene = sceneInfra?.scene
sceneInfra?.setOnCamChange(this.onCamChange)
}
onCamChange = () => {
const orthoFactor = orthoScale(setupSingleton.camera)
const orthoFactor = orthoScale(sceneInfra.camera)
Object.values(this.activeSegments).forEach((segment) => {
const factor =
setupSingleton.camera instanceof OrthographicCamera
sceneInfra.camera instanceof OrthographicCamera
? orthoFactor
: perspScale(setupSingleton.camera, segment)
: perspScale(sceneInfra.camera, segment)
if (
segment.userData.from &&
segment.userData.to &&
@ -135,9 +138,9 @@ class ClientSideScene {
})
if (this.axisGroup) {
const factor =
setupSingleton.camera instanceof OrthographicCamera
sceneInfra.camera instanceof OrthographicCamera
? orthoFactor
: perspScale(setupSingleton.camera, this.axisGroup)
: perspScale(sceneInfra.camera, this.axisGroup)
const x = this.axisGroup.getObjectByName(X_AXIS)
x?.scale.set(1, factor, 1)
const y = this.axisGroup.getObjectByName(Y_AXIS)
@ -259,11 +262,11 @@ class ClientSideScene {
sketchGroup.position[1],
sketchGroup.position[2]
)
const orthoFactor = orthoScale(setupSingleton.camera)
const orthoFactor = orthoScale(sceneInfra.camera)
const factor =
setupSingleton.camera instanceof OrthographicCamera
sceneInfra.camera instanceof OrthographicCamera
? orthoFactor
: perspScale(setupSingleton.camera, dummy)
: perspScale(sceneInfra.camera, dummy)
sketchGroup.value.forEach((segment, index) => {
let segPathToNode = getNodePathFromSourceRange(
draftSegment ? truncatedAst : kclManager.ast,
@ -310,7 +313,7 @@ class ClientSideScene {
this.scene.add(group)
if (!draftSegment) {
setupSingleton.setCallbacks({
sceneInfra.setCallbacks({
onDrag: (args) => {
this.onDragSegment({
...args,
@ -320,7 +323,7 @@ class ClientSideScene {
onMove: () => {},
onClick: (args) => {
if (!args || !args.object) {
setupSingleton.modelingSend({
sceneInfra.modelingSend({
type: 'Set selection',
data: {
selectionType: 'singleCodeCursor',
@ -331,7 +334,7 @@ class ClientSideScene {
const { object } = args
const event = getEventForSegmentSelection(object)
if (!event) return
setupSingleton.modelingSend(event)
sceneInfra.modelingSend(event)
},
onMouseEnter: ({ object }) => {
// TODO change the color of the segment to yellow?
@ -351,15 +354,15 @@ class ClientSideScene {
parent.userData.pathToNode,
'CallExpression'
).node
setupSingleton.highlightCallback([node.start, node.end])
sceneInfra.highlightCallback([node.start, node.end])
const yellow = 0xffff00
colorSegment(object, yellow)
return
}
setupSingleton.highlightCallback([0, 0])
sceneInfra.highlightCallback([0, 0])
},
onMouseLeave: ({ object }) => {
setupSingleton.highlightCallback([0, 0])
sceneInfra.highlightCallback([0, 0])
const parent = getParentGroup(object)
const isSelected = parent?.userData?.isSelected
colorSegment(object, isSelected ? 0x0000ff : 0xffffff)
@ -372,7 +375,7 @@ class ClientSideScene {
},
})
} else {
setupSingleton.setCallbacks({
sceneInfra.setCallbacks({
onDrag: () => {},
onClick: async (args) => {
if (!args) return
@ -427,7 +430,7 @@ class ClientSideScene {
},
})
}
setupSingleton.controls.enableRotate = false
sceneInfra.controls.enableRotate = false
}
updateAstAndRejigSketch = async (
sketchPathToNode: PathToNode,
@ -530,7 +533,7 @@ class ClientSideScene {
this.sceneProgramMemory = programMemory
const sketchGroup = programMemory.root[variableDeclarationName]
.value as Path[]
const orthoFactor = orthoScale(setupSingleton.camera)
const orthoFactor = orthoScale(sceneInfra.camera)
sketchGroup.forEach((segment, index) => {
const segPathToNode = getNodePathFromSourceRange(
modifiedAst,
@ -546,9 +549,9 @@ class ClientSideScene {
// const prevSegment = sketchGroup.slice(index - 1)[0]
const type = group?.userData?.type
const factor =
setupSingleton.camera instanceof OrthographicCamera
sceneInfra.camera instanceof OrthographicCamera
? orthoFactor
: perspScale(setupSingleton.camera, group)
: perspScale(sceneInfra.camera, group)
if (type === TANGENTIAL_ARC_TO_SEGMENT) {
this.updateTangentialArcToSegment({
prevSegment: sketchGroup[index - 1],
@ -705,9 +708,9 @@ class ClientSideScene {
}
async animateAfterSketch() {
if (isReducedMotion()) {
setupSingleton.usePerspectiveCamera()
sceneInfra.usePerspectiveCamera()
} else {
await setupSingleton.animateToPerspective()
await sceneInfra.animateToPerspective()
}
}
removeSketchGrid() {
@ -740,7 +743,7 @@ class ClientSideScene {
reject()
}
}
setupSingleton.controls.enableRotate = true
sceneInfra.controls.enableRotate = true
this.activeSegments = {}
// maybe should reset onMove etc handlers
if (shouldResolve) resolve(true)
@ -759,7 +762,7 @@ class ClientSideScene {
})
}
setupDefaultPlaneHover() {
setupSingleton.setCallbacks({
sceneInfra.setCallbacks({
onMouseEnter: ({ object }) => {
if (object.parent.userData.type !== DEFAULT_PLANES) return
const type: DefaultPlane = object.userData.type
@ -784,7 +787,7 @@ class ClientSideScene {
planeString = posNorm ? 'XZ' : '-XZ'
normal = posNorm ? [0, 1, 0] : [0, -1, 0]
}
setupSingleton.modelingSend({
sceneInfra.modelingSend({
type: 'Select default plane',
data: {
plane: planeString,
@ -798,7 +801,7 @@ class ClientSideScene {
export type DefaultPlaneStr = 'XY' | 'XZ' | 'YZ' | '-XY' | '-XZ' | '-YZ'
export const clientSideScene = new ClientSideScene()
export const sceneEntitiesManager = new SceneEntities()
// calculations/pure-functions/easy to test so no excuse not to

View File

@ -1,5 +1,5 @@
import { Quaternion } from 'three'
import { isQuaternionVertical } from './setup'
import { isQuaternionVertical } from './sceneInfra'
describe('isQuaternionVertical', () => {
it('should identify vertical quaternions', () => {

View File

@ -24,7 +24,6 @@ import {
Object3DEventMap,
} from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { useRef, useEffect, useState } from 'react'
import { engineCommandManager } from 'lang/std/engineConnection'
import { v4 as uuidv4 } from 'uuid'
import { isReducedMotion, roundOff, throttle } from 'lib/utils'
@ -33,9 +32,7 @@ import { useModelingContext } from 'hooks/useModelingContext'
import { deg2Rad } from 'lib/utils2d'
import * as TWEEN from '@tweenjs/tween.js'
import { MouseGuard, cameraMouseDragGuards } from 'lib/cameraControls'
import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
import { SourceRange } from 'lang/wasm'
import { useStore } from 'useStore'
import { Axis } from 'lib/selections'
import { createGridHelper } from './helpers'
@ -181,7 +178,7 @@ interface onMoveCallbackArgs {
intersection: Intersection<Object3D<Object3DEventMap>>
}
type ReactCameraProperties =
export type ReactCameraProperties =
| {
type: 'perspective'
fov?: number
@ -195,8 +192,11 @@ type ReactCameraProperties =
quaternion: [number, number, number, number]
}
class SetupSingleton {
static instance: SetupSingleton
// This singleton class is responsible for all of the under the hood setup for the client side scene.
// That is the cameras and switching between them, raycasters for click mouse events and their abstractions (onClick etc), setting up controls.
// Anything that added the the scene for the user to interact with is probably in SceneEntities.ts
class SceneInfra {
static instance: SceneInfra
scene: Scene
camera: PerspectiveCamera | OrthographicCamera
renderer: WebGLRenderer
@ -333,7 +333,7 @@ class SetupSingleton {
const light = new AmbientLight(0x505050) // soft white light
this.scene.add(light)
SetupSingleton.instance = this
SceneInfra.instance = this
}
private _isCamMovingCallback: (isMoving: boolean, isTween: boolean) => void =
() => {}
@ -713,7 +713,7 @@ class SetupSingleton {
} | null => {
this.planeRaycaster.setFromCamera(
this.currentMouseVector,
setupSingleton.camera
sceneInfra.camera
)
const planeIntersects = this.planeRaycaster.intersectObjects(
this.scene.children,
@ -976,7 +976,7 @@ class SetupSingleton {
if (planesGroup) this.scene.remove(planesGroup)
}
updateOtherSelectionColors = (otherSelections: Axis[]) => {
const axisGroup = setupSingleton.scene.children.find(
const axisGroup = sceneInfra.scene.children.find(
({ userData }) => userData?.type === AXIS_GROUP
)
const axisMap: { [key: string]: Axis } = {
@ -998,247 +998,7 @@ class SetupSingleton {
}
}
export const setupSingleton = new SetupSingleton()
function useShouldHideScene(): { hideClient: boolean; hideServer: boolean } {
const [isCamMoving, setIsCamMoving] = useState(false)
const [isTween, setIsTween] = useState(false)
const { state } = useModelingContext()
useEffect(() => {
setupSingleton.setIsCamMovingCallback((isMoving, isTween) => {
setIsCamMoving(isMoving)
setIsTween(isTween)
})
}, [])
if (DEBUG_SHOW_BOTH_SCENES || !isCamMoving)
return { hideClient: false, hideServer: false }
let hideServer = state.matches('Sketch') || state.matches('Sketch no face')
if (isTween) {
hideServer = false
}
return { hideClient: !hideServer, hideServer }
}
export const ClientSideScene = ({
cameraControls,
}: {
cameraControls: ReturnType<
typeof useGlobalStateContext
>['settings']['context']['cameraControls']
}) => {
const canvasRef = useRef<HTMLDivElement>(null)
const { state, send } = useModelingContext()
const { hideClient, hideServer } = useShouldHideScene()
const { setHighlightRange } = useStore((s) => ({
setHighlightRange: s.setHighlightRange,
highlightRange: s.highlightRange,
}))
// Listen for changes to the camera controls setting
// and update the client-side scene's controls accordingly.
useEffect(() => {
setupSingleton.setInteractionGuards(cameraMouseDragGuards[cameraControls])
}, [cameraControls])
useEffect(() => {
setupSingleton.updateOtherSelectionColors(
state?.context?.selectionRanges?.otherSelections || []
)
}, [state?.context?.selectionRanges?.otherSelections])
useEffect(() => {
if (!canvasRef.current) return
const canvas = canvasRef.current
canvas.appendChild(setupSingleton.renderer.domElement)
setupSingleton.animate()
setupSingleton.setHighlightCallback(setHighlightRange)
canvas.addEventListener('mousemove', setupSingleton.onMouseMove, false)
canvas.addEventListener('mousedown', setupSingleton.onMouseDown, false)
canvas.addEventListener('mouseup', setupSingleton.onMouseUp, false)
setupSingleton.setSend(send)
return () => {
canvas?.removeEventListener('mousemove', setupSingleton.onMouseMove)
canvas?.removeEventListener('mousedown', setupSingleton.onMouseDown)
canvas?.removeEventListener('mouseup', setupSingleton.onMouseUp)
}
}, [])
return (
<div
ref={canvasRef}
className={`absolute inset-0 h-full w-full transition-all duration-300 ${
hideClient ? 'opacity-0' : 'opacity-100'
} ${hideServer ? 'bg-black' : ''} ${
!hideClient && !hideServer && state.matches('Sketch')
? 'bg-black/80'
: ''
}`}
></div>
)
}
const throttled = throttle((a: ReactCameraProperties) => {
if (a.type === 'perspective' && a.fov) {
setupSingleton.dollyZoom(a.fov)
}
}, 1000 / 15)
export const CamDebugSettings = () => {
const [camSettings, setCamSettings] = useState<ReactCameraProperties>({
type: 'perspective',
fov: 12,
position: [0, 0, 0],
quaternion: [0, 0, 0, 1],
})
const [fov, setFov] = useState(12)
useEffect(() => {
setupSingleton.setReactCameraPropertiesCallback(setCamSettings)
}, [setupSingleton])
useEffect(() => {
if (camSettings.type === 'perspective' && camSettings.fov) {
setFov(camSettings.fov)
}
}, [(camSettings as any)?.fov])
return (
<div>
<h3>cam settings</h3>
perspective cam
<input
type="checkbox"
checked={camSettings.type === 'perspective'}
onChange={(e) => {
if (camSettings.type === 'perspective') {
setupSingleton.useOrthographicCamera()
} else {
setupSingleton.usePerspectiveCamera()
}
}}
/>
{camSettings.type === 'perspective' && (
<input
type="range"
min="4"
max="90"
step={0.5}
value={fov}
onChange={(e) => {
setFov(parseFloat(e.target.value))
throttled({
...camSettings,
fov: parseFloat(e.target.value),
})
}}
className="w-full cursor-pointer pointer-events-auto"
/>
)}
{camSettings.type === 'perspective' && (
<div>
<span>fov</span>
<input
type="number"
value={camSettings.fov}
className="text-black w-16"
onChange={(e) => {
setupSingleton.setCam({
...camSettings,
fov: parseFloat(e.target.value),
})
}}
/>
</div>
)}
{camSettings.type === 'orthographic' && (
<>
<div>
<span>fov</span>
<input
type="number"
value={camSettings.zoom}
className="text-black w-16"
onChange={(e) => {
setupSingleton.setCam({
...camSettings,
zoom: parseFloat(e.target.value),
})
}}
/>
</div>
</>
)}
<div>
Position
<ul className="flex">
<li>
<span className="pl-2 pr-1">x:</span>
<input
type="number"
step={5}
data-testid="cam-x-position"
value={camSettings.position[0]}
className="text-black w-16"
onChange={(e) => {
setupSingleton.setCam({
...camSettings,
position: [
parseFloat(e.target.value),
camSettings.position[1],
camSettings.position[2],
],
})
}}
/>
</li>
<li>
<span className="pl-2 pr-1">y:</span>
<input
type="number"
step={5}
data-testid="cam-y-position"
value={camSettings.position[1]}
className="text-black w-16"
onChange={(e) => {
setupSingleton.setCam({
...camSettings,
position: [
camSettings.position[0],
parseFloat(e.target.value),
camSettings.position[2],
],
})
}}
/>
</li>
<li>
<span className="pl-2 pr-1">z:</span>
<input
type="number"
step={5}
data-testid="cam-z-position"
value={camSettings.position[2]}
className="text-black w-16"
onChange={(e) => {
setupSingleton.setCam({
...camSettings,
position: [
camSettings.position[0],
camSettings.position[1],
parseFloat(e.target.value),
],
})
}}
/>
</li>
</ul>
</div>
</div>
)
}
export const sceneInfra = new SceneInfra()
function convertThreeCamValuesToEngineCam({
position,

View File

@ -25,9 +25,9 @@ import {
TANGENTIAL_ARC_TO_SEGMENT,
TANGENTIAL_ARC_TO_SEGMENT_BODY,
TANGENTIAL_ARC_TO__SEGMENT_DASH,
} from './clientSideScene'
} from './sceneEntities'
import { getTangentPointFromPreviousArc } from 'lib/utils2d'
import { ARROWHEAD } from './setup'
import { ARROWHEAD } from './sceneInfra'
export function straightSegment({
from,

View File

@ -1,10 +1,10 @@
import { useState, useEffect } from 'react'
import { setupSingleton } from '../clientSideScene/setup'
import { sceneInfra } from '../clientSideScene/sceneInfra'
import { engineCommandManager } from 'lang/std/engineConnection'
import { throttle, isReducedMotion } from 'lib/utils'
const updateDollyZoom = throttle(
(newFov: number) => setupSingleton.dollyZoom(newFov),
(newFov: number) => sceneInfra.dollyZoom(newFov),
1000 / 15
)
@ -15,19 +15,19 @@ export const CamToggle = () => {
useEffect(() => {
engineCommandManager.waitForReady.then(async () => {
setupSingleton.dollyZoom(fov)
sceneInfra.dollyZoom(fov)
})
}, [])
const toggleCamera = () => {
if (isPerspective) {
isReducedMotion()
? setupSingleton.useOrthographicCamera()
: setupSingleton.animateToOrthographic()
? sceneInfra.useOrthographicCamera()
: sceneInfra.animateToOrthographic()
} else {
isReducedMotion()
? setupSingleton.usePerspectiveCamera()
: setupSingleton.animateToPerspective()
? sceneInfra.usePerspectiveCamera()
: sceneInfra.animateToPerspective()
}
setIsPerspective(!isPerspective)
}
@ -60,9 +60,9 @@ export const CamToggle = () => {
<button
onClick={() => {
if (enableRotate) {
setupSingleton.controls.enableRotate = false
sceneInfra.controls.enableRotate = false
} else {
setupSingleton.controls.enableRotate = true
sceneInfra.controls.enableRotate = true
}
setEnableRotate(!enableRotate)
}}

View File

@ -1,7 +1,7 @@
import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel'
import { AstExplorer } from './AstExplorer'
import { EngineCommands } from './EngineCommands'
import { CamDebugSettings } from 'clientSideScene/setup'
import { CamDebugSettings } from 'clientSideScene/ClientSideSceneComp'
export const DebugPanel = ({ className, ...props }: CollapsiblePanelProps) => {
return (

View File

@ -33,8 +33,8 @@ import { applyConstraintIntersect } from './Toolbar/Intersect'
import { applyConstraintAbsDistance } from './Toolbar/SetAbsDistance'
import useStateMachineCommands from 'hooks/useStateMachineCommands'
import { modelingMachineConfig } from 'lib/commandBarConfigs/modelingCommandConfig'
import { setupSingleton } from 'clientSideScene/setup'
import { getSketchQuaternion } from 'clientSideScene/clientSideScene'
import { sceneInfra } from 'clientSideScene/sceneInfra'
import { getSketchQuaternion } from 'clientSideScene/sceneEntities'
import { startSketchOnDefault } from 'lang/modifyAst'
import { Program } from 'lang/wasm'
@ -197,7 +197,7 @@ export const ModelingMachineProvider = ({
// remove body item at varDecIndex
newAst.body = newAst.body.filter((_, i) => i !== varDecIndex)
await kclManager.executeAstMock(newAst, { updates: 'code' })
setupSingleton.setCallbacks({
sceneInfra.setCallbacks({
onClick: () => {},
})
},
@ -208,7 +208,7 @@ export const ModelingMachineProvider = ({
)
await kclManager.updateAst(modifiedAst, false)
const quaternion = getSketchQuaternion(pathToNode, normal)
await setupSingleton.tweenCameraToQuaternion(quaternion)
await sceneInfra.tweenCameraToQuaternion(quaternion)
return {
sketchPathToNode: pathToNode,
sketchNormalBackUp: normal,
@ -222,7 +222,7 @@ export const ModelingMachineProvider = ({
sketchPathToNode || [],
sketchNormalBackUp
)
await setupSingleton.tweenCameraToQuaternion(quaternion)
await sceneInfra.tweenCameraToQuaternion(quaternion)
},
'Get horizontal info': async ({
selectionRanges,

View File

@ -15,7 +15,7 @@ import { Models } from '@kittycad/lib'
import { engineCommandManager } from '../lang/std/engineConnection'
import { useModelingContext } from 'hooks/useModelingContext'
import { useKclContext } from 'lang/KclSingleton'
import { ClientSideScene } from 'clientSideScene/setup'
import { ClientSideScene } from 'clientSideScene/ClientSideSceneComp'
export const Stream = ({ className = '' }: { className?: string }) => {
const [isLoading, setIsLoading] = useState(true)

View File

@ -26,7 +26,7 @@ import interact from '@replit/codemirror-interact'
import { engineCommandManager } from '../lang/std/engineConnection'
import { kclManager, useKclContext } from 'lang/KclSingleton'
import { ModelingMachineEvent } from 'machines/modelingMachine'
import { setupSingleton } from 'clientSideScene/setup'
import { sceneInfra } from 'clientSideScene/sceneInfra'
export const editorShortcutMeta = {
formatCode: {
@ -119,7 +119,7 @@ export const TextEditor = ({
if (!editorView) {
setEditorView(viewUpdate.view)
}
if (setupSingleton.selected) return // mid drag
if (sceneInfra.selected) return // mid drag
const ignoreEvents: ModelingMachineEvent['type'][] = [
'Equip Line tool',
'Equip tangential arc to',

View File

@ -99,7 +99,7 @@ class KclManager {
})
})
} else {
localStorage?.setItem(PERSIST_CODE_TOKEN, code)
safteLSSetItem(PERSIST_CODE_TOKEN, code)
}
}
@ -154,16 +154,16 @@ class KclManager {
this.code = ''
return
}
const storedCode = localStorage.getItem(PERSIST_CODE_TOKEN)
const storedCode = safeLSGetItem(PERSIST_CODE_TOKEN) || ''
// TODO #819 remove zustand persistence logic in a few months
// short term migration, shouldn't make a difference for tauri app users
// anyway since that's filesystem based.
const zustandStore = JSON.parse(localStorage.getItem('store') || '{}')
const zustandStore = JSON.parse(safeLSGetItem('store') || '{}')
if (storedCode === null && zustandStore?.state?.code) {
this.code = zustandStore.state.code
localStorage.setItem(PERSIST_CODE_TOKEN, this._code)
safteLSSetItem(PERSIST_CODE_TOKEN, this._code)
zustandStore.state.code = ''
localStorage.setItem('store', JSON.stringify(zustandStore))
safteLSSetItem('store', JSON.stringify(zustandStore))
} else if (storedCode === null) {
this.code = bracket
} else {
@ -457,3 +457,13 @@ export function KclContextProvider({
</KclContext.Provider>
)
}
function safeLSGetItem(key: string) {
if (typeof window === 'undefined') return null
return localStorage?.getItem(key)
}
function safteLSSetItem(key: string, value: string) {
if (typeof window === 'undefined') return
localStorage?.setItem(key, value)
}

View File

@ -30,7 +30,7 @@ import {
createFirstArg,
} from './std/sketch'
import { isLiteralArrayOrStatic } from './std/sketchcombos'
import { DefaultPlaneStr } from 'clientSideScene/clientSideScene'
import { DefaultPlaneStr } from 'clientSideScene/sceneEntities'
import { roundOff } from 'lib/utils'
export function startSketchOnDefault(

View File

@ -5,7 +5,7 @@ import { exportSave } from 'lib/exportSave'
import { v4 as uuidv4 } from 'uuid'
import * as Sentry from '@sentry/react'
import { getNodePathFromSourceRange } from 'lang/queryAst'
import { setupSingleton } from 'clientSideScene/setup'
import { sceneInfra } from 'clientSideScene/sceneInfra'
let lastMessage = ''
@ -1012,7 +1012,7 @@ export class EngineCommandManager {
gizmo_mode: true,
},
})
setupSingleton.onStreamStart()
sceneInfra.onStreamStart()
executeCode(undefined, true)
},

View File

@ -14,11 +14,11 @@ import { CommandArgument } from './commandTypes'
import {
STRAIGHT_SEGMENT,
TANGENTIAL_ARC_TO_SEGMENT,
clientSideScene,
sceneEntitiesManager,
getParentGroup,
} from 'clientSideScene/clientSideScene'
} from 'clientSideScene/sceneEntities'
import { Mesh } from 'three'
import { AXIS_GROUP, X_AXIS } from 'clientSideScene/setup'
import { AXIS_GROUP, X_AXIS } from 'clientSideScene/sceneInfra'
export const X_AXIS_UUID = 'ad792545-7fd3-482a-a602-a93924e3055b'
export const Y_AXIS_UUID = '680fd157-266f-4b8a-984f-cdf46b8bdf01'
@ -401,7 +401,7 @@ function updateSceneObjectColors(codeBasedSelections: Selection[]) {
console.error('error parsing code in processCodeMirrorRanges', e)
return
}
Object.values(clientSideScene.activeSegments).forEach((segmentGroup) => {
Object.values(sceneEntitiesManager.activeSegments).forEach((segmentGroup) => {
if (
![STRAIGHT_SEGMENT, TANGENTIAL_ARC_TO_SEGMENT].includes(
segmentGroup?.userData?.type

View File

@ -44,11 +44,11 @@ import { Models } from '@kittycad/lib/dist/types/src'
import { ModelingCommandSchema } from 'lib/commandBarConfigs/modelingCommandConfig'
import {
DefaultPlaneStr,
clientSideScene,
sceneEntitiesManager,
quaternionFromSketchGroup,
sketchGroupFromPathToNode,
} from 'clientSideScene/clientSideScene'
import { setupSingleton } from 'clientSideScene/setup'
} from 'clientSideScene/sceneEntities'
import { sceneInfra } from 'clientSideScene/sceneInfra'
export const MODELING_PERSIST_KEY = 'MODELING_PERSIST_KEY'
@ -605,7 +605,7 @@ export const modelingMachine = createMachine(
if (!sketchPathToNode) return {}
return getSketchMetadataFromPathToNode(sketchPathToNode)
}),
'hide default planes': () => setupSingleton.removeDefaultPlanes(),
'hide default planes': () => sceneInfra.removeDefaultPlanes(),
'reset sketch metadata': assign({
sketchPathToNode: null,
sketchEnginePathId: '',
@ -632,7 +632,7 @@ export const modelingMachine = createMachine(
kclManager.ast,
kclManager.programMemory
)
clientSideScene.updateAstAndRejigSketch(
sceneEntitiesManager.updateAstAndRejigSketch(
sketchPathToNode || [],
modifiedAst
)
@ -644,7 +644,7 @@ export const modelingMachine = createMachine(
kclManager.ast,
kclManager.programMemory
)
clientSideScene.updateAstAndRejigSketch(
sceneEntitiesManager.updateAstAndRejigSketch(
sketchPathToNode || [],
modifiedAst
)
@ -657,7 +657,7 @@ export const modelingMachine = createMachine(
selectionRanges,
constraint: 'setVertDistance',
})
clientSideScene.updateAstAndRejigSketch(
sceneEntitiesManager.updateAstAndRejigSketch(
sketchPathToNode || [],
modifiedAst
)
@ -667,7 +667,7 @@ export const modelingMachine = createMachine(
selectionRanges,
constraint: 'setHorzDistance',
})
clientSideScene.updateAstAndRejigSketch(
sceneEntitiesManager.updateAstAndRejigSketch(
sketchPathToNode || [],
modifiedAst
)
@ -677,7 +677,7 @@ export const modelingMachine = createMachine(
selectionRanges,
constraint: 'snapToXAxis',
})
clientSideScene.updateAstAndRejigSketch(
sceneEntitiesManager.updateAstAndRejigSketch(
sketchPathToNode || [],
modifiedAst
)
@ -687,7 +687,7 @@ export const modelingMachine = createMachine(
selectionRanges,
constraint: 'snapToYAxis',
})
clientSideScene.updateAstAndRejigSketch(
sceneEntitiesManager.updateAstAndRejigSketch(
sketchPathToNode || [],
modifiedAst
)
@ -696,7 +696,7 @@ export const modelingMachine = createMachine(
const { modifiedAst } = applyConstraintEqualLength({
selectionRanges,
})
clientSideScene.updateAstAndRejigSketch(
sceneEntitiesManager.updateAstAndRejigSketch(
sketchPathToNode || [],
modifiedAst
)
@ -705,7 +705,7 @@ export const modelingMachine = createMachine(
const { modifiedAst } = applyConstraintEqualAngle({
selectionRanges,
})
clientSideScene.updateAstAndRejigSketch(
sceneEntitiesManager.updateAstAndRejigSketch(
sketchPathToNode || [],
modifiedAst
)
@ -717,7 +717,7 @@ export const modelingMachine = createMachine(
const { modifiedAst } = applyRemoveConstrainingValues({
selectionRanges,
})
clientSideScene.updateAstAndRejigSketch(
sceneEntitiesManager.updateAstAndRejigSketch(
sketchPathToNode || [],
modifiedAst
)
@ -742,59 +742,61 @@ export const modelingMachine = createMachine(
},
'conditionally equip line tool': (_, { type }) => {
if (type === 'done.invoke.animate-to-face') {
setupSingleton.modelingSend('Equip Line tool')
sceneInfra.modelingSend('Equip Line tool')
}
},
'setup client side sketch segments': ({ sketchPathToNode }, { type }) => {
if (Object.keys(clientSideScene.activeSegments).length > 0) {
clientSideScene.tearDownSketch({ removeAxis: false }).then(() => {
clientSideScene.setupSketch({
if (Object.keys(sceneEntitiesManager.activeSegments).length > 0) {
sceneEntitiesManager
.tearDownSketch({ removeAxis: false })
.then(() => {
sceneEntitiesManager.setupSketch({
sketchPathToNode: sketchPathToNode || [],
})
})
} else {
clientSideScene.setupSketch({
sceneEntitiesManager.setupSketch({
sketchPathToNode: sketchPathToNode || [],
})
}
},
'animate after sketch': () => {
clientSideScene.animateAfterSketch()
sceneEntitiesManager.animateAfterSketch()
},
'tear down client sketch': () => {
if (clientSideScene.activeSegments) {
clientSideScene.tearDownSketch({ removeAxis: false })
if (sceneEntitiesManager.activeSegments) {
sceneEntitiesManager.tearDownSketch({ removeAxis: false })
}
},
'remove sketch grid': () => clientSideScene.removeSketchGrid(),
'remove sketch grid': () => sceneEntitiesManager.removeSketchGrid(),
'set up draft line': ({ sketchPathToNode }) => {
clientSideScene.setUpDraftLine(sketchPathToNode || [])
sceneEntitiesManager.setUpDraftLine(sketchPathToNode || [])
},
'set up draft arc': ({ sketchPathToNode }) => {
clientSideScene.setUpDraftArc(sketchPathToNode || [])
sceneEntitiesManager.setUpDraftArc(sketchPathToNode || [])
},
'set up draft line without teardown': ({ sketchPathToNode }) =>
clientSideScene.setupSketch({
sceneEntitiesManager.setupSketch({
sketchPathToNode: sketchPathToNode || [],
draftSegment: 'line',
}),
'show default planes': () => {
setupSingleton.showDefaultPlanes()
clientSideScene.setupDefaultPlaneHover()
sceneInfra.showDefaultPlanes()
sceneEntitiesManager.setupDefaultPlaneHover()
},
'setup noPoints onClick listener': ({ sketchPathToNode }) => {
clientSideScene.createIntersectionPlane()
sceneEntitiesManager.createIntersectionPlane()
const sketchGroup = sketchGroupFromPathToNode({
pathToNode: sketchPathToNode || [],
ast: kclManager.ast,
programMemory: kclManager.programMemory,
})
const quaternion = quaternionFromSketchGroup(sketchGroup)
clientSideScene.intersectionPlane &&
clientSideScene.intersectionPlane.setRotationFromQuaternion(
sceneEntitiesManager.intersectionPlane &&
sceneEntitiesManager.intersectionPlane.setRotationFromQuaternion(
quaternion
)
setupSingleton.setCallbacks({
sceneInfra.setCallbacks({
onClick: async (args) => {
if (!args) return
const { intersection2d } = args
@ -805,13 +807,13 @@ export const modelingMachine = createMachine(
[intersection2d.x, intersection2d.y]
)
await kclManager.updateAst(modifiedAst, false)
clientSideScene.removeIntersectionPlane()
setupSingleton.modelingSend('Add start point')
sceneEntitiesManager.removeIntersectionPlane()
sceneInfra.modelingSend('Add start point')
},
})
},
'add axis n grid': ({ sketchPathToNode }) =>
clientSideScene.createSketchAxis(sketchPathToNode || []),
sceneEntitiesManager.createSketchAxis(sketchPathToNode || []),
},
// end actions
}