-
Notifications
You must be signed in to change notification settings - Fork 0
wip #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
wip #29
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -131,6 +131,26 @@ export function mutateCreateLayer( | |
| layer.contentOffset = input.contentOffset; | ||
| } | ||
|
|
||
| // Set enter/exit transitions if provided | ||
| if (input.enterTransition) { | ||
| const preset = getPresetById(input.enterTransition.presetId); | ||
| if (preset) { | ||
| layer.enterTransition = { | ||
| presetId: input.enterTransition.presetId, | ||
| duration: input.enterTransition.duration | ||
| }; | ||
| } | ||
| } | ||
| if (input.exitTransition) { | ||
| const preset = getPresetById(input.exitTransition.presetId); | ||
| if (preset) { | ||
| layer.exitTransition = { | ||
| presetId: input.exitTransition.presetId, | ||
| duration: input.exitTransition.duration | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| // Mutate project | ||
| ctx.project.layers.push(layer); | ||
|
|
||
|
|
@@ -252,6 +272,34 @@ export function mutateEditLayer(ctx: MutationContext, input: EditLayerInput): Ed | |
| layer.contentOffset = Math.max(0, input.contentOffset); | ||
| } | ||
|
|
||
| // Update enter/exit transitions | ||
| if (input.enterTransition !== undefined) { | ||
| if (input.enterTransition) { | ||
| const preset = getPresetById(input.enterTransition.presetId); | ||
| if (preset) { | ||
| layer.enterTransition = { | ||
| presetId: input.enterTransition.presetId, | ||
| duration: input.enterTransition.duration | ||
| }; | ||
| } | ||
| } else { | ||
| layer.enterTransition = undefined; | ||
| } | ||
| } | ||
| if (input.exitTransition !== undefined) { | ||
| if (input.exitTransition) { | ||
| const preset = getPresetById(input.exitTransition.presetId); | ||
| if (preset) { | ||
| layer.exitTransition = { | ||
| presetId: input.exitTransition.presetId, | ||
| duration: input.exitTransition.duration | ||
| }; | ||
| } | ||
| } else { | ||
| layer.exitTransition = undefined; | ||
| } | ||
| } | ||
|
Comment on lines
+276
to
+301
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: rg -n 'EditLayerInputSchema|LayerTransitionSchema' --type=ts -B 2 -A 5Repository: epavanello/devmotion Length of output: 3265 🏁 Script executed: sed -n '198,242p' src/lib/ai/schemas.tsRepository: epavanello/devmotion Length of output: 1486 🏁 Script executed: rg -n 'LayerTransitionFieldSchema' --type=ts -B 2 -A 5Repository: epavanello/devmotion Length of output: 2155 The The description comment states "set to null to remove", but To support clearing transitions via enterTransition: LayerTransitionFieldSchema.nullable().optional().describe(...)Alternatively, remove the dead 🤖 Prompt for AI Agents |
||
|
|
||
| return { | ||
| success: true, | ||
| layerId: resolvedId, | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -45,6 +45,19 @@ const TimingFieldsSchema = z.object({ | |||||||||||||||||||||||||
| .describe('Start offset for trimming media content (seconds)') | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // ============================================ | ||||||||||||||||||||||||||
| // Layer Transition (enter/exit preset) | ||||||||||||||||||||||||||
| // ============================================ | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const LayerTransitionFieldSchema = z | ||||||||||||||||||||||||||
| .object({ | ||||||||||||||||||||||||||
| presetId: AnimationPresetIdSchema.describe('Animation preset ID to apply as transition'), | ||||||||||||||||||||||||||
| duration: z.number().positive().describe('Transition duration in seconds (typically 0.3-0.8)') | ||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||
| .describe( | ||||||||||||||||||||||||||
| 'Automatic animation applied at layer enter/exit. Position presets are relative offsets from the layer base position. Scale/opacity are factors (0→1 means invisible→visible).' | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // ============================================ | ||||||||||||||||||||||||||
| // Layer Type + Props Union | ||||||||||||||||||||||||||
| // ============================================ | ||||||||||||||||||||||||||
|
|
@@ -123,9 +136,17 @@ export const CreateLayerInputSchema = z | |||||||||||||||||||||||||
| // Layer type and properties | ||||||||||||||||||||||||||
| layer: LayerTypePropsUnion, | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Animation (preset OR custom keyframes) | ||||||||||||||||||||||||||
| // Transitions (automatic enter/exit animations, no keyframes created) | ||||||||||||||||||||||||||
| enterTransition: LayerTransitionFieldSchema.optional().describe( | ||||||||||||||||||||||||||
| 'Auto-play animation when layer enters (e.g., fade-in, slide-in-left). Applied as offset/factor on base transform.' | ||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||
| exitTransition: LayerTransitionFieldSchema.optional().describe( | ||||||||||||||||||||||||||
| 'Auto-play animation when layer exits (e.g., fade-out, slide-out-right). Applied as offset/factor on base transform.' | ||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Animation (preset OR custom keyframes - baked as keyframes) | ||||||||||||||||||||||||||
| animation: CreateLayerAnimationSchema.optional().describe( | ||||||||||||||||||||||||||
| 'Animation: preset OR custom keyframes' | ||||||||||||||||||||||||||
| 'Animation as keyframes: preset (baked at startTime) OR custom keyframes' | ||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||
| .refine( | ||||||||||||||||||||||||||
|
|
@@ -199,7 +220,15 @@ export const EditLayerInputSchema = z | |||||||||||||||||||||||||
| .describe('Layer-specific properties to update (merged with existing)'), | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Timing fields | ||||||||||||||||||||||||||
| ...TimingFieldsSchema.shape | ||||||||||||||||||||||||||
| ...TimingFieldsSchema.shape, | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Transitions (automatic enter/exit animations) | ||||||||||||||||||||||||||
| enterTransition: LayerTransitionFieldSchema.optional().describe( | ||||||||||||||||||||||||||
| 'Set enter transition preset. Omit to keep existing, set to null to remove.' | ||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||
| exitTransition: LayerTransitionFieldSchema.optional().describe( | ||||||||||||||||||||||||||
| 'Set exit transition preset. Omit to keep existing, set to null to remove.' | ||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||
|
Comment on lines
+226
to
+231
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, check the schema definitions in schemas.ts
cat -n src/lib/ai/schemas.ts | sed -n '50,70p'Repository: epavanello/devmotion Length of output: 987 🏁 Script executed: # Check the CreateLayerInputSchema definition
cat -n src/lib/ai/schemas.ts | sed -n '138,155p'Repository: epavanello/devmotion Length of output: 1031 🏁 Script executed: # Check the EditLayerInputSchema definition around lines 220-235
cat -n src/lib/ai/schemas.ts | sed -n '220,240p'Repository: epavanello/devmotion Length of output: 976 🏁 Script executed: # Search for how enterTransition/exitTransition are handled in mutations
rg -n 'enterTransition|exitTransition' --type=ts src/lib -B3 -A3Repository: epavanello/devmotion Length of output: 12983 Change The EditLayerInputSchema description tells the AI to "set to null to remove," but Use Fix: Use .nullish()- enterTransition: LayerTransitionFieldSchema.optional().describe(
+ enterTransition: LayerTransitionFieldSchema.nullish().describe(
'Set enter transition preset. Omit to keep existing, set to null to remove.'
),
- exitTransition: LayerTransitionFieldSchema.optional().describe(
+ exitTransition: LayerTransitionFieldSchema.nullish().describe(
'Set exit transition preset. Omit to keep existing, set to null to remove.'
)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||
| .refine( | ||||||||||||||||||||||||||
| (data) => { | ||||||||||||||||||||||||||
|
|
@@ -295,11 +324,12 @@ export const animationTools = { | |||||||||||||||||||||||||
| - Position, rotation, scale, anchor point | ||||||||||||||||||||||||||
| - Layer-specific props (text content, colors, sizes, etc.) | ||||||||||||||||||||||||||
| - Style (opacity, blur, filters, drop shadow) | ||||||||||||||||||||||||||
| - Animation via preset OR custom keyframes | ||||||||||||||||||||||||||
| - Enter/exit transitions (automatic preset animations at layer boundaries) | ||||||||||||||||||||||||||
| - Animation via preset (baked as keyframes) OR custom keyframes | ||||||||||||||||||||||||||
| - Timing (enter/exit times, content duration/offset) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Example: Create a text layer with animation: | ||||||||||||||||||||||||||
| { "layer": { "type": "text", "props": { "content": "Hello World", "fontSize": 48, "fill": "#ffffff" } }, "transform": { "position": { "x": 0, "y": -200 } }, "animation": { "preset": { "id": "fade-in", "startTime": 0, "duration": 0.5 } } }`, | ||||||||||||||||||||||||||
| Example with enter transition: | ||||||||||||||||||||||||||
| { "layer": { "type": "text", "props": { "content": "Hello", "fontSize": 48, "fill": "#fff" } }, "transform": { "position": { "x": 0, "y": -200 } }, "enterTransition": { "presetId": "fade-in", "duration": 0.5 }, "exitTransition": { "presetId": "fade-out", "duration": 0.3 } }`, | ||||||||||||||||||||||||||
| inputSchema: CreateLayerInputSchema | ||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -308,6 +338,7 @@ Example: Create a text layer with animation: | |||||||||||||||||||||||||
| - Provide only the fields you want to change | ||||||||||||||||||||||||||
| - transform/style sections replace entire object if provided | ||||||||||||||||||||||||||
| - props are merged with existing props | ||||||||||||||||||||||||||
| - enterTransition/exitTransition: set automatic enter/exit animations | ||||||||||||||||||||||||||
| - Use layer ID from create_layer response or layer name`, | ||||||||||||||||||||||||||
| inputSchema: EditLayerInputSchema | ||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Silent failure for invalid
presetId— AI receivessuccess: trueeven if transition not appliedWhen
getPresetById(input.enterTransition.presetId)returnsundefined(invalid ID), the transition is silently dropped andmutateCreateLayerstill returnssuccess: true. The AI has no signal that the transition was rejected, which could cause it to assume the transition is in effect or repeatedly submit the same invalid preset ID.The same pattern repeats for
exitTransition(lines 144–152) and inmutateEditLayer(lines 278–284, 291–297).🛡️ Proposed fix — surface invalid preset ID in the output message
if (input.enterTransition) { const preset = getPresetById(input.enterTransition.presetId); if (preset) { layer.enterTransition = { presetId: input.enterTransition.presetId, duration: input.enterTransition.duration }; + } else { + console.warn(`[mutateCreateLayer] Unknown enterTransition presetId: "${input.enterTransition.presetId}"`); } }For
mutateEditLayer, include the warning in the returned message so the AI can self-correct.🤖 Prompt for AI Agents