diff --git a/src/features/animation/__tests__/sequences-test.ts b/src/features/animation/__tests__/sequences-test.ts
index 863ba33..684d5be 100644
--- a/src/features/animation/__tests__/sequences-test.ts
+++ b/src/features/animation/__tests__/sequences-test.ts
@@ -3,6 +3,7 @@ import {
createInitialSequences,
duplicateSequence,
getSequenceSpring,
+ NEUTRAL_EXPRESSION_ID,
normalizeSequencesForExpressions,
parseSequences,
remapSequencesAfterExpressionDelete,
@@ -88,6 +89,21 @@ describe('editable avatar sequences', () => {
expect(normalized.steps[0].expressionId).toBe(initialExpressions[0].id)
})
+ it('preserves the system neutral target during normalization', () => {
+ const sequence = createInitialSequences()[0]
+ const [normalized] = normalizeSequencesForExpressions(
+ [
+ {
+ ...sequence,
+ steps: [{ ...sequence.steps[0], expressionId: NEUTRAL_EXPRESSION_ID }],
+ },
+ ],
+ []
+ )
+
+ expect(normalized.steps[0].expressionId).toBe(NEUTRAL_EXPRESSION_ID)
+ })
+
it('maps transition styles and durations to distinct spring dynamics', () => {
const smooth = getSequenceSpring('smooth', 900, 7)
const snappy = getSequenceSpring('snappy', 250, 7)
diff --git a/src/features/animation/components/SequenceWorkspace.tsx b/src/features/animation/components/SequenceWorkspace.tsx
index 32c8cc1..6bf0f84 100644
--- a/src/features/animation/components/SequenceWorkspace.tsx
+++ b/src/features/animation/components/SequenceWorkspace.tsx
@@ -25,7 +25,8 @@ import { ControlSection, InspectorCard, PanelTitle } from '@/app/components/comm
import { NumericField } from '@/app/components/controls'
import {
createSequenceStep,
- findExpressionIndex,
+ NEUTRAL_EXPRESSION_ID,
+ resolveSequenceExpression,
type AvatarSequence,
type SequenceStep,
} from '@/features/animation/sequences'
@@ -37,6 +38,7 @@ import {
import { type BodyNode } from '@/features/avatar/body'
import { ExpressionPreview } from '@/features/avatar/components/ExpressionWorkspace'
import { type Expression } from '@/features/avatar/geometry'
+import { defaultExpression } from '@/features/avatar/presets'
import { type SurfaceConfig } from '@/features/avatar/surfaces'
export function SequenceWorkspace({
editing,
@@ -268,9 +270,8 @@ export function SequenceWorkspace({
{editing.draft.steps.length ? (
{editing.draft.steps.map((step, position) => {
- const expressionIndex = findExpressionIndex(expressions, step.expressionId)
- const preset = expressions[expressionIndex]
- if (!preset) return null
+ const resolved = resolveSequenceExpression(expressions, step.expressionId)
+ if (!resolved.expression) return null
const card = (
)
@@ -318,16 +327,20 @@ export function SequenceWorkspace({
draggedStepId.current = null
}}
>
-
-
-
- onEditExpression(expressionIndex, preset)}
- >
- {t('Modifier')}
-
-
-
+ {resolved.neutral ? (
+ card
+ ) : (
+
+
+
+ onEditExpression(resolved.index, resolved.expression)}
+ >
+ {t('Modifier')}
+
+
+
+ )}
)
})}
@@ -408,6 +421,28 @@ export function SequenceWorkspace({
subtitle="Sélectionne un preset pour l’ajouter à la fin de la timeline."
/>
+
{expressions.map((preset, index) => (
-
@@ -1225,7 +1215,8 @@ export function StudioInspector({ controller }: { controller: StudioController }
{group.sequences.map(sequence => {
const firstStep = sequence.steps[0]
const firstExpression = firstStep
- ? expressionById.get(firstStep.expressionId)
+ ? resolveSequenceExpression(expressions, firstStep.expressionId)
+ .expression
: undefined
const card = (