Skip to content

Commit c0a233a

Browse files
committed
Merge branch 'alpha' into timeline-video-render
2 parents 98edbed + c1ba045 commit c0a233a

23 files changed

Lines changed: 646 additions & 256 deletions

File tree

apps/desktop/src/renderer/engine.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { MidiInput, MidiInputPanel, MidiGlobalPanel } from '@hedron-gl/midi-inpu
55
import { GamepadInput, GamepadInputPanel, GamepadGlobalPanel } from '@hedron-gl/gamepad-input'
66
import { LFOInput, LFOInputPanel } from '@hedron-gl/lfo-input'
77
import { AudioInput, AudioInputPanel, AudioGlobalPanel } from '@hedron-gl/audio-input'
8-
import { TimelineInput, TimelineGlobalPanel } from '@hedron-gl/timeline'
8+
import { TimelineInput, TimelineGlobalPanel, TimelineInputPanel } from '@hedron-gl/timeline'
99
import { SceneControlPlugin, SceneControlGlobalPanel } from '@hedron-gl/scene-control'
1010
import { VideoRenderPlugin, VideoRenderGlobalPanel } from '@hedron-gl/video-render'
1111
import { videoRenderCallbacks } from '@renderer/utils/renderVideo/videoRenderCallbacks'
@@ -39,6 +39,7 @@ export const pluginViews = {
3939
lfo: LFOInputPanel,
4040
audio: AudioInputPanel,
4141
gamepad: GamepadInputPanel,
42+
['timeline-track']: TimelineInputPanel,
4243
},
4344
globalPanel: {
4445
['audio-input']: AudioGlobalPanel,

packages/app-store/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"devDependencies": {
4747
"@types/node": "^25.0.0",
4848
"tsup": "^8.3.6",
49-
"typescript": "^5.6.2"
49+
"typescript": "^5.9.3"
5050
},
5151
"peerDependencies": {
5252
"react": "^18.3.1"

packages/app-store/src/appStore.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export interface AppState {
4848
selectedSketches: ProjectData['app']['selectedSketches'] // TODO: should be part of ProjectData
4949
selectedNodes: ProjectData['app']['selectedNodes']
5050
selectedInputs: ProjectData['app']['selectedInputs']
51+
5152
openedControlGroups: ProjectData['app']['openedControlGroups']
5253
sketchesDir: string | null
5354
globalDialogId: DialogId | null
@@ -66,6 +67,15 @@ export interface AppState {
6667
removeFromSaveList: (path: string) => void
6768
setSketchesServerBuildResult: (result: BuildResult | null) => void
6869
cleanupStaleReferences: (engineData: EngineData) => void
70+
71+
/** @deprecated -- this state handler will be moved to the timeline plugin */
72+
setActiveTimelineComponentId: (id: string | null) => void
73+
/** @deprecated -- this state will be moved to the timeline plugin */
74+
activeTimelineComponentId: string | null
75+
/** @deprecated -- this state handler will be moved to the timeline plugin */
76+
setSelectedTimelineTrackId: (trackId: string | null) => void
77+
/** @deprecated -- this state will be moved to the timeline plugin */
78+
selectedTimelineTrackId: string | null
6979
}
7080

7181
export type SetState = StoreApi<AppState>['setState']
@@ -93,6 +103,8 @@ export const createAppStore = () =>
93103
currentSavePath: null,
94104
selectedNodes: {},
95105
selectedInputs: {},
106+
activeTimelineComponentId: null,
107+
selectedTimelineTrackId: null,
96108
openedControlGroups: {},
97109
saveList: [],
98110
sketchesServerBuildResult: null,
@@ -150,6 +162,16 @@ export const createAppStore = () =>
150162
state.selectedInputs[nodeId] = inputId
151163
})
152164
},
165+
setActiveTimelineComponentId: (id) => {
166+
set((state) => {
167+
state.activeTimelineComponentId = id
168+
})
169+
},
170+
setSelectedTimelineTrackId: (id) => {
171+
set((state) => {
172+
state.selectedTimelineTrackId = id
173+
})
174+
},
153175
setOpenedControlGroup: (sketchId: string, groupIndex: number, isOpen: boolean) => {
154176
set((state) => {
155177
if (!state.openedControlGroups[sketchId]) {

packages/gamepad-input/src/GamepadGlobalPanel.tsx

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
import React, { useState, useEffect, useCallback } from 'react'
2-
import {
3-
findNodeWithKeyFromIdList,
4-
HedronEngine,
5-
InputNode,
6-
Nodes,
7-
nodesAsArray,
8-
ParamValues,
9-
} from '@hedron-gl/engine'
2+
import { HedronEngine, InputNode, Nodes, nodesAsArray, ParamValues } from '@hedron-gl/engine'
103
import {
114
useEngineStore,
125
Card,
136
CardBody,
147
CardContent,
158
Collapsible,
169
ControlGrid,
10+
getNodeOptionNodes,
1711
NodeContainer,
1812
} from '@hedron-gl/ui-core'
1913
import { GamepadInput } from './GamepadInput'
@@ -167,18 +161,11 @@ const findMatchingInputsForEvent = (
167161
.filter((input) => {
168162
if (input.nodeType !== 'input' || input.inputType !== 'gamepad') return false
169163

170-
const controllerIndexNode = findNodeWithKeyFromIdList(
171-
nodes,
172-
'controllerIndex',
173-
input.childGroups.optionNodeIds,
174-
)
175-
176-
const inputTypeNode = findNodeWithKeyFromIdList(
177-
nodes,
178-
'inputType',
179-
input.childGroups.optionNodeIds,
180-
)
181-
const indexNode = findNodeWithKeyFromIdList(nodes, 'index', input.childGroups.optionNodeIds)
164+
const {
165+
controllerIndex: controllerIndexNode,
166+
inputType: inputTypeNode,
167+
index: indexNode,
168+
} = getNodeOptionNodes({ nodes }, input.id)
182169

183170
if (!controllerIndexNode || !inputTypeNode || !indexNode) return false
184171

@@ -238,11 +225,7 @@ const getInputsForController = (
238225
return nodesAsArray(nodes).filter((node) => {
239226
if (node.nodeType !== 'input' || node.inputType !== 'gamepad') return false
240227

241-
const controllerIndexNode = findNodeWithKeyFromIdList(
242-
nodes,
243-
'controllerIndex',
244-
node.childGroups.optionNodeIds,
245-
)
228+
const { controllerIndex: controllerIndexNode } = getNodeOptionNodes({ nodes }, node.id)
246229

247230
if (!controllerIndexNode) return false
248231

@@ -429,12 +412,7 @@ const ControllerItem: React.FC<ControllerItemProps> = ({
429412
if (!lastEvent) return null
430413

431414
const matchingInput = controllerInputs.find((input) => {
432-
const inputTypeNode = findNodeWithKeyFromIdList(
433-
nodes,
434-
'inputType',
435-
input.childGroups.optionNodeIds,
436-
)
437-
const indexNode = findNodeWithKeyFromIdList(nodes, 'index', input.childGroups.optionNodeIds)
415+
const { inputType: inputTypeNode, index: indexNode } = getNodeOptionNodes({ nodes }, input.id)
438416

439417
if (!inputTypeNode || !indexNode) return false
440418

packages/midi-input/src/MidiGlobalPanel.tsx

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import React, { useState, useEffect } from 'react'
2-
import { findNodeWithKeyFromIdList, HedronEngine, ParamNode, ShotNode } from '@hedron-gl/engine'
3-
import { useEngineStore, ControlGrid, NodeContainer } from '@hedron-gl/ui-core'
2+
import { HedronEngine, ParamNode, ShotNode } from '@hedron-gl/engine'
3+
import { useEngineStore, ControlGrid, NodeContainer, getNodeOptionNodes } from '@hedron-gl/ui-core'
44
import { MIDIEvent, MidiMessageType, midiMessageNames } from '@hedron-gl/midi-manager'
55
import { MidiInput } from './MidiInput'
6+
import { doesMidiEventMatchInput } from './utils'
67
import styles from './MidiGlobalPanel.module.css'
8+
import { NOTE_MODE_ON } from './constants'
79

810
interface MidiGlobalPanelProps {
911
engine: HedronEngine
@@ -69,24 +71,34 @@ export const MidiGlobalPanel: React.FC<MidiGlobalPanelProps> = ({ engine }) => {
6971
Object.values(nodes).forEach((input) => {
7072
if (input?.nodeType !== 'input' || input.inputType !== 'midi') return
7173

72-
const channelNode = findNodeWithKeyFromIdList(
73-
nodes,
74-
'channel',
75-
input.childGroups.optionNodeIds,
76-
)
77-
const noteNode = findNodeWithKeyFromIdList(nodes, 'note', input.childGroups.optionNodeIds)
78-
const typeNode = findNodeWithKeyFromIdList(nodes, 'type', input.childGroups.optionNodeIds)
74+
const {
75+
channel: channelNode,
76+
note: noteNode,
77+
type: typeNode,
78+
noteMode: noteModeNode,
79+
} = getNodeOptionNodes({ nodes }, input.id)
7980

8081
if (!channelNode || !noteNode || !typeNode) return
8182

82-
const channelValue = paramValues[channelNode.id]
83-
const noteValue = paramValues[noteNode.id]
84-
const typeValue = paramValues[typeNode.id]
83+
const channelValue = paramValues[channelNode.id] as number | undefined
84+
const noteValue = paramValues[noteNode.id] as number | undefined
85+
const typeValue = paramValues[typeNode.id] as number | undefined
86+
const noteModeValue = noteModeNode
87+
? ((paramValues[noteModeNode.id] as number | undefined) ?? NOTE_MODE_ON)
88+
: NOTE_MODE_ON
89+
90+
if (channelValue === undefined || noteValue === undefined || typeValue === undefined) {
91+
return
92+
}
8593

8694
if (
87-
channelValue === event.channel &&
88-
noteValue === event.note &&
89-
typeValue === event.type
95+
doesMidiEventMatchInput({
96+
event,
97+
channel: channelValue,
98+
note: noteValue,
99+
type: typeValue,
100+
noteMode: noteModeValue,
101+
})
90102
) {
91103
const targetNode = nodes[input.targetNodeId] as ParamNode | ShotNode
92104
if (targetNode) {
@@ -130,6 +142,7 @@ export const MidiGlobalPanel: React.FC<MidiGlobalPanelProps> = ({ engine }) => {
130142
<div>
131143
<ControlGrid>
132144
<NodeContainer nodeId={`${globalNodeId}-smoothing`} />
145+
<NodeContainer nodeId={`${globalNodeId}-autoMidiLearn`} />
133146
</ControlGrid>
134147

135148
<div className={styles.section}>

0 commit comments

Comments
 (0)