{
  "provenance": {
    "generator": "scripts/emit-agent-spec.mjs",
    "artifact": "scene-schema",
    "appCommit": "d294e83ba492d25631d1082d96e95c8ac9ea8cb8",
    "schemaVersion": 10,
    "engineVersion": "1.0.0",
    "sourcesHash": "sha256:448c03150707152de42be71fc2a88361b1182ad2185cc360cec784a9ad7c531f",
    "contentHash": "sha256:8d2a346737d6e2d62e819b243f745800662b90f1d9ad7b1e690ddbf8c0e6e080",
    "note": "appCommit is null in the committed artifact by construction — see the header of scripts/emit-agent-spec.mjs. sourcesHash identifies the inputs and is reproducible."
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://motion-studio.app/spec/scene-schema.json",
  "title": "Motion Studio scene",
  "description": "Scene file format, schemaVersion 10. Generated from the app's own registry.js — do not edit by hand.",
  "type": "object",
  "required": [
    "templateId",
    "config"
  ],
  "properties": {
    "version": {
      "const": 2,
      "$comment": "scene envelope version (ExportMenu.buildScene) — distinct from meta.schemaVersion"
    },
    "templateId": {
      "enum": [
        "orbit",
        "carousel",
        "stack",
        "band",
        "coverflow",
        "grid",
        "sphere"
      ]
    },
    "config": {
      "type": "object"
    },
    "canvas": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "aspectRatio": {
          "enum": [
            "1:1",
            "9:16",
            "16:9"
          ]
        },
        "fps": {
          "type": "number"
        },
        "background": {
          "type": "object"
        }
      }
    },
    "assets": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "type": {
            "enum": [
              "image",
              "video"
            ],
            "$comment": "absent in scenes older than schemaVersion 5 → read as image"
          }
        }
      }
    },
    "meta": {
      "type": "object",
      "properties": {
        "engine": {
          "type": "string"
        },
        "schemaVersion": {
          "type": "integer"
        },
        "template": {
          "enum": [
            "orbit",
            "carousel",
            "stack",
            "band",
            "coverflow",
            "grid",
            "sphere"
          ]
        },
        "created": {
          "type": "string"
        }
      }
    }
  },
  "oneOf": [
    {
      "title": "orbit",
      "properties": {
        "templateId": {
          "const": "orbit"
        },
        "config": {
          "type": "object",
          "additionalProperties": false,
          "description": "Omitted fields fall back to schema defaults on import (mergeSceneConfig).",
          "properties": {
            "interaction": {
              "type": "object",
              "additionalProperties": false,
              "description": "Playback interaction. Filled from app defaults when omitted (normalizeInteraction).",
              "properties": {
                "drag": {
                  "type": "boolean"
                },
                "scroll": {
                  "type": "boolean"
                },
                "onRelease": {
                  "enum": [
                    "resume",
                    "stay"
                  ]
                },
                "cursor": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "gravity": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "hover": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "face": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              }
            },
            "cardRatio": {
              "enum": [
                "1:1",
                "4:3",
                "3:4",
                "16:9",
                "9:16"
              ]
            },
            "count": {
              "type": "number",
              "minimum": 3,
              "maximum": 30,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cardSize": {
              "type": "number",
              "minimum": 120,
              "maximum": 1200,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cornerRadius": {
              "type": "number",
              "minimum": 0,
              "maximum": 50,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "orbitRadius": {
              "type": "number",
              "minimum": 100,
              "maximum": 700,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "planeX": {
              "type": "number",
              "minimum": -90,
              "maximum": 90,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "planeZ": {
              "type": "number",
              "minimum": -90,
              "maximum": 90,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "orient": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "perspective": {
              "type": "number",
              "minimum": 400,
              "maximum": 1600,
              "$comment": "slider step 10 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "direction": {
              "enum": [
                "forward",
                "reverse"
              ]
            },
            "motion": {
              "enum": [
                "continuous",
                "step"
              ]
            },
            "ease": {
              "enum": [
                "none",
                "power2.inOut",
                "power4.inOut",
                "expo.out",
                "back.out",
                "elastic.out",
                "custom"
              ]
            },
            "easeCustom": {
              "const": [
                0.42,
                0,
                0.58,
                1
              ]
            },
            "hold": {
              "type": "number",
              "minimum": 0,
              "maximum": 80,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cycles": {
              "type": "number",
              "minimum": 1,
              "maximum": 6,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "duration": {
              "type": "number",
              "minimum": 2,
              "maximum": 60,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "jitterAmount": {
              "type": "number",
              "minimum": 0,
              "maximum": 50,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "jitterSpeed": {
              "type": "number",
              "minimum": 0.5,
              "maximum": 8,
              "$comment": "slider step 0.5 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "rotationDrift": {
              "type": "number",
              "minimum": 0,
              "maximum": 15,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "tiltX": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "tiltY": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "tiltZ": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "fade": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "scale": {
              "type": "number",
              "minimum": 10,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "rotationX": {
              "type": "number",
              "minimum": -45,
              "maximum": 45,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "rotationY": {
              "type": "number",
              "minimum": -45,
              "maximum": 45,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "rotationZ": {
              "type": "number",
              "minimum": -45,
              "maximum": 45,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "zoom": {
              "type": "number",
              "minimum": 50,
              "maximum": 300,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "offsetX": {
              "type": "number",
              "minimum": -500,
              "maximum": 500,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "offsetY": {
              "type": "number",
              "minimum": -500,
              "maximum": 500,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            }
          }
        }
      },
      "required": [
        "templateId"
      ]
    },
    {
      "title": "carousel",
      "properties": {
        "templateId": {
          "const": "carousel"
        },
        "config": {
          "type": "object",
          "additionalProperties": false,
          "description": "Omitted fields fall back to schema defaults on import (mergeSceneConfig).",
          "properties": {
            "interaction": {
              "type": "object",
              "additionalProperties": false,
              "description": "Playback interaction. Filled from app defaults when omitted (normalizeInteraction).",
              "properties": {
                "drag": {
                  "type": "boolean"
                },
                "scroll": {
                  "type": "boolean"
                },
                "onRelease": {
                  "enum": [
                    "resume",
                    "stay"
                  ]
                },
                "cursor": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "gravity": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "hover": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "face": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              }
            },
            "cardRatio": {
              "enum": [
                "1:1",
                "4:3",
                "3:4",
                "16:9",
                "9:16"
              ]
            },
            "count": {
              "type": "number",
              "minimum": 1,
              "maximum": 30,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cardSize": {
              "type": "number",
              "minimum": 120,
              "maximum": 1200,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cornerRadius": {
              "type": "number",
              "minimum": 0,
              "maximum": 50,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "gap": {
              "type": "number",
              "minimum": -300,
              "maximum": 400,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "angle": {
              "type": "number",
              "minimum": 0,
              "maximum": 360,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "depth": {
              "type": "number",
              "minimum": -100,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "stacking": {
              "enum": [
                "forward",
                "backward"
              ]
            },
            "perspective": {
              "type": "number",
              "minimum": 1000,
              "maximum": 10000,
              "$comment": "slider step 10 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "rotationX": {
              "type": "number",
              "minimum": -180,
              "maximum": 180,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "rotationY": {
              "type": "number",
              "minimum": -180,
              "maximum": 180,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "rotationZ": {
              "type": "number",
              "minimum": -180,
              "maximum": 180,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "direction": {
              "enum": [
                "forward",
                "reverse"
              ]
            },
            "motion": {
              "enum": [
                "continuous",
                "step"
              ]
            },
            "ease": {
              "enum": [
                "none",
                "power2.inOut",
                "power4.inOut",
                "expo.out",
                "back.out",
                "elastic.out",
                "custom"
              ]
            },
            "easeCustom": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 4,
              "maxItems": 4
            },
            "hold": {
              "type": "number",
              "minimum": 0,
              "maximum": 80,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cycles": {
              "type": "number",
              "minimum": 1,
              "maximum": 6,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "duration": {
              "type": "number",
              "minimum": 2,
              "maximum": 60,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "lift": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "tiltX": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "tiltY": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "tiltZ": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "fade": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "sizeGradient": {
              "type": "number",
              "minimum": -100,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "zoom": {
              "type": "number",
              "minimum": 50,
              "maximum": 300,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "offsetX": {
              "type": "number",
              "minimum": -500,
              "maximum": 500,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "offsetY": {
              "type": "number",
              "minimum": -500,
              "maximum": 500,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            }
          }
        }
      },
      "required": [
        "templateId"
      ]
    },
    {
      "title": "stack",
      "properties": {
        "templateId": {
          "const": "stack"
        },
        "config": {
          "type": "object",
          "additionalProperties": false,
          "description": "Omitted fields fall back to schema defaults on import (mergeSceneConfig).",
          "properties": {
            "interaction": {
              "type": "object",
              "additionalProperties": false,
              "description": "Playback interaction. Filled from app defaults when omitted (normalizeInteraction).",
              "properties": {
                "drag": {
                  "type": "boolean"
                },
                "scroll": {
                  "type": "boolean"
                },
                "onRelease": {
                  "enum": [
                    "resume",
                    "stay"
                  ]
                },
                "cursor": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "gravity": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "hover": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "face": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              }
            },
            "cardRatio": {
              "enum": [
                "1:1",
                "4:3",
                "3:4",
                "16:9",
                "9:16"
              ]
            },
            "count": {
              "type": "number",
              "minimum": 3,
              "maximum": 10,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cardSize": {
              "type": "number",
              "minimum": 120,
              "maximum": 1200,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cornerRadius": {
              "type": "number",
              "minimum": 0,
              "maximum": 50,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "stackOffsetX": {
              "type": "number",
              "minimum": -80,
              "maximum": 80,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "stackOffsetY": {
              "type": "number",
              "minimum": -80,
              "maximum": 80,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "stackDepth": {
              "type": "number",
              "minimum": 0,
              "maximum": 200,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "exitDirection": {
              "enum": [
                "right",
                "left",
                "up",
                "down"
              ]
            },
            "exitDistance": {
              "type": "number",
              "minimum": 100,
              "maximum": 800,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "direction": {
              "enum": [
                "forward",
                "reverse"
              ]
            },
            "motion": {
              "enum": [
                "continuous",
                "step"
              ]
            },
            "ease": {
              "enum": [
                "none",
                "power2.inOut",
                "power4.inOut",
                "expo.out",
                "back.out",
                "elastic.out",
                "custom"
              ]
            },
            "easeCustom": {
              "const": [
                0.42,
                0,
                0.58,
                1
              ]
            },
            "hold": {
              "type": "number",
              "minimum": 0,
              "maximum": 80,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cycles": {
              "type": "number",
              "minimum": 1,
              "maximum": 6,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "duration": {
              "type": "number",
              "minimum": 2,
              "maximum": 60,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "jitterAmount": {
              "const": 0
            },
            "jitterSpeed": {
              "const": 2
            },
            "rotationDrift": {
              "type": "number",
              "minimum": 0,
              "maximum": 15,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "tiltX": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "tiltY": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "tiltZ": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "fade": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "scale": {
              "type": "number",
              "minimum": 10,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "zoom": {
              "type": "number",
              "minimum": 50,
              "maximum": 300,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "offsetX": {
              "type": "number",
              "minimum": -500,
              "maximum": 500,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "offsetY": {
              "type": "number",
              "minimum": -500,
              "maximum": 500,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "rotationX": {
              "const": 0,
              "$comment": "locked default — not a panel control"
            },
            "rotationY": {
              "const": 0,
              "$comment": "locked default — not a panel control"
            },
            "rotationZ": {
              "const": 0,
              "$comment": "locked default — not a panel control"
            },
            "perspective": {
              "const": 1000,
              "$comment": "locked default — not a panel control"
            }
          }
        }
      },
      "required": [
        "templateId"
      ]
    },
    {
      "title": "band",
      "properties": {
        "templateId": {
          "const": "band"
        },
        "config": {
          "type": "object",
          "additionalProperties": false,
          "description": "Omitted fields fall back to schema defaults on import (mergeSceneConfig).",
          "properties": {
            "interaction": {
              "type": "object",
              "additionalProperties": false,
              "description": "Playback interaction. Filled from app defaults when omitted (normalizeInteraction).",
              "properties": {
                "drag": {
                  "type": "boolean"
                },
                "scroll": {
                  "type": "boolean"
                },
                "onRelease": {
                  "enum": [
                    "resume",
                    "stay"
                  ]
                },
                "cursor": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "gravity": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "hover": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "face": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              }
            },
            "cardRatio": {
              "enum": [
                "1:1",
                "4:3",
                "3:4",
                "16:9",
                "9:16"
              ]
            },
            "cardSize": {
              "type": "number",
              "minimum": 30,
              "maximum": 500,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cornerRadius": {
              "type": "number",
              "minimum": 0,
              "maximum": 50,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "lens": {
              "type": "number",
              "minimum": -100,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "curve": {
              "type": "number",
              "minimum": -100,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "heightGradient": {
              "type": "number",
              "minimum": -650,
              "maximum": 650,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "axisRotation": {
              "type": "number",
              "minimum": -180,
              "maximum": 180,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cardTilt": {
              "type": "number",
              "minimum": -30,
              "maximum": 30,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "gap": {
              "type": "number",
              "minimum": -30,
              "maximum": 40,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "direction": {
              "enum": [
                "forward",
                "reverse"
              ]
            },
            "motion": {
              "enum": [
                "continuous",
                "step"
              ]
            },
            "ease": {
              "enum": [
                "none",
                "power2.inOut",
                "power4.inOut",
                "expo.out",
                "back.out",
                "elastic.out",
                "custom"
              ]
            },
            "easeCustom": {
              "const": [
                0.42,
                0,
                0.58,
                1
              ]
            },
            "cycles": {
              "type": "number",
              "minimum": 1,
              "maximum": 6,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "duration": {
              "type": "number",
              "minimum": 2,
              "maximum": 60,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "zoom": {
              "type": "number",
              "minimum": 50,
              "maximum": 300,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "offsetX": {
              "type": "number",
              "minimum": -500,
              "maximum": 500,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "offsetY": {
              "type": "number",
              "minimum": -500,
              "maximum": 500,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            }
          }
        }
      },
      "required": [
        "templateId"
      ]
    },
    {
      "title": "coverflow",
      "properties": {
        "templateId": {
          "const": "coverflow"
        },
        "config": {
          "type": "object",
          "additionalProperties": false,
          "description": "Omitted fields fall back to schema defaults on import (mergeSceneConfig).",
          "properties": {
            "interaction": {
              "type": "object",
              "additionalProperties": false,
              "description": "Playback interaction. Filled from app defaults when omitted (normalizeInteraction).",
              "properties": {
                "drag": {
                  "type": "boolean"
                },
                "scroll": {
                  "type": "boolean"
                },
                "onRelease": {
                  "enum": [
                    "resume",
                    "stay"
                  ]
                },
                "cursor": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "gravity": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "hover": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "face": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              }
            },
            "count": {
              "type": "number",
              "minimum": 3,
              "maximum": 30,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cardRatio": {
              "enum": [
                "1:1",
                "4:3",
                "3:4",
                "16:9",
                "9:16"
              ]
            },
            "cardSize": {
              "type": "number",
              "minimum": 60,
              "maximum": 200,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cornerRadius": {
              "type": "number",
              "minimum": 0,
              "maximum": 50,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "gap": {
              "type": "number",
              "minimum": -80,
              "maximum": 40,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "sideRotation": {
              "type": "number",
              "minimum": -85,
              "maximum": 85,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "depthFalloff": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "focusEmphasis": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "direction": {
              "enum": [
                "forward",
                "reverse"
              ]
            },
            "motion": {
              "enum": [
                "continuous",
                "step"
              ]
            },
            "ease": {
              "enum": [
                "none",
                "power2.inOut",
                "power4.inOut",
                "expo.out",
                "back.out",
                "elastic.out",
                "custom"
              ]
            },
            "easeCustom": {
              "const": [
                0.42,
                0,
                0.58,
                1
              ]
            },
            "cycles": {
              "type": "number",
              "minimum": 1,
              "maximum": 6,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "duration": {
              "type": "number",
              "minimum": 2,
              "maximum": 60,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "zoom": {
              "type": "number",
              "minimum": 50,
              "maximum": 300,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "offsetX": {
              "type": "number",
              "minimum": -500,
              "maximum": 500,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "offsetY": {
              "type": "number",
              "minimum": -500,
              "maximum": 500,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "perspective": {
              "type": "number",
              "minimum": 2000,
              "maximum": 10000,
              "$comment": "slider step 10 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            }
          }
        }
      },
      "required": [
        "templateId"
      ]
    },
    {
      "title": "grid",
      "properties": {
        "templateId": {
          "const": "grid"
        },
        "config": {
          "type": "object",
          "additionalProperties": false,
          "description": "Omitted fields fall back to schema defaults on import (mergeSceneConfig).",
          "properties": {
            "interaction": {
              "type": "object",
              "additionalProperties": false,
              "description": "Playback interaction. Filled from app defaults when omitted (normalizeInteraction).",
              "properties": {
                "drag": {
                  "type": "boolean"
                },
                "scroll": {
                  "type": "boolean"
                },
                "onRelease": {
                  "enum": [
                    "resume",
                    "stay"
                  ]
                },
                "cursor": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "gravity": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "hover": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "face": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              }
            },
            "cardRatio": {
              "enum": [
                "1:1",
                "4:3",
                "3:4",
                "16:9",
                "9:16"
              ]
            },
            "columns": {
              "type": "number",
              "minimum": 5,
              "maximum": 20,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "rows": {
              "type": "number",
              "minimum": 5,
              "maximum": 20,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cardSize": {
              "type": "number",
              "minimum": 60,
              "maximum": 400,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cornerRadius": {
              "type": "number",
              "minimum": 0,
              "maximum": 50,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "gap": {
              "type": "number",
              "minimum": -40,
              "maximum": 120,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "waypoints": {
              "type": "array",
              "items": {
                "type": "integer",
                "minimum": 0
              }
            },
            "travelDuration": {
              "type": "number",
              "minimum": 0.2,
              "maximum": 20,
              "$comment": "slider step 0.1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "dwell": {
              "type": "number",
              "minimum": 0,
              "maximum": 10,
              "$comment": "slider step 0.1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "ease": {
              "enum": [
                "none",
                "power2.inOut",
                "power4.inOut",
                "expo.out",
                "back.out",
                "elastic.out",
                "custom"
              ]
            },
            "easeCustom": {
              "const": [
                0.42,
                0,
                0.58,
                1
              ]
            },
            "highlightScale": {
              "type": "number",
              "minimum": 1,
              "maximum": 1.3,
              "$comment": "slider step 0.01 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "dimOthers": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cameraMode": {
              "enum": [
                "route",
                "pan",
                "parallax"
              ]
            },
            "depth": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "density": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "sway": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "scatterSeed": {
              "type": "integer"
            },
            "zoom": {
              "type": "number",
              "minimum": 20,
              "maximum": 600,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "offsetX": {
              "type": "number",
              "minimum": -500,
              "maximum": 500,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "offsetY": {
              "type": "number",
              "minimum": -500,
              "maximum": 500,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            }
          }
        }
      },
      "required": [
        "templateId"
      ]
    },
    {
      "title": "sphere",
      "properties": {
        "templateId": {
          "const": "sphere"
        },
        "config": {
          "type": "object",
          "additionalProperties": false,
          "description": "Omitted fields fall back to schema defaults on import (mergeSceneConfig).",
          "properties": {
            "interaction": {
              "type": "object",
              "additionalProperties": false,
              "description": "Playback interaction. Filled from app defaults when omitted (normalizeInteraction).",
              "properties": {
                "drag": {
                  "type": "boolean"
                },
                "scroll": {
                  "type": "boolean"
                },
                "onRelease": {
                  "enum": [
                    "resume",
                    "stay"
                  ]
                },
                "cursor": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "gravity": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "hover": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    },
                    "face": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "strength": {
                          "type": "number"
                        },
                        "radius": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              }
            },
            "cardRatio": {
              "enum": [
                "1:1",
                "4:3",
                "3:4",
                "16:9",
                "9:16"
              ]
            },
            "count": {
              "type": "number",
              "minimum": 12,
              "maximum": 400,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cardSize": {
              "type": "number",
              "minimum": 24,
              "maximum": 400,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "cornerRadius": {
              "type": "number",
              "minimum": 0,
              "maximum": 50,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "radius": {
              "type": "number",
              "minimum": 150,
              "maximum": 900,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "tilt": {
              "type": "number",
              "minimum": -60,
              "maximum": 60,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "duration": {
              "type": "number",
              "minimum": 4,
              "maximum": 120,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "direction": {
              "enum": [
                "forward",
                "reverse"
              ]
            },
            "farScale": {
              "type": "number",
              "minimum": 10,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "farOpacity": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "highlightScale": {
              "type": "number",
              "minimum": 1,
              "maximum": 3,
              "$comment": "slider step 0.01 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "dimOthers": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "zoom": {
              "type": "number",
              "minimum": 50,
              "maximum": 300,
              "$comment": "slider step 1 (UI granularity — deliberately not multipleOf; see emit-agent-spec.mjs)"
            },
            "rotationX": {
              "const": 0,
              "$comment": "locked default — not a panel control"
            },
            "rotationY": {
              "const": 0,
              "$comment": "locked default — not a panel control"
            },
            "rotationZ": {
              "const": 0,
              "$comment": "locked default — not a panel control"
            },
            "perspective": {
              "const": 1000,
              "$comment": "locked default — not a panel control"
            },
            "offsetX": {
              "const": 0,
              "$comment": "locked default — not a panel control"
            },
            "offsetY": {
              "const": 0,
              "$comment": "locked default — not a panel control"
            }
          }
        }
      },
      "required": [
        "templateId"
      ]
    }
  ]
}
