stillmade-sdk 0.1.42 → 0.1.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/.stillmade/sdk-baseline.json +6 -8
  2. package/AGENTS.md +15 -10
  3. package/FRAME_VIEWS.md +113 -0
  4. package/INTERFACE_DESIGN.md +62 -22
  5. package/MOBILE_UI.md +4 -2
  6. package/MODULES.md +152 -6
  7. package/PASTE_TO_LLM.md +35 -25
  8. package/README.md +3 -2
  9. package/SDK.md +994 -550
  10. package/UI_AESTHETIC.md +22 -2
  11. package/blocks/generate/package.js +1 -0
  12. package/blocks/generate/versions/1.0.0/package.js +463 -0
  13. package/docs/build/audio-to-editor.md +36 -0
  14. package/docs/build/block-builder-contract.md +150 -0
  15. package/docs/build/comfyui.md +227 -0
  16. package/docs/build/concepts.md +40 -0
  17. package/docs/build/context.md +159 -0
  18. package/docs/build/cookbook.md +57 -0
  19. package/docs/build/custom-interface.md +617 -0
  20. package/docs/build/data-types.md +83 -0
  21. package/docs/build/frame-views.md +259 -0
  22. package/docs/build/generate-media.md +59 -0
  23. package/docs/build/github-applications.md +314 -0
  24. package/docs/build/hosted-images.md +214 -0
  25. package/docs/build/hosted-music.md +39 -0
  26. package/docs/build/hosted-speech.md +157 -0
  27. package/docs/build/hosted-text.md +246 -0
  28. package/docs/build/image-description.md +49 -0
  29. package/docs/build/interface-design.md +343 -0
  30. package/docs/build/javascript.md +63 -0
  31. package/docs/build/local-preview.md +61 -0
  32. package/docs/build/media-analysis.md +27 -0
  33. package/docs/build/media.md +400 -0
  34. package/docs/build/mobile-ui.md +106 -0
  35. package/docs/build/modules.md +487 -0
  36. package/docs/build/original-blocks.md +70 -0
  37. package/docs/build/outside-apis.md +128 -0
  38. package/docs/build/production-context-templates.md +12 -0
  39. package/docs/build/project-storage.md +94 -0
  40. package/docs/build/quickstart.md +48 -0
  41. package/docs/build/recipes.md +103 -0
  42. package/docs/build/script-handoff.md +45 -0
  43. package/docs/build/script-writer.md +34 -0
  44. package/docs/build/state.md +223 -0
  45. package/docs/build/testing.md +112 -0
  46. package/docs/build/timeline-edits.md +116 -0
  47. package/docs/build/timeline-proposals.md +76 -0
  48. package/docs/build/transcription.md +59 -0
  49. package/docs/build/triggers.md +59 -0
  50. package/docs/build/tutorial.md +52 -0
  51. package/docs/build/typescript.md +34 -0
  52. package/docs/build/video-generation.md +61 -0
  53. package/docs/build/web-reading.md +37 -0
  54. package/docs/build/with-your-ai.md +27 -0
  55. package/docs/changelog.md +9 -0
  56. package/docs/creators.md +21 -0
  57. package/docs/distribute/discovery.md +43 -0
  58. package/docs/distribute/imports.md +58 -0
  59. package/docs/distribute/publishing.md +29 -0
  60. package/docs/distribute/sdk-versions.md +36 -0
  61. package/docs/distribute/selling.md +14 -0
  62. package/docs/distribute/teams.md +60 -0
  63. package/docs/distribute/versioning.md +28 -0
  64. package/docs/examples.md +23 -0
  65. package/docs/gallery.md +26 -0
  66. package/docs/index.md +50 -0
  67. package/docs/native-mcp.md +307 -0
  68. package/docs/project-types/automation.md +43 -0
  69. package/docs/project-types/batches.md +50 -0
  70. package/docs/project-types/build.md +42 -0
  71. package/docs/project-types/completion.md +15 -0
  72. package/docs/project-types/conditions.md +21 -0
  73. package/docs/project-types/hosted-review.md +115 -0
  74. package/docs/project-types/onboarding.md +75 -0
  75. package/docs/project-types/running.md +309 -0
  76. package/docs/project-types/testing.md +72 -0
  77. package/docs/reference/application-artifacts.md +87 -0
  78. package/docs/reference/authoring-guide.md +134 -0
  79. package/docs/reference/browser-applications.md +267 -0
  80. package/docs/reference/capabilities.md +45 -0
  81. package/docs/reference/cli.md +71 -0
  82. package/docs/reference/connection-api.md +59 -0
  83. package/docs/reference/cooperative-jobs.md +13 -0
  84. package/docs/reference/desktop-capabilities.md +172 -0
  85. package/docs/reference/desktop-execution.md +77 -0
  86. package/docs/reference/errors.md +233 -0
  87. package/docs/reference/execution.md +800 -0
  88. package/docs/reference/first-party-blocks.md +40 -0
  89. package/docs/reference/generation-models.md +59 -0
  90. package/docs/reference/limits.md +306 -0
  91. package/docs/reference/manifest-kinds-controls.md +36 -0
  92. package/docs/reference/manifest.md +181 -0
  93. package/docs/reference/operations.md +36 -0
  94. package/docs/reference/package-jobs.md +35 -0
  95. package/docs/reference/parity.md +55 -0
  96. package/docs/reference/permissions.md +86 -0
  97. package/docs/reference/ports.md +26 -0
  98. package/docs/reference/types.md +268 -0
  99. package/docs/reference/universal-resolver.md +303 -0
  100. package/docs/reference/view-bridge.md +60 -0
  101. package/docs/reference/view-rules.md +15 -0
  102. package/docs/reference/workspace-sync.md +25 -0
  103. package/docs/sdk.md +34 -0
  104. package/docs/tools/block-remix.md +211 -0
  105. package/docs/tools/llm.md +2213 -0
  106. package/docs/tools/repository-adaptation.md +613 -0
  107. package/examples/check-clip.stillmade.json +4 -1
  108. package/examples/generate-video.stillmade.json +6 -2
  109. package/examples/research-topic.stillmade.json +5 -1
  110. package/examples/text-workflow.stillmade.json +3 -32
  111. package/examples/timeline-polish.stillmade.json +11 -3
  112. package/examples/transcribe-audio.stillmade.json +11 -3
  113. package/package.json +1 -1
  114. package/packages/block-cli/cli.js +13 -6
  115. package/packages/block-cli/dev-host/assets/host.js +76 -38
  116. package/packages/block-cli/dev-host/assets/index.css +1 -1
  117. package/packages/block-cli/format.js +1 -1
  118. package/packages/block-cli/templates.js +31 -13
  119. package/packages/block-cli/type-packages.js +119 -0
  120. package/packages/block-platform/block-readiness.js +5 -0
  121. package/packages/block-platform/canvas.js +2 -1
  122. package/packages/block-platform/catalog.js +27 -48
  123. package/packages/block-platform/native-host-inventory.js +0 -226
  124. package/packages/block-platform/plain-descriptions.js +1 -25
  125. package/packages/block-platform/project-type-starters.js +13 -53
  126. package/packages/block-platform/script-handoff.js +2 -4
  127. package/packages/block-platform/type-workspace.js +2 -0
  128. package/packages/block-sdk/appearance.js +3 -1
  129. package/packages/block-sdk/block-tier.js +1 -1
  130. package/packages/block-sdk/builder-contract.js +10 -8
  131. package/packages/block-sdk/capabilities.js +1 -1
  132. package/packages/block-sdk/contracts.js +6 -2
  133. package/packages/block-sdk/first-party-identities.js +1 -84
  134. package/packages/block-sdk/first-party-packages.js +3 -85
  135. package/packages/block-sdk/generation-catalog.js +15 -3
  136. package/packages/block-sdk/index.d.ts +2 -1
  137. package/packages/block-sdk/media-analysis-example.js +1 -1
  138. package/packages/block-sdk/mock-host.js +7 -1
  139. package/packages/block-sdk/module-host-calls.js +35 -10
  140. package/packages/block-sdk/module-hosted.js +15 -2
  141. package/packages/block-sdk/module-media-access.js +71 -0
  142. package/packages/block-sdk/module-node.js +1 -1
  143. package/packages/block-sdk/portable-media-actions.js +1 -1
  144. package/packages/block-sdk/runtime.js +1 -1
  145. package/packages/block-sdk/timeline-proposal-example.js +1 -1
  146. package/packages/block-sdk/transcription-example.js +1 -1
  147. package/packages/block-sdk/video-generation-example.js +1 -1
  148. package/packages/block-sdk/view-bridge.js +4 -1
  149. package/packages/block-sdk/view-design.js +17 -14
  150. package/packages/block-sdk/web-example.js +1 -1
  151. package/packages/design-system/block-kit.css +48 -12
  152. package/packages/design-system/block-kit.html +3 -2
  153. package/blocks/mcp-motion-planner/versions/1.1.0/package.js +0 -97
  154. package/blocks/motion-designer/versions/1.0.1/package.js +0 -173318
  155. package/blocks/motion-designer/versions/1.0.2/package.js +0 -173318
  156. package/blocks/motion-frame-review/versions/1.1.1/package.js +0 -465
  157. package/blocks/motion-frame-review/versions/1.1.2/package.snapshot.js +0 -572
  158. package/blocks/narration/package.js +0 -1
  159. package/blocks/narration/versions/1.0.0/package.js +0 -221
  160. package/blocks/narration/versions/1.0.1/package.js +0 -221
  161. package/blocks/native/sm.animated-scene/versions/2.0.0/package.js +0 -475
  162. package/blocks/native/sm.animated-scene/versions/2.1.0/package.js +0 -498
  163. package/blocks/native/sm.animated-scene/versions/2.2.0/package.js +0 -524
  164. package/blocks/native/sm.animated-scene/versions/2.3.0/package.js +0 -618
  165. package/blocks/native/sm.animated-scene/versions/2.3.1/package.js +0 -618
  166. package/blocks/native/sm.animated-scene/versions/2.3.2/package.js +0 -723
  167. package/blocks/native/sm.animated-scene/versions/2.3.3/package.js +0 -723
  168. package/blocks/native/sm.animated-scene/versions/2.3.4/package.js +0 -676
  169. package/blocks/native/sm.animated-scene/versions/2.3.5/package.js +0 -693
  170. package/blocks/native/sm.animated-scene/versions/2.3.6/package.js +0 -700
  171. package/blocks/native/sm.animated-scene/versions/2.3.7/package.js +0 -747
  172. package/blocks/native/sm.animated-scene/versions/2.3.8/package.js +0 -769
  173. package/blocks/native/sm.animated-scene/versions/2.3.9/package.js +0 -769
  174. package/blocks/native/sm.animated-scene-assistant/versions/1.0.0/package.js +0 -183
  175. package/blocks/native/sm.blueprint/versions/2.0.0/package.js +0 -358
  176. package/blocks/native/sm.blueprint/versions/2.1.0/package.js +0 -358
  177. package/blocks/native/sm.blueprint/versions/2.1.1/package.js +0 -358
  178. package/blocks/native/sm.blueprint/versions/2.1.2/package.js +0 -358
  179. package/blocks/native/sm.blueprint/versions/2.1.3/package.js +0 -381
  180. package/blocks/native/sm.blueprint/versions/2.1.4/package.js +0 -381
  181. package/blocks/native/sm.blueprint/versions/2.1.5/package.js +0 -339
  182. package/blocks/native/sm.blueprint/versions/2.1.6/package.js +0 -356
  183. package/blocks/native/sm.blueprint/versions/2.1.7/package.js +0 -363
  184. package/blocks/native/sm.blueprint/versions/2.1.8/package.js +0 -410
  185. package/blocks/native/sm.blueprint/versions/2.1.9/package.js +0 -422
  186. package/blocks/native/sm.blueprint-assistant/versions/1.0.0/package.js +0 -172
  187. package/blocks/native/sm.chat/versions/2.0.0/package.js +0 -144
  188. package/blocks/native/sm.chat/versions/2.0.1/package.js +0 -97
  189. package/blocks/native/sm.chat/versions/2.0.2/package.js +0 -100
  190. package/blocks/native/sm.chat/versions/2.0.3/package.js +0 -100
  191. package/blocks/native/sm.continue-if/versions/1.0.0/package.js +0 -168
  192. package/blocks/native/sm.describe-media/versions/2.0.0/package.js +0 -153
  193. package/blocks/native/sm.describe-media/versions/2.0.1/package.js +0 -156
  194. package/blocks/native/sm.describe-media/versions/2.1.0/package.js +0 -140
  195. package/blocks/native/sm.image-editor/versions/2.0.0/package.js +0 -183
  196. package/blocks/native/sm.image-editor/versions/2.0.1/package.js +0 -190
  197. package/blocks/native/sm.new-items/versions/1.0.0/package.js +0 -191
  198. package/blocks/native/sm.pick-photos/versions/1.0.0/package.js +0 -334
  199. package/blocks/native/sm.quality-audit/versions/1.0.0/package.js +0 -192
  200. package/blocks/native/sm.quality-audit/versions/1.0.1/package.js +0 -192
  201. package/blocks/native/sm.quality-audit/versions/1.0.2/package.js +0 -195
  202. package/blocks/native/sm.research/versions/2.0.0/package.js +0 -175
  203. package/blocks/native/sm.research/versions/2.0.1/package.js +0 -184
  204. package/blocks/native/sm.research/versions/2.0.2/package.js +0 -187
  205. package/blocks/native/sm.script/versions/2.0.0/package.js +0 -144
  206. package/blocks/native/sm.script/versions/2.1.0/package.js +0 -144
  207. package/blocks/native/sm.script/versions/2.1.1/package.js +0 -144
  208. package/blocks/native/sm.script/versions/2.1.2/package.js +0 -105
  209. package/blocks/native/sm.script/versions/2.1.3/package.js +0 -152
  210. package/blocks/native/sm.script/versions/2.1.4/package.js +0 -156
  211. package/blocks/native/sm.script/versions/2.1.5/package.js +0 -156
  212. package/blocks/native/sm.shot-plan/versions/2.0.0/package.js +0 -301
  213. package/blocks/native/sm.shot-plan/versions/2.1.0/package.js +0 -528
  214. package/blocks/native/sm.shot-plan/versions/2.1.1/package.js +0 -528
  215. package/blocks/native/sm.shot-plan/versions/2.1.2/package.js +0 -528
  216. package/blocks/native/sm.shot-plan/versions/2.1.3/package.js +0 -536
  217. package/blocks/native/sm.shot-plan/versions/2.2.0/package.js +0 -800
  218. package/blocks/native/sm.shot-plan/versions/2.2.1/package.js +0 -920
  219. package/blocks/native/sm.shot-plan-assistant/versions/1.0.0/package.js +0 -173
  220. package/blocks/native/sm.stock-search/versions/2.0.0/package.js +0 -174
  221. package/blocks/native/sm.thumbnail/versions/2.0.0/package.js +0 -137
  222. package/blocks/native/sm.thumbnail/versions/2.0.1/package.js +0 -140
  223. package/blocks/native/sm.transcribe/versions/2.0.0/package.js +0 -163
  224. package/blocks/native/sm.transcribe/versions/2.0.1/package.js +0 -168
  225. package/blocks/native/sm.whiteboard-assistant/versions/1.0.0/package.js +0 -175
  226. package/blocks/native/sm.youtube/versions/2.0.0/package.js +0 -217
  227. package/blocks/occasion-story/package.js +0 -1
  228. package/blocks/occasion-story/versions/1.0.0/package.js +0 -1658
  229. package/blocks/occasion-story/versions/1.0.1/package.js +0 -1699
  230. package/blocks/occasion-story/versions/1.0.2/package.js +0 -1682
  231. package/blocks/photo-reel-composer/versions/1.0.0/package.js +0 -3043
  232. package/blocks/photo-reel-composer/versions/1.0.1/package.js +0 -3026
  233. package/blocks/photo-reel-composer/versions/1.0.2/package.js +0 -4149
  234. package/blocks/product-ad-variants/versions/1.0.0/package.js +0 -2911
  235. package/blocks/product-launch-director/versions/1.0.0/package.js +0 -103
  236. package/blocks/release-visuals/package.js +0 -1
  237. package/blocks/release-visuals/versions/1.0.0/package.js +0 -1492
  238. package/blocks/release-visuals/versions/1.0.1/package.js +0 -1517
  239. package/blocks/release-visuals/versions/1.0.2/package.js +0 -1500
  240. package/blocks/screen-recorder/package.js +0 -1
  241. package/blocks/screen-recorder/versions/1.0.0/package.js +0 -223
  242. package/blocks/screen-recorder/versions/1.0.1/package.js +0 -223
  243. package/blocks/short-form-finish/package.js +0 -1
  244. package/blocks/short-form-finish/versions/1.0.0/package.js +0 -1043
  245. package/blocks/short-form-finish/versions/1.0.1/package.js +0 -1043
  246. package/blocks/short-form-finish/versions/1.0.2/package.js +0 -1043
  247. package/blocks/short-form-finish/versions/1.0.3/package.js +0 -1026
  248. package/examples/saas-product-launch-reviewed-source.stillmade.json +0 -383
  249. package/examples/saas-product-launch.stillmade.json +0 -304
  250. package/packages/block-platform/dealer-inventory-video-project-type.js +0 -38
  251. package/packages/block-platform/first-revenue-project-types.js +0 -46
  252. package/packages/block-platform/fixture-starters.js +0 -13
  253. package/packages/block-platform/launch-project-source.js +0 -10
  254. package/packages/block-platform/launch-project.js +0 -30
  255. package/packages/block-platform/motion-project-types.js +0 -55
  256. package/packages/block-platform/motion-starters.js +0 -14
  257. package/packages/block-platform/product-ad-variants-project-type.js +0 -30
  258. package/packages/block-platform/product-launch-updated.js +0 -90
  259. package/packages/block-platform/revenue-review-project-types.js +0 -36
  260. package/packages/block-platform/revenue-review-starters.js +0 -13
  261. package/packages/block-platform/script-writer.js +0 -29
  262. package/packages/block-platform/website-source-block.js +0 -14
