← PicsartCONTENT HISTORY

Update to Picsart

Snapshot Oct 9, 2026 · 18:02 UTC · version 2.1.0

Collection source: downloaded plugin package.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "description": "Turn static material into a real motion-designed video — a Figma design's LAYERS, or the user's own uploaded assets (photos, logos, screenshots, clips), become a composed, animated ad/reel where elements slide, scroll, type on, parallax, and smart-animate, tuned by eye, then rendered. The user can describe the motion they want, or let the skill analyze the assets and propose a concept. Use when the user wants to animate a design or assets, \"make an ad/reel/video from these images/frames/screens\", add motion to a Figma flow, or bring static material to life. Not for stitching footage the user already edited, and not for generating footage from a pure text idea (that's text-to-video).",
  "included_files": [
    {
      "relative_path": "references/ASSET-COMPOSITION.md",
      "size_in_bytes": 6170
    },
    {
      "relative_path": "references/AUTHORING-FLOW.md",
      "size_in_bytes": 19553
    },
    {
      "relative_path": "references/CHOREOGRAPHY.md",
      "size_in_bytes": 5586
    },
    {
      "relative_path": "references/COMPOSE-FUNDAMENTALS.md",
      "size_in_bytes": 4287
    },
    {
      "relative_path": "references/ELEMENT-MOTION.md",
      "size_in_bytes": 4684
    },
    {
      "relative_path": "references/ENGINE-GOTCHAS.md",
      "size_in_bytes": 7137
    },
    {
      "relative_path": "references/MOTION-PATTERNS.md",
      "size_in_bytes": 7840
    },
    {
      "relative_path": "references/MOTION-PRINCIPLES.md",
      "size_in_bytes": 30692
    },
    {
      "relative_path": "references/MOTION-TROUBLESHOOTING.md",
      "size_in_bytes": 10094
    },
    {
      "relative_path": "references/MP-SCENE-VOCABULARY.md",
      "size_in_bytes": 11658
    },
    {
      "relative_path": "references/SCENE-VALIDATION.md",
      "size_in_bytes": 6034
    },
    {
      "relative_path": "references/STUDYING-MOTION.md",
      "size_in_bytes": 1485
    },
    {
      "relative_path": "references/TOOL-ROUTING.md",
      "size_in_bytes": 19049
    },
    {
      "relative_path": "references/TRANSITIONS.md",
      "size_in_bytes": 17922
    },
    {
      "relative_path": "references/WIDGET-FEEDBACK.md",
      "size_in_bytes": 5269
    }
  ],
  "name": "motion",
  "skill_md_contents": "---\nname: motion\ndescription: Turn static material into a real motion-designed video — a Figma design's LAYERS, or the user's own uploaded assets (photos, logos, screenshots, clips), become a composed, animated ad/reel where elements slide, scroll, type on, parallax, and smart-animate, tuned by eye, then rendered. The user can describe the motion they want, or let the skill analyze the assets and propose a concept. Use when the user wants to animate a design or assets, \"make an ad/reel/video from these images/frames/screens\", add motion to a Figma flow, or bring static material to life. Not for stitching footage the user already edited, and not for generating footage from a pure text idea (that's text-to-video).\n---\n\n# ChatGPT and Codex integration\n\nApply these host conventions throughout this skill and its references.\n\n- Discover the connected Picsart tools and use their actual names and schemas.\n  The `picsart_*` names in the workflow identify tools, not a fixed host namespace.\n  If the connection is missing, explain that Picsart must be connected; continue\n  script and shot planning when possible. Never invent tool results or renders.\n- Read board decisions from the current user message and attached widget context.\n  Use `read_widget_context` only if the host actually exposes that tool. Do not\n  assume ChatGPT has Claude's context reader. Treat a board's initial tool result\n  and unsent widget state as previews, never as user approval. If a submitted\n  decision has no accessible payload, explain briefly and use the text fallback\n  to collect the missing decision; do not guess or repeat charged operations.\n- Use the host's available question interface or one concise conversational\n  question for preset choices.\n- UI rendering and delivery of feedback are the remote MCP server's responsibility.\n  If a board is unavailable, present its relevant options in text and record the\n  user's selection using the same documented feedback fields. Do not claim that\n  a plugin manifest makes Claude-specific widgets compatible with ChatGPT.\n- Save `motion.json` and artifacts in the user's writable project workspace, not\n  the installed plugin directory. If persistent file tools are unavailable,\n  keep a structured project checkpoint in the conversation and provide it for\n  download when the host supports files. Never claim a file was saved without\n  confirmation from a file tool.\n- Honor the user's current instructions and already authorized scope. Preserve\n  quoted spend limits and production locks; do not infer authorization from a\n  preview, a timeout, or a connection being installed. A timed-out charged call\n  needs a status check before considering a retry.\n- This package holds six film skills (`film`, `film-development`, `film-assets`, `film-scenes`, `film-edit`, `film-finishing`) and three motion skills (`motion`, `motion-import`, `motion-design`). Route between them directly.\n- `motion-import` reads a design's layers through the Figma app's tools. If Figma is not connected in this host, use its flat-frame fallback and say so once.\n\n\n### Motion server compatibility\n\nThese host conventions qualify tool and widget instructions below. Discover\nlive tool names and schemas before invoking the pipeline. A ZIP update changes\ninstructions; it does not deploy new server tools.\n\nWhen `picsart_scene_editor` is available, it accepts `scene`, `title` and\n`notes` and emits `scene_editor_feedback` v1. Accept without edits or comments\nreturns `verdict: \"approved\"`; Submit after edits or comments returns\n`verdict: \"needs_changes\"`. Read the returned `document` when `edited` is true:\nframe comments carry `instruction`, and timeline comments carry `text`, `start`\nand `end`. Opening the editor is a preview, never approval. If the tool is\nabsent, use the preview and text-review fallback already described in this skill.\n\nDedicated import/gradient/tracking tools in the new workflow may require a\nnewer MCP deployment. Call them only when exposed. Use a documented live\nrecipe or the source's explicit fallback when it supports the same operation;\notherwise explain the missing capability before proceeding with that step.\nKeep the original editable assets and the current scene intact.\n\n# Motion — a static design becomes a motion-designed ad\n\nThe frames are not the video. They are a **design**, and a design is made of **layers**:\npanels, headlines, buttons, images, lists. Motion design animates those *elements* — a\nlist scrolls, a headline types on, a card slides in with a stagger, a tap-dot pulses,\nthe shared chrome **smart-animates** from one screen to the next, everything moving with\ndepth. Bind a frame as one flat PNG and all of that is impossible — you get a slideshow.\n\nSo the first principle of this pipeline: **the design comes in as layers, and the video\nis a composite of moving elements — never a montage of flat screens.** A real ad is\nbuilt the way the After-Effects reference is built: each element on its own layer, each\nwith its own motion, shared elements carried between frames.\n\nOne economic law runs underneath: **the motion loop is free; the one paid capability is video\ngeneration, and it is always credit-gated.** Every tool the compose/motion/preview loop touches —\nlayer ingest, compose/`patch_scene`, layout queries, `validate`, the panel, and the renders\nthemselves (`picsart_media_export`, `picsart_media_contact_sheet`) — is on the connector's\nzero-credit list (verified against live billing), so for all of that: **never tell the designer an\naction will cost credits, and never hesitate to render for cost reasons — there is no cost.** The\n**sole exception** is **generating video** (`picsart_generate` and the generative tools), which spends\ncredits — and it **never runs without the designer's explicit, informed consent**: show the balance,\nquote the exact cost, get a yes (full gate in *Video generation* below). No other part of this\npipeline charges.\n\n**Ignore the \"charged\"-looking badge on `export` / `contact_sheet`.** Both dispatch a real GPU\nrender and leave a Drive-saved file, so they carry a *behavioral* annotation (`readOnlyHint:\nfalse`, artifact-producing) that a connector UI or permission prompt may surface as \"writes\" /\n\"charged.\" That flag is about **behavior, not price** — the credit cost is still **zero**\n(they're in the server's `FREE_TOOLS`). Do not read that badge as a credit charge or warn the\ndesigner about it. Still author with care: a render costs *time* even when it costs nothing, so\ndecide on the panel's free previews and render the export when the reel is worth rendering.\n\n## When to read which reference (mandatory, lazy)\n\nReferences are not loaded with this skill — **read each one at its step, before doing that\nstep**, not \"if you happen to need it\":\n\n| Before you… | Read |\n|---|---|\n| touch any tool, or wonder which tool answers a question | [`references/TOOL-ROUTING.md`](references/TOOL-ROUTING.md) |\n| compose ANY scene — the rules **both** paths share (highest-level-tool, hosting/CSP, Drive, live text/fonts, placement, treatment, the eye) | [`references/COMPOSE-FUNDAMENTALS.md`](references/COMPOSE-FUNDAMENTALS.md) — read alongside whichever compose path applies; **the tools are the same, only the ingest differs** |\n| import a **Figma** design / compose frames from its layers | [`references/AUTHORING-FLOW.md`](references/AUTHORING-FLOW.md) — the Figma golden path (coords, layer kinds) on top of the fundamentals |\n| compose a scene from **uploaded assets** (photos/logos/screenshots/clips) — grid / stack / collage / montage | [`references/ASSET-COMPOSITION.md`](references/ASSET-COMPOSITION.md) — the non-Figma compose path (upload, probe, layout, fit-to-canvas) |\n| decide *what* motion a change deserves (easing, duration, reduced-motion) | [`references/MOTION-PRINCIPLES.md`](references/MOTION-PRINCIPLES.md) |\n| author a named pattern (scroll, type-on, tap-dot, progressive text) | [`references/MOTION-PATTERNS.md`](references/MOTION-PATTERNS.md) |\n| author a seam between two frames | [`references/TRANSITIONS.md`](references/TRANSITIONS.md) |\n| stagger/sequence multiple elements in one beat | [`references/CHOREOGRAPHY.md`](references/CHOREOGRAPHY.md) |\n| choose ANY motion, or author scene JSON — the full menu of **layer kinds, motion presets, text animations, looks, effects, transitions, masks** (Figma AND from-scratch alike) | [`references/MP-SCENE-VOCABULARY.md`](references/MP-SCENE-VOCABULARY.md) — enumerate it via `get_capabilities`; don't hand-roll what a preset/look/effect already does |\n| act on any widget/panel response | [`references/WIDGET-FEEDBACK.md`](references/WIDGET-FEEDBACK.md) |\n| validate a scene — before showing ANY render, or when \"it validates but looks wrong\" | [`references/SCENE-VALIDATION.md`](references/SCENE-VALIDATION.md) — schema ≠ correct; the eye is the real check, ground truth branches by route |\n| a render/preview looks wrong or a tool errors | [`references/MOTION-TROUBLESHOOTING.md`](references/MOTION-TROUBLESHOOTING.md) |\n| write the first keyframe / nested comp / zoom math / opacity from Figma | [`references/ENGINE-GOTCHAS.md`](references/ENGINE-GOTCHAS.md) — silent-bug rules (local clocks, one track per channel, sRGB→linear opacity, fixed-point zoom) |\n\n## Context discipline — never load the whole design at once\n\nTool results live in the context window for the rest of the session, so what you fetch is what you\npay for — in tokens, in cost, and in the model's attention. **On Claude Desktop / the MCP connector\n(where this plugin runs) there is no file-offload: a big result goes straight into context or the\ncall errors** — a whole-page `get_metadata` on a real storyboard is ~100KB+ and overflows. So fetch\nnarrowly, hold little, and persist facts to state:\n\n- **Frame INDEX once, cheaply.** Read the top-level frame list — ids, names, left→right order,\n  dimensions — from the page/canvas node **without drilling into each frame's tree**. That's all you\n  need to know what exists and the running order.\n- **Full layer tree per PAIR, then release it.** Pull a frame's full nested tree only when you reach\n  its pair, and keep at most the **current pair (A + B)** in working context — don't accumulate frame\n  7's tree while authoring 2→3. **The payoff of that narrow breadth is affordable DEPTH:** because\n  you're holding only one or two frames, you can retrieve *everything* about them — every sub-layer,\n  exact coords, ink bounds via `use_figma`, styles — which is exactly the completeness correct\n  composition needs and which you could never afford across the whole storyboard at once. Narrow\n  breadth buys full depth where it matters.\n- **Scan the sequence with COMPACT tools, not full metadata.** Scroll-run / matched-element / zoom\n  detection rides on `picsart_media_diff_layouts` / `query_layout`, which return small geometry\n  deltas — peek ahead only as far as a run actually extends, never full-read the whole storyboard.\n- **Persist resolved facts to `motion.json` / the scene doc, not the conversation.** Once a frame's\n  coords, matchKeys, or the frame index are resolved, they live in state — so the next pair doesn't\n  re-hold them in context, and a compacted or fresh session re-reads the file instead of re-fetching\n  Figma. State is the memory; context is scratch.\n\n## Flat vs. layered — the difference that is the whole product\n\n| Flat-frame montage (the anti-goal) | Layered motion design (this skill) |\n|---|---|\n| each frame is one sealed PNG | each frame is its **layers**, each movable |\n| motion = a transition at the seam | motion = every **element** animates (slide, scroll, type-on, parallax, tap) |\n| screens **cross-dissolve** | shared elements **smart-animate** A→B (matched motion) |\n| reads as a slideshow | reads as an ad |\n\nFlat montage is the **fallback only** — used when a design's layers genuinely cannot be\nhad (a rasterized image, no Figma access). When you fall back to it, say so plainly:\n*\"without the design's layers this becomes a slideshow, not motion design.\"* Never\nchoose it while layers are available.\n\n## Scope — phased\n\n- **Phase 1 (now): motion-design static material into an ad/reel.** A Figma design's layers — or\n  the user's own uploaded assets — → a composed, animated MP Scene → tuned by eye → rendered. All\n  of what follows.\n- **Also available: generate footage when the design needs it.** When a beat calls for real\n  generated video (a video card/element, or the designer asks to generate a clip with a model of\n  their choice), that's supported — but it spends credits, so it runs behind the cost-consent gate\n  (see *Video generation*). It's a capability within the flow, not a separate phase.\n- **Phase 2 (later): generate a *new* video from a given one.** A video-to-video pass,\n  once the server's v2v path is wired. Don't build it yet; keep the hook\n  (`motion.json.source` can name a given video, not only a design).\n\n## 0. Triage — route before anything\n\nThe plugin animates **static material**, and material arrives several ways. Route first — the route\nsets the **ground truth** you'll later validate the rendered result against, by eye:\n\n| User brings | Route | Ground truth |\n|---|---|---|\n| A **Figma design / flow** with layers | **this skill**, Figma ingest (Stage 1) — run the opening tool sequence in [`references/TOOL-ROUTING.md`](references/TOOL-ROUTING.md) | **match the design** |\n| **Their own assets** (photos, logos, screenshots, clips) **+ a described motion** | **this skill**, asset ingest — `picsart_media_upload` the files, `probe_media` them, then compose and author the motion **to the brief** | **match the brief** |\n| **Their own assets, but NO motion described** | **this skill**, **propose mode** — analyze the assets (`probe_media` + **view them**), then **offer 2–3 concrete motion concepts** for the user to pick; author the chosen one | **the concept they picked** |\n| An existing **MP Scene** to keep editing | **this skill**, resume — open the editor on it and edit | the current scene |\n| **Flat exported images of a design** whose layers can't be had | **this skill**, flat-fallback — warn it will be a slideshow, and offer layered if they can share the Figma file | the flat frames |\n| Footage already edited, to stitch | not this — that is a plain montage | — |\n| A clip from a **pure text idea** (no assets) | not this — that is text-to-video generation | — |\n\nThe dividing line is **static material in, motion authored** — the material may be a Figma design\n*or* the user's own assets. Note the difference between a **photo/asset reel** (the images *are* the\ncontent — a first-class raster route, not a degradation) and **flat PNGs of a design** (layers were\nlost — the announced slideshow fallback); don't treat uploaded photos as a failed layered import.\n\n**Two postures — do not blur them.** With a Figma design or a stated brief you are in a **fidelity**\nposture: build exactly that, and *propose* anything extra separately — **never invent** (the whole\n\"change only what was asked\" discipline). With assets and no brief you are in a **proposal** posture:\ninventing a concept is the *job* — but you still **offer 2–3 options and get a pick before authoring**,\nnever run off and build one unasked. Both postures meet at one rule: **a concrete plan is agreed\nbefore motion is authored** — a matching plan in fidelity mode, a chosen concept in proposal mode.\n\n**If the page holds SEVERAL distinct sequences/storyboards, list them and ask which to animate\nfirst.** A Figma page routinely carries multiple reels side by side; don't silently start on the first\ncluster. Group the frames into their sequences (by spacing/section/naming) from the cheap frame index,\nname what you found, and let the designer pick the running order before composing anything\n(`references/AUTHORING-FLOW.md` §1).\n\n**Never start from — or hand back — an animated video pulled from Drive.** `picsart_media_export`\nauto-saves its render to Drive, but that video is an **output, not an input**: do not list Drive\nfor a prior render and reuse it as the result or the source. **Always author the motion from\nscratch**, from the design's layers/frames. The only valid inputs are the Figma design (or flat\nframes) and an in-progress MP Scene — never a rendered video. A Drive export is read-only\nhistory; open the MP Scene and re-author, don't re-serve the old video.\n**The one exception: the designer explicitly asks for it.** If they name a previously created\nDrive video and ask to use it (\"take the video we rendered yesterday\", \"use the export from\nDrive\"), then using it is honoring their instruction, not a shortcut — fetch that video and do\nwhat they asked with it. The rule bans *you* reaching for a prior render on your own initiative;\nit never overrides an explicit user request.\n\n## Propose mode — assets in, no brief\n\nWhen the user brings **assets but doesn't say what motion they want**, you propose it. This is the one\nplace where inventing is the job — but it stays disciplined: analyze, offer a small menu, build the pick.\n\n1. **Analyze the assets — by looking.** `picsart_media_upload` the files, `picsart_media_probe_media`\n   for dims / fps / duration, and **view each asset with your own vision** (the same eye that validates\n   output — [`references/SCENE-VALIDATION.md`](references/SCENE-VALIDATION.md)). You cannot propose\n   sensible motion for material you have not seen.\n2. **Classify what you have.** Photos? a logo / brand mark? app screenshots? a product shot? a video\n   clip? text? The class drives the concept: photos → a promo/reel (recipe `photo-promo`); screens → a\n   UI walkthrough (`ui-motion`); a logo → a brand sting; mixed → a title + montage.\n3. **Offer 2–3 concrete concepts — not one, and never a blank \"how do you want it?\"** Each concept is a\n   short, specific pitch the user can choose between, differing in *approach* (e.g. calm/premium vs\n   punchy/ad vs playful), and each naming: the **format** (ratio/fps), the **layout** (how the assets\n   are arranged — a grid, a stack, a collage, a montage/sequence, or a single focus; assets need not be\n   one-per-screen), the **key moves** (its 2–3 signature animations), and the **rough pacing/length**.\n   Use `motion-intent` to derive the moves from the intent each concept expresses, and `apply_scene_template`\n   (montage/collage/title families) as a starting layout where it fits. Keep the concepts genuinely\n   distinct — a real creative-direction menu, not three shades of one idea.\n4. **User picks (or steers).** They choose one, or blend (\"option 2 but calmer\") — fold that into a\n   single agreed concept. That concept is now the **ground truth** you validate the render against\n   (`SCENE-VALIDATION.md` rung 4, chosen-concept branch).\n5. **Author the pick** — compose the assets into a scene (a scene template or `patch_scene`), author\n   the concept's moves (`apply_motion_preset` / `apply_text_animation` / keyframes), then validate by\n   eye and preview for approval, exactly as the fidelity path does.\n\n**Deciding the layout — like a designer, not a checklist.** Don't tally asset properties to pick\n\"show all at once vs give each focus.\" Decide it the way designers actually do:\n\n- **Message and hierarchy first.** Ask what the piece must *say* — \"we have range/lots\" makes the\n  **set** the hero (grid / collage / stack); \"this one is the star\" makes a **single** asset the hero\n  (focus). Then rank primary → secondary → rest; it's rarely all-equal (even a grid usually has one\n  bigger or first tile).\n- **Motion usually dissolves the choice.** You can show many **and** guide attention one at a time by\n  **revealing in sequence** (a staggered grid/collage), or by **establishing then pushing in** (the\n  whole set lands, then the camera moves to the hero). So \"together vs focus\" is most often a *pacing*\n  choice on the same layout, not a hard fork.\n- **Budget by time.** How many beats fit the length — nine items in 6s → a grid that reveals; five in\n  20s → walk through them.\n- **Then let the pick decide.** Spread the 2–3 concepts across that real axis (e.g. all-at-once grid\n  vs spotlight-each vs establish→detail) and let the user choose — the decision is settled by reacting\n  to concrete options, exactly as a designer roughs out directions rather than deciding by rule.\n\n**Read the theme / occasion, and let it drive the concept.** When the assets or brief carry a theme\nor occasion — Christmas, Valentine's, back-to-school, a sale, a brand's own palette/vibe — reflect it:\na themed **colour palette**, and where it fits, a few **themed accent elements** (an authored\nsnowflake/ornament/heart shape, a seasonal texture) and a matching motion register. Read the theme by\n**looking** at the assets (the eye) and from what the user said — don't assume one. Put it in the\n2–3 concepts and let the user pick, and keep it to a **few coherent accents** (MOTION-PRINCIPLES §7),\nnever a snow-globe of decorations.\n\n> **This themed-invention licence is PROPOSAL MODE ONLY.** With a Figma design or a stated brief you\n> are in fidelity posture: the theme's colours and shapes are **already the designer's** — respect the\n> design's palette and **do not invent themed decorations onto it** (that is exactly the trust-breaking\n> invention the \"animate existing layers only\" rule forbids — see `ENGINE-GOTCHAS.md`). Offer a themed\n> addition as a separate proposal; never sprinkle it in.\n\n**Do not skip the menu and build one concept unasked** — that is the proposal-mode form of running\nahead. Propose → pick → author, every time. Once a concept is picked you are back in **fidelity\nposture to that concept**: build what was chosen, and propose any extras separately.\n\n## Working mode for uploaded assets — part by part, or the whole motion at once\n\nThe pair-by-pair rhythm (Stage 3 below) is for **frame sequences** — a Figma storyboard gives natural\nA→B pairs to work through. **Uploaded assets have no frames**, so there is nothing to pair. Before\nauthoring, **offer the user how they want to work**:\n\n- **Part by part** — build and approve the motion in pieces, beat by beat. A \"part\" is a **beat, not\n  one asset**: a single beat can move several assets together — a grid of photos revealing, a stack\n  fanning out, a row sliding in, a title typing over a collage. Safer for a longer or multi-beat piece\n  — the user steers as it grows, and one wrong call doesn't compound.\n- **The whole motion-added version at once** — author the entire motion, render it, and show the full\n  result, then refine from there. Faster for a short or simple piece (a single logo sting, a 3-photo\n  reel), where seeing the whole thing is the quickest way to react.\n\nOffer both, recommend by size (part-by-part for multi-beat/longer, whole for short/simple), and let\nthe user pick — don't assume. Either way the **eye-check + preview-approve gate still applies**\n([`references/SCENE-VALIDATION.md`](references/SCENE-VALIDATION.md)): part-by-part approves each piece\nas it's added; whole-at-once approves the full render, then iterates.\n\n## Tool names — read this first\n\nTwo families on this plugin's `picsart-gen-ai` connector, and they are wired differently:\n\n- **Scene tools — `picsart_media_*`.** Import, compose, validate, patch, translate,\n  export, contact-sheet: the media/scene tools, surfaced under the `picsart_media_` prefix.\n  Server recipes and older docs name `mp_export`, `mp_patch_scene`, etc.; translate `mp_<x>` →\n  `picsart_media_<x>`.\n- **Panel tools — `picsart_<widget>`, gen-ai-native and new.** The widget-opening tools\n  are **not** media-tools proxies — they are registered directly in the gen-ai server,\n  each bound to a `ui://` widget resource. This plugin's is **`picsart_scene_editor`** (the\n  scene editor — the pair-review surface: it **plays** the MP Scene document in the browser, free,\n  and returns the designer's verdict + edit-request comments; **pass it a `scene` document, never\n  video/media**). It is a *review* surface — motion is authored by you through\n  `picsart_media_patch_scene`, not picked per-layer inside the panel. `picsart_scene_editor`\n  **replaces the old `picsart_scene_inspector`** (and its `mp_inspect_scene` / `mp_suggest_motion`\n  drafts) — do **not** read those as tool names; they no longer exist. (This workflow does not require the\n  `picsart_motion_setup` format console, which production may expose — the video format\n  (ratio/fps/energy) is decided directly; see `motion-import` *Set the format*.) `picsart_scene_editor` is the complete panel\n  surface. Full contract: `docs/widget-specs/mp-scene-editor.md`.\n\n**Show the motion in the scene editor — don't re-export a video each time.** After authoring\na pair, open `picsart_scene_editor` **on the whole scene built so far** (title it for the current\npair, e.g. \"f3→f4\", so the designer knows where to look), so they watch the pair play **in context**\nand can scrub straight to it — never a 2-frame sub-scene. That panel is the viewing surface, free,\nand cheaper/faster than exporting\njust to see a result. It **renders no file** — do not look for a `videoUrl` or save anything to\nDrive from its reply. Reserve `picsart_media_export` for the final deliverable and for the error\nfallback below. Do **not**\nbatch — never render a contact sheet of every frame as the main flow (that is what produces \"all\nframes at once\").\n\n**If a `picsart_scene_editor` call errors — a 503, a transport failure, or any\nexception — do not leave the designer with nothing.** Export the **whole scene** (the full\nreel end to end, **not** just the current pair's A→B window) with `picsart_media_export` and\n**show the result video** so they can still see the motion play, then continue the\npair-by-pair flow once the panel recovers. Exporting a preview render is free\n(`picsart_media_export` is 0-credit), so this costs nothing. The panel itself already falls\nback to a video on a render error; this is the same move at the tool level. The\ncontact-sheet + the host question interface path is the **last resort** — reach for it only if the\nexport also fails, and never stall because of a panel error.\n\n**What you SHOW is always the whole reel — even while authoring one pair.** Pair scope is an\n*authoring* focus (it makes it easy to work one seam at a time), but every time the designer sees\nthe motion — the editor preview of a pair, an error-fallback video, any \"let me see it\" export —\nshow the **whole scene built so far**, positioned at the current pair, **never just that pair's\nwindow** (e.g. not only the 3→4 transition in isolation). The editor plays a timeline, so opening it\non the whole scene lets the designer watch 3→4 *in context* and scrub to it; a 2-frame sub-scene\nthrows that context away. \"Whole scene so far\" = every composed frame up to now (later, uncomposed\nframes simply aren't there yet). The designer navigates pair by pair; what they watch is the reel.\n\n**Ground your facts in tools; own your judgment; author through tools.** The real work of\nthis plugin lives in the tools — but the *judgment* about what to do is yours. Three different\nactivities, three different rules:\n\n- **Facts come from tools — never invent them.** The design's layers, geometry, stacking\n  order, fonts, layout; what changed between two frames; the valid presets/easings; whether a\n  scene validates or rendered — these are *ground truth*. **Do not eyeball, describe, or infer\n  the composition from the image and act on that guess** — your visual read is not a substitute\n  and will be wrong about coordinates, layer boundaries, and fonts. Read each through the tool\n  that owns it: `picsart_media_query_layout`, `picsart_media_diff_layouts` (what changed between\n  two frames — opacity-blind, so check fades yourself), `picsart_media_get_capabilities`,\n  `picsart_media_probe_media`, `picsart_media_list_fonts`, `picsart_media_validate_scene`.\n- **Judgment is yours — apply it on the facts, with the designer.** What moves, which preset,\n  what timing, which element is focal, essential vs decorative, when to override a default — this\n  is the work you are here to do; no tool decides it for you. Drive it from the tool-resolved\n  layers + `get_capabilities` presets and judge it on rendered previews (the scene editor, or\n  an exported video). Deciding *what* is your job — **but never\n  stop at describing it in prose**: author it and show the render.\n- **Author through tools — never hand-write the artifact.** `picsart_media_patch_scene`,\n  `picsart_media_apply_motion_preset`, `picsart_media_apply_text_animation`,\n  `picsart_media_apply_scene_template`, `picsart_media_apply_effect`. **Never hand-write scene\n  JSON, or type a coordinate/value you didn't get from a tool** — mint every edit through the tool.\n- **Show / preview**: `picsart_scene_editor` (view the motion moving) or `picsart_media_export` (a rendered video). Never describe motion in prose.\n- **Validate / render**: `picsart_media_validate_scene`, `picsart_media_export`. Run `picsart_media_layout_lint` too whenever it's in your tool list — a cheap automatic overlap/z-order pass over the whole timeline, done **before** the `contact_sheet` eye check (it's opacity-blind, so the eye check follows it, never replaces it).\n\nThe failure to avoid isn't *thinking* — it's **fabricating a fact you could have looked up, or\nhand-building an artifact a tool should mint.** Think all you want about *what* the motion should\nbe; get every *fact* it rests on from a tool, and *author* it through one.\n\n**Without the panel (the `picsart_scene_editor` widget not connected — a valid,\nlower-fidelity setup) you STILL must use the media tools**: read via\n`picsart_media_query_layout`, author via `picsart_media_patch_scene` /\n`picsart_media_apply_motion_preset`, show via `picsart_media_export` /\n`picsart_media_contact_sheet`. The panels' absence is a degraded *surface* — it is **not**\npermission to invent facts (coordinates, layers, fonts) or hand-author the motion.\n\nIf a tool you genuinely need is unavailable (not connected, or it errors), **say so and stop**\n— never silently fall back to doing the work yourself and proceeding as if you had the real data.\n\n**Do the least work yourself — reach for the highest-level tool that does the job.** You are an \norchestrator; the mp-scene server is the engine. Before assembling anything by hand out of\nmany low-level ops, check whether the server already does it in one call: a **scene template**\n(`apply_scene_template` — montage/collage/title families) before hand-building a composition; a\n**motion preset** (`apply_motion_preset`) or **text animation** (`apply_text_animation`) before\nhand-keyframing; `quickstart` / the **recipes** before inventing a step sequence; `patch_scene`\nfor *edits*, not for constructing whole scenes op by op. The chat's judgment goes into WHAT to\ndo (which layer, which motion, what timing — with the designer); the server does the HOW.\n\n## The edit loop — every designer instruction is a tool round-trip\n\nThe designer's job is to **point and say**; yours is to **run the tools**. Every instruction —\n*\"speed this up\", \"remove the animation from that\", \"update the easing\", \"this button has an\nextra outline\", \"make the CTA pop later\"* — is handled the same way, and **never** by describing\nthe change or acting on what the image looks like:\n\n1. **Locate** — resolve the target through `picsart_media_query_layout` (`intrinsics:true`): the\n   exact layer id, its box, its active window, its authored content. If the designer clicked a\n   layer in the panel, the selection already carries the id + time — still confirm the *current*\n   state through the tool, don't assume it.\n2. **Edit** — apply the change with the right tool (full map in\n   [`references/TOOL-ROUTING.md`](references/TOOL-ROUTING.md)): almost always\n   `picsart_media_patch_scene` (`set` to change a value, `remove` to drop one), id-anchored;\n   `apply_motion_preset` / `apply_text_animation` when **adding** motion. Values (easings, presets)\n   come from `get_capabilities`, paths from `get_scene_schema` — **never invented**.\n3. **Validate** — `patch_scene` re-validates inside itself; a `severity:error` fails the batch with\n   diagnostics. Read them, fix, retry — never proceed on an invalid scene.\n4. **Show** — re-open the panel on the pair (or `export` the whole reel) so the designer **sees**\n   the result, not a description. The edit minted a **new `sceneRef`** — always work from the latest.\n5. **Repeat** — one instruction at a time, pair by pair, advancing only on the designer's approval.\n\nThe whole product is this loop: the designer speaks small, specific edits; you turn each into a\ntool call and show the result. If you ever catch yourself reasoning about coordinates, easings, or\nlayers **from the picture** instead of the tools, stop — that is the failure mode.\n\n## Lean on the server's recipes — don't duplicate them\n\nThe scene/media tools reach this plugin **through the MCP connector**: they are the\n`picsart_media_*` tools, and their authoritative step sequences are the server's **recipes**. Ask the\nserver rather than hardcoding:\n\n- `picsart_media_quickstart` — the on-ramp for common jobs; it also surfaces the relevant\n  recipe steps.\n- `picsart_media_list_recipes` / `picsart_media_get_recipe` — the recipe catalogue and a named\n  recipe's steps. **When present, fetch the official recipes before hand-authoring:**\n  **`mp-figma-storyboard-to-scene`** (the canonical Figma→scene flow), **`mp-motion-intent`** /\n  **`mp-motion-patterns`** / **`mp-motion-mechanics`** (craft), **`mp-transition-authoring`**,\n  **`mp-scene-format-architecture`** (the format). **Availability varies by connector** — these\n  are commonly **not mirrored today**; if the two tools aren't in your tool list, that's normal,\n  not an error: fall back to this plugin's references + `picsart_media_quickstart` and proceed.\n\n**This skill orchestrates; the recipe supplies the steps.** When a recipe and this skill\ndisagree on a *step*, the recipe wins; the gates, the motion vocabulary, and the panel\nturns this skill adds are its own job.\n\n## The pipeline — 5 stages, gates between them\n\n| Stage | Does | Skill | Gate to pass |\n|---|---|---|---|\n| 1 · Import | Figma design → each frame's **layer tree** (elements + transforms + assets); matched elements tagged; format set | `motion-import` | every animatable layer has an asset/content + transform; matched elements tagged; format set |\n| 2 · Compose | rebuild each frame as a **layered MP Scene** (elements placed by transform), verified to match the design | this skill | each composed frame `validate`s clean **and** renders identical to its design |\n| 3 · Motion (interactive) | author real motion **one pair at a time** — per-element animation + matched-element smart-animate for frames A→B | `motion-design` | **every pair** approved on a moving preview, not a still |\n| 4 · Preview | filmstrip across each pair and the whole cut | this skill | motion reviewed on real frames before the deliverable is rendered |\n| 5 · Deliver | from the MP Scene: `export → mp4` for the final video (free); the MP Scene itself stays the editable source | this skill | mp4 exported and verified once |\n\n**Gates are the product.** The expensive mistake is exporting motion the designer never\nwatched — a still hides everything. A gate passes only on evidence (a tool result, a\nrecorded waiver, a user's yes) or a conscious override. Before naming the next stage,\nprint the gate check with ✓/✗ and the evidence.\n\n**Export and Drive-save are user-initiated — never automatic.** Do **not** call\n`picsart_media_export` on your own to \"show\" a result (the editor already plays it on\nfree frames), and do **not** upload or save the output to Picsart Drive (`picsart_drive`,\n`driveSave`) as an automatic step. Both the final render *and* saving to Drive\nhappen only when the designer explicitly asks for them (or clicks the panel's own\ncontrol) — offer them, don't perform them. Producing a deliverable and stashing it in the\nuser's Drive without being asked is exactly the silent, unwanted side effect this gate\nexists to prevent.\n\n## Stage 2 — compose the layers into live frames\n\n> **HARD GATE — READ BEFORE COMPOSING. A frame is rebuilt from its LAYERS, never from a screenshot\n> of the frame.** The single most common failure is taking one `get_screenshot` of the whole frame\n> (or of a group) and dropping it in as one image. **That is wrong, always.** A `get_screenshot` of a\n> frame or a multi-element group is **never** a scene layer. Each design node becomes its **own**\n> scene layer, authored as its native kind (text→`text`, rects/cards/borders/circles/masks→`shape`,\n> icons/logos→vector, only true photos/video→a raster asset). An icon/logo's SVG paths become a\n> live shape via `picsart_media_import_svg_path`, not an uploaded SVG. A node's Figma **paint** (fill,\n> box-shadow, gradient) comes over natively via `picsart_media_import_figma_paint`, not by\n> baking the node. Only what it reports in `skipped` may stay baked, and you disclose it.\n>\n> **Definition of done (check it):** a composed frame's layer count roughly matches the design\n> frame's node count. A frame that has one `media` layer covering the whole thing, or a handful of\n> big raster slabs, is a **failed** composition — throw it out and rebuild from the per-node tree.\n> If you don't have the per-node kinds/coords yet, that's the signal to **fetch this frame's full\n> layer tree** (you're only holding one or two frames, so you can afford all of it — see *Context\n> discipline*), **not** to fall back to a screenshot.\n>\n> If you catch yourself reaching for a whole-frame or whole-group screenshot \"to save time\" or \"to\n> fix CSP,\" stop — that is the exact shortcut that produces a slideshow instead of motion design.\n\nDo **not** bind frames to `mpscene://montage` — that treats a frame as one flat clip and\nthrows away every element. Instead **rebuild each frame as a composition of scene\nlayers**: one scene layer per imported design layer, positioned by its `transform`\n(x, y, w, h, rotation, opacity, z-order). Author this with `picsart_media_patch_scene`\n(or a compose recipe if the server exposes one), never the montage template.\n\n**Layered means LIVE, not rasterized — a hard requirement.** Text is always a live `text`\nlayer (font by file URL), never a baked PNG; solid/gradient rectangles, cards, borders, circles\nand masks are `color`/shape layers; icons and logos stay **vectors** where supported; a raster\nasset is reserved for **true imagery** (photos, videos, textures, or an effect the engine can't\nreproduce — disclosed to the designer when baked in). Never flatten a group whose children carry\ntext or animate independently into one screenshot: a flattened slab can only fade/scale as a whole,\nwhich forfeits every per-element move Stage 3 exists for. The full kind-triage lives in\n`references/AUTHORING-FLOW.md` §5.\n\n- **\"Upload every asset\" means EXTERNAL MEDIA ONLY — it does NOT mean \"turn every visual element\n  into an uploaded image.\"** Drive/`upload` applies only to external media files (photos, videos,\n  textures, unavoidable raster). **Native scene shapes, vectors, and live text must remain authored\n  elements and must never be converted to raster images merely for upload or CSP compatibility.**\n  PNG export is a **fallback** for genuine raster content or a truly unsupported vector — not the\n  default, and never a way to make a card/component/screen \"uploadable.\" (This is the exact trap that\n  produces a rebuilt-from-screenshots frame that diverges from the design.)\n- **A CSP/blob failure is fixed by changing ONLY the affected asset's URL or format — never by\n  flattening.** Re-host that one image to a Picsart URL (or convert an unsupported vector to a raster\n  *for that element alone*); do **not** rasterize the card, component, or whole screen it sits in to\n  make the error go away. Flattening to dodge CSP destroys the layering and is a wrong ad.\n- **Audit every node's kind BEFORE composing** — shape / vector / text / photo / video — and author\n  each as its native kind (above). This layer-type pass is a required step, not optional; skipping it\n  is how shapes and text get wrongly baked.\n- **If Figma metadata shows no text but the reference visibly has text, STOP and verify the node/\n  frame before authoring — do not proceed on the exported assets.** A `get_metadata` call can land on\n  the wrong node (a rectangle, a collapsed instance) or not expand the frame's nested tree, returning\n  no text for a frame that clearly contains it. That is a signal to re-inspect the full nested\n  structure / correct frame node (`get_metadata` on the right frame, `use_figma` for the tree), never\n  to reconstruct from the visible screenshots and omit the text. Missing text in the read = read\n  again, don't guess.\n\n- **A composed frame must render identical to the static design — proven by comparison, not\n  assumed.** Render one `contact_sheet` frame at the frame's hold start and put it **side by side\n  with the source** (`get_screenshot` of the Figma frame). Look specifically for **text that\n  clipped, wrapped, or shifted** versus the design (the alignment/box traps above), layers that\n  landed off-position, and wrong z-order. Skipping this compare is how a mispositioned or\n  wrapped headline ships — it is a wrong ad, cheaply caught now.\n- **Compose one frame, PREVIEW it, and wait for the designer before the next — never\n  batch-compose the storyboard.** After each frame is composed, actually **render it and show it**\n  (the `contact_sheet`/editor still beside the source) and let the designer confirm it before\n  you compose the next frame. The preview is a **hard precondition to advancing, not a formality\n  you narrate past**: proceeding on your own \"it should match\" judgment — *without having rendered\n  and shown the frame* — is the skipped-preview failure, the same one the pair rhythm below exists\n  to prevent. If you catch yourself *describing* a frame instead of *showing* it, stop and render\n  it. The designer should never have to ask you to preview — and the reverse holds too:\n  **never ask the designer for a go-ahead to render.** A free render (`validate_scene`,\n  `contact_sheet`, the editor panel) needs no permission — run it, show the result, and let\n  the designer react to what they see. \"Approve the render when it pops up\" / \"say go and I'll\n  run it\" is a dead turn where the result should already be on screen.\n- **You do NOT have to compose the whole storyboard before any motion — compose and motion\n  INTERLEAVE per pair.** The stage table lists Compose (2) before Motion (3), but that is the order\n  *for a given frame*, not a barrier across the whole reel. The rhythm: **compose frame 1 → animate\n  frame 1's opening beat → then, for each pair, compose the next frame only when its pair comes up, and\n  motion it.** Composing every frame first and only then starting motion both **delays the motion the\n  designer is waiting to see** and contradicts *\"open with frame 1's entrance before pair 1→2\"* (Stage\n  3). Rebuild just-in-time, pair by pair.\n- **Matched elements stay one continuous layer across the frames they appear in**, keyed\n  by `matchKey` from import — that is what lets Stage 3 smart-animate them rather than\n  cross-dissolve. A header present in frames 1–4 is *one* layer with four transform\n  states, not four separate headers.\n- **Duration is derived by default; an explicit target is opt-in and soft.** By default\n  (`duration.mode: \"derived\"` — the console's checked box) the total is `$sum` of the\n  holds, each grown to fit its own motion (a 1.2s type-on needs a hold ≥ 1.2s), so it\n  *grows as motion is added*. A designer may instead set `duration.mode: \"target\"` with a\n  length — a **soft budget**: holds scale toward it where there is slack, but never below\n  each hold's motion-minimum, so a too-short target **lengthens** the video rather than\n  clipping an animation. Never silently clip motion to hit a number; a target the motion\n  overflows is shown, not enforced.\n\n- **Every asset URL in the scene must be Picsart-hosted (`pastatic`/`gcdn`) — never a `figma.com`,\n  `data:`, or `blob:` URL.** A Figma `get_screenshot` returns a `figma.com/api/mcp/asset/…` URL and\n  browsers hand you `blob:` object URLs; **do not author either into the scene.** First lift every\n  image to a durable Picsart URL with `picsart_media_upload` (or `picsart_drive`) and author *that*.\n  The catch: server-side `export`/`contact_sheet` **can** fetch `figma.com`, so they render fine and\n  hide the problem — but the browser preview's Content-Security-Policy blocks these hosts\n  (`csp: blocked connect-src … figma.com`, `csp: blocked img-src … blob:`), so the layer goes blank\n  or the engine fails. **Validation and a clean contact-sheet are NOT proof it loads in the preview.**\n  Fix a blocked scene by re-uploading the offending assets and `patch_scene`-ing their `uri` to the\n  Picsart URLs. (Full detail: `references/AUTHORING-FLOW.md` §5.)\n- **A text layer's font is always the resolved `.ttf`/`.otf` file URL from `picsart_media_list_fonts`\n  (or an `assets[]` `{ type: \"font\", id, uri }` entry carrying it) — never a family name (\"Inter\")\n  and never a bare catalog key (\"gilroy-semibold\").** A key *passes* `validate_scene` but the\n  editor/exporter engine **fails to boot** on it (no catalog wired → *\"cannot read fontLocation…\n  font is a NAME\"* → the still/video fallback): **validation ≠ boot for fonts.** Match the design's\n  typeface to a catalog entry, then author that entry's **URL**, which hands the engine a location.\n- **A text layer carries the design's real horizontal alignment and box behaviour — never a\n  guessed one.** Author the `alignment` Figma actually set (`textAlignHorizontal`), because the\n  anchor follows it: a **left**-aligned layer's `position.x` is the box's **left edge**, a\n  **center**-aligned layer's is the box **center**. Defaulting a headline to `center` (and so to a\n  center-of-box x) is the classic tell — it drags left-aligned copy off toward the middle/right.\n  And if Figma's text sits in a **fixed-width box that overflows the frame**, it **clips** there;\n  a scene text layer with only a point anchor + font size will instead **soft-wrap** the overlong\n  line at the space. Carry the box width (so it clips like the design) or drop the font size so the\n  single line fits — never let it silently wrap to two lines.\n- **A missing font is surfaced, never silently swapped.** For every text layer, check its\n  typeface against `picsart_media_list_fonts` (the platform's available fonts) — **or\n  `picsart_media_discover_fonts`** when `list_fonts` isn't on your connector, or to live-search a\n  font not in the bundled snapshot (it returns a `.ttf`/`.otf` URL you author directly). If the\n  design's font is **not available from the media tools** — neither tool can find it — do\n  **not** quietly substitute a fallback and move on. **Tell the designer plainly**: name\n  the missing font, name the fallback you'd otherwise use, and say the text will render in\n  that fallback (different metrics → the layout can shift). Let them decide — pick an\n  available font, supply/upload the font, or accept the fallback knowingly. A silently\n  swapped font is a wrong ad that reads as \"close enough\" until someone notices.\n\nThen `picsart_media_validate_scene` — free, catches schema errors before any render is\nspent on a broken scene.\n\n## Stage 3 — the real motion design (the whole point)\n\nThis is where a slideshow becomes an ad. You **author** the motion through\n`picsart_media_patch_scene` / the apply tools, then **show** it in `picsart_scene_editor` (the\ngen-ai widget tool, **not** a `picsart_media_*` proxy): it plays the pair's MP Scene document in\nthe browser, free, and the designer approves it or sends it back with edit-request comments (pins\nand marked stretches, each with its own instruction). Full contract in\n`docs/widget-specs/mp-scene-editor.md` and `references/WIDGET-FEEDBACK.md`; the authoring\ncraft is in the `motion-design` skill.\n\n**The motion vocabulary** — what \"real motion design\" is made of, all per-element:\n\n- **Entrances / exits** — fade, slide (from an edge), scale/pop, blur-in, mask-reveal.\n- **Continuous** — list **scroll**, **parallax** (layers drift by depth), text **type-on**,\n  counters, marquees.\n- **Interaction simulation** — the **tap-dot pulse** and cursor moves that make a UI look\n  driven (the magenta taps in the reference).\n- **Matched-element smart-animate** — a shared layer **morphs its transform/opacity/content\n  from frame A to frame B**, so the interface *moves* between screens instead of dissolving.\n- **Kinetic type** — headlines animating in word-by-word or with a character stagger; and the\n  **assembling sentence**, where shared words *persist and re-position* across frames while new words\n  enter (`AI` → `AI Effects` → `AI Effects made easy.`) — not a per-frame re-type, and never a cut\n  (recipe: `MOTION-PATTERNS.md` *\"Progressive text build\"*).\n- **Camera** — a gentle push-in/scale on the whole comp for emphasis; or, when a connective\n  through-line (a stroke, road, path, ribbon, type baseline — any content, not only a vector) runs\n  off one frame's edge and continues into the next, **tile the frames into one world canvas** at the\n  offset that makes the line continuous and **travel the viewport along it while the line draws on in\n  sync** — one continuous shot, not a cut. (The pan is an **empty-\"world\"-layer rig**, not a\n  `composition.camera` pan, which is a v1 no-op — detection + full recipe in `references/TRANSITIONS.md`.)\n- **Brand outro** — the closing logo lockup.\n\nCraft rules: entrances ease **out**, stagger siblings (~0.05–0.12s apart) rather than\nfiring together, and let the matched elements carry continuity so new elements are the\nonly things entering at a seam. Depth sells it — background panels drift less than\nforeground.\n\nKeep the motion legible: lead with the simplest move that reads (a preset entrance, a matched\nsmart-animate), tune params only when the designer asks, and drop to raw keyframes only for what a\npreset can't express. The designer judges the result on the played scene, not a description.\n\n### Work pair by pair — the default rhythm\n\n**HARD RULE — one pair at a time, and STOP for approval before the next.** Never\nauthor, compose, or review more than **one pair (two adjacent frames, A→B)** in a single\nturn. Do **not** run ahead across the whole storyboard, do **not** batch multiple pairs or\nall frames at once, and do **not** author the next pair until the designer has **explicitly\napproved** the current one. Present one pair → wait → only after the approval comes back do\nyou advance to the next. Jumping ahead — composing or motioning several pairs before the\nfirst is approved — is the single most common failure this rhythm exists to prevent.\n\n**This pair rhythm is for FRAME SEQUENCES (a Figma storyboard).** Uploaded assets have no frames —\nthey're arranged into one composition (a **grid, stack, collage, montage, or single focus** — not\none-asset-per-screen by default) and worked by the **working mode the user picked** (part by part, or\nthe whole motion at once — see *Working mode for uploaded assets*), never by A→B pairs.\n\n**The preview is mandatory and self-standing — never skip it and never wait to be asked.**\n\"Present\" means you **actually call the preview** (`picsart_scene_editor` / `picsart_media_export`)\nand show the result; it does **not** mean describing the motion in prose, citing a `validate_scene`\npass, or saying it \"should\" look right. Advancing without a shown preview — or only previewing\nbecause the designer *reminded* you to — is itself the violation, even if the motion turns out fine.\nEvery pair ends the same way: **shown preview → explicit designer yes → next.** No shown preview,\nno advance; no explicit yes, no advance.\n\n**And the preview that proves MOTION is the editor, not stills.** Contact-sheet / still exports are\nfine for the Stage-2 *position* render-match, but the still renderer and the browser editor **draw some\nmoving things differently** (a photo scaling from its edge looked right in stills yet overlapped a\nsibling in the editor). So judge motion on `picsart_scene_editor` (or a played export), never a\nstill — `references/MOTION-TROUBLESHOOTING.md` §\"It looked right in the stills but wrong when it played\".\n\n**Approval gates what the designer SEES, never your intention to render it.** Free calls —\n`validate_scene`, `contact_sheet`, opening the editor, an export used as a preview — run\nwithout asking: render first, show, *then* wait for the reaction. Never ask \"shall I render?\",\nnever report that a preview \"needs your go-ahead\", and **never tell the designer to type \"go\"\n(or any keyword) to continue** — the designer speaks in design terms (\"snappier\", \"approved\",\n\"change the easing\"), not in control tokens. The compose/motion/preview loop is free, so it never\ngates on cost. The actions that **do** require an explicit ask are **saving to Drive** and\n**generating video** — the latter behind the full cost-consent gate (show credits → preflight cost →\nexplicit yes; see *Video generation*). Those two aside, act on free calls without asking.\n\n**Open with frame 1's entrance, before pair 1→2.** The reel starts with motion, not a frozen\nframe — author frame 1's own elements animating **in** at `t=0` (entrances by role, staggered by\nhierarchy), get that opening beat approved, and only then start pair 1→2. A static first frame that\njumps into the first transition is a slideshow tell (full craft in the `motion-design` skill,\n*The opening beat*).\n\n**First, analyze the whole frame sequence — a \"pair\" isn't always two frames.** Before you start\npairing, read the run with the diff tools (`picsart_media_diff_layouts` / `query_layout`, never by\neye) and find the stretches that are really **one motion across several frames**: a **scroll** (frame\nk, k+1, k+2… are the same page translated along one axis), a **zoom/pan** (B is A scaled/cropped), or\na **highlight-in-place** (B is A with emphasis). Those runs collapse into a **single continuous beat\nover one unit of content** — you animate the whole scroll as one gesture, not frame-by-frame with a\nstop on each waypoint (full detection + authoring in [`references/TRANSITIONS.md`](references/TRANSITIONS.md)).\n**This is a judgment that highly depends on the case** — how many frames belong to the run, whether\nit's truly one scroll or genuinely separate screens, where it should pause — so decide it per design\nfrom the tool-read facts, not from a fixed rule, and confirm on the played result. Everything below\nabout \"pairs\" applies to these grouped beats too: one is authored, shown, and approved at a time.\n\n**Then work in the imported Figma order, from the top** — the first beat (frame 1's opening, then\n1→2 or the first grouped run), then the next, and so on. \"The next\" always means the next in\nsequence. **Never open with a middle or last beat (e.g. 8→9), and never hop between non-adjacent\nones** — not even when a later frame looks more interesting. Picking out of order is the same failure\nas running ahead, pointed sideways: the storyboard is animated from the top, so the designer reviews\nit the way it plays.\n\nAuthor motion **one pair at a time** (the reference was built the same way — screen to\nscreen):\n\n1. Focus **exactly one pair** — the **earliest pair not yet approved** (start at 1→2): frame A,\n   the motion, frame B. Nothing beyond this pair is touched yet. (Open `picsart_scene_editor`\n   on this pair to view the motion.)\n2. **Propose the motion — author it, don't ask first.** Lead with the best role×energy /\n   principle-based suggestion for the pair: each element's entrance/continuous motion **and** the\n   matched-element smart-animate carrying shared layers A→B. A rendered proposal on screen is a far\n   better prompt than a blank *\"how do you want this to move?\"* — so author, then show. (If the\n   designer *has* stated an idea, author that instead — never impose your proposal over a stated one.)\n3. **Show it moving, framed as a proposal** — open `picsart_scene_editor` **on the whole scene\n   built so far** (titled for this pair) to play the motion in context (or export the whole reel):\n   *\"Here's f2→f3 — tell me what to change.\"* The designer approves or sends it back with comments.\n4. **Take direction and revise.** The designer reacts to what they see — \"snappier\", \"drop that\n   element\", \"slower on the CTA\". Fold each request into the pair and re-show. Expect a few passes;\n   each maps to timing / staggering / element inventory, not a fresh design.\n5. **Wait for the designer's explicit approval.** Only after it arrives do you flip that\n   pair `approved: true` in `motion.json.seams` and move to the **next** pair. No approval →\n   no advance, full stop.\n\n**One decision per turn**, the running cut stays playable, and the **gate is met only\nwhen every pair is approved**. Never self-approve by describing motion — the yes comes\nfrom the designer, on a moving preview. Touch a shared frame and you may change both its\npairs, so re-preview the neighbour.\n\nThe panel does not latch: every edit writes a new scene document and `sceneRef` moves —\nalways edit the latest. And when the editor returns an **`edited` document**, that becomes the\nlatest — patch further changes onto it, not onto the copy you opened with.\n\n## Video generation — opt-in, and CREDIT-GATED (the one paid capability)\n\nSometimes the design needs **generated footage** — a video card/element that should be real motion,\nor the designer asks to generate a clip with the model they want. This is the plugin's only\ncredit-spending path, so it is **always gated on the designer's explicit, informed consent.** Use it\nonly when the design genuinely needs it or the designer asks — never on your own initiative to \"fill\"\nsomething. Run this flow **in order, and never skip the gate**:\n\n1. **Show the balance FIRST.** Call `picsart_credits` and tell the designer what they have (`balance`,\n   plus `nextResetDate` if the pool refills) **before** anything is chosen — this frames every cost\n   decision that follows.\n2. **Let the designer pick the model.** Narrow with `picsart_media`/`picsart_model_catalog` (plain\n   data, no UI), then open **`picsart_model_choice`** with 2–3 candidates that fit the brief (exactly\n   one marked `recommended`, each with a `creditsNote`); the pick returns as widget context. Don't\n   pick silently when the trade-offs (duration vs resolution vs cost vs audio) are the designer's.\n3. **Assemble params** with `picsart_model_params` (the model's schema) — prompt, duration, aspect,\n   resolution.\n4. **Get the EXACT cost — `picsart_preflight`** (free): it validates the params *and* returns\n   `credits`, the dry-run price with no charge. Fix every `errors` entry before going on.\n5. **Ask for consent, showing the number.** State it plainly — *\"this will cost ~N credits; you have\n   M\"* — and wait for an explicit **yes**. **No preflight cost shown + no explicit yes = no\n   generation.** This is a hard gate: the only credit-spending action in the plugin, never run\n   unasked. If `preflight` returns `credits: null` (pricing unavailable), say so and either get\n   consent to proceed at unknown cost or stop — never charge silently.\n6. **Generate** with `picsart_generate` (video defaults to `async: true` → a job handle; pass the\n   project's `folderUid` so the take is filed under this design).\n7. **Monitor** with `picsart_render_monitor` on the job(s) — it polls and posts the finished URL back;\n   never ask the designer to wait or check.\n8. **Place the result** as a `media` layer in the scene (it's real external footage — a legitimate\n   video asset, the one uploaded asset that's generated rather than exported from Figma), positioned\n   like any other layer, then previewed in the editor for approval as usual.\n\n## Formats — MP Scene is the source of truth\n\nEverything is authored and edited as an **MP Scene** — the format the SDK natively\nsupports and the one every `picsart_media_*` edit / validate / query tool speaks, and the\none `sceneRef` points at. The **mp4** is *derived* from it at Stage 5 (`export`). The MP\nScene is the single editable source of truth — keep it and edit it; the mp4 is the final\nrender, never an editing surface.\n\n## The state — `motion.json`\n\nKeep project state in `motion.json`, updated whole at every milestone. **Never print it\nin chat** — a request to *see* something opens the panel, not the data.\n\n```json\n{\n  \"project\": \"ai-playground-ad\", \"stage\": 3,\n  \"source\": { \"kind\": \"figma\", \"fileKey\": \"…\", \"frames\": [\"node:1:2\", \"node:1:8\"] },\n  \"target\": { \"ratio\": \"9:16\", \"width\": 1080, \"height\": 1920, \"fps\": 30 },\n  \"sceneRef\": \".mp-ai-output/scenes/<hash>.json\",\n  \"frames\": [\n    { \"id\": \"f1\", \"name\": \"model picker\", \"hold\": 3.0,\n      \"layers\": [\n        { \"id\": \"f1_tabs\", \"role\": \"chrome\", \"type\": \"group\", \"matchKey\": \"tabs\",\n          \"transform\": { \"x\": 80, \"y\": 120, \"w\": 920, \"h\": 96, \"opacity\": 1, \"z\": 10 },\n          \"asset\": { \"url\": \"https://…/tabs.png\" },\n          \"motion\": [ { \"kind\": \"slide\", \"from\": \"top\", \"at\": 0, \"duration\": 0.5, \"easing\": \"ease_out\" } ] },\n        { \"id\": \"f1_list\", \"role\": \"content\", \"type\": \"raster\",\n          \"transform\": { \"x\": 80, \"y\": 260, \"w\": 920, \"h\": 1300, \"opacity\": 1, \"z\": 5 },\n          \"asset\": { \"url\": \"https://…/model-list.png\" },\n          \"motion\": [ { \"kind\": \"scroll\", \"axis\": \"y\", \"by\": -600, \"at\": 0.6, \"duration\": 1.8, \"easing\": \"ease_in_out\" } ] },\n        { \"id\": \"f1_tap\", \"role\": \"fx\", \"type\": \"vector\",\n          \"transform\": { \"x\": 610, \"y\": 940, \"w\": 64, \"h\": 64, \"opacity\": 0, \"z\": 20 },\n          \"motion\": [ { \"kind\": \"tap_pulse\", \"at\": 2.4, \"duration\": 0.4 } ] }\n      ] }\n  ],\n  \"matched\": [ { \"key\": \"tabs\", \"layers\": { \"f1\": \"f1_tabs\", \"f2\": \"f2_tabs\" } } ],\n  \"seams\": [ { \"between\": [\"f1\", \"f2\"], \"kind\": \"smart-animate\", \"approved\": false } ],\n  \"gates\": { \"1\": \"passed\", \"2\": \"passed\", \"3\": null, \"4\": null, \"5\": null },\n  \"blocked_on\": null\n}\n```\n\nWhy the shape: a **layer** carries its own `transform`, `asset`/`content`, and a `motion`\nlist; `matchKey` links a layer to its twin in the next frame so `matched[]` can drive a\nsmart-animate; a **seam** is a `smart-animate` (matched layers morph) rather than a flat\ntransition wherever elements are shared. `sceneRef` **moves** with every edit — store\nthe latest.\n\nA layer's **`type`** records what it *is*, which is what `motion-import` decided the export\nformat from: **`text`** (live text — the string + font, animatable per-line/char), **`vector`**\n(icon/logo/shape kept as SVG or a flat fill — stays crisp at any scale), **`raster`** (a photo\nor complex image baked to PNG), or **`group`**. Don't record a vector or text layer as a raster\nPNG — that's the defaulting mistake that softens the ad at every scale but the one it was baked\nat (see `motion-import`).\n\n**`motion[].kind` labels above are DESCRIPTIVE project state — NOT `apply_motion_preset` ids.**\nEach is *realized* through a real mp-scene mechanism, and you must map it, not pass the label to the\nengine: `slide` → `apply_motion_preset(\"slide_in\")`; `tap_pulse` → **`apply_motion_preset(\"tap_pulse\")`\n— this IS a real preset** (verified on current builds; a one-shot dip to ~0.92 and back, `at` = when it\nfires, `appliesTo` includes `shape`; older text here said it didn't exist — that's out of date);\n`scroll` / `smart-animate` → `position`/`scale`/`opacity` **keyframes** via `patch_scene` (there is no\n`scroll` preset). So the label→mechanism map is: some labels are presets (`slide`, `tap_pulse`), some\nare keyframes (`scroll`, `smart-animate`) — **resolve every id from `get_capabilities`** rather than\nassuming a label is or isn't a preset, and only if your build lacks `tap_pulse` compose it from\n`scale_pop` + `opacity` keyframes. Hand-authoring a whole animation \"from scratch\" when a real preset\n(`scale_pop`, `slide_in`, `fade_in`, `tap_pulse`…) fits is the anti-pattern (see *\"reach for the\nhighest-level tool\"*); keyframe only the part no preset covers.\n\n## Cost ledger\n\n| Free (everything in this plugin's loop) | Charged, no rollback |\n|---|---|\n| layer import, compose, `validate`, layout queries, the panel and its motion previews, filmstrip, **and the renders** — `picsart_media_export`, `picsart_media_contact_sheet` (GPU renders that move no credits) | **generative** tools only — image/video/audio generation, remove-bg and kin |\n\n**A dropped call is never a failed render.** An export usually completed even when the\nconnection dropped — check first (`picsart_job_status`, recent Drive files), never\nblind-retry (each retry re-renders and re-saves to Drive), never present a completed\nrender as an error.\n\n## Traps\n\n- **Binding a frame as a flat PNG when its layers were available.** This is *the*\n  slideshow trap, and the reason for the whole layered rewrite. Layers in → elements\n  move; flat in → screens dissolve.\n- **Not tagging matched elements**, so shared chrome cross-dissolves instead of\n  smart-animating — the single biggest tell of \"slideshow, not ad\".\n- **Over-splitting** a design into hundreds of nodes (noise) or **under-splitting** so\n  nothing can move independently. A layer is anything that moves on its own or persists\n  across frames.\n- Firing all entrances together instead of staggering; no depth/parallax, so it reads flat.\n- Judging an export from a **still**; editing a **stale `sceneRef`**; losing the scene to\n  an **expired CDN link** because nothing was saved to Drive.\n"
}

SHA-256 of public snapshot: a15f3f145f2873969c2e8dd6cc25d8da8b703a3941297a66125471400e5f9535