Centralize door animation state and operation mapping
This commit is contained in:
@@ -33,6 +33,13 @@ export {
|
||||
} from './hooks/spatial-grid/spatial-grid-sync'
|
||||
export { useSpatialQuery } from './hooks/spatial-grid/use-spatial-query'
|
||||
export { loadAssetUrl, saveAsset } from './lib/asset-storage'
|
||||
export {
|
||||
clampDoorOperationState,
|
||||
getDoorRenderOpenAmount,
|
||||
getGarageVisibleOpeningRatio,
|
||||
isOperationDoorType,
|
||||
SECTIONAL_GARAGE_RENDER_OPEN_SCALE,
|
||||
} from './lib/door-operation'
|
||||
export { getRenderableSlabPolygon } from './lib/slab-polygon'
|
||||
export {
|
||||
detectSpacesForLevel,
|
||||
@@ -61,6 +68,7 @@ export {
|
||||
} from './store/history-control'
|
||||
export {
|
||||
type ControlValue,
|
||||
type DoorInteractiveState,
|
||||
type ItemInteractiveState,
|
||||
useInteractive,
|
||||
} from './store/use-interactive'
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import type { DoorNode, DoorType } from '../schema/nodes/door'
|
||||
|
||||
export const SECTIONAL_GARAGE_RENDER_OPEN_SCALE = 0.88
|
||||
|
||||
export function clampDoorOperationState(value: number | undefined) {
|
||||
return Math.max(0, Math.min(1, value ?? 0))
|
||||
}
|
||||
|
||||
export function isOperationDoorType(
|
||||
doorType: DoorType | DoorNode['doorType'] | string | undefined,
|
||||
) {
|
||||
return (
|
||||
doorType === 'folding' ||
|
||||
doorType === 'pocket' ||
|
||||
doorType === 'barn' ||
|
||||
doorType === 'sliding' ||
|
||||
doorType === 'garage-sectional' ||
|
||||
doorType === 'garage-rollup' ||
|
||||
doorType === 'garage-tiltup'
|
||||
)
|
||||
}
|
||||
|
||||
export function getDoorRenderOpenAmount(
|
||||
doorType: DoorType | DoorNode['doorType'],
|
||||
operationState: number | undefined,
|
||||
) {
|
||||
const openAmount = clampDoorOperationState(operationState)
|
||||
return doorType === 'garage-sectional'
|
||||
? openAmount * SECTIONAL_GARAGE_RENDER_OPEN_SCALE
|
||||
: openAmount
|
||||
}
|
||||
|
||||
export function getGarageVisibleOpeningRatio(
|
||||
doorType: DoorType | DoorNode['doorType'],
|
||||
operationState: number | undefined,
|
||||
) {
|
||||
if (doorType === 'garage-sectional') {
|
||||
return Math.min(1, clampDoorOperationState(operationState) / SECTIONAL_GARAGE_RENDER_OPEN_SCALE)
|
||||
}
|
||||
|
||||
return clampDoorOperationState(operationState)
|
||||
}
|
||||
@@ -12,8 +12,14 @@ export type ItemInteractiveState = {
|
||||
controlValues: ControlValue[]
|
||||
}
|
||||
|
||||
export type DoorInteractiveState = {
|
||||
operationState?: number
|
||||
swingAngle?: number
|
||||
}
|
||||
|
||||
type InteractiveStore = {
|
||||
items: Record<AnyNodeId, ItemInteractiveState>
|
||||
doors: Record<AnyNodeId, DoorInteractiveState>
|
||||
|
||||
/** Initialize a node's interactive state from its asset definition (idempotent) */
|
||||
initItem: (itemId: AnyNodeId, interactive: Interactive) => void
|
||||
@@ -23,6 +29,12 @@ type InteractiveStore = {
|
||||
|
||||
/** Remove a node's state (e.g. on unmount) */
|
||||
removeItem: (itemId: AnyNodeId) => void
|
||||
|
||||
/** Set transient door open state without committing it to the scene node */
|
||||
setDoorOpenState: (doorId: AnyNodeId, value: DoorInteractiveState) => void
|
||||
|
||||
/** Clear transient door open state */
|
||||
removeDoorOpenState: (doorId: AnyNodeId) => void
|
||||
}
|
||||
|
||||
const defaultControlValue = (interactive: Interactive, index: number): ControlValue => {
|
||||
@@ -40,6 +52,7 @@ const defaultControlValue = (interactive: Interactive, index: number): ControlVa
|
||||
|
||||
export const useInteractive = create<InteractiveStore>((set, get) => ({
|
||||
items: {},
|
||||
doors: {},
|
||||
|
||||
initItem: (itemId, interactive) => {
|
||||
const { controls } = interactive
|
||||
@@ -74,4 +87,23 @@ export const useInteractive = create<InteractiveStore>((set, get) => ({
|
||||
return { items: rest }
|
||||
})
|
||||
},
|
||||
|
||||
setDoorOpenState: (doorId, value) => {
|
||||
set((state) => ({
|
||||
doors: {
|
||||
...state.doors,
|
||||
[doorId]: {
|
||||
...state.doors[doorId],
|
||||
...value,
|
||||
},
|
||||
},
|
||||
}))
|
||||
},
|
||||
|
||||
removeDoorOpenState: (doorId) => {
|
||||
set((state) => {
|
||||
const { [doorId]: _, ...rest } = state.doors
|
||||
return { doors: rest }
|
||||
})
|
||||
},
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user