@@ -19,16 +19,18 @@ export const BLOCK_KIT_CLASSES=Object.freeze({
19
19
  'sm-actions':'The action row: one .sm-primary, optional .sm-quiet buttons and .sm-icon buttons (aria-label and title required).',
20
20
  'sm-status':'Live state beside the action: data-state="loading|success|waiting|error" and a few words.',
21
21
  'sm-more':'A <details> for secondary settings; starts closed.',
22
- 'sm-hint':'A <details> info toggle for an explanation that might help; starts closed.',
22
+ 'sm-hint':'A <details> (i) for an explanation that might help; its words show on hover or focus, or a tap on touch screens.',
23
23
  'sm-gallery':'A grid of results or media. data-size="small" for input files: more tiles per row as the screen widens, never bigger tiles.',
24
24
  'sm-media-off':'A picture or clip that cannot show here (on another device, or it did not open): a quiet tile in its own shape (--sm-photo-ratio, the tile\'s shape in a gallery) holding the image-off glyph, with the reason in aria-label and title and no words inside.',
25
- 'sm-glyph':'A small icon drawn in currentColor: data-glyph="play|pause|plus|close|check|chevron|upload|image|image-off|video|audio|text|spark|info|warning|spinner".',
25
+ 'sm-add':'The add tile for an input\'s files: <button class="sm-add" data-stillmade-add="<input>" aria-label="Add photos">. StillMade opens its own picker and saves the files; never an <input type=file>. Each tile of a list can carry .sm-tile-tools with data-stillmade-move and data-stillmade-remove buttons (data-index, data-to).',
26
+ 'sm-scrim':'Words over a photo or video, in a positioned box such as an sm-stage: a see-through shade of the page under them, in every theme. var(--scrim) is the same shade for your own rules; never color-mix() or a fixed rgba().',
27
+ 'sm-glyph':'A small icon drawn in currentColor: data-glyph="play|pause|plus|close|check|chevron|chevron-left|chevron-right|upload|image|image-off|video|audio|text|spark|info|warning|spinner".',
26
28
  });
