Skip to content

Commit 102dbb3

Browse files
keyframes working for all non-vector values (#657)
* keyframes working for all non-vector values * onNewInput returns the node rather than ID for convenience * vector tracks have children * useCallback to fix scrubbing in story * vector tracks working with timeline * tidy * adding/deleting vector components * types tidy * story fix * parent keyframe selected state * tidy * fix for 0 value keyframes * removed active region for keyframes * collapsible vector tracks * copilot review fixes
1 parent 5549e84 commit 102dbb3

27 files changed

Lines changed: 701 additions & 178 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ out
1414
.sketches-server
1515
dev-settings.json
1616
chrome-extensions
17-
packages/ui-core/storybook-static/*
17+
**/storybook-static/*

apps/desktop/src/renderer/components/SelectedNode/SelectedNode.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ export const SelectedNode = () => {
4444
Object.values(engine.plugins).map((plugin) => ({
4545
label: plugin.name,
4646
onClick: () => {
47-
const id = engine.addInput(plugin.inputType, selectedNode.id)
48-
if (!id) return
47+
const newInput = engine.addInput(plugin.inputType, selectedNode.id)
48+
if (!newInput) return
4949

50-
setSelectedInputId(selectedNode.id, id)
50+
setSelectedInputId(selectedNode.id, newInput.id)
5151
},
5252
})),
5353
[selectedNode.id, setSelectedInputId],

packages/engine/src/HedronEngine/HedronEngine.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
ConfigCustomNode,
2929
ChildGroupsLoose,
3030
Resources,
31+
Input,
3132
} from '@store/types'
3233
import { getSketchesOfModuleId } from '@store/selectors/getSketchesOfModuleId'
3334
import { createEngineStore, EngineStore } from '@store/engineStore'
@@ -288,7 +289,7 @@ export class HedronEngine {
288289
this.store.getState().updateMultipleParamValues(nodeIds, values)
289290
}
290291

291-
public addInput(inputType: string, targetNodeId: string) {
292+
public addInput(inputType: string, targetNodeId: string): Input | undefined {
292293
const plugin = Object.values(this.plugins).find((p) => p.inputType === inputType)
293294

294295
if (!plugin) {
@@ -298,7 +299,7 @@ export class HedronEngine {
298299

299300
const state = this.store.getState()
300301

301-
const targetNode = state.nodes[targetNodeId]
302+
const targetNode = state.nodes[targetNodeId] as Param | Shot
302303

303304
const numAlready = targetNode?.childGroups?.inputNodeIds?.length ?? 0
304305

@@ -311,17 +312,17 @@ export class HedronEngine {
311312

312313
const addInput = this.store.getState().addInput
313314

314-
const inputId = addInput(input)
315+
const newInput = addInput(input)
315316

316317
/**
317318
* FIXME: Once `optionNodesConfig` is removed, we wont need this
318319
* All plugins will use `onNewInput` to add these manually
319320
* */
320-
this.addOptionNodes(inputId, plugin.optionNodesConfig ?? [])
321+
this.addOptionNodes(newInput.id, plugin.optionNodesConfig ?? [])
321322

322-
plugin.onNewInput?.(this, inputId)
323+
plugin.onNewInput?.(this, newInput, targetNode)
323324

324-
return inputId
325+
return newInput
325326
}
326327

327328
/**

packages/engine/src/plugins/Plugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export interface IPlugin {
5656
/**
5757
* Optional callback called after each input for this plugin is added
5858
*/
59-
onNewInput?: (engine: HedronEngine, inputId: string) => void
59+
onNewInput?: (engine: HedronEngine, newInput: Input, targetNode: Param | Shot) => void
6060
}
6161

6262
// eslint-disable-next-line @typescript-eslint/no-explicit-any

packages/engine/src/store/actionCreators/addSketch.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ export const createAddSketch: SetterCreator<'addSketch'> = (setState) => (module
1111
for (const nodeConfig of config.nodes) {
1212
const id = createUniqueId()
1313
nodeIds.push(id)
14-
// TODO: We're handing newSketchId as a parentId but sketches aren't yet nodes (this might break things...)
15-
addNode(state, id, newSketchId, nodeConfig)
14+
// FIXME: Add sketch parent ID here once sketches are nodes
15+
addNode(state, id, null, nodeConfig)
1616
}
1717

1818
state.sketches[newSketchId] = {

packages/engine/src/store/actionCreators/createAddInput.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ensureNodeConfig } from '@store/shared/ensureConfig'
22
import { addNode } from '@store/shared/addNode'
3-
import { SetterCreator } from '@store/types'
3+
import { Input, SetterCreator } from '@store/types'
44
import { createUniqueId } from '@utils/createUniqueId'
55

66
export const createAddInput: SetterCreator<'addInput'> =
@@ -10,6 +10,8 @@ export const createAddInput: SetterCreator<'addInput'> =
1010

1111
const optionNodeIds: string[] = []
1212

13+
let newInput: Input | undefined = undefined
14+
1315
setState((state) => {
1416
for (const cfg of optionsNodeConfig) {
1517
const optionNodeId = createUniqueId()
@@ -21,9 +23,11 @@ export const createAddInput: SetterCreator<'addInput'> =
2123
}
2224

2325
if (state.nodes[id]) {
26+
newInput = state.nodes[id] as Input
2427
return
2528
}
26-
state.nodes[id] = {
29+
30+
newInput = {
2731
...inputConfig,
2832
childGroups: {
2933
optionNodeIds,
@@ -33,9 +37,17 @@ export const createAddInput: SetterCreator<'addInput'> =
3337
nodeType: 'input',
3438
}
3539

40+
state.nodes[id] = newInput
41+
3642
// Add children Ids to target node (so that cleanup works if target node is deleted)
3743
state.nodes[inputConfig.targetNodeId]?.childGroups.inputNodeIds.push(id)
3844
})
3945

40-
return id
46+
if (!newInput) {
47+
throw new Error(
48+
'Failed to create new input. This is likely a bug in the engine store, as it should have been created in the setState callback.',
49+
)
50+
}
51+
52+
return newInput as Input
4153
}

packages/engine/src/store/types/Engine.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ interface Actions {
3737
addInput: (
3838
inputConfig: Omit<Input, 'id' | 'optionNodeIds' | 'childGroups' | 'nodeType'>,
3939
optionsNodeConfig?: readonly (ConfigParam | ConfigShot)[],
40-
) => string
40+
) => Input
4141
deleteNode: (nodeId: string) => void
4242
}
4343

packages/engine/src/store/types/Param.ts

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -152,25 +152,6 @@ export type ParamValueType = Param['valueType'] | null
152152
export type ParamVector = ParamVector2 | ParamVector3 | ParamRGB
153153
export type ParamVectorValueType = ParamVector['valueType']
154154

155-
// Record ensures every ParamValueTypeWithChildren member is listed — adding a new
156-
// type that extends NodeParamWithChildrenBase will cause a compile error here if
157-
// it isn't included.
158-
const paramValueTypesWithChildren: Record<ParamVectorValueType, true> = {
159-
vector3: true,
160-
vector2: true,
161-
rgb: true,
162-
}
163-
164-
export const isParamVectorValueType = (
165-
paramValueType: ParamValueType,
166-
): paramValueType is ParamVectorValueType => {
167-
return paramValueType != null && paramValueType in paramValueTypesWithChildren
168-
}
169-
170-
export const isParamVector = (node: Param): node is ParamVector => {
171-
return node.nodeType === 'param' && node.valueType in paramValueTypesWithChildren
172-
}
173-
174155
export type EnsureRequiredValueType<T> = T extends { valueType?: infer V }
175156
? Omit<T, 'valueType'> & { valueType: V }
176157
: T
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { ParamValueType, ParamVector, ParamVectorValueType } from './Param'
2+
import { Node } from './Node'
3+
import type { HedronEngine } from '@HedronEngine/HedronEngine'
4+
5+
// Record ensures every ParamValueTypeWithChildren member is listed — adding a new
6+
// type that extends NodeParamWithChildrenBase will cause a compile error here if
7+
// it isn't included.
8+
const paramValueTypesWithChildren: Record<ParamVectorValueType, true> = {
9+
vector3: true,
10+
vector2: true,
11+
rgb: true,
12+
}
13+
14+
export const isParamVectorValueType = (
15+
paramValueType: ParamValueType,
16+
): paramValueType is ParamVectorValueType => {
17+
return paramValueType != null && paramValueType in paramValueTypesWithChildren
18+
}
19+
20+
export const isParamVector = (node: Node): node is ParamVector => {
21+
return node.nodeType === 'param' && node.valueType in paramValueTypesWithChildren
22+
}
23+
24+
export const isParamVectorComponent = (node: Node, engine: HedronEngine) => {
25+
let isComponent = false
26+
27+
if (node.nodeType !== 'param') return false
28+
29+
for (const parentId of node.parentIds) {
30+
const parentNode = engine.getNode(parentId)!
31+
32+
if (isParamVector(parentNode)) {
33+
isComponent = true
34+
}
35+
}
36+
37+
return isComponent
38+
}

packages/engine/src/store/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export * from './Input'
77
export * from './Node'
88
export * from './Engine'
99
export * from './Resources'
10+
export * from './guards'

0 commit comments

Comments
 (0)