27
29
 
28
30
  // The design principles for every Block interface, in priority order.
29
31
  export const BLOCK_INTERFACE_PRINCIPLES=Object.freeze([
30
32
  'Function first: unless the person asks for a design direction, build from the Block kit (`sm-block`, `sm-stage`, `sm-choices`, `sm-actions`, `sm-more`) and ship little or no CSS of your own. A direction the person names wins over the kit.',
31
- 'Show the thing being made: the preview, media or result gets the largest area (`sm-stage`). A picture or clip the Block makes fills it in its own shape, as large as fits; several fill it as a grid, each big enough to watch. Small tiles are for the files a person gives the Block, never for what it makes. A clip is a `<video controls>`, which StillMade plays in its own player with full screen, and a picture in `sm-stage` or `sm-gallery` (or marked `data-stillmade-expand`) gets StillMade\'s full-screen button; leave out `controls` only when the Block drives playback itself. Never a JSON dump, source editor, manifest or diagnostic panel unless the task is about source.',
33
+ 'Show the thing being made: the preview, media or result gets the largest area (`sm-stage`), and every part shows at once: before the first run the result\'s place is drawn in the shape and size of what is coming (a 9:16 frame for a vertical clip, lines for text, a player bar for sound), so the result fills it instead of popping in. On a wide screen what goes in sits on the left and the result on the right; they stack only on narrow screens and phones. A picture or clip the Block makes fills it in its own shape, as large as fits; several fill it as a grid, each big enough to watch. Small tiles are for the files a person gives the Block, never for what it makes. A clip is a `<video controls>`, which StillMade plays in its own player with full screen, and a picture in `sm-stage` or `sm-gallery` (or marked `data-stillmade-expand`) gets StillMade\'s full-screen button; leave out `controls` only when the Block drives playback itself. Never a JSON dump, source editor, manifest or diagnostic panel unless the task is about source.',
32
34
  'One obvious next action: one solid `sm-primary` in the kit\'s ink, never restyled to the background or a ghost outline; peers are `sm-quiet` buttons or named icons, and close is an X icon. Seven or fewer choices in view.',
33
35
  'Speak the job unless the person or creator asks otherwise. The action button names what it does in the job\'s words (`manifest.action`: "Plan the tour"; AI pictures, video and sound start with Generate and say what, the person\'s own media cut or rendered says Make: "Generate voiceover", "Make 6 clips"), never "Make it", "Run", "Run step", "Submit", "Process" or a bare "Generate"; progress counts the job\'s units ("4 of 9 rooms"), never "Processing"; results and problems use its words in one line. Show no credit numbers: StillMade puts the price beside the verb on its own run button ("Write · 1 credit"), with a chip for the model, quality or count when they can change. Pressing it runs at that price; a confirmation appears only when the server price is higher than the one shown.',
34
36
  'Pictures over words: choices people see or hear are thumbnails, swatches, samples or glyphs (`sm-choices`), not word lists. Icons carry an accessible name and tooltip; never emoji.',
@@ -38,13 +40,14 @@ export const BLOCK_INTERFACE_PRINCIPLES=Object.freeze([
38
40
  'Strong defaults; secondary settings go in `sm-more`, closed.',
39
41
  'Compact: the whole Block fits one laptop screen without scrolling. A short setting is one row, its label beside the control; no card around a single control.',
40
42
  'Status is a dot or a few words ("No narration yet"), never a paragraph; the reason sits behind an `sm-hint`.',
41
- 'Files are tiles: a saved file is a thumbnail or chip and adding one is a + tile. Never the bare browser file picker, and no size limits in view until a file is too big.',
43
+ 'Files are tiles: a saved file is a thumbnail or chip and adding one is the + tile (`<button class="sm-add" data-stillmade-add="<input>">`), which opens StillMade\'s picker. Never an `<input type="file">` or the bare browser file picker, and no size limits in view until a file is too big.',
42
44
  'Rare tools (update, schedule, history, reload) are named icon buttons beside the action, never sections under the work.',
43
45
  'An (i) beside anything a newcomer could misread: a setting, status or number whose effect is not obvious from its label gets a closed `sm-hint` with one or two sentences. Give every input that needs one a `description`; StillMade shows it as that (i). Obvious controls get none.',
44
46
  'One workspace: no cards inside cards, no second title, step counter or Back/Next bar; the host owns navigation.',
47
+ 'One page per job (November 3, 2026): a guided job\'s screen holds the inputs and settings, then a cheap check before the expensive run (the script and a voice sample before the video, a second `StillMade.run` that StillMade prices on its own), then the result; never a second Block or Step for the check. A workspace a person works in (a CAD tool, a canvas, an editor) is its own Block, and turning what it made into something else is the next one.',
45
48
  'Status sits beside the action it describes (`sm-status`), in a few words.',
46
49
  'Keep the page in normal scroll flow; no sticky media or control strips unless the editing task needs them.',
47
- 'Use the width: from 860px wide the kit puts the controls on the left at a reading width (300–380px) and the result (`sm-stage`) fills the right, in its real shape; under that everything stacks with the result first and the action within reach. Extra width goes to the result, never to wider text fields. Before there is a result, the stage previews what will be made from the inputs. `data-layout="stack"` opts out.',
50
+ 'Use the width: from 860px wide the kit puts the controls on the left at a reading width (300–380px) and the result (`sm-stage`) fills the right, in its real shape; under that everything stacks in the page\'s order: the inputs, the action in normal flow (never pinned), then the result\'s place under it, so put `sm-stage` after `sm-actions`. Extra width goes to the result, never to wider text fields. Before there is a result, the stage previews what will be made from the inputs. `data-layout="stack"` opts out.',
48
51
  'Size with the kit, never fixed sizes: no fixed pixel widths or heights for the workspace or stage, no 100vh, no position:fixed panels. StillMade zooms a Block\'s screen to fill the space it has (up to 150%, never down to a phone layout on a computer), so a Block laid out with the kit\'s spacing fills its Step without empty space, and it centers a standard view narrower than its Step. An app that lays itself out (full-size canvas or WebGL, its own scroll, pan or zoom, its own Ctrl/Cmd +/- keys) puts `data-stillmade-layout="own"` on its outermost element, and StillMade then never centers, zooms or takes those keys.',
49
52
  'Group what the person sets in one `sm-fields` (or `sm-settings` for short ones): the kit gives the group its own surface, so the inputs, the settings and the result read as separate parts. Settings sit side by side (`sm-settings`), next to what they change. Three or four short options are one segmented row (`data-segmented`), not a row of big tiles.',
50
53
  'Lists fill the width at a small size: input files are small tiles (`sm-gallery data-size="small"`), many items are one line each (`sm-list`): a thumbnail, one line of text, a short fact. Tapping an item opens all of its fields in place. Extra width means more items per row, never bigger cards.',
@@ -68,16 +71,14 @@ export const INTERFACE_DESIGN_RULES=Object.freeze([
68
71
  ]);
69
72
 
70
73
  const occurrences=(source,pattern)=>(source.match(pattern)||[]).length;
71
- // A file input someone sees as the browser's own picker: not hidden and not inside a label tile.
74
+ // A file input of the view's own, shown or hidden in a label tile (November 3, 2026: a hidden one behind a label
75
+ // still skips StillMade's picker, its working copies and device media). Files are added with the sm-add tile.
72
76
  // One forward scan with indexOf, so odd source never makes it slow.
73
- function bareFilePicker(html){
77
+ function ownFileInput(html){
74
78
  const lower=html.toLowerCase();
75
79
  for(let at=lower.indexOf('<input');at!==-1;at=lower.indexOf('<input',at+6)){
76
80
  const end=lower.indexOf('>',at);if(end===-1)return false;
77
- const tag=lower.slice(at,end);
78
- if(!/\btype\s*=\s*["']?file\b/.test(tag)||/\bhidden\b|display\s*:\s*none|\bsm-sr\b/.test(tag))continue;
79
- const label=lower.lastIndexOf('<label',at),closed=lower.lastIndexOf('</label>',at);
80
- if(label===-1||closed>label)return true;
81
+ if(/\btype\s*=\s*["']?file\b/.test(lower.slice(at,end)))return true;
81
82
  }
82
83
  return false;
83
84
  }
@@ -308,8 +309,8 @@ export function reviewViewDesign(view){
308
309
  const longText=[...primary.matchAll(/<p\b[^>]*>([\s\S]*?)<\/p>/gi)].filter(match=>words(match[1])>20).length;
309
310
  if(longText)warnings.push('A visible paragraph runs past twenty words. Drop words nobody needs; put helpful explanation in a closed <details class="sm-hint">.');
310
311
  if(/<select\b/i.test(primary)&&/<(?:img|video|audio)\b/i.test(primary)===false&&/\b(?:voice|font|look|style|color|colour|template|theme|music|sound)\b/i.test(primary))warnings.push('People choose something they see or hear from a word list. Show each option as a picture or sample in <fieldset class="sm-choices">.');
311
- // Compact: a bare browser file picker and printed size limits each take rows nobody needs.
312
- if(bareFilePicker(primary))warnings.push('A bare file picker is in view. Show files as tiles: a + tile (a label around a hidden file input) and a thumbnail or chip for each saved file.');
312
+ // Compact: the view's own file picker and printed size limits each take rows nobody needs.
313
+ if(ownFileInput(primary))warnings.push('The view has a file input of its own. Show files as tiles: a thumbnail or chip for each saved file and the + tile, <button class="sm-add" data-stillmade-add="<input>" aria-label="Add photos">, which opens StillMade\'s picker and saves the files.');
313
314
  if(/\bup to \d+\s*(?:mb|gb|kb)\b/i.test(primary.replace(/<[^<>]*>/g,' ')))warnings.push('A size limit is printed in view. Say it only when a file is too big.');
314
315
  if(stackedLabel(primary,view.css))warnings.push('A short setting has its label above the control. Put the label beside it: <div class="sm-field"><label for="x">Label</label><input id="x"></div>, or several side by side in .sm-settings.');
315
316
  const rareTool=rareToolSection(html);
@@ -328,12 +329,14 @@ export function reviewViewDesign(view){
328
329
 
329
330
  // October 30, 2026: Chat presses a button on a Block's own screen only when it carries data-stillmade-action
330
331
  // (naming what it does); an unmarked button is out of Chat's reach. The number of buttons in view.html without one.
332
+ // The + tile (data-stillmade-add) is not counted: StillMade's picker opens only from the person's own click.
331
333
  export function unmarkedButtons(view){
332
334
  const html=String(view?.html||''),lower=html.toLowerCase();let count=0;
333
335
  for(let start=lower.indexOf('<button');start!==-1;start=lower.indexOf('<button',start+7)){
334
336
  if(!/[\s>/]/.test(lower[start+7]||''))continue;
335
337
  const end=lower.indexOf('>',start);if(end===-1)break;
336
- if(!/\sdata-stillmade-action\s*=/.test(lower.slice(start,end)))count++;
338
+ const tag=lower.slice(start,end);
339
+ if(!/\sdata-stillmade-(?:action|add)\s*=/.test(tag))count++;
337
340
  }
338
341
  return count;
339
342
  }
@@ -8,7 +8,7 @@ export const webFetch={
8
8
  tests:[{name:'Read a public page',input:{url:'https://en.wikipedia.org/wiki/Tide'},expectations:{summary:{kind:'text',minLength:20,maxLength:4000}}}],
9
9
  };
10
10
  export const webResearch={
11
- manifest:{schemaVersion:1,sdkVersion:'0.1.0',id:'example.research-topic',action:{label:'Research topic',running:'Researching topic…'},version:'1.0.0',name:'Research a topic',description:'Search the web for a topic and return a cited summary.',kind:'task',runtime:'capability',entry:'src/capability.json',license:'MIT',provenance:EXAMPLE_PROVENANCE,inputs:{topic:{type:'text',primary:true,semantic:'research_topic',required:true,description:'What to research.'}},outputs:{findings:{type:'json',primary:true,semantic:'research_findings',description:'Summary and the sources it came from.'}},permissions:{project:[],capabilities:['web.research'],network:[],filesystem:[],secrets:[]},ui:[{control:'text',port:'topic'}]},
11
+ manifest:{schemaVersion:1,sdkVersion:'0.1.0',id:'example.research-topic',action:{label:'Research topic',running:'Researching topic…'},version:'1.0.0',name:'Research a topic',description:'Search the web for a topic and return a cited summary.',kind:'task',runtime:'capability',entry:'src/capability.json',license:'MIT',provenance:EXAMPLE_PROVENANCE,inputs:{topic:{type:'text',primary:true,semantic:'research_topic',required:true,description:'What to research.'}},outputs:{findings:{type:'json',primary:true,semantic:'research_findings',description:'Summary and the sources it came from.',schema:{summary:'text',sources:'json[]'}}},permissions:{project:[],capabilities:['web.research'],network:[],filesystem:[],secrets:[]},ui:[{control:'text',port:'topic'}]},
12
12
  capability:{schemaVersion:1,operation:'web.research',topic:{$input:'topic'},output:'findings'},
13
13
  tests:[{name:'Tides',input:{topic:'How tides work'},expectations:{findings:{kind:'json',includes:['summary']}}}],
14
14
  };
@@ -16,7 +16,7 @@
16
16
  .sm-actions one .sm-primary, optional .sm-quiet / .sm-icon
17
17
  .sm-status short live state beside the action
18
18
  .sm-more everything secondary, collapsed
19
- .sm-hint an info toggle for words that might help, collapsed
19
+ .sm-hint an (i) whose words show on hover or focus (a tap on touch screens)
20
20
  .sm-empty what an empty stage shows: a glyph, a few words, one action
21
21
  .sm-glyph icons drawn in CSS with currentColor (no SVG or url needed)
22
22
  .sm-media-off a picture or clip that cannot show here: a quiet tile, no words
@@ -35,8 +35,8 @@
35
35
  :where(.sm-block[data-layout="split"]) > :where(.sm-stage){grid-row:span 6}
36
36
  }
37
37
  /* Wide views (October 19, 2026): the controls keep a reading width on the left and
38
- the result fills the rest on the right. Under 860px everything stacks with the
39
- result first. data-layout="stack" opts out; "split" keeps its older layout. */
38
+ the result fills the rest on the right. Under 860px everything stacks in page order, so
39
+ the stage goes after the actions: the result's place under the button. data-layout="stack" opts out; "split" keeps its older layout. */
40
40
  @container (min-width:860px){
41
41
  :where(.sm-block:not([data-layout]):has(> .sm-stage)){grid-template-columns:minmax(300px,380px) minmax(0,1fr);align-items:start;column-gap:var(--s-5,24px);row-gap:var(--s-4,16px)}
42
42
  :where(.sm-block:not([data-layout]):has(> .sm-stage)) > :where(*){grid-column:1}
@@ -52,11 +52,13 @@
52
52
 
53
53
  /* ---------- The stage: the object being made gets the main surface ---------- */
54
54
  :where(.sm-stage){position:relative;display:grid;place-items:center;min-height:220px;padding:var(--s-3,12px);border-radius:var(--r-3,8px);background:var(--bg-inset);overflow:hidden}
55
- :where(.sm-stage[data-ratio="16:9"]){aspect-ratio:16/9;min-height:0}
56
- :where(.sm-stage[data-ratio="9:16"]){aspect-ratio:9/16;min-height:0;max-height:70vh;justify-self:center;width:auto;height:min(70vh,640px)}
57
- :where(.sm-stage[data-ratio="1:1"]){aspect-ratio:1;min-height:0}
55
+ :where(.sm-stage:is([data-ratio="16:9"],[data-ratio="16/9"])){aspect-ratio:16/9;min-height:0}
56
+ :where(.sm-stage:is([data-ratio="9:16"],[data-ratio="9/16"])){aspect-ratio:9/16;min-height:0;max-height:70vh;justify-self:center;width:auto;height:min(70vh,640px)}
57
+ :where(.sm-stage:is([data-ratio="1:1"],[data-ratio="1/1"])){aspect-ratio:1;min-height:0}
58
58
  :where(.sm-stage) > :where(img,video,canvas){display:block;max-width:100%;max-height:100%;object-fit:contain;border-radius:var(--r-2,4px)}
59
59
  :where(.sm-stage[data-fill]) > :where(img,video,canvas){width:100%;height:100%;object-fit:cover}
60
+ /* A picture the view has not filled yet draws nothing, never a broken-image icon (November 3, 2026). */
61
+ :where(.sm-stage) :where(img:not([src]),img[src=""]){display:none}
60
62
 
61
63
  /* ---------- Empty state: a picture and a few words, never a paragraph ---------- */
62
64
  :where(.sm-empty){display:grid;justify-items:center;gap:var(--s-3,12px);padding:var(--s-5,24px) var(--s-4,16px);text-align:center;color:var(--fg-muted)}
@@ -130,8 +132,8 @@
130
132
  :where(.sm-choices) > :where(label:has(input:disabled):not(:has(input:checked))){opacity:.45}
131
133
  :where(.sm-choices) :where(img,video,canvas,.sm-swatch){display:block;width:100%;aspect-ratio:var(--sm-tile-ratio,1);object-fit:cover;border-radius:var(--r-2,4px);background:var(--bg-inset)}
132
134
  :where(.sm-choices) :where(.sm-glyph){--sm-glyph-size:28px;margin:10px 0 4px}
133
- :where(.sm-choices[data-ratio="16:9"]){--sm-tile-ratio:16/9}
134
- :where(.sm-choices[data-ratio="9:16"]){--sm-tile-ratio:9/16}
135
+ :where(.sm-choices:is([data-ratio="16:9"],[data-ratio="16/9"])){--sm-tile-ratio:16/9}
136
+ :where(.sm-choices:is([data-ratio="9:16"],[data-ratio="9/16"])){--sm-tile-ratio:9/16}
135
137
  :where(.sm-choices[data-compact]) > :where(label){grid-auto-flow:column;justify-content:center;align-content:center;align-items:center;min-height:var(--touch-target,44px);padding:6px 12px}
136
138
  :where(.sm-choices[data-compact]) :where(.sm-glyph){--sm-glyph-size:18px;margin:0}
137
139
  :where(.sm-choices) :where(audio){width:100%;height:32px;position:relative;z-index:1}
@@ -199,6 +201,36 @@
199
201
  Its edge separates it from a stage or gallery tile of the same colour; in a gallery it takes the tile's shape. */
200
202
  :where(.sm-media-off){display:inline-grid;place-items:center;box-sizing:border-box;width:min(100%,320px);aspect-ratio:var(--sm-photo-ratio,4/3);border:1px solid var(--border-tok);border-radius:var(--r-2,4px);background:var(--bg-inset);color:var(--fg-subtle,var(--fg-muted));vertical-align:top}
201
203
  :where(.sm-gallery) :where(.sm-media-off){display:grid;width:100%;aspect-ratio:var(--sm-tile-ratio,1);border-radius:inherit}
204
+ /* The add tile (November 3, 2026): a dashed + after an input's files, as on StillMade's Step page. With
205
+ data-stillmade-add naming the input, StillMade opens its own picker and saves the files as its own tiles do; they
206
+ arrive through onInput. Never an <input type="file"> of the Block's own.
207
+ <button type="button" class="sm-add" data-stillmade-add="listingPhotos" aria-label="Add photos" title="Add photos"></button>
208
+ Alone it is a small square; in an .sm-gallery it takes the tile's shape. Words inside show under the +. A viewer and
209
+ an input an earlier Step fills see no tile. */
210
+ :where(.sm-add){display:inline-grid;place-items:center;align-content:center;gap:2px;box-sizing:border-box;min-width:52px;min-height:52px;margin:0;padding:6px;border:1px dashed var(--border-strong);border-radius:var(--r-2,4px);background:transparent;color:var(--fg-muted);font:inherit;font-size:max(12px,var(--fs-caption,.8125rem));line-height:1.2;cursor:pointer}
211
+ :where(.sm-add)::before{content:"+";font-size:20px;line-height:1}
212
+ :where(.sm-add):hover{color:var(--fg);border-style:solid}
213
+ :where(.sm-add):focus-visible{outline:2px solid var(--signal);outline-offset:3px}
214
+ :where(.sm-add):disabled,:where(.sm-add[aria-busy="true"]){opacity:.45;cursor:default}
215
+ :where(.sm-gallery) :where(.sm-add){display:grid;width:100%;aspect-ratio:var(--sm-tile-ratio,1);border-radius:var(--r-3,8px);background:transparent}
216
+ /* A scrim (November 3, 2026): words over a photo or video read in every theme (a listing Block could not write one:
217
+ a Block's CSS takes only theme tokens, and color-mix() over them is refused). --scrim is the page's background, partly
218
+ see-through, for a Block's own rules (background:var(--scrim)); .sm-scrim lays it over the bottom of a positioned box
219
+ (an sm-stage, a gallery tile) under the words inside it.
220
+ <figure class="sm-stage" data-fill><img src="..." alt=""><figcaption class="sm-scrim">12 Elm Street</figcaption></figure> */
221
+ :where(:root,[data-mode]){--scrim:color-mix(in srgb,var(--bg) 72%,transparent)}
222
+ :where(.sm-scrim){position:absolute;inset:auto 0 0 0;margin:0;padding:var(--s-5,24px) var(--s-3,12px) var(--s-3,12px);background:linear-gradient(to top,var(--scrim) 55%,transparent);color:var(--fg)}
223
+ /* A tile's own tools (the same day): move and remove buttons in an .sm-tile-tools inside a gallery tile, wired by
224
+ data-stillmade-move and data-stillmade-remove (FRAME_VIEWS.md, "Removing and reordering files"). They sit in the
225
+ tile's top corner on a solid chip, show on hover or focus where there is a pointer and always on touch, and are hidden
226
+ with the + tile from viewers and for an input an earlier Step fills. */
227
+ :where(.sm-gallery) :where(.sm-tile-tools){position:absolute;top:4px;right:4px;display:flex;gap:2px}
228
+ :where(.sm-gallery) :where(.sm-tile-tools) > :where(button){--sm-glyph-size:14px;display:grid;place-items:center;box-sizing:border-box;min-width:24px;height:24px;margin:0;padding:0 4px;border:0;border-radius:var(--r-2,4px);background:var(--bg);color:var(--fg);font:inherit;font-size:16px;line-height:1;cursor:pointer}
229
+ :where(.sm-gallery) :where(.sm-tile-tools) > :where(button):focus-visible{outline:2px solid var(--signal);outline-offset:1px}
230
+ :where(.sm-gallery) :where(.sm-tile-tools) > :where(button:disabled,button[aria-busy="true"]){opacity:.45;cursor:default}
231
+ /* Three tools fit a 92px small tile on touch: 3 x 28 + gaps. */
232
+ @media (pointer:coarse){:where(.sm-gallery) :where(.sm-tile-tools) > :where(button){min-width:28px;height:28px}}
233
+ @media (hover:hover){:where(.sm-gallery) > :where(:not(:hover,:focus-within)) :where(.sm-tile-tools){opacity:0}}
202
234
 
203
235
  /* ---------- Status: a glyph and a few words, next to the action ---------- */
204
236
  :where(.sm-status){display:inline-flex;align-items:center;gap:var(--s-2,8px);min-height:24px;font-size:var(--fs-body-s,.875rem);color:var(--fg-muted)}
@@ -233,11 +265,12 @@
233
265
  :where(.sm-hint) > :where(summary){display:inline-grid;place-items:center;width:var(--touch-target,44px);height:var(--touch-target,44px);margin:-8px;min-height:0;padding:0;border:0;list-style:none;color:var(--fg-subtle);cursor:pointer}
234
266
  :where(.sm-hint) > :where(summary)::-webkit-details-marker{display:none}
235
267
  :where(.sm-hint) > :where(summary)::before{content:"i";display:grid;place-items:center;width:15px;height:15px;border:1.5px solid currentColor;border-radius:50%;font:600 10px/1 var(--font-body);font-style:normal}
236
- :where(.sm-hint) > :where(summary):hover,:where(.sm-hint[open]) > :where(summary){color:var(--fg)}
268
+ :where(.sm-hint:hover,.sm-hint:focus-within,.sm-hint[open]) > :where(summary){color:var(--fg)}
269
+ /* The words float over the page and never push it around (owner, November 3, 2026: "it makes me click and makes the ui weird"). */
237
270
  :where(.sm-hint) > :where(:not(summary)){position:absolute;z-index:5;inset-inline-start:0;top:100%;width:max-content;max-width:min(280px,calc(100cqi - 32px));margin:4px 0 0;padding:10px 12px;border:1px solid var(--border-tok);border-radius:var(--r-3,8px);background:var(--bg-elev-2);color:var(--fg);font-size:var(--fs-body-s,.875rem);line-height:1.45;box-shadow:var(--shadow-1)}
238
- /* Outside a label row there is no safe anchor, so the explanation opens in the flow instead. */
239
- :where(:not(.sm-label)) > :where(.sm-hint[open]){display:block}
240
- :where(:not(.sm-label)) > :where(.sm-hint) > :where(:not(summary)){position:static;width:auto;max-width:60ch}
271
+ :where(.sm-hint:hover,.sm-hint:focus-within)::details-content{content-visibility:visible}
272
+ /* With a mouse, hovering shows the words and a click does nothing: the click lands on the closed <details>, not its summary. Touch screens keep the tap. */
273
+ @media (hover:hover){:where(.sm-hint) > :where(summary){pointer-events:none}}
241
274
 
242
275
  /* ---------- Glyphs: small icons drawn with currentColor ----------
243
276
  <span class="sm-glyph" data-glyph="upload" aria-hidden="true"></span>
@@ -250,6 +283,9 @@
250
283
  :where(.sm-glyph[data-glyph="close"])::before{transform:rotate(45deg)}
251
284
  :where(.sm-glyph[data-glyph="check"])::before{left:36%;top:12%;width:30%;height:58%;border:solid currentColor;border-width:0 2px 2px 0;transform:rotate(45deg)}
252
285
  :where(.sm-glyph[data-glyph="chevron"])::before{left:30%;top:22%;width:40%;height:40%;border:solid currentColor;border-width:0 2px 2px 0;transform:rotate(45deg)}
286
+ /* Earlier and later (a tile's move tools, November 3, 2026). */
287
+ :where(.sm-glyph[data-glyph="chevron-left"])::before{left:36%;top:30%;width:40%;height:40%;border:solid currentColor;border-width:0 0 2px 2px;transform:rotate(45deg)}
288
+ :where(.sm-glyph[data-glyph="chevron-right"])::before{left:24%;top:30%;width:40%;height:40%;border:solid currentColor;border-width:2px 2px 0 0;transform:rotate(45deg)}
253
289
  :where(.sm-glyph[data-glyph="upload"])::before{left:10%;right:10%;bottom:10%;height:35%;border:2px solid currentColor;border-top:0;border-radius:0 0 3px 3px}
254
290
  :where(.sm-glyph[data-glyph="upload"])::after{left:25%;right:25%;top:4%;height:62%;background:currentColor;clip-path:polygon(50% 0,100% 45%,60% 45%,60% 100%,40% 100%,40% 45%,0 45%)}
255
291
  :where(.sm-glyph[data-glyph="image"])::before{inset:12%;border:2px solid currentColor;border-radius:3px}
@@ -21,7 +21,7 @@
21
21
  Drop it if nobody needs it to finish the task (intros, "how it works",
22
22
  restating the Block name, describing what is already visible).
23
23
  Picture it if a glyph, thumbnail, swatch or sample says the same thing.
24
- Collapse it if it might help some people: .sm-hint (info toggle) for an
24
+ Collapse it if it might help some people: .sm-hint (an (i) that shows on hover) for an
25
25
  explanation, .sm-more for secondary settings.
26
26
  Keep it for errors, spending or credit approvals, stale inputs and
27
27
  anything destructive. Keep those visible, in few words.
@@ -111,7 +111,8 @@
111
111
  <li><span class="sm-swatch swatch-a" style="display:block;aspect-ratio:3/2"></span></li>
112
112
  <li><span class="sm-swatch swatch-b" style="display:block;aspect-ratio:3/2"></span></li>
113
113
  <li><span class="sm-swatch swatch-c" style="display:block;aspect-ratio:3/2"></span></li>
114
- <li><label class="sm-empty" style="padding:8px;aspect-ratio:3/2" aria-label="Add photos" title="Add photos"><span class="sm-glyph" data-glyph="plus" aria-hidden="true"></span><input type="file" hidden multiple></label></li>
114
+ <!-- The add tile: StillMade opens its own picker for the named input and saves the files; they arrive through onInput. -->
115
+ <li><button type="button" class="sm-add" data-stillmade-add="listingPhotos" aria-label="Add photos" title="Add photos"></button></li>
115
116
  </ul>
116
117
  </div>
117
118
  <ol class="sm-list" data-peek>
@@ -1,97 +0,0 @@
1
- // Generated immutable package data.
2
- export default {
3
- "manifest": {
4
- "schemaVersion": 1,
5
- "sdkVersion": "0.1.0",
6
- "id": "stillmade.mcp-motion-planner",
7
- "name": "Motion Plan",
8
- "version": "1.1.0",
9
- "kind": "workspace",
10
- "runtime": "javascript",
11
- "entry": "src/run.js",
12
- "description": "Review a visual scene plan authored through StillMade MCP, adjust its source only when needed, and hand the approved structure to Frame Review locally.",
13
- "inputs": {
14
- "plan": {
15
- "type": "text",
16
- "primary": true,
17
- "required": false,
18
- "semantic": "project_brief",
19
- "sources": [
20
- "project",
21
- "user"
22
- ],
23
- "description": "A complete motion-design-package between BEGIN_MOTION_PLAN and END_MOTION_PLAN, or a concise fallback brief."
24
- },
25
- "brief": {
26
- "type": "text",
27
- "required": false,
28
- "description": "Optional plain-language fallback when an MCP-authored plan has not been supplied."
29
- }
30
- },
31
- "outputs": {
32
- "designPackage": {
33
- "type": "text",
34
- "primary": true,
35
- "role": "motion_design_package",
36
- "description": "Validated version 1 motion design package for Frame Review and Motion Designer."
37
- },
38
- "report": {
39
- "type": "metadata",
40
- "description": "Local scene-count, duration, source, and zero-credit validation report."
41
- }
42
- },
43
- "permissions": {
44
- "project": [],
45
- "actions": [],
46
- "network": [],
47
- "filesystem": [],
48
- "secrets": []
49
- },
50
- "ui": [
51
- {
52
- "control": "text",
53
- "port": "plan"
54
- }
55
- ],
56
- "platforms": {
57
- "phone": {
58
- "supported": true
59
- },
60
- "browser": {
61
- "supported": true
62
- },
63
- "desktop": {
64
- "supported": true
65
- }
66
- },
67
- "license": "MIT",
68
- "provenance": {
69
- "notice": "MIT License\n\nCopyright (c) <year> <copyright holders>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and \nassociated documentation files (the \"Software\"), to deal in the Software without restriction, including \nwithout limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell \ncopies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the \nfollowing conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial \nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT \nLIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO \nEVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER \nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE \nUSE OR OTHER DEALINGS IN THE SOFTWARE.\n"
70
- }
71
- },
72
- "code": "\n const text=value=>value==null?'':String(value),clone=value=>JSON.parse(JSON.stringify(value));\n const source=text(input.plan||input.brief).trim();\n const begin='BEGIN_MOTION_PLAN',end='END_MOTION_PLAN';\n let candidate=null;\n const start=source.indexOf(begin),finish=source.indexOf(end,start+begin.length);\n const encoded=start>=0&&finish>start?source.slice(start+begin.length,finish).trim():source;\n if(encoded.startsWith('{')){try{candidate=JSON.parse(encoded)}catch{throw new Error('The MCP motion plan is not valid JSON. Ask the connected assistant to repair the exact plan before continuing.')}}\n if(!candidate){\n const brief=source||'Create a concise product motion graphic.';\n candidate={schemaVersion:1,revision:'local-'+brief.length,kind:'motion-design-package',brief,audience:'Product-minded creative teams',creativeIntent:{idea:'Show the product as a living creative system',tone:'confident, precise, cinematic',visualLanguage:'editorial product UI, oversized type, clean vector geometry',motionCharacter:'restrained acceleration with decisive cuts',density:'open',avoid:['generic slideshow','floating mockup carousel','invented product claims']},constraints:{required:['Use only supplied product evidence and exact saved assets','Keep the composition editable'],preferences:['Prefer coded SVG, kinetic type, masks, camera moves, and real UI'],locks:[]},references:[],intendedOutputs:[{aspect:'16:9',durationSec:30,channel:'product launch'}],style:{background:'#0A0A0A',foreground:'#F7F0DB',accent:'#F2A93B',fontDirection:'editorial grotesk with monospace details'},product:{name:'StillMade',url:'',targetBuyer:'creative teams',promise:'Build complete visual productions from connected modular Blocks',availability:'',cta:{label:'Build with StillMade',destination:''},benefits:[]},scenes:[\n {id:'scene-1',goal:'Open with a singular promise',copy:{eyebrow:'STILLMADE',headline:'Make the whole thing.',support:'One connected creative system.'},durationSec:4,visualApproach:'Oversized masked typography and a precise vector aperture',layout:'centered poster',motionIntent:'restrained reveal, then sharp exit',assetIds:[],evidenceRefs:[],locks:[]},\n {id:'scene-2',goal:'Establish the modular workflow',copy:{eyebrow:'BLOCKS THAT WORK TOGETHER',headline:'From idea to final cut.',support:'Plan, review, design, and edit in one flow.'},durationSec:5,visualApproach:'Editable node path with semantic icons and cropped UI evidence when supplied',layout:'offset editorial',motionIntent:'measured camera push with sequential connections',assetIds:[],evidenceRefs:[],locks:[]},\n {id:'scene-3',goal:'Show visual review before animation',copy:{eyebrow:'APPROVE THE LOOK FIRST',headline:'See the frames. Then make them move.',support:'Choose a 3, 5, or 10 second review cadence.'},durationSec:5,visualApproach:'A grid of exact approved styleframes with one selected frame expanding full bleed',layout:'modular proof grid',motionIntent:'staggered tiles, magnetic selection, mask expansion',assetIds:[],evidenceRefs:[],locks:[]},\n {id:'scene-4',goal:'Reveal coded construction',copy:{eyebrow:'EDITABLE BY DESIGN',headline:'Real layers. Real timing. Real control.',support:'SVG, kinetic type, camera, transitions, and exact assets.'},durationSec:6,visualApproach:'Split view between coded vector layers and the live composition',layout:'copy on the left with product UI on the right',motionIntent:'typewriter detail, controlled parallax, precise callouts',assetIds:[],evidenceRefs:[],locks:[]},\n {id:'scene-5',goal:'Show the final editor handoff',copy:{eyebrow:'FINISH IN YOUR EDITOR',headline:'Polish without starting over.',support:'Every scene arrives as an editable timeline.'},durationSec:5,visualApproach:'Full-width timeline with layered motion scene clips and a final export target',layout:'full-bleed product UI',motionIntent:'timeline scrub, clip focus, restrained zoom',assetIds:[],evidenceRefs:[],locks:[]},\n {id:'scene-6',goal:'Close on the product promise',copy:{eyebrow:'STILLMADE',headline:'Make more than a clip.',support:'Build the system behind it.'},durationSec:5,visualApproach:'Return to the opening aperture as the product mark resolves',layout:'centered hero statement',motionIntent:'confident lockup and clean hold',assetIds:[],evidenceRefs:[],locks:[]}\n ],audio:{mode:'silent',assetIds:[],captions:[],notes:'Designed to work silently; optional sound design can accent transitions.'},unresolved:['Add exact StillMade UI screenshots or recordings as content assets before claiming visible product behavior.'],branch:{intent:'create',parentRevision:null}};\n }\n if(!candidate||Array.isArray(candidate)||candidate.schemaVersion!==1||candidate.kind!=='motion-design-package')throw new Error('Connect a version 1 motion-design-package authored by the StillMade MCP assistant.');\n if(!Array.isArray(candidate.scenes)||candidate.scenes.length<1||candidate.scenes.length>12)throw new Error('The MCP motion plan needs 1 to 12 scenes.');\n const ids=new Set();let duration=0;\n for(const scene of candidate.scenes){\n if(!scene||typeof scene!=='object'||Array.isArray(scene)||!text(scene.id).trim()||ids.has(scene.id))throw new Error('Every planned scene needs a distinct stable ID.');\n ids.add(scene.id);const seconds=Number(scene.durationSec);if(!Number.isFinite(seconds)||seconds<1||seconds>20)throw new Error('Every planned scene needs a duration from 1 to 20 seconds.');duration+=seconds;\n if(!scene.copy||typeof scene.copy!=='object'||!text(scene.copy.headline||scene.goal).trim())throw new Error('Every planned scene needs a communication goal or approved headline.');\n }\n if(duration>180)throw new Error('The complete MCP motion plan cannot exceed 180 seconds.');\n const plan=clone(candidate);plan.revision=text(plan.revision).trim()||'mcp-authored-1';plan.branch=plan.branch&&typeof plan.branch==='object'?plan.branch:{intent:'create',parentRevision:null};\n return {designPackage:JSON.stringify(plan),report:{schemaVersion:1,source:start>=0?'mcp-authored':'local-fallback',sceneCount:plan.scenes.length,durationSec:duration,creditCost:0,ready:true}};\n",
73
- "view": {
74
- "html": "<main class=\"planner\"><section class=\"overview\"><div class=\"ready\"><i class=\"plan-icon\" aria-hidden=\"true\"></i><div><small>CONNECTED PLAN</small><h2 id=\"planTitle\">Motion plan</h2></div></div><div class=\"metrics\" aria-label=\"Plan summary\"><span><i class=\"scene-icon\" aria-hidden=\"true\"></i><strong id=\"sceneCount\">—</strong> scenes</span><span><i class=\"time-icon\" aria-hidden=\"true\"></i><strong id=\"duration\">—</strong></span><span><i class=\"local-icon\" aria-hidden=\"true\"></i>Local · 0 credits</span></div><p id=\"idea\">Connect a brief or an assistant-authored plan to begin.</p><button id=\"use\" type=\"button\">Use this plan</button><output id=\"status\" role=\"status\">Waiting for a motion plan.</output></section><section class=\"storyboard\"><header><div><small>STORYBOARD</small><h2>Scenes and motion</h2></div><span id=\"format\">16:9</span></header><div id=\"scenes\" class=\"scenes\"></div></section><details><summary>Plan source</summary><p>Edit the structured source only when you need exact copy, timing, or scene IDs.</p><textarea id=\"source\" rows=\"14\" aria-label=\"Motion plan source\"></textarea></details></main>",
75
- "css": ".planner{container:motion-plan/inline-size;max-width:1160px;margin:0 auto;padding:12px;color:var(--fg);font-family:var(--font-body)}section,details{border:1px solid var(--border-tok);border-radius:var(--r-3);background:var(--bg-elev-1)}.overview{padding:20px}.ready,section header,.metrics,.metrics span,.scene-head,.scene-meta{display:flex;align-items:center}.ready{gap:12px}.ready h2,section header h2{margin:2px 0 0;font-family:var(--font-display);font-size:26px;font-style:italic;font-weight:200}.ready small,section header small,.scene small{font:600 11px/1.2 var(--font-mono);letter-spacing:.09em;color:var(--fg-muted)}.plan-icon{position:relative;width:30px;height:30px;border:1px solid var(--border-strong);border-radius:var(--r-2)}.plan-icon:before,.plan-icon:after{content:\"\";position:absolute;left:7px;right:7px;height:1px;background:var(--fg)}.plan-icon:before{top:10px;box-shadow:0 5px 0 var(--fg)}.plan-icon:after{top:20px;width:9px}.metrics{gap:8px;flex-wrap:wrap;margin:18px 0 12px}.metrics span,.scene-meta span{gap:7px;padding:7px 10px;border:1px solid var(--border-tok);border-radius:999px;color:var(--fg-muted);font-size:12px}.metrics strong{color:var(--fg)}.scene-icon,.local-icon{position:relative;width:14px;height:12px;border:1px solid currentColor}.scene-icon:after{content:\"\";position:absolute;inset:2px;border-top:1px solid currentColor;border-bottom:1px solid currentColor}.time-icon{position:relative;width:13px;height:13px;border:1px solid currentColor;border-radius:50%}.time-icon:before{content:\"\";position:absolute;left:6px;top:2px;width:1px;height:5px;background:currentColor;transform-origin:bottom;transform:rotate(-35deg)}.local-icon{border-radius:50%;width:12px;height:12px}.local-icon:after{content:\"\";position:absolute;left:3px;top:3px;width:4px;height:2px;border-left:1px solid currentColor;border-bottom:1px solid currentColor;transform:rotate(-45deg)}#idea{max-width:720px;margin:0 0 16px;color:var(--fg-muted);line-height:1.5}button{min-height:44px;padding:10px 18px;border:0;border-radius:999px;background:var(--fg);color:var(--bg);font:600 14px var(--font-body)}button:disabled{opacity:.5}output{display:inline-block;margin-left:12px;color:var(--fg-muted);font-size:13px}.storyboard{margin-top:12px;padding:20px}.storyboard>header{justify-content:space-between;gap:16px}.storyboard>header>span{font:600 12px var(--font-mono);color:var(--fg-muted)}.scenes{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:16px}.scene{min-width:0;padding:14px;border:1px solid var(--border-tok);border-radius:var(--r-2);background:var(--bg)}.scene-head{justify-content:space-between;gap:10px}.scene-index{font:600 11px var(--font-mono);color:var(--fg-muted)}.scene-duration{font:600 11px var(--font-mono);color:var(--fg)}.scene h3{margin:14px 0 6px;font-size:16px;line-height:1.15}.scene p{margin:0;color:var(--fg-muted);font-size:13px;line-height:1.4}.scene-meta{gap:6px;flex-wrap:wrap;margin-top:14px}.scene-meta span{padding:5px 8px;font-size:11px}.empty{grid-column:1/-1;padding:28px;text-align:center;color:var(--fg-muted)}details{margin-top:12px;padding:14px 16px}summary{cursor:pointer;font-weight:600}details p{color:var(--fg-muted);font-size:13px}textarea{box-sizing:border-box;width:100%;min-height:240px;padding:12px;border:1px solid var(--border-tok);border-radius:var(--r-2);background:var(--bg);color:var(--fg);font:12px/1.5 var(--font-mono);resize:vertical}@container motion-plan (max-width:760px){.scenes{grid-template-columns:repeat(2,minmax(0,1fr))}}@container motion-plan (max-width:500px){.planner{padding:4px}.overview,.storyboard{padding:14px}.scenes{grid-template-columns:1fr}output{display:block;margin:10px 0 0}}",
76
- "javascript": "const e=id=>document.getElementById(id),source=e('source'),button=e('use');let current=null;const text=value=>value==null?'':String(value);const read=value=>{const raw=text(value).trim(),begin='BEGIN_MOTION_PLAN',end='END_MOTION_PLAN',start=raw.indexOf(begin),finish=raw.indexOf(end,start+begin.length),encoded=start>=0&&finish>start?raw.slice(start+begin.length,finish).trim():raw;if(!encoded.startsWith('{'))return null;try{return JSON.parse(encoded)}catch{return null}};const card=(scene,index)=>({tag:'article',className:'scene',children:[{tag:'div',className:'scene-head',children:[{tag:'span',className:'scene-index',text:String(index+1).padStart(2,'0')},{tag:'span',className:'scene-duration',text:String(scene.durationSec||0)+'s'}]},{tag:'small',text:text(scene.copy&&scene.copy.eyebrow||scene.goal||'SCENE')},{tag:'h3',text:text(scene.copy&&scene.copy.headline||scene.goal||'Untitled scene')},{tag:'p',text:text(scene.visualApproach||scene.copy&&scene.copy.support||'Visual direction will be resolved in Frame Review.')},{tag:'div',className:'scene-meta',children:[{tag:'span',text:text(scene.layout||'Layout')},{tag:'span',text:text(scene.motionIntent||'Motion')}]}]});const show=plan=>{current=plan;const scenes=Array.isArray(plan&&plan.scenes)?plan.scenes:[],duration=scenes.reduce((sum,scene)=>sum+(Number(scene.durationSec)||0),0);e('sceneCount').textContent=scenes.length?String(scenes.length):'—';e('duration').textContent=scenes.length?String(duration)+' sec':'—';e('idea').textContent=text(plan&&plan.creativeIntent&&plan.creativeIntent.idea||plan&&plan.brief||'Connect a brief or an assistant-authored plan to begin.');e('format').textContent=text(plan&&plan.intendedOutputs&&plan.intendedOutputs[0]&&plan.intendedOutputs[0].aspect||'16:9');e('planTitle').textContent=text(plan&&plan.product&&plan.product.name?plan.product.name+' motion plan':'Motion plan');StillMade.render('scenes',scenes.length?scenes.map(card):[{tag:'p',className:'empty',text:'Your scene cards will appear here. The structured source stays out of the way.'}]);button.textContent=scenes.length?'Use this plan':'Create plan from brief'};StillMade.onInput(values=>{const incoming=values.plan||values.brief||'';source.value=incoming;show(read(incoming))});source.addEventListener('input',()=>show(read(source.value)));button.addEventListener('click',async()=>{button.disabled=true;e('status').textContent='Checking copy, timing, and scene IDs…';try{const result=await StillMade.run({plan:source.value});const plan=read(result.designPackage);show(plan);e('status').textContent=String(result.report.sceneCount)+' scenes · '+String(result.report.durationSec)+' seconds · ready for Frame Review.'}catch(error){e('status').textContent=error.message||'The plan could not be prepared.'}finally{button.disabled=false}});show(null);"
77
- },
78
- "tests": [
79
- {
80
- "name": "Build a zero-credit fallback motion plan",
81
- "input": {
82
- "brief": "Create a StillMade product-launch motion graphic."
83
- },
84
- "expected": {
85
- "designPackage": "{\"schemaVersion\":1,\"revision\":\"local-49\",\"kind\":\"motion-design-package\",\"brief\":\"Create a StillMade product-launch motion graphic.\",\"audience\":\"Product-minded creative teams\",\"creativeIntent\":{\"idea\":\"Show the product as a living creative system\",\"tone\":\"confident, precise, cinematic\",\"visualLanguage\":\"editorial product UI, oversized type, clean vector geometry\",\"motionCharacter\":\"restrained acceleration with decisive cuts\",\"density\":\"open\",\"avoid\":[\"generic slideshow\",\"floating mockup carousel\",\"invented product claims\"]},\"constraints\":{\"required\":[\"Use only supplied product evidence and exact saved assets\",\"Keep the composition editable\"],\"preferences\":[\"Prefer coded SVG, kinetic type, masks, camera moves, and real UI\"],\"locks\":[]},\"references\":[],\"intendedOutputs\":[{\"aspect\":\"16:9\",\"durationSec\":30,\"channel\":\"product launch\"}],\"style\":{\"background\":\"#0A0A0A\",\"foreground\":\"#F7F0DB\",\"accent\":\"#F2A93B\",\"fontDirection\":\"editorial grotesk with monospace details\"},\"product\":{\"name\":\"StillMade\",\"url\":\"\",\"targetBuyer\":\"creative teams\",\"promise\":\"Build complete visual productions from connected modular Blocks\",\"availability\":\"\",\"cta\":{\"label\":\"Build with StillMade\",\"destination\":\"\"},\"benefits\":[]},\"scenes\":[{\"id\":\"scene-1\",\"goal\":\"Open with a singular promise\",\"copy\":{\"eyebrow\":\"STILLMADE\",\"headline\":\"Make the whole thing.\",\"support\":\"One connected creative system.\"},\"durationSec\":4,\"visualApproach\":\"Oversized masked typography and a precise vector aperture\",\"layout\":\"centered poster\",\"motionIntent\":\"restrained reveal, then sharp exit\",\"assetIds\":[],\"evidenceRefs\":[],\"locks\":[]},{\"id\":\"scene-2\",\"goal\":\"Establish the modular workflow\",\"copy\":{\"eyebrow\":\"BLOCKS THAT WORK TOGETHER\",\"headline\":\"From idea to final cut.\",\"support\":\"Plan, review, design, and edit in one flow.\"},\"durationSec\":5,\"visualApproach\":\"Editable node path with semantic icons and cropped UI evidence when supplied\",\"layout\":\"offset editorial\",\"motionIntent\":\"measured camera push with sequential connections\",\"assetIds\":[],\"evidenceRefs\":[],\"locks\":[]},{\"id\":\"scene-3\",\"goal\":\"Show visual review before animation\",\"copy\":{\"eyebrow\":\"APPROVE THE LOOK FIRST\",\"headline\":\"See the frames. Then make them move.\",\"support\":\"Choose a 3, 5, or 10 second review cadence.\"},\"durationSec\":5,\"visualApproach\":\"A grid of exact approved styleframes with one selected frame expanding full bleed\",\"layout\":\"modular proof grid\",\"motionIntent\":\"staggered tiles, magnetic selection, mask expansion\",\"assetIds\":[],\"evidenceRefs\":[],\"locks\":[]},{\"id\":\"scene-4\",\"goal\":\"Reveal coded construction\",\"copy\":{\"eyebrow\":\"EDITABLE BY DESIGN\",\"headline\":\"Real layers. Real timing. Real control.\",\"support\":\"SVG, kinetic type, camera, transitions, and exact assets.\"},\"durationSec\":6,\"visualApproach\":\"Split view between coded vector layers and the live composition\",\"layout\":\"copy on the left with product UI on the right\",\"motionIntent\":\"typewriter detail, controlled parallax, precise callouts\",\"assetIds\":[],\"evidenceRefs\":[],\"locks\":[]},{\"id\":\"scene-5\",\"goal\":\"Show the final editor handoff\",\"copy\":{\"eyebrow\":\"FINISH IN YOUR EDITOR\",\"headline\":\"Polish without starting over.\",\"support\":\"Every scene arrives as an editable timeline.\"},\"durationSec\":5,\"visualApproach\":\"Full-width timeline with layered motion scene clips and a final export target\",\"layout\":\"full-bleed product UI\",\"motionIntent\":\"timeline scrub, clip focus, restrained zoom\",\"assetIds\":[],\"evidenceRefs\":[],\"locks\":[]},{\"id\":\"scene-6\",\"goal\":\"Close on the product promise\",\"copy\":{\"eyebrow\":\"STILLMADE\",\"headline\":\"Make more than a clip.\",\"support\":\"Build the system behind it.\"},\"durationSec\":5,\"visualApproach\":\"Return to the opening aperture as the product mark resolves\",\"layout\":\"centered hero statement\",\"motionIntent\":\"confident lockup and clean hold\",\"assetIds\":[],\"evidenceRefs\":[],\"locks\":[]}],\"audio\":{\"mode\":\"silent\",\"assetIds\":[],\"captions\":[],\"notes\":\"Designed to work silently; optional sound design can accent transitions.\"},\"unresolved\":[\"Add exact StillMade UI screenshots or recordings as content assets before claiming visible product behavior.\"],\"branch\":{\"intent\":\"create\",\"parentRevision\":null}}",
86
- "report": {
87
- "schemaVersion": 1,
88
- "source": "local-fallback",
89
- "sceneCount": 6,
90
- "durationSec": 30,
91
- "creditCost": 0,
92
- "ready": true
93
- }
94
- }
95
- }
96
- ]
97
- };