stillmade-sdk 0.1.40 → 0.1.42

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 (63) hide show
  1. package/.stillmade/sdk-baseline.json +19 -19
  2. package/AGENTS.md +6 -2
  3. package/FRAME_VIEWS.md +41 -0
  4. package/INTERFACE_DESIGN.md +100 -8
  5. package/MOBILE_UI.md +3 -1
  6. package/PASTE_TO_LLM.md +18 -13
  7. package/SDK.md +200 -37
  8. package/UI_AESTHETIC.md +93 -4
  9. package/examples/check-clip.stillmade.json +4 -0
  10. package/examples/clean-text.stillmade.json +4 -0
  11. package/examples/custom-interface.stillmade.json +4 -0
  12. package/examples/describe-image.stillmade.json +4 -0
  13. package/examples/foley-cue.stillmade.json +4 -0
  14. package/examples/generate-image.stillmade.json +4 -0
  15. package/examples/generate-video.stillmade.json +4 -0
  16. package/examples/module-word-stats/stillmade.block.json +4 -0
  17. package/examples/narrate-script.stillmade.json +4 -0
  18. package/examples/numbered-takes.stillmade.json +4 -0
  19. package/examples/research-topic.stillmade.json +4 -0
  20. package/examples/score-a-scene.stillmade.json +4 -0
  21. package/examples/script-draft.stillmade.json +4 -0
  22. package/examples/summarize-page.stillmade.json +4 -0
  23. package/examples/text-workflow.stillmade.json +4 -0
  24. package/examples/thicken-lines.stillmade.json +4 -0
  25. package/examples/timeline-polish.stillmade.json +4 -0
  26. package/examples/transcribe-audio.stillmade.json +4 -0
  27. package/examples/word-count.stillmade.json +4 -0
  28. package/package.json +1 -1
  29. package/packages/block-cli/dev-host/assets/host.js +208 -37
  30. package/packages/block-cli/dev-host/assets/index.css +1 -1
  31. package/packages/block-cli/ready-gate.js +4 -0
  32. package/packages/block-cli/templates.js +7 -7
  33. package/packages/block-platform/block-readiness.js +24 -2
  34. package/packages/block-platform/canvas.js +17 -0
  35. package/packages/block-platform/catalog.js +21 -6
  36. package/packages/block-platform/host-release-manifests.js +95 -0
  37. package/packages/block-platform/native-host-inventory.js +29 -4
  38. package/packages/block-platform/node-defaults.js +1 -0
  39. package/packages/block-platform/project-context.js +1 -1
  40. package/packages/block-platform/script-handoff.js +1 -1
  41. package/packages/block-platform/step-groups.js +3 -1
  42. package/packages/block-sdk/audio-generation-example.js +2 -2
  43. package/packages/block-sdk/builder-contract.js +15 -4
  44. package/packages/block-sdk/capability-example.js +1 -1
  45. package/packages/block-sdk/contracts.js +3 -1
  46. package/packages/block-sdk/examples.js +3 -3
  47. package/packages/block-sdk/image-description-example.js +1 -1
  48. package/packages/block-sdk/image-generation-example.js +1 -1
  49. package/packages/block-sdk/index.d.ts +2 -2
  50. package/packages/block-sdk/media-analysis-example.js +1 -1
  51. package/packages/block-sdk/module-example.js +1 -1
  52. package/packages/block-sdk/speech-example.js +1 -1
  53. package/packages/block-sdk/state-example.js +1 -1
  54. package/packages/block-sdk/timeline-proposal-example.js +1 -1
  55. package/packages/block-sdk/transcription-example.js +1 -1
  56. package/packages/block-sdk/trigger-examples.js +2 -2
  57. package/packages/block-sdk/video-generation-example.js +1 -1
  58. package/packages/block-sdk/view-design.js +119 -18
  59. package/packages/block-sdk/web-example.js +2 -2
  60. package/packages/block-sdk/workspace-navigation.js +6 -2
  61. package/packages/design-system/block-kit.css +33 -6
  62. package/packages/design-system/block-kit.html +14 -4
  63. package/packages/design-system/theme.css +6 -5
package/SDK.md CHANGED
@@ -201,7 +201,7 @@ The archive needs Node.js 22 or later and nothing else; its runtime is bundled,
201
201
 
202
202
  ## Block builder contract
203
203
 
204
- Contract `stillmade.block-builder@1.12.0`. Humans, coding agents, imported source, GitHub repositories and generated code all adapt to the Block platform; anything that becomes a StillMade Block obeys this contract.
204
+ Contract `stillmade.block-builder@1.17.0`. Humans, coding agents, imported source, GitHub repositories and generated code all adapt to the Block platform; anything that becomes a StillMade Block obeys this contract.
205
205
 
206
206
  ### Source of truth
207
207
 
@@ -263,9 +263,13 @@ Give the Block a short, plain name of 40 characters or fewer that says what it d
263
263
 
264
264
  Name each input for what the person brings, in the job's words: `sermonVideo` for a sermon clip Block, `listingPhotos` for a listing, `lessonSlides` for a lesson podcast. StillMade titles the input from that name ("Sermon video") and words its drop area from it ("Drop your sermon video here", the formats, "Choose a video"), in StillMade and the SDK preview, so never draw your own upload box for an input. Keep a bare type name (`video`, `file`) only when any file of that kind does the job. The `description` says what makes a good one.
265
265
 
266
+ ### Speak the job
267
+
268
+ These are StillMade's defaults: unless the person or the creator asked for something else, every screen speaks the job in its own words and adds nothing else. `manifest.action` names the Step's button, {label:"Plan the tour", running:"Planning the tour…"}, and StillMade adds the price ("Plan the tour · 1 credit"). Every Block whose Step shows StillMade's button declares it: any Block without its own screen, and any that calls operations. Without it StillMade can only guess from the Block's name or output ("Make clips"), and the readiness gate and StillMade's own builder send the Block back until it names the job. When the Block makes a picture, video or sound with AI the label starts with Generate and says what ("Generate tour", "Generate voiceover"); one that cuts or renders the person's own media says Make ("Make 6 clips"); never "Make it", "Run", "Submit", "Process" or a bare "Generate". The main button stands out: one solid `sm-primary` in the kit's ink, never restyled to the background; everything else is `sm-quiet` or an `sm-icon`, and close is an X icon. Report progress in the job's units with `stillmade.progress(fraction, label)` ("Moving through the kitchen, 4 of 9 rooms"), never "Processing". Head the result in the job's words ("9 rooms", "Your tour · 44 s"), never "Output". Say a problem in one line with its fix beside it ("No bathroom photo. Guests look for one." and Add photo). Stay quiet: no welcome text, tips under fields, tours or banners, and at most one line of guidance on a screen, only where the next move is not obvious; anything more goes in the input's `description`, which StillMade shows behind an (i). Say nothing about how the Block works (where it runs, saving, syncing, recovery, accounts, credits) or where a file is kept: StillMade tells the person what they need as one short notification, or nothing; never a sentence on the page, and never the same line under each item. Every drop area offers "Use a reference", which fills the Step from the person's saved photos, videos and notes: media inputs fill by kind, so take `video` or `asset` where a clip works as well as a photo, and text inputs fill by plain names and labels (`productName`, `website`, `brandColors`, `fonts`, `voice`, and `details` or `notes` for the reference's note); never build your own reference picker. Days and times are picked, never typed: use the `date` type, which StillMade shows as a calendar, with a list of times when the input is about a time (`postAt`, `startsAt`); a custom view uses `<input type="date">` or `type="datetime-local"`. Posting is a connector Step of its own, and StillMade words its button from the app and action ("Post to Instagram"). Before handing the Block back, clear every Wording note that `gate` and readiness list, unless the person asked for those words.
269
+
266
270
  ### Interface
267
271
 
268
- If the capability needs UI, use the Block UI SDK: generated `manifest.ui` controls first; a sandboxed custom view (`view.html`/`view.css`/`view.js`) only when the core interaction needs one. Build custom views from the Block kit the host injects (`block-kit.css`): the result in `sm-stage`, picks as pictures in `sm-choices`, one `sm-primary` naming the action (Write, Generate; never "Run") and no price (StillMade's run button adds it), extras in a closed `sm-more`; a look the person names wins. Fit one laptop screen without scrolling: label beside control, status in a few words, files as tiles, rare tools as icons, (i) on unclear controls. These compact rules are for a job or an ingredient. Size the view to the Block's tier (block-tier.js): an app, a workspace a person works in for a while (video editor, 3D configurator, CAD or drawing tool), looks and works like that kind of app instead of a compact page: its canvas or stage fills the view, with the panels, toolbars, inspector or timeline such an app has, direct manipulation (select, drag, zoom), keyboard shortcuts and undo; it keeps the host appearance and Block kit controls, its panels may scroll, and on a phone its tools fold into sheets while the canvas stays usable. Never shrink an app into a form of fields and one button. Drop words nobody needs; put helpful ones in a closed `sm-hint`. Mark each button `data-stillmade-action="what it does"` and label each field: Chat presses and fills them. Expose the capability, not the implementation: sensible defaults, previews, progress, clear errors, visible outputs. Show no raw JSON, internal IDs, filesystem details, provider terms or developer settings unless the Block is a developer tool. When a person chooses among options they need to hear or see (voices, music, fonts, looks, templates, images), let them preview each option before choosing: a sample or thumbnail from the Block's own files or the host's free samples, never a paid generation. Skip previews only when there is nothing to preview. Choices StillMade owns (voices, models in the run review) already show samples. Follow the host appearance (Light, Dark and White) and one elastic layout: stacked on a 320px phone with no sideways scroll (result first, action pinned), and from 860px the controls left (≤380px), the result filling the right. Short settings sit side by side, each label beside its control (`sm-field`, `sm-settings`; three or four short options as one `data-segmented` row); many items are one line each (`sm-list`) that open in place; input files are small tiles (`sm-gallery data-size="small"`); on a phone chip rows scroll sideways and long lists show three. Compacting moves controls, never deletes them.
272
+ If the capability needs UI, use the Block UI SDK: generated `manifest.ui` controls first; a sandboxed custom view (`view.html`/`view.css`/`view.js`) only when the core interaction needs one. Build custom views from the Block kit the host injects (`block-kit.css`): the result in `sm-stage`, picks as pictures in `sm-choices`, the picked one in the kit's ink fill (never restyled to an outline, a tint or the page's background) so it reads at a glance, one solid `sm-primary` naming the action in the job's words ("Plan the tour", "Generate voiceover"; never "Run" or "Make it") and no price (StillMade's run button adds it), extras in a closed `sm-more`; a look the person names wins. Fit one laptop screen without scrolling: label beside control, status in a few words, files as tiles, rare tools as icons, (i) on unclear controls. These compact rules are for a job or an ingredient. Size the view to the Block's tier (block-tier.js): an app, a workspace a person works in for a while (video editor, 3D configurator, CAD or drawing tool), looks and works like that kind of app instead of a compact page: its canvas or stage fills the view, with the panels, toolbars, inspector or timeline such an app has, direct manipulation (select, drag, zoom), keyboard shortcuts and undo; it keeps the host appearance and Block kit controls, its panels may scroll, and on a phone its tools fold into sheets while the canvas stays usable. Never shrink an app into a form of fields and one button. StillMade centers a standard view narrower than its Step and zooms a view to fill its space; 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. StillMade draws one player for every `<video controls>` (play, timeline, time, sound and full screen, shown while the pointer is on the video, with keys and touch) and a full-screen button on result pictures in `sm-stage` or `sm-gallery` and on any element marked `data-stillmade-expand` (the same value makes one set of pictures, `off` removes it); `data-stillmade-player="native"` keeps the browser's controls, and a `<video>` without `controls` is the Block's own and is never touched. A picture or clip that cannot show here (kept on another device, or it did not open) keeps its place as a quiet `sm-media-off` tile in its own shape with the `image-off` glyph and the reason in its label, never words in its place. Drop words nobody needs; put helpful ones in a closed `sm-hint`. Mark each button `data-stillmade-action="what it does"` and label each field: Chat presses and fills them. Expose the capability, not the implementation: sensible defaults, previews, progress, clear errors, visible outputs. Show no raw JSON, internal IDs, filesystem details, provider terms or developer settings unless the Block is a developer tool. When a person chooses among options they need to hear or see (voices, music, fonts, looks, templates, images), let them preview each option before choosing: a sample or thumbnail from the Block's own files or the host's free samples, never a paid generation. Skip previews only when there is nothing to preview. Choices StillMade owns (voices, models in the run review) already show samples. Follow the host appearance (Light, Dark and White) and one elastic layout: stacked on a 320px phone with no sideways scroll (result first, action pinned), and from 860px the controls left (≤380px), the result filling the right. Short settings sit side by side, each label beside its control (`sm-field`, `sm-settings`; three or four short options as one `data-segmented` row); many items are one line each (`sm-list`) that open in place; input files are small tiles (`sm-gallery data-size="small"`); on a phone chip rows scroll sideways and long lists show three. Compacting moves controls, never deletes them.
269
273
 
270
274
  ### Shared editing
271
275
 
@@ -1020,6 +1024,9 @@ inline handlers, links, file inputs, network attributes, and raw HTML are reject
1020
1024
  `await StillMade.previewMedia(reference)` opens an authorized `audio` or `video`
1021
1025
  reference as a temporary playback copy and returns `{kind, url, mimeType, bytes}`.
1022
1026
  Assign its URL to an existing `<audio controls>` or `<video controls>` element.
1027
+ StillMade plays a `<video controls>` in its own player, with full screen; leave
1028
+ out `controls` when the Block drives playback itself, or add
1029
+ `data-stillmade-player="native"` to keep the browser's controls.
1023
1030
  The host requires an exact reference from this Block’s bound input, an explicitly
1024
1031
  selected project asset, permitted project context, or a host-recorded output.
1025
1032
  A URL alone is insufficient. Preview has host file pickers for audio/video inputs;
@@ -1741,6 +1748,47 @@ rest. Colors written with them follow Light, Dark and White automatically.
1741
1748
  Frame views are not required to use them; the appearance check reports
1742
1749
  hard-coded colors as advice instead of refusing the view.
1743
1750
 
1751
+ ### Layout
1752
+
1753
+ StillMade zooms a view to fill the space its Step gives it (up to 150%), and
1754
+ Ctrl/Cmd +, - and 0 size the view while it has focus. It never centers a frame
1755
+ view; a standard view narrower than its Step is centered by its margins.
1756
+
1757
+ An app that lays itself out (a full-size canvas or WebGL, its own scroll, pan
1758
+ or zoom, its own Ctrl/Cmd +/- keys, as in a CAD or drawing tool) puts
1759
+ `data-stillmade-layout="own"` on its outermost element:
1760
+
1761
+ ```html
1762
+ <div id="root" data-stillmade-layout="own"></div>
1763
+ ```
1764
+
1765
+ StillMade then never centers or zooms it and leaves Ctrl/Cmd +, - and 0 to the
1766
+ app. Without the attribute StillMade also stays out of the way when the view
1767
+ looks like an app: no page padding, a clipped page, a root as tall as the frame,
1768
+ fixed over half of it or scrolling over half of it, a canvas, SVG or
1769
+ `touch-action: none` surface over 40% of it, or a canvas or SVG of 300x200 or
1770
+ more with `touch-action: none` (as Three.js's controls set it). Mark the root
1771
+ anyway, in `view.html` rather than from code: StillMade reads it before the view
1772
+ starts, so the app never shows StillMade's size control or loses a key to it,
1773
+ even while it is still loading.
1774
+
1775
+ A `<video controls>` plays in StillMade's player, the same one as everywhere in
1776
+ StillMade: play, timeline, time, sound and full screen along the bottom, shown
1777
+ while the pointer is on the video, with keys on the focused video (Space or K,
1778
+ the arrows, M, F) and touch. Full screen goes through StillMade, right after a
1779
+ click or key in the view; the frame itself has no `allow="fullscreen"`. A
1780
+ `<video>` without `controls` is the Block's own and StillMade never touches it,
1781
+ so a Block that drives playback (its own timeline, an editor or CAD viewer)
1782
+ leaves `controls` out, and `data-stillmade-player="native"` keeps the browser's
1783
+ controls. Result pictures from `StillMade.previewImage` in `sm-stage` or
1784
+ `sm-gallery`, and any element marked `data-stillmade-expand`, get a full-screen
1785
+ button in the bottom-right corner while the pointer is on them; pictures with
1786
+ the same value (`data-stillmade-expand="shots"`) open as one set, and
1787
+ `data-stillmade-expand="off"` removes the button. The keyboard reaches them
1788
+ too: such a picture without a `tabindex` of its own joins the tab order,
1789
+ keyboard focus on it shows the button, Enter or Space opens the viewer, and
1790
+ closing the viewer gives the focus back to the picture.
1791
+
1744
1792
  ### Assets
1745
1793
 
1746
1794
  Images, fonts, JSON, audio and video the view needs ship as files named by
@@ -2851,6 +2899,10 @@ mutate the input or commit changes to a project. `BlockError` includes `code` an
2851
2899
  },
2852
2900
  "sdkVersion": "0.1.0",
2853
2901
  "id": "example.clean-text",
2902
+ "action": {
2903
+ "label": "Clean text",
2904
+ "running": "Cleaning text…"
2905
+ },
2854
2906
  "version": "1.0.0",
2855
2907
  "name": "Clean text",
2856
2908
  "description": "Trims extra space from text and returns a clean copy for the next step.",
@@ -3000,6 +3052,10 @@ delivery through it; an extracted source folder does not satisfy this boundary.
3000
3052
  },
3001
3053
  "sdkVersion": "0.1.0",
3002
3054
  "id": "example.thicken-lines",
3055
+ "action": {
3056
+ "label": "Thicken lines",
3057
+ "running": "Thickening lines…"
3058
+ },
3003
3059
  "version": "1.0.1",
3004
3060
  "name": "Thicken line art",
3005
3061
  "description": "Expands dark outlines in an image while preserving surrounding colors, creating a new image for the next production step.",
@@ -3330,6 +3386,10 @@ Use saved memory for small counters or preferences that belong to one placement.
3330
3386
  "schemaVersion": 1,
3331
3387
  "sdkVersion": "0.1.0",
3332
3388
  "id": "example.numbered-takes",
3389
+ "action": {
3390
+ "label": "Number takes",
3391
+ "running": "Numbering takes…"
3392
+ },
3333
3393
  "version": "1.0.0",
3334
3394
  "name": "Numbered takes",
3335
3395
  "description": "Label successive creative takes with an independent counter for each production placement.",
@@ -5526,6 +5586,10 @@ Recipe packages contain `manifest`, `recipe`, and `tests`. JavaScript packages c
5526
5586
  },
5527
5587
  "sdkVersion": "0.1.0",
5528
5588
  "id": "example.word-count",
5589
+ "action": {
5590
+ "label": "Count words",
5591
+ "running": "Counting words…"
5592
+ },
5529
5593
  "version": "1.0.0",
5530
5594
  "name": "Word count",
5531
5595
  "description": "Counts words and returns trimmed text using isolated JavaScript.",
@@ -6028,7 +6092,7 @@ export interface BlockViewBridge { connectDocument(options:import('./document-st
6028
6092
  export interface SdkCompatibility { status:'supported'|'unsupported'|'invalid'; declared:unknown; runtimeVersion:string; message:string; }
6029
6093
  export function sdkCompatibility(declared:unknown,runtimeVersion?:string):SdkCompatibility;
6030
6094
  export type Port = { type: string; imageMode?: 'pixels'|'reference'; role?: string; context?: keyof typeof CONTEXT_FIELDS; primary?: boolean; required?: boolean; default?: unknown; min?: number; max?: number; description?: string } & Partial<import('./semantic-contracts.js').SemanticContract>;
6031
- export interface Manifest { schemaVersion: 1; id: string; name: string; version: string; sdkVersion: SdkVersionRange; description: string; kind: 'task'|'workspace'|'editor-extension'|'composite'; inputs: Record<string, Port>; outputs: Record<string, Port>; runtime: 'recipe'|'javascript'|'module'|'comfyui'|'capability'; jobs?: {kind:'cooperative';version:1}; state?: {scope:'step';version:number;initial:Record<string,unknown>;migrations?:StateMigration[]}; entry?: string; permissions: { project: string[]; desktop?: DesktopPermission[]; capabilities?: ['comfyui.execute']|['text.generate']|['audio.speech']|['audio.transcribe']|['image.generate']|['video.generate']|['image.describe']|['timeline.propose']|['workspace.propose']|['connection.execute']; network?: never[]; filesystem?: never[]; secrets?: never[] }; desktopTools?:DesktopToolDeclaration[]; uiLayout?: {kind:'tabs'|'sections';groups:{id:string;label:string;inputs:string[];outputs:string[];collapsed?:boolean}[]}; ui?: ({ control: 'text'|'number'|'slider'|'checkbox'|'asset'; port: string; label?: string; when?: {port:string;equals:string|boolean} } | {control:'select'|'multiselect';port:string;options:string[];label?:string;when?:{port:string;equals:string|boolean}} | {control:'gallery';port:string;label?:string} | {control:'before-after';port:string;before:string;label?:string})[]; }
6095
+ export interface Manifest { schemaVersion: 1; id: string; name: string; version: string; sdkVersion: SdkVersionRange; description: string; action?: { label: string; running?: string }; kind: 'task'|'workspace'|'editor-extension'|'composite'; inputs: Record<string, Port>; outputs: Record<string, Port>; runtime: 'recipe'|'javascript'|'module'|'comfyui'|'capability'; jobs?: {kind:'cooperative';version:1}; state?: {scope:'step';version:number;initial:Record<string,unknown>;migrations?:StateMigration[]}; entry?: string; permissions: { project: string[]; desktop?: DesktopPermission[]; capabilities?: ['comfyui.execute']|['text.generate']|['audio.speech']|['audio.transcribe']|['image.generate']|['video.generate']|['image.describe']|['timeline.propose']|['workspace.propose']|['connection.execute']; network?: never[]; filesystem?: never[]; secrets?: never[] }; desktopTools?:DesktopToolDeclaration[]; uiLayout?: {kind:'tabs'|'sections';groups:{id:string;label:string;inputs:string[];outputs:string[];collapsed?:boolean}[]}; ui?: ({ control: 'text'|'number'|'slider'|'checkbox'|'asset'; port: string; label?: string; when?: {port:string;equals:string|boolean} } | {control:'select'|'multiselect';port:string;options:string[];label?:string;when?:{port:string;equals:string|boolean}} | {control:'gallery';port:string;label?:string} | {control:'before-after';port:string;before:string;label?:string})[]; }
6032
6096
  export interface BlockView { html: string; css?: string; themedCss?: string; javascript?: string; appearance?: 'host'|'original'; }
6033
6097
  /** A frame view: any interface code (frameworks, SVG, canvas, drag) with assets named by SHA-256. */
6034
6098
  export interface FrameView { runtime: 'frame'; html: string; css?: string; themedCss?: string; javascript?: string; appearance?: 'host'|'original'; files?: {schemaVersion: 1; files: Record<string, {sha256: string; bytes: number; mediaType: string}>}; }
@@ -6428,7 +6492,7 @@ export * from './native-host-providers.js';
6428
6492
 
6429
6493
  export {blockRemixPolicy,assertRemixReady,REMIX_AUTHORING_REQUIREMENT} from './remix-policy.js';
6430
6494
  export interface SdkCompatibility {status:'supported'|'unsupported'|'invalid';declared:unknown;runtimeVersion:string;message:string}
6431
- export interface Manifest { schemaVersion: 1; id: string; name: string; version: string; sdkVersion: SdkVersionRange; description: string; kind: 'task'|'workspace'|'editor-extension'|'composite'; inputs: Record<string, Port>; outputs: Record<string, Port>; runtime: 'recipe'|'javascript'|'module'|'comfyui'|'capability'; jobs?: {kind:'cooperative';version:1}; state?: {scope:'step';version:number;initial:Record<string,unknown>;migrations?:StateMigration[]}; entry?: string; permissions: { project: string[]; desktop?: DesktopPermission[]; capabilities?: ['comfyui.execute']|['text.generate']|['audio.speech']|['audio.transcribe']|['image.generate']|['video.generate']|['image.describe']|['timeline.propose']|['workspace.propose']|['connection.execute']; network?: never[]; filesystem?: never[]; secrets?: never[] }; uiLayout?: {kind:'tabs'|'sections';groups:{id:string;label:string;inputs:string[];outputs:string[];collapsed?:boolean}[]}; ui?: ({ control: 'text'|'number'|'slider'|'checkbox'|'asset'; port: string; label?: string; when?: {port:string;equals:string|boolean} } | {control:'select'|'multiselect';port:string;options:string[];label?:string;when?:{port:string;equals:string|boolean}} | {control:'gallery';port:string;label?:string} | {control:'before-after';port:string;before:string;label?:string})[]; }
6495
+ export interface Manifest { schemaVersion: 1; id: string; name: string; version: string; sdkVersion: SdkVersionRange; description: string; action?: { label: string; running?: string }; kind: 'task'|'workspace'|'editor-extension'|'composite'; inputs: Record<string, Port>; outputs: Record<string, Port>; runtime: 'recipe'|'javascript'|'module'|'comfyui'|'capability'; jobs?: {kind:'cooperative';version:1}; state?: {scope:'step';version:number;initial:Record<string,unknown>;migrations?:StateMigration[]}; entry?: string; permissions: { project: string[]; desktop?: DesktopPermission[]; capabilities?: ['comfyui.execute']|['text.generate']|['audio.speech']|['audio.transcribe']|['image.generate']|['video.generate']|['image.describe']|['timeline.propose']|['workspace.propose']|['connection.execute']; network?: never[]; filesystem?: never[]; secrets?: never[] }; uiLayout?: {kind:'tabs'|'sections';groups:{id:string;label:string;inputs:string[];outputs:string[];collapsed?:boolean}[]}; ui?: ({ control: 'text'|'number'|'slider'|'checkbox'|'asset'; port: string; label?: string; when?: {port:string;equals:string|boolean} } | {control:'select'|'multiselect';port:string;options:string[];label?:string;when?:{port:string;equals:string|boolean}} | {control:'gallery';port:string;label?:string} | {control:'before-after';port:string;before:string;label?:string})[]; }
6432
6496
  export interface BlockPackage { portable?: PortableMetadata; manifest: Manifest; view?: BlockView|FrameView; code?: string; module?: ModuleDescriptor; comfyui?: ComfyWorkflow; capability?: ConnectedCapability|TextGenerationCapability|SpeechCapability|TranscriptionCapability|ImageGenerationCapability|VideoGenerationCapability|ImageDescriptionCapability|TimelineProposalCapability; recipe?: { schemaVersion: 1; steps: { id: string; op: string; args: Record<string, unknown> }[]; outputs: Record<string, unknown> }; tests: { name: string; input: Record<string, unknown>; expected?: Record<string, unknown>; state?: BlockState; expectedState?: BlockState; expectations?: Record<string, ConnectedResultExpectation|ComfyImageExpectation|CapabilityTextExpectation|CapabilityAudioExpectation|CapabilityTranscriptExpectation|CapabilityImageExpectation|CapabilityVideoExpectation|CapabilityTimelineExpectation> }[]; }
6433
6497
  export type CapabilityInvocation = TextGenerationInvocation|SpeechInvocation|TranscriptionInvocation|ImageGenerationInvocation|VideoGenerationInvocation|ImageDescriptionInvocation|TimelineProposalInvocation;
6434
6498
  export interface CapabilityResult { outputs: Record<string, unknown>; metadata?: Record<string, unknown>; mediaReceipts?: Record<string, SpeechMediaReceipt|GeneratedAudioMediaReceipt|GeneratedImageMediaReceipt|GeneratedVideoMediaReceipt>; }
@@ -7389,9 +7453,9 @@ Ask the assistant to return source files or one `.stillmade.json` package. Run t
7389
7453
 
7390
7454
  <!-- builder-contract:start (generated by npm run build:sdk; do not edit) -->
7391
7455
 
7392
- ### Block builder contract (stillmade.block-builder@1.12.0)
7456
+ ### Block builder contract (stillmade.block-builder@1.17.0)
7393
7457
 
7394
- Contract `stillmade.block-builder@1.12.0`. Humans, coding agents, imported source, GitHub repositories and generated code all adapt to the Block platform; anything that becomes a StillMade Block obeys this contract.
7458
+ Contract `stillmade.block-builder@1.17.0`. Humans, coding agents, imported source, GitHub repositories and generated code all adapt to the Block platform; anything that becomes a StillMade Block obeys this contract.
7395
7459
 
7396
7460
  ### Source of truth
7397
7461
 
@@ -7453,9 +7517,13 @@ Give the Block a short, plain name of 40 characters or fewer that says what it d
7453
7517
 
7454
7518
  Name each input for what the person brings, in the job's words: `sermonVideo` for a sermon clip Block, `listingPhotos` for a listing, `lessonSlides` for a lesson podcast. StillMade titles the input from that name ("Sermon video") and words its drop area from it ("Drop your sermon video here", the formats, "Choose a video"), in StillMade and the SDK preview, so never draw your own upload box for an input. Keep a bare type name (`video`, `file`) only when any file of that kind does the job. The `description` says what makes a good one.
7455
7519
 
7520
+ ### Speak the job
7521
+
7522
+ These are StillMade's defaults: unless the person or the creator asked for something else, every screen speaks the job in its own words and adds nothing else. `manifest.action` names the Step's button, {label:"Plan the tour", running:"Planning the tour…"}, and StillMade adds the price ("Plan the tour · 1 credit"). Every Block whose Step shows StillMade's button declares it: any Block without its own screen, and any that calls operations. Without it StillMade can only guess from the Block's name or output ("Make clips"), and the readiness gate and StillMade's own builder send the Block back until it names the job. When the Block makes a picture, video or sound with AI the label starts with Generate and says what ("Generate tour", "Generate voiceover"); one that cuts or renders the person's own media says Make ("Make 6 clips"); never "Make it", "Run", "Submit", "Process" or a bare "Generate". The main button stands out: one solid `sm-primary` in the kit's ink, never restyled to the background; everything else is `sm-quiet` or an `sm-icon`, and close is an X icon. Report progress in the job's units with `stillmade.progress(fraction, label)` ("Moving through the kitchen, 4 of 9 rooms"), never "Processing". Head the result in the job's words ("9 rooms", "Your tour · 44 s"), never "Output". Say a problem in one line with its fix beside it ("No bathroom photo. Guests look for one." and Add photo). Stay quiet: no welcome text, tips under fields, tours or banners, and at most one line of guidance on a screen, only where the next move is not obvious; anything more goes in the input's `description`, which StillMade shows behind an (i). Say nothing about how the Block works (where it runs, saving, syncing, recovery, accounts, credits) or where a file is kept: StillMade tells the person what they need as one short notification, or nothing; never a sentence on the page, and never the same line under each item. Every drop area offers "Use a reference", which fills the Step from the person's saved photos, videos and notes: media inputs fill by kind, so take `video` or `asset` where a clip works as well as a photo, and text inputs fill by plain names and labels (`productName`, `website`, `brandColors`, `fonts`, `voice`, and `details` or `notes` for the reference's note); never build your own reference picker. Days and times are picked, never typed: use the `date` type, which StillMade shows as a calendar, with a list of times when the input is about a time (`postAt`, `startsAt`); a custom view uses `<input type="date">` or `type="datetime-local"`. Posting is a connector Step of its own, and StillMade words its button from the app and action ("Post to Instagram"). Before handing the Block back, clear every Wording note that `gate` and readiness list, unless the person asked for those words.
7523
+
7456
7524
  ### Interface
7457
7525
 
7458
- If the capability needs UI, use the Block UI SDK: generated `manifest.ui` controls first; a sandboxed custom view (`view.html`/`view.css`/`view.js`) only when the core interaction needs one. Build custom views from the Block kit the host injects (`block-kit.css`): the result in `sm-stage`, picks as pictures in `sm-choices`, one `sm-primary` naming the action (Write, Generate; never "Run") and no price (StillMade's run button adds it), extras in a closed `sm-more`; a look the person names wins. Fit one laptop screen without scrolling: label beside control, status in a few words, files as tiles, rare tools as icons, (i) on unclear controls. These compact rules are for a job or an ingredient. Size the view to the Block's tier (block-tier.js): an app, a workspace a person works in for a while (video editor, 3D configurator, CAD or drawing tool), looks and works like that kind of app instead of a compact page: its canvas or stage fills the view, with the panels, toolbars, inspector or timeline such an app has, direct manipulation (select, drag, zoom), keyboard shortcuts and undo; it keeps the host appearance and Block kit controls, its panels may scroll, and on a phone its tools fold into sheets while the canvas stays usable. Never shrink an app into a form of fields and one button. Drop words nobody needs; put helpful ones in a closed `sm-hint`. Mark each button `data-stillmade-action="what it does"` and label each field: Chat presses and fills them. Expose the capability, not the implementation: sensible defaults, previews, progress, clear errors, visible outputs. Show no raw JSON, internal IDs, filesystem details, provider terms or developer settings unless the Block is a developer tool. When a person chooses among options they need to hear or see (voices, music, fonts, looks, templates, images), let them preview each option before choosing: a sample or thumbnail from the Block's own files or the host's free samples, never a paid generation. Skip previews only when there is nothing to preview. Choices StillMade owns (voices, models in the run review) already show samples. Follow the host appearance (Light, Dark and White) and one elastic layout: stacked on a 320px phone with no sideways scroll (result first, action pinned), and from 860px the controls left (≤380px), the result filling the right. Short settings sit side by side, each label beside its control (`sm-field`, `sm-settings`; three or four short options as one `data-segmented` row); many items are one line each (`sm-list`) that open in place; input files are small tiles (`sm-gallery data-size="small"`); on a phone chip rows scroll sideways and long lists show three. Compacting moves controls, never deletes them.
7526
+ If the capability needs UI, use the Block UI SDK: generated `manifest.ui` controls first; a sandboxed custom view (`view.html`/`view.css`/`view.js`) only when the core interaction needs one. Build custom views from the Block kit the host injects (`block-kit.css`): the result in `sm-stage`, picks as pictures in `sm-choices`, the picked one in the kit's ink fill (never restyled to an outline, a tint or the page's background) so it reads at a glance, one solid `sm-primary` naming the action in the job's words ("Plan the tour", "Generate voiceover"; never "Run" or "Make it") and no price (StillMade's run button adds it), extras in a closed `sm-more`; a look the person names wins. Fit one laptop screen without scrolling: label beside control, status in a few words, files as tiles, rare tools as icons, (i) on unclear controls. These compact rules are for a job or an ingredient. Size the view to the Block's tier (block-tier.js): an app, a workspace a person works in for a while (video editor, 3D configurator, CAD or drawing tool), looks and works like that kind of app instead of a compact page: its canvas or stage fills the view, with the panels, toolbars, inspector or timeline such an app has, direct manipulation (select, drag, zoom), keyboard shortcuts and undo; it keeps the host appearance and Block kit controls, its panels may scroll, and on a phone its tools fold into sheets while the canvas stays usable. Never shrink an app into a form of fields and one button. StillMade centers a standard view narrower than its Step and zooms a view to fill its space; 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. StillMade draws one player for every `<video controls>` (play, timeline, time, sound and full screen, shown while the pointer is on the video, with keys and touch) and a full-screen button on result pictures in `sm-stage` or `sm-gallery` and on any element marked `data-stillmade-expand` (the same value makes one set of pictures, `off` removes it); `data-stillmade-player="native"` keeps the browser's controls, and a `<video>` without `controls` is the Block's own and is never touched. A picture or clip that cannot show here (kept on another device, or it did not open) keeps its place as a quiet `sm-media-off` tile in its own shape with the `image-off` glyph and the reason in its label, never words in its place. Drop words nobody needs; put helpful ones in a closed `sm-hint`. Mark each button `data-stillmade-action="what it does"` and label each field: Chat presses and fills them. Expose the capability, not the implementation: sensible defaults, previews, progress, clear errors, visible outputs. Show no raw JSON, internal IDs, filesystem details, provider terms or developer settings unless the Block is a developer tool. When a person chooses among options they need to hear or see (voices, music, fonts, looks, templates, images), let them preview each option before choosing: a sample or thumbnail from the Block's own files or the host's free samples, never a paid generation. Skip previews only when there is nothing to preview. Choices StillMade owns (voices, models in the run review) already show samples. Follow the host appearance (Light, Dark and White) and one elastic layout: stacked on a 320px phone with no sideways scroll (result first, action pinned), and from 860px the controls left (≤380px), the result filling the right. Short settings sit side by side, each label beside its control (`sm-field`, `sm-settings`; three or four short options as one `data-segmented` row); many items are one line each (`sm-list`) that open in place; input files are small tiles (`sm-gallery data-size="small"`); on a phone chip rows scroll sideways and long lists show three. Compacting moves controls, never deletes them.
7459
7527
 
7460
7528
  ### Shared editing
7461
7529
 
@@ -7563,16 +7631,16 @@ In isolated computation code, StillMade.emit(outputName,value) collects declared
7563
7631
 
7564
7632
  ### Hosted text generation
7565
7633
 
7566
- For hosted text generation use {manifest,capability,tests}, runtime:"capability", entry:"src/capability.json", permissions.capabilities:["text.generate"]. Do not write fetch or async calls in JavaScript. The host owns model, provider, BYOK, credits and explicit run consent; never put those fields or keys in package source. One required primary input text|script|brief (structured values require text), one primary output text|script. capability:{schemaVersion:1,operation:"text.generate",prompt:{"$input":"promptPort"},system:"instructions",maxTokens:1200,output:"outputPort"}. Prompt max 32000 characters, system max 8000, maxTokens integer 1..4096. Include 1..3 tests with concrete input and expectations:{outputPort:{kind:"text" or "script",minLength:1,maxLength:12000,includes:["optional required literal"]}} instead of exact expected text. Hosted behavior tests require a separately confirmed model/payment quote; never claim they ran while authoring. Example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.script-draft","version":"1.0.0","name":"Draft a short script","description":"Turn a production brief into a short narration draft using an approved text-generation call.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"prompt":{"type":"text","primary":true,"semantic":"production_brief","required":true,"description":"Production brief that guides the narration draft."}},"outputs":{"script":{"type":"script","primary":true,"semantic":"narration_script","description":"A concise narration script based on the supplied brief."}},"permissions":{"project":[],"capabilities":["text.generate"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"text","port":"prompt"}]},"capability":{"schemaVersion":1,"operation":"text.generate","prompt":{"$input":"prompt"},"system":"Write a concise narration script. Return only the script text.","maxTokens":1200,"output":"script"},"tests":[{"name":"A short opening narration","input":{"prompt":"Write two narration sentences about a quiet forest at sunrise."},"expectations":{"script":{"kind":"script","minLength":20,"maxLength":6000}}}]}.
7634
+ For hosted text generation use {manifest,capability,tests}, runtime:"capability", entry:"src/capability.json", permissions.capabilities:["text.generate"]. Do not write fetch or async calls in JavaScript. The host owns model, provider, BYOK, credits and explicit run consent; never put those fields or keys in package source. One required primary input text|script|brief (structured values require text), one primary output text|script. capability:{schemaVersion:1,operation:"text.generate",prompt:{"$input":"promptPort"},system:"instructions",maxTokens:1200,output:"outputPort"}. Prompt max 32000 characters, system max 8000, maxTokens integer 1..4096. Include 1..3 tests with concrete input and expectations:{outputPort:{kind:"text" or "script",minLength:1,maxLength:12000,includes:["optional required literal"]}} instead of exact expected text. Hosted behavior tests require a separately confirmed model/payment quote; never claim they ran while authoring. Example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.script-draft","action":{"label":"Write script","running":"Writing script…"},"version":"1.0.0","name":"Draft a short script","description":"Turn a production brief into a short narration draft using an approved text-generation call.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"prompt":{"type":"text","primary":true,"semantic":"production_brief","required":true,"description":"Production brief that guides the narration draft."}},"outputs":{"script":{"type":"script","primary":true,"semantic":"narration_script","description":"A concise narration script based on the supplied brief."}},"permissions":{"project":[],"capabilities":["text.generate"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"text","port":"prompt"}]},"capability":{"schemaVersion":1,"operation":"text.generate","prompt":{"$input":"prompt"},"system":"Write a concise narration script. Return only the script text.","maxTokens":1200,"output":"script"},"tests":[{"name":"A short opening narration","input":{"prompt":"Write two narration sentences about a quiet forest at sunrise."},"expectations":{"script":{"kind":"script","minLength":20,"maxLength":6000}}}]}.
7567
7635
 
7568
7636
  ### Hosted media operations
7569
7637
 
7570
- For audio transcription, use runtime:"capability", operation:"audio.transcribe" and permissions.capabilities:["audio.transcribe"]. Declare one primary audio input with an asset control, one text language input defaulting to "auto", and one primary transcript output. Bind the two inputs through capability.audio and capability.language. Provider, model, payment and credentials belong to the host. Fixtures use transcript word-count bounds, never invented provider text. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.transcribe-audio","version":"1.0.0","name":"Transcribe audio","description":"Turn one persistent audio file into reviewed text with word timings.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"audio":{"type":"audio","primary":true},"language":{"type":"text","default":"auto"}},"outputs":{"transcript":{"type":"transcript","primary":true}},"permissions":{"project":[],"capabilities":["audio.transcribe"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"asset","port":"audio"},{"control":"select","port":"language","options":["auto","en","es","fr","de","it","pt","ja","ko","zh"]}]},"capability":{"schemaVersion":1,"operation":"audio.transcribe","audio":{"$input":"audio"},"language":{"$input":"language"},"output":"transcript"},"tests":[{"name":"timed speech","input":{"audio":{"kind":"audio","assetId":"audio-1","versionId":"version-1","url":"/api/media/example/audio.mp3","mimeType":"audio/mpeg"},"language":"en"},"expectations":{"transcript":{"kind":"transcript","minWords":1,"maxWords":1000}}}]}.
7571
- For narration or speech synthesis, use runtime:"capability", operation:"audio.speech" and permissions.capabilities:["audio.speech"]. One required primary text or script input feeds capability.text via {$input:"portName"}; a script value contains schemaVersion:1 and text. One primary audio output is named by capability.output. Text must be at most 3800 characters. The host owns the voice, model, provider, billing and BYOK. Do not put those choices in package code. Tests use audio expectations (WAV, duration and byte bounds), never invented exact audio. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.narrate-script","version":"1.0.0","name":"Narrate a script","description":"Turn a short script into a reviewed speech recording using a host-selected voice.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"script":{"type":"script","primary":true,"semantic":"narration_script","required":true,"description":"Narration script to render as speech."}},"outputs":{"audio":{"type":"audio","primary":true,"semantic":"speech_audio","description":"Speech audio generated from the narration script."}},"permissions":{"project":[],"capabilities":["audio.speech"],"network":[],"filesystem":[],"secrets":[]},"ui":[]},"capability":{"schemaVersion":1,"operation":"audio.speech","text":{"$input":"script"},"output":"audio"},"tests":[{"name":"Read a short welcome","input":{"script":{"schemaVersion":1,"text":"Welcome to the quiet forest."}},"expectations":{"audio":{"kind":"audio","format":"wav","minDuration":0.1,"maxDuration":30,"minBytes":46,"maxBytes":1500000}}}]}.
7572
- For image generation, use runtime:"capability", operation:"image.generate" and permissions.capabilities:["image.generate"]. One required primary text input feeds capability.prompt via {$input:"portName"}; one primary image output is named by capability.output. Prompt limit 32000 characters. The supported output is PNG 1024x1024, at most 12000000 bytes. Tests use image expectations, never fabricated generated URLs or pixels. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.generate-image","version":"1.0.0","name":"Generate an image","description":"Generate a square PNG from a short visual prompt using an approved host request.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"prompt":{"type":"text","primary":true,"semantic":"image_prompt","required":true,"description":"Visual description of the image to generate."}},"outputs":{"image":{"type":"image","primary":true,"semantic":"generated_image","description":"The generated square PNG image."}},"permissions":{"project":[],"capabilities":["image.generate"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"text","port":"prompt"}]},"capability":{"schemaVersion":1,"operation":"image.generate","prompt":{"$input":"prompt"},"output":"image"},"tests":[{"name":"A simple forest illustration","input":{"prompt":"A simple illustration of a quiet forest with clear dark outlines and soft green colors."},"expectations":{"image":{"kind":"image","format":"png","width":1024,"height":1024,"minBytes":67,"maxBytes":12000000}}}]}.
7573
- For image or video analysis (what a photo shows, which photos show different angles, the words on a menu or sign), use runtime:"capability", operation:"media.analyze" and permissions.capabilities:["media.analyze"]: StillMade credits pay for it, while image.describe runs only on the person's own OpenRouter key, so never use it. Declare one primary image input, one image[] input of one to four images, or one video input (with optional start and end number inputs, bound through capability.range:{start:{"$input":"start"},end:{"$input":"end"}}), and one primary text or json output. capability:{schemaVersion:1,operation:"media.analyze",media:{"$input":"photo"},question:"what to look for, at most 2,000 characters",output:"notes"}; a text output gets each picture's summary, a json output {schemaVersion:1,items}. For a quick rating of photos (sorting or picking), add detail:"check": images only, one short answer each, one credit per call of up to four photos instead of four credits per picture. The host loads only owned media and controls provider, model, payment and approval. Tests give saved references and expect json that includes summary, or text length bounds, never invented live answers. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.check-clip","version":"1.0.0","name":"Check a clip","description":"Answer a production question about a saved video clip, with timestamps.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"clip":{"type":"video","primary":true,"semantic":"source_video","required":true,"description":"Saved video to check."},"start":{"type":"number","required":false,"min":0,"semantic":"range_start","description":"Optional start of the range to look at closely, in seconds."},"end":{"type":"number","required":false,"min":0,"semantic":"range_end","description":"Optional end of the range, in seconds (at most 12 seconds after the start)."}},"outputs":{"report":{"type":"json","primary":true,"semantic":"media_findings","description":"Summary, timeline, on-screen text and issues found."}},"permissions":{"project":[],"capabilities":["media.analyze"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"asset","port":"clip"},{"control":"number","port":"start"},{"control":"number","port":"end"}]},"capability":{"schemaVersion":1,"operation":"media.analyze","media":{"$input":"clip"},"question":"Is the product logo clearly visible, and when? List any on-screen text and visible defects.","range":{"start":{"$input":"start"},"end":{"$input":"end"}},"output":"report"},"tests":[{"name":"A saved clip","input":{"clip":{"kind":"video","assetId":"clip-1","versionId":"v1","url":"/api/media/owner/clip.mp4"}},"expectations":{"report":{"kind":"json","includes":["summary"]}}}]}.
7574
- For AI-directed editing, use runtime:"capability", operation:"timeline.propose" and permissions.capabilities:["timeline.propose"]. Declare one current timeline input, up to three additional typed context inputs, and one timeline-edit output. Bind every input exactly once through capability.context; declare context.timeline.read and timeline.propose. StillMade controls the provider, strict JSON validation, stale-before checks, preview and Apply. Tests declare timeline-edit command bounds, never fabricated provider results. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.timeline-polish","version":"1.0.0","name":"Timeline polish","description":"Turn a timeline and editing direction into a bounded proposal that remains reviewable before Apply.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"timeline":{"type":"timeline","context":"timeline","primary":true},"direction":{"type":"text","default":"Polish this cut conservatively."}},"outputs":{"edit":{"type":"timeline-edit","primary":true}},"permissions":{"project":["context.timeline.read","timeline.propose"],"capabilities":["timeline.propose"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"text","port":"direction"}]},"capability":{"schemaVersion":1,"operation":"timeline.propose","context":{"timeline":{"$input":"timeline"},"direction":{"$input":"direction"}},"instruction":"Use only supported timeline-edit commands, exact before snapshots, and the current activeTimelineId. Preserve media and locked items. Return strict JSON only.","maxTokens":2000,"output":"edit"},"tests":[{"name":"one restrained edit","input":{"timeline":{"schemaVersion":1,"activeTimelineId":"timeline-1","tracks":[{"id":"video"}],"clips":[{"id":"clip-1","trackId":"video","start":0,"duration":4}],"audioItems":[],"captions":[]},"direction":"Add a soft transition."},"expectations":{"edit":{"kind":"timeline-edit","minCommands":1,"maxCommands":10}}}]}.
7575
- For video generation use runtime:"capability", operation:"video.generate", permissions.capabilities:["video.generate"], one primary text input and one primary video output. capability.prompt references the input and capability.output names the output. Prompt limit 32000. Tests declare MP4 duration, dimensions and byte bounds; never fabricate video URLs. The enabled host selects its supported model, duration, resolution, payment and approved quote; packages cannot choose provider settings or dispatch jobs. Shipped example: {"manifest":{"schemaVersion":1,"id":"example.generate-video","name":"Generate video","version":"1.0.0","sdkVersion":"0.1.0","description":"Turn a production prompt into a short video using an approved host provider.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"prompt":{"type":"text","primary":true,"required":true}},"outputs":{"video":{"type":"video","primary":true}},"permissions":{"project":[],"capabilities":["video.generate"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"port":"prompt","control":"text"}]},"capability":{"schemaVersion":1,"operation":"video.generate","prompt":{"$input":"prompt"},"output":"video"},"tests":[{"name":"Produces a bounded MP4 sample","input":{"prompt":"A paper boat floating across a calm blue pond. Gentle camera movement."},"expectations":{"video":{"kind":"video","format":"mp4","minDuration":1,"maxDuration":60,"minBytes":32,"maxBytes":67108864,"minWidth":1,"maxWidth":3840,"minHeight":1,"maxHeight":3840}}}]}.
7638
+ For audio transcription, use runtime:"capability", operation:"audio.transcribe" and permissions.capabilities:["audio.transcribe"]. Declare one primary audio input with an asset control, one text language input defaulting to "auto", and one primary transcript output. Bind the two inputs through capability.audio and capability.language. Provider, model, payment and credentials belong to the host. Fixtures use transcript word-count bounds, never invented provider text. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.transcribe-audio","action":{"label":"Transcribe audio","running":"Transcribing…"},"version":"1.0.0","name":"Transcribe audio","description":"Turn one persistent audio file into reviewed text with word timings.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"audio":{"type":"audio","primary":true},"language":{"type":"text","default":"auto"}},"outputs":{"transcript":{"type":"transcript","primary":true}},"permissions":{"project":[],"capabilities":["audio.transcribe"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"asset","port":"audio"},{"control":"select","port":"language","options":["auto","en","es","fr","de","it","pt","ja","ko","zh"]}]},"capability":{"schemaVersion":1,"operation":"audio.transcribe","audio":{"$input":"audio"},"language":{"$input":"language"},"output":"transcript"},"tests":[{"name":"timed speech","input":{"audio":{"kind":"audio","assetId":"audio-1","versionId":"version-1","url":"/api/media/example/audio.mp3","mimeType":"audio/mpeg"},"language":"en"},"expectations":{"transcript":{"kind":"transcript","minWords":1,"maxWords":1000}}}]}.
7639
+ For narration or speech synthesis, use runtime:"capability", operation:"audio.speech" and permissions.capabilities:["audio.speech"]. One required primary text or script input feeds capability.text via {$input:"portName"}; a script value contains schemaVersion:1 and text. One primary audio output is named by capability.output. Text must be at most 3800 characters. The host owns the voice, model, provider, billing and BYOK. Do not put those choices in package code. Tests use audio expectations (WAV, duration and byte bounds), never invented exact audio. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.narrate-script","action":{"label":"Generate voiceover","running":"Generating voiceover…"},"version":"1.0.0","name":"Narrate a script","description":"Turn a short script into a reviewed speech recording using a host-selected voice.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"script":{"type":"script","primary":true,"semantic":"narration_script","required":true,"description":"Narration script to render as speech."}},"outputs":{"audio":{"type":"audio","primary":true,"semantic":"speech_audio","description":"Speech audio generated from the narration script."}},"permissions":{"project":[],"capabilities":["audio.speech"],"network":[],"filesystem":[],"secrets":[]},"ui":[]},"capability":{"schemaVersion":1,"operation":"audio.speech","text":{"$input":"script"},"output":"audio"},"tests":[{"name":"Read a short welcome","input":{"script":{"schemaVersion":1,"text":"Welcome to the quiet forest."}},"expectations":{"audio":{"kind":"audio","format":"wav","minDuration":0.1,"maxDuration":30,"minBytes":46,"maxBytes":1500000}}}]}.
7640
+ For image generation, use runtime:"capability", operation:"image.generate" and permissions.capabilities:["image.generate"]. One required primary text input feeds capability.prompt via {$input:"portName"}; one primary image output is named by capability.output. Prompt limit 32000 characters. The supported output is PNG 1024x1024, at most 12000000 bytes. Tests use image expectations, never fabricated generated URLs or pixels. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.generate-image","action":{"label":"Generate image","running":"Generating image…"},"version":"1.0.0","name":"Generate an image","description":"Generate a square PNG from a short visual prompt using an approved host request.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"prompt":{"type":"text","primary":true,"semantic":"image_prompt","required":true,"description":"Visual description of the image to generate."}},"outputs":{"image":{"type":"image","primary":true,"semantic":"generated_image","description":"The generated square PNG image."}},"permissions":{"project":[],"capabilities":["image.generate"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"text","port":"prompt"}]},"capability":{"schemaVersion":1,"operation":"image.generate","prompt":{"$input":"prompt"},"output":"image"},"tests":[{"name":"A simple forest illustration","input":{"prompt":"A simple illustration of a quiet forest with clear dark outlines and soft green colors."},"expectations":{"image":{"kind":"image","format":"png","width":1024,"height":1024,"minBytes":67,"maxBytes":12000000}}}]}.
7641
+ For image or video analysis (what a photo shows, which photos show different angles, the words on a menu or sign), use runtime:"capability", operation:"media.analyze" and permissions.capabilities:["media.analyze"]: StillMade credits pay for it, while image.describe runs only on the person's own OpenRouter key, so never use it. Declare one primary image input, one image[] input of one to four images, or one video input (with optional start and end number inputs, bound through capability.range:{start:{"$input":"start"},end:{"$input":"end"}}), and one primary text or json output. capability:{schemaVersion:1,operation:"media.analyze",media:{"$input":"photo"},question:"what to look for, at most 2,000 characters",output:"notes"}; a text output gets each picture's summary, a json output {schemaVersion:1,items}. For a quick rating of photos (sorting or picking), add detail:"check": images only, one short answer each, one credit per call of up to four photos instead of four credits per picture. The host loads only owned media and controls provider, model, payment and approval. Tests give saved references and expect json that includes summary, or text length bounds, never invented live answers. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.check-clip","action":{"label":"Check clip","running":"Checking clip…"},"version":"1.0.0","name":"Check a clip","description":"Answer a production question about a saved video clip, with timestamps.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"clip":{"type":"video","primary":true,"semantic":"source_video","required":true,"description":"Saved video to check."},"start":{"type":"number","required":false,"min":0,"semantic":"range_start","description":"Optional start of the range to look at closely, in seconds."},"end":{"type":"number","required":false,"min":0,"semantic":"range_end","description":"Optional end of the range, in seconds (at most 12 seconds after the start)."}},"outputs":{"report":{"type":"json","primary":true,"semantic":"media_findings","description":"Summary, timeline, on-screen text and issues found."}},"permissions":{"project":[],"capabilities":["media.analyze"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"asset","port":"clip"},{"control":"number","port":"start"},{"control":"number","port":"end"}]},"capability":{"schemaVersion":1,"operation":"media.analyze","media":{"$input":"clip"},"question":"Is the product logo clearly visible, and when? List any on-screen text and visible defects.","range":{"start":{"$input":"start"},"end":{"$input":"end"}},"output":"report"},"tests":[{"name":"A saved clip","input":{"clip":{"kind":"video","assetId":"clip-1","versionId":"v1","url":"/api/media/owner/clip.mp4"}},"expectations":{"report":{"kind":"json","includes":["summary"]}}}]}.
7642
+ For AI-directed editing, use runtime:"capability", operation:"timeline.propose" and permissions.capabilities:["timeline.propose"]. Declare one current timeline input, up to three additional typed context inputs, and one timeline-edit output. Bind every input exactly once through capability.context; declare context.timeline.read and timeline.propose. StillMade controls the provider, strict JSON validation, stale-before checks, preview and Apply. Tests declare timeline-edit command bounds, never fabricated provider results. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.timeline-polish","action":{"label":"Suggest edit","running":"Suggesting edit…"},"version":"1.0.0","name":"Timeline polish","description":"Turn a timeline and editing direction into a bounded proposal that remains reviewable before Apply.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"timeline":{"type":"timeline","context":"timeline","primary":true},"direction":{"type":"text","default":"Polish this cut conservatively."}},"outputs":{"edit":{"type":"timeline-edit","primary":true}},"permissions":{"project":["context.timeline.read","timeline.propose"],"capabilities":["timeline.propose"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"text","port":"direction"}]},"capability":{"schemaVersion":1,"operation":"timeline.propose","context":{"timeline":{"$input":"timeline"},"direction":{"$input":"direction"}},"instruction":"Use only supported timeline-edit commands, exact before snapshots, and the current activeTimelineId. Preserve media and locked items. Return strict JSON only.","maxTokens":2000,"output":"edit"},"tests":[{"name":"one restrained edit","input":{"timeline":{"schemaVersion":1,"activeTimelineId":"timeline-1","tracks":[{"id":"video"}],"clips":[{"id":"clip-1","trackId":"video","start":0,"duration":4}],"audioItems":[],"captions":[]},"direction":"Add a soft transition."},"expectations":{"edit":{"kind":"timeline-edit","minCommands":1,"maxCommands":10}}}]}.
7643
+ For video generation use runtime:"capability", operation:"video.generate", permissions.capabilities:["video.generate"], one primary text input and one primary video output. capability.prompt references the input and capability.output names the output. Prompt limit 32000. Tests declare MP4 duration, dimensions and byte bounds; never fabricate video URLs. The enabled host selects its supported model, duration, resolution, payment and approved quote; packages cannot choose provider settings or dispatch jobs. Shipped example: {"manifest":{"schemaVersion":1,"id":"example.generate-video","action":{"label":"Generate video","running":"Generating video…"},"name":"Generate video","version":"1.0.0","sdkVersion":"0.1.0","description":"Turn a production prompt into a short video using an approved host provider.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"prompt":{"type":"text","primary":true,"required":true}},"outputs":{"video":{"type":"video","primary":true}},"permissions":{"project":[],"capabilities":["video.generate"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"port":"prompt","control":"text"}]},"capability":{"schemaVersion":1,"operation":"video.generate","prompt":{"$input":"prompt"},"output":"video"},"tests":[{"name":"Produces a bounded MP4 sample","input":{"prompt":"A paper boat floating across a calm blue pond. Gentle camera movement."},"expectations":{"video":{"kind":"video","format":"mp4","minDuration":1,"maxDuration":60,"minBytes":32,"maxBytes":67108864,"minWidth":1,"maxWidth":3840,"minHeight":1,"maxHeight":3840}}}]}.
7576
7644
  A capability package performs exactly one supported operation. A job that needs several (transcribe a recording, then find what is said in it; write words, then voice them), or code between two operations, is one module Block that calls each with stillmade.hosted.run (Module Blocks); never split one job into part Blocks, and never invent a combined capability runtime. Hosted image, speech and video source can be statically validated while authoring, but real fixture/sample generation requires the user's subsequent model/payment selection and quote confirmation. Do not claim those calls ran. Deterministic image transformations should remain sandboxed recipe or JavaScript code when supported; do not generate a new image as a substitute for processing an existing one.
7577
7645
 
7578
7646
  ### Module Blocks
@@ -7599,7 +7667,7 @@ To propose changes to an existing blueprint, panels, board, canvas, or animation
7599
7667
 
7600
7668
  *When:* StillMade's builder adds this section when the request needs memory, counting or persistence, or refines a stateful Block.
7601
7669
 
7602
- For memory use runtime:"javascript", manifest.state:{scope:"step",version:1,initial:{...}}, permissions.project including "state.step". Code receives mutable plain-object state separately from input. Mutate state and return only declared output bindings; never return a state envelope as an undeclared output. Each test needs expectedState:{version:1,value:{...}}; a test may supply state:{version:1,value:{...}} to verify continuation. Memory is bounded to 64 KiB and scoped to a placement. The host saves it only with accepted successful output; previews use disposable memory. No localStorage, files, global or account-shared state. Interactive selections support successive memory; unattended future-media execution is not supported for stateful Blocks. Preserve the state schema/version during refinement unless the user requests a schema change. For an explicit upgrade, the new version may declare manifest.state.migrations:[{fromVersion:1,operations:[{op:"rename",from:"oldField",to:"newField"},{op:"default",key:"labels",value:[]}]}], targeting its enclosing state.version (for example 2). Use only ordered top-level rename/default/remove operations; remove uses {op:"remove",key:"field"}. Renames require an existing source and absent destination, defaults never overwrite, removals require an existing field. At most 16 distinct older fromVersion routes, 64 operations each, and 64 KiB combined declarations and intermediate state. No chains, downgrade, arbitrary code or automatic application. Bump the Block version when source or migrations change, retain unrelated state, and never invent an old field layout. Owners preview and explicitly apply migrations to exact archived source-bound state through the project host; authoring does not mutate existing projects. New execution fixtures use the target state version. Exact example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.numbered-takes","version":"1.0.0","name":"Numbered takes","description":"Label successive creative takes with an independent counter for each production placement.","kind":"task","runtime":"javascript","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"text":{"type":"text","primary":true,"semantic":"draft_text","required":true,"description":"Creative take text to label with the next number."}},"outputs":{"text":{"type":"text","primary":true,"semantic":"numbered_take","description":"The supplied take prefixed with its saved sequence number."}},"permissions":{"project":["state.step"]},"state":{"scope":"step","version":1,"initial":{"count":0}},"ui":[{"port":"text","control":"text"}]},"code":"state.count += 1; return {text: \"Take \" + state.count + \": \" + input.text.trim()};","tests":[{"name":"First take","input":{"text":" Opening scene "},"expected":{"text":"Take 1: Opening scene"},"expectedState":{"version":1,"value":{"count":1}}},{"name":"Continues saved numbering","input":{"text":"Alternate ending"},"state":{"version":1,"value":{"count":4}},"expected":{"text":"Take 5: Alternate ending"},"expectedState":{"version":1,"value":{"count":5}}}]}.
7670
+ For memory use runtime:"javascript", manifest.state:{scope:"step",version:1,initial:{...}}, permissions.project including "state.step". Code receives mutable plain-object state separately from input. Mutate state and return only declared output bindings; never return a state envelope as an undeclared output. Each test needs expectedState:{version:1,value:{...}}; a test may supply state:{version:1,value:{...}} to verify continuation. Memory is bounded to 64 KiB and scoped to a placement. The host saves it only with accepted successful output; previews use disposable memory. No localStorage, files, global or account-shared state. Interactive selections support successive memory; unattended future-media execution is not supported for stateful Blocks. Preserve the state schema/version during refinement unless the user requests a schema change. For an explicit upgrade, the new version may declare manifest.state.migrations:[{fromVersion:1,operations:[{op:"rename",from:"oldField",to:"newField"},{op:"default",key:"labels",value:[]}]}], targeting its enclosing state.version (for example 2). Use only ordered top-level rename/default/remove operations; remove uses {op:"remove",key:"field"}. Renames require an existing source and absent destination, defaults never overwrite, removals require an existing field. At most 16 distinct older fromVersion routes, 64 operations each, and 64 KiB combined declarations and intermediate state. No chains, downgrade, arbitrary code or automatic application. Bump the Block version when source or migrations change, retain unrelated state, and never invent an old field layout. Owners preview and explicitly apply migrations to exact archived source-bound state through the project host; authoring does not mutate existing projects. New execution fixtures use the target state version. Exact example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.numbered-takes","action":{"label":"Number takes","running":"Numbering takes…"},"version":"1.0.0","name":"Numbered takes","description":"Label successive creative takes with an independent counter for each production placement.","kind":"task","runtime":"javascript","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"text":{"type":"text","primary":true,"semantic":"draft_text","required":true,"description":"Creative take text to label with the next number."}},"outputs":{"text":{"type":"text","primary":true,"semantic":"numbered_take","description":"The supplied take prefixed with its saved sequence number."}},"permissions":{"project":["state.step"]},"state":{"scope":"step","version":1,"initial":{"count":0}},"ui":[{"port":"text","control":"text"}]},"code":"state.count += 1; return {text: \"Take \" + state.count + \": \" + input.text.trim()};","tests":[{"name":"First take","input":{"text":" Opening scene "},"expected":{"text":"Take 1: Opening scene"},"expectedState":{"version":1,"value":{"count":1}}},{"name":"Continues saved numbering","input":{"text":"Alternate ending"},"state":{"version":1,"value":{"count":4}},"expected":{"text":"Take 5: Alternate ending"},"expectedState":{"version":1,"value":{"count":5}}}]}.
7603
7671
 
7604
7672
  ### Editor timeline proposals
7605
7673
 
@@ -7625,7 +7693,7 @@ Optional custom view interfaces are supported, but generated manifest.ui control
7625
7693
 
7626
7694
  *When:* StillMade's builder adds this section when the person asks for an interface, preview or controls, or refines a Block that has one.
7627
7695
 
7628
- A custom interface is the optional package-level view:{html,css?,themedCss?,javascript?}; when refining, preserve and refine base.view. Design it by StillMade's interface principles, in order: 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. 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. Never a JSON dump, source editor, manifest or diagnostic panel unless the task is about source. One obvious next action (`sm-primary`); peers are quiet buttons or named icons. Seven or fewer choices in view. The action button names what it does ("Write", "Generate image", "Make video"), never "Run", "Run step", "Submit" or "Review cost". 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. 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. Words only when needed. Drop what nobody needs to finish the task (intros, "how it works", restating the Block name). Words that might help start collapsed (`sm-hint`, `sm-more`). Errors, spending approvals, stale inputs and destructive steps stay visible, in few words. Strong defaults; secondary settings go in `sm-more`, closed. 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. Status is a dot or a few words ("No narration yet"), never a paragraph; the reason sits behind an `sm-hint`. 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. Rare tools (update, schedule, history, reload) are named icon buttons beside the action, never sections under the work. 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. One workspace: no cards inside cards, no second title, step counter or Back/Next bar; the host owns navigation. Status sits beside the action it describes (`sm-status`), in a few words. Keep the page in normal scroll flow; no sticky media or control strips unless the editing task needs them. 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. 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. 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. 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. On a phone chip and segment rows scroll sideways instead of wrapping; long lists show their first three with "N more" (`data-peek`) and long text five lines until tapped (`sm-clamp`). Nothing is lost when a Block gets smaller: every control stays on the screen, behind an (i), in `sm-more`, or inside the item it belongs to. Compacting moves controls; it never deletes them. Text scene descriptions are planning notes, never a storyboard or an approved frame. Its DOM controller is separate from manifest runtime code. The view may also declare appearance:"original" or "host". For an imported design, preserve its colors with appearance:"original" and view.css; no themed replacement is required. Preserve base.view.appearance when refining unless the user requests a change. Omitted/host appearance retains the existing Light, Dark and White requirement: supply semantic colors in view.css or a complete replacement view.themedCss. An original-style view may optionally supply valid themedCss for a StillMade appearance preview. Use StillMade variables (--bg,--fg,--fg-muted,--border-tok,--r-3) only when opting into host styling; do not redefine host tokens in the themed variant. Appearance never relaxes sandbox constraints: no CSS escapes/filters/blending, imports/url(), or element.style mutations in JS. Use classes for UI state; media pixels retain their colors. Both CSS fields have the same 32 KiB limit; all existing shared-state, security and permission checks still apply. Declare elements in html, bind with document.getElementById/querySelector and addEventListener; use literal property access, array methods, textContent, input.value, button.disabled and canvas. Initial values: StillMade.onInput(values=>{...}); await StillMade.run(inputBindings) returns validated output bindings from the isolated package runtime; catch errors and show results. No computation in the DOM controller; put it in code/recipe. Disable the action button while pending.
7696
+ A custom interface is the optional package-level view:{html,css?,themedCss?,javascript?}; when refining, preserve and refine base.view. Design it by StillMade's interface principles, in order: 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. 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. 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. 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. 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. A picked option reads at a glance: keep the kit's ink fill on an `sm-choices` pick, never restyled to an outline, a tint or the page's background. Media that cannot show here (on another device, or it did not open) keeps its place as a quiet `sm-media-off` tile in its own shape, never words in its place. Words only when needed. Drop what nobody needs to finish the task (intros, "how it works", restating the Block name). Words that might help start collapsed (`sm-hint`, `sm-more`). Errors, spending approvals, stale inputs and destructive steps stay visible, in few words. Strong defaults; secondary settings go in `sm-more`, closed. 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. Status is a dot or a few words ("No narration yet"), never a paragraph; the reason sits behind an `sm-hint`. 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. Rare tools (update, schedule, history, reload) are named icon buttons beside the action, never sections under the work. 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. One workspace: no cards inside cards, no second title, step counter or Back/Next bar; the host owns navigation. Status sits beside the action it describes (`sm-status`), in a few words. Keep the page in normal scroll flow; no sticky media or control strips unless the editing task needs them. 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. 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. 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. 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. On a phone chip and segment rows scroll sideways instead of wrapping; long lists show their first three with "N more" (`data-peek`) and long text five lines until tapped (`sm-clamp`). Nothing is lost when a Block gets smaller: every control stays on the screen, behind an (i), in `sm-more`, or inside the item it belongs to. Compacting moves controls; it never deletes them. Text scene descriptions are planning notes, never a storyboard or an approved frame. Say nothing about how the Block works: no notes on where it runs (this device, StillMade Desktop, the cloud), saving, syncing, recovery, accounts, credits or where a file is kept. StillMade tells the person what they need as one short notification, or nothing; never a sentence on the page, and never the same line under each item. References fill your inputs: every drop area in StillMade offers "Use a reference", and the person's saved photos, videos and notes fill the Step with no typing. Media inputs fill by kind, so take `video` or `asset` wherever a clip works as well as a photo; text inputs fill by plain names and labels (`productName`, `website`, `brandColors`, `fonts`, `voice`, and `details` or `notes` for the reference's note). Never build your own reference picker or library upload. Days and times are picked, never typed: a `date` input is a calendar, with a list of times when it is about a time (`postAt`, `startsAt`, a label with Time, When or Starts). In a custom view use `<input type="date">` or `type="datetime-local"`, never a text box for a date. Posting is its own Step: sending a result to Instagram, TikTok, email or any app is a connector Step after the Block, worded by StillMade ("Post to Instagram"). A Block never posts from inside itself. Its DOM controller is separate from manifest runtime code. The view may also declare appearance:"original" or "host". For an imported design, preserve its colors with appearance:"original" and view.css; no themed replacement is required. Preserve base.view.appearance when refining unless the user requests a change. Omitted/host appearance retains the existing Light, Dark and White requirement: supply semantic colors in view.css or a complete replacement view.themedCss. An original-style view may optionally supply valid themedCss for a StillMade appearance preview. Use StillMade variables (--bg,--fg,--fg-muted,--border-tok,--r-3) only when opting into host styling; do not redefine host tokens in the themed variant. Appearance never relaxes sandbox constraints: no CSS escapes/filters/blending, imports/url(), or element.style mutations in JS. Use classes for UI state; media pixels retain their colors. Both CSS fields have the same 32 KiB limit; all existing shared-state, security and permission checks still apply. Declare elements in html, bind with document.getElementById/querySelector and addEventListener; use literal property access, array methods, textContent, input.value, button.disabled and canvas. Initial values: StillMade.onInput(values=>{...}); await StillMade.run(inputBindings) returns validated output bindings from the isolated package runtime; catch errors and show results. No computation in the DOM controller; put it in code/recipe. Disable the action button while pending.
7629
7697
  Standard custom view code (no `view.config.json` frame runtime) is checked before it runs. These rules come straight from the validator; frame views run in their own sandbox and may build the page with ordinary DOM calls such as `createElement`:
7630
7698
 
7631
7699
  - **HTML elements:** only `div`, `section`, `article`, `header`, `footer`, `main`, `aside`, `nav`, `h1`, `h2`, `h3`, `h4`, `p`, `span`, `strong`, `em`, `i`, `small`, `br`, `hr`, `label`, `input`, `textarea`, `button`, `select`, `option`, `optgroup`, `fieldset`, `legend`, `output`, `progress`, `meter`, `ul`, `ol`, `li`, `dl`, `dt`, `dd`, `figure`, `figcaption`, `img`, `video`, `audio`, `source`, `canvas`, `table`, `thead`, `tbody`, `tfoot`, `tr`, `th`, `td`, `pre`, `code`, `details`, `summary`. No scripts, iframes, SVG, forms, comments or inline event attributes; media URLs must be `data:` or `blob:`.
@@ -8317,7 +8385,8 @@ exact permission, such as `context.versions.read`.
8317
8385
  `ui` is an array of `{ "control": "...", "port": "inputName" }` objects.
8318
8386
  Control must be one of `text`, `number`, `slider`, `checkbox`, `asset`, `select`,
8319
8387
  `multiselect`, `file`, `date`, `color`, `url`, `richtext`, `list` or `grid`, bound to an
8320
- existing input. Labels come from port names/descriptions. For a numeric slider,
8388
+ existing input. A field's label is its `ui` entry's `label` when given, in the job's
8389
+ words ("When to post"), else its port name; its (i) is the port's `description`. For a numeric slider,
8321
8390
  give its input `type`, `min`, `max`, and `default`. Use `asset` for an image input.
8322
8391
  For a custom visual interface, add the optional `view` object below. Do not supply React components, external dependencies, or a hosted UI URL.
8323
8392
 
@@ -9695,7 +9764,9 @@ still owns specialized workspace layout. A 320 CSS-pixel phone viewport leaves
9695
9764
  less than 320 pixels inside the host's preview gutters. Size from the embedded
9696
9765
  view's actual container, avoid a 320-pixel minimum width, wrap long labels, and
9697
9766
  isolate intentional canvas/timeline panning from
9698
- the surrounding toolbar. Provide visible buttons or menus for actions otherwise
9767
+ the surrounding toolbar. A `<video controls>` gets StillMade's player, whose
9768
+ 44-pixel controls a tap shows for 3 seconds (a first tap never starts playback),
9769
+ and a result picture's full-screen button shows for 3 seconds after a tap on it. Provide visible buttons or menus for actions otherwise
9699
9770
  available by hover, drag, right-click, or keyboard shortcut. Label fields and
9700
9771
  announce loading, errors, and completed output with `role="status"`,
9701
9772
  `role="alert"`, or `aria-live` as appropriate. For deterministic custom-view
@@ -9803,7 +9874,7 @@ piece in Light, Dark and White.
9803
9874
  </div>
9804
9875
 
9805
9876
  <div class="sm-actions">
9806
- <button type="button" class="sm-primary" id="run" data-stillmade-action="run">Make it</button>
9877
+ <button type="button" class="sm-primary" id="run" data-stillmade-action="make the clip">Make the clip</button>
9807
9878
  <p class="sm-status" id="status" role="status"></p>
9808
9879
  </div>
9809
9880
 
@@ -9819,7 +9890,7 @@ piece in Light, Dark and White.
9819
9890
  | `sm-block` | The one workspace. `data-layout="split"` puts the stage beside the controls on wide screens. |
9820
9891
  | `sm-stage` | The thing being made: preview, media or result. `data-ratio="16:9"`, `"9:16"` or `"1:1"`. |
9821
9892
  | `sm-empty` | An empty stage: a glyph, at most five words, one action. |
9822
- | `sm-choices` | Picks shown as pictures (`img`, `.sm-swatch`, `.sm-glyph`) and one or two words. `data-compact` for short text chips, `data-segmented` for one connected row of three or four short options. Chips and segments scroll sideways on a phone. Give the `fieldset` an `id` and `data-stillmade-share` so teammates see the same pick. |
9893
+ | `sm-choices` | Picks shown as pictures (`img`, `.sm-swatch`, `.sm-glyph`) and one or two words. `data-compact` for short text chips, `data-segmented` for one connected row of three or four short options. The pick is filled with the kit's ink, so it reads at a glance; a `disabled` fieldset keeps its pick and fades the rest. Chips and segments scroll sideways on a phone. Give the `fieldset` an `id` and `data-stillmade-share` so teammates see the same pick. |
9823
9894
  | `sm-field`, `sm-fields` | One short setting on one row, its label beside the control; a responsive group of them. On a phone the control wraps under its label only when both do not fit. A textarea, picture choices, file tiles or a list keep the label above. |
9824
9895
  | `sm-settings` | Short settings side by side, each label beside its control; a narrow cell wraps the control under its label. |
9825
9896
  | `sm-list` | Many items, one line each: a thumbnail, one line of text, a short fact. An item that opens in place is an `li` holding a `details`. `data-peek` shows three on a phone, with a last `li.sm-list-more` button that sets `data-open`. |
@@ -9829,7 +9900,8 @@ piece in Light, Dark and White.
9829
9900
  | `sm-more` | A closed `<details>` for secondary settings. |
9830
9901
  | `sm-hint` | A closed `<details>` info toggle for an explanation that might help. |
9831
9902
  | `sm-gallery` | A grid of results or media. `data-size="small"` for input files: more tiles per row as the screen widens. |
9832
- | `sm-glyph` | A small icon in `currentColor`: `play`, `pause`, `plus`, `close`, `check`, `chevron`, `upload`, `image`, `video`, `audio`, `text`, `spark`, `info`, `warning`, `spinner`. Works in standard views, which cannot use SVG. |
9903
+ | `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, the reason in `aria-label` and `title`, no words inside. |
9904
+ | `sm-glyph` | A small icon in `currentColor`: `play`, `pause`, `plus`, `close`, `check`, `chevron`, `upload`, `image`, `image-off`, `video`, `audio`, `text`, `spark`, `info`, `warning`, `spinner`. Works in standard views, which cannot use SVG. |
9833
9905
 
9834
9906
  **Function first.** When the person building a Block does not ask for a look,
9835
9907
  use the kit as is: they want it to work and be easy to use. When they name a
@@ -9845,8 +9917,9 @@ designs keep `appearance: "original"`.
9845
9917
  | might help some people (what a setting does, a format limit) | Put them in a closed `sm-hint`, or secondary settings in a closed `sm-more`. |
9846
9918
  | report an error, a spending approval, a stale input or a destructive step | Keep them visible, in few words. Say what to do next. |
9847
9919
 
9848
- Buttons say the action in one to three words ("Make it", "Export"). Status says
9849
- the state in one to four words ("Making", "Ready", "Needs approval").
9920
+ Buttons say the action in the job's words, one to four of them ("Plan the tour",
9921
+ "Make 6 clips", "Export"), never "Make it". Status says the state in one to four
9922
+ words ("Making the clip", "Ready", "Needs approval").
9850
9923
 
9851
9924
  The button that makes something names what it makes ("Write", "Generate image",
9852
9925
  "Make video"), never "Run", "Run step", "Submit" or "Review cost", and says the
@@ -9860,7 +9933,56 @@ the same single priced button. Pressing a priced button runs at that price; a
9860
9933
  confirmation appears only when the server's price is higher than the one shown.
9861
9934
  Do not write credit numbers in the Block.
9862
9935
 
9863
- ### 3. Rules
9936
+ ### 3. Speak the job
9937
+
9938
+ These are StillMade's defaults for every Block, and they apply wherever the
9939
+ person or the creator has not asked for something else. What they ask for wins.
9940
+
9941
+ - **The job's words everywhere.** Bringing ("Your listing photos"), starting
9942
+ ("Plan the tour"), working ("Moving through the kitchen, 4 of 9 rooms"),
9943
+ done ("Your tour · 44 s") and problems ("No bathroom photo. Guests look for
9944
+ one." with Add photo beside it). Never "Make it", "Run", "Submit",
9945
+ "Process", "Processing", "Output" or "Result".
9946
+ - **Name the Step's button in `manifest.action`**:
9947
+ `{"label":"Plan the tour","running":"Planning the tour…"}`. StillMade adds the
9948
+ price ("Plan the tour · 1 credit"). A picture, video or sound made with AI
9949
+ starts with Generate and says what ("Generate tour", "Generate voiceover");
9950
+ cutting or rendering the person's own media says Make ("Make 6 clips").
9951
+ Bare "Generate" or "Make" is not enough.
9952
+ - **The main button stands out.** One solid `sm-primary` per screen, in the
9953
+ kit's ink, never restyled to the page's background or a ghost outline; every
9954
+ other button is `sm-quiet` or an `sm-icon`. Close is an X icon, not the word.
9955
+ - **Quiet.** At most one line of guidance on a screen, only where the next
9956
+ move is not obvious. No welcome text, tips under fields, tours or banners.
9957
+ Anything more goes in the input's `description`, which StillMade shows
9958
+ behind an (i).
9959
+ - **Say nothing about how the Block works.** No notes on where it runs (this
9960
+ device, StillMade Desktop, the cloud), saving, syncing, recovery, accounts,
9961
+ credits or where a file is kept: StillMade says what a person needs, as one
9962
+ short notification, or nothing. Never a sentence on the page, and never the
9963
+ same line under each item.
9964
+ - **References fill your inputs.** Every drop area in StillMade offers "Use a
9965
+ reference": the person's saved photos, videos and notes fill the Step's
9966
+ fields with no typing. Media inputs fill by kind, so take `video` or `asset`
9967
+ wherever a clip works as well as a photo. Text inputs fill by their name and
9968
+ label: name them plainly (`productName`, `website`, `brandColors`, `fonts`,
9969
+ `voice`), and give the one that takes a reference's note a name such as
9970
+ `details`, `notes` or `listingDetails`; when a note has to be split across
9971
+ several fields StillMade does it free. Never build your own reference
9972
+ picker or library upload.
9973
+ - **Days and times are picked, never typed.** Use the `date` type. StillMade
9974
+ shows a calendar, and a list of times as well when the input is about a time
9975
+ (a name such as `postAt` or `startsAt`, a label with Time, When or Starts, or
9976
+ a value with a time). In a custom view use `<input type="date">` or
9977
+ `type="datetime-local"`, never a text box for a date.
9978
+ - **Posting is its own Step.** Sending a result to Instagram, TikTok, email or
9979
+ any app is a connector Step after the Block, and StillMade words its button
9980
+ ("Post to Instagram"). A Block never posts from inside itself.
9981
+ - **Chat can do all of it.** Every button carries `data-stillmade-action`
9982
+ naming what it does and every field a label, so the project's Chat can press
9983
+ and fill them.
9984
+
9985
+ ### 4. Rules
9864
9986
 
9865
9987
  These are requirements for every author, person or model. Not all are checked
9866
9988
  automatically. An explicit request from the person can authorize a named
@@ -9912,7 +10034,16 @@ exception, never unrelated technical UI.
9912
10034
  within reach. Extra width goes to the result, never to wider text
9913
10035
  fields. Before there is a result, the stage previews what will be made
9914
10036
  from the inputs given so far, not an empty box. `data-layout="stack"`
9915
- keeps one column.
10037
+ keeps one column. StillMade zooms a view to fill its space and centers a
10038
+ standard view narrower than its Step (by its margins only, so a margin
10039
+ the view sets wins). An app that lays itself out (full-size canvas or
10040
+ WebGL, its own scroll, pan or zoom, its own Ctrl/Cmd +/- keys) puts
10041
+ `data-stillmade-layout="own"` on its outermost element, and StillMade
10042
+ then never centers, zooms or takes those keys. StillMade plays every
10043
+ `<video controls>` in its own player with full screen, and puts a
10044
+ full-screen button on result pictures in `sm-stage` or `sm-gallery` and
10045
+ on anything marked `data-stillmade-expand`; a `<video>` without
10046
+ `controls` is the Block's own and is never touched.
9916
10047
  17. Settings sit side by side, next to what they change. Short settings are
9917
10048
  an `sm-settings` grid, and three or four short options (Low / Med /
9918
10049
  High, 16:9 / 9:16 / 1:1) are one `data-segmented` row, not big tiles.
@@ -9927,8 +10058,24 @@ exception, never unrelated technical UI.
9927
10058
  20. Nothing is lost when a Block gets smaller. Every control stays on the
9928
10059
  screen, behind an (i), in `sm-more`, or inside the item it belongs to.
9929
10060
  Compacting moves controls; it never deletes them.
9930
-
9931
- ### 4. What StillMade checks
10061
+ 21. A picked option reads at a glance. The kit fills an `sm-choices` pick with
10062
+ its ink (`--fg` behind `--bg` words, the same inversion as every
10063
+ segmented control in StillMade); never restyle it to an outline, a tint or
10064
+ the page's background. A locked row (`disabled`, or a person who can only
10065
+ view) keeps its pick filled, fades the other options and does not react to
10066
+ the pointer.
10067
+ 22. Media that cannot show here (kept on another device, or it did not open)
10068
+ keeps its place as a quiet `sm-media-off` tile in its own shape with the
10069
+ `image-off` glyph, the reason in its `aria-label` and `title`. Never words
10070
+ in its place:
10071
+
10072
+ ```html
10073
+ <span class="sm-media-off" role="img" aria-label="On another device" title="On another device" style="--sm-photo-ratio:3/2">
10074
+ <span class="sm-glyph" data-glyph="image-off" aria-hidden="true"></span>
10075
+ </span>
10076
+ ```
10077
+
10078
+ ### 5. What StillMade checks
9932
10079
 
9933
10080
  - Admission rejects a primary textarea of 12 or more rows when no task
9934
10081
  presentation (stage, media, list or `StillMade.render`) is detected
@@ -9937,6 +10084,11 @@ exception, never unrelated technical UI.
9937
10084
  ungrouped options, more than one `h1`, a visible paragraph over twenty words,
9938
10085
  a word dropdown for something people see or hear, a bare browser file
9939
10086
  picker, and a size limit printed in view.
10087
+ - Readiness notes settings left loose on the page: three or more `sm-field`
10088
+ outside an `sm-fields`, `sm-settings`, `sm-more` or `sm-list` group. The kit
10089
+ gives that group its own surface, so the inputs, the settings and the result
10090
+ read apart; the SDK gate and StillMade's builder send the note back like any
10091
+ Wording note.
9940
10092
  - Admission warns about the compact rules it can see in the source: a short
9941
10093
  input or select whose label sits above it outside `sm-field` / `sm-settings`
9942
10094
  (a `<br>` between them, or a label made `display: block`); a heading,
@@ -9952,6 +10104,17 @@ exception, never unrelated technical UI.
9952
10104
  (`blockKitProblems`; the failing rules are `BLOCK_KIT_READINESS_RULES`). StillMade's own Block builder also sends back a custom
9953
10105
  view that is not built from `sm-block`, unless the person asked for their
9954
10106
  own look (`appearance: "original"`).
10107
+ - Admission warns, and readiness lists a "Wording" limitation, when a button
10108
+ says "Make it", "Generate", "Create", "Process" or "Do it"; when progress
10109
+ says "Processing", "Loading" or "Working"; when a visible line explains where
10110
+ the Block runs or how it saves; when a date is typed into a text box; when
10111
+ the CSS turns `sm-primary` into a background-coloured button; when the CSS
10112
+ takes the ink fill off a pick (`.sm-choices label:has(input:checked)` with a
10113
+ transparent or page-coloured background, or the ink as its text colour); and
10114
+ when the page or a string in its code says where a file is kept ("Only on
10115
+ this device", "Not on this device"). Clear
10116
+ every one before you hand the Block back, unless the person asked for those
10117
+ words. They never refuse a release.
9955
10118
  - The host supplies the Project Type step bar and omits its own title and frame
9956
10119
  around custom views, and does not add a "Technical result" disclosure.
9957
10120
  - HTML, JavaScript, permission and appearance validation are separate checks.
@@ -12541,7 +12704,7 @@ Music, sound effects and catalog voices are stored as the provider's measured MP
12541
12704
  | `document` | Presents a `document` or Markdown `text` output as formatted text. |
12542
12705
  | `chart` | Draws a `table` (optional `x` and `y` column names) or `number[]` output as a `bar` or `line` chart (`chart`). |
12543
12706
  | `code` | Presents a `text`, `json` or `object` output as code with a copy button (optional `language`). |
12544
- | `player` | Plays an `audio` or `video` output (or a list of them). |
12707
+ | `player` | Plays an `audio` or `video` output (or a list of them); a video plays in StillMade's player, with full screen. |
12545
12708
  | `download` | Offers a `file`, `file[]` or `file-bundle` output as a download through the host export policy. |
12546
12709
 
12547
12710
  ## First-party Blocks
@@ -12652,16 +12815,16 @@ In isolated computation code, StillMade.emit(outputName,value) collects declared
12652
12815
 
12653
12816
  ### Hosted text generation
12654
12817
 
12655
- For hosted text generation use {manifest,capability,tests}, runtime:"capability", entry:"src/capability.json", permissions.capabilities:["text.generate"]. Do not write fetch or async calls in JavaScript. The host owns model, provider, BYOK, credits and explicit run consent; never put those fields or keys in package source. One required primary input text|script|brief (structured values require text), one primary output text|script. capability:{schemaVersion:1,operation:"text.generate",prompt:{"$input":"promptPort"},system:"instructions",maxTokens:1200,output:"outputPort"}. Prompt max 32000 characters, system max 8000, maxTokens integer 1..4096. Include 1..3 tests with concrete input and expectations:{outputPort:{kind:"text" or "script",minLength:1,maxLength:12000,includes:["optional required literal"]}} instead of exact expected text. Hosted behavior tests require a separately confirmed model/payment quote; never claim they ran while authoring. Example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.script-draft","version":"1.0.0","name":"Draft a short script","description":"Turn a production brief into a short narration draft using an approved text-generation call.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"prompt":{"type":"text","primary":true,"semantic":"production_brief","required":true,"description":"Production brief that guides the narration draft."}},"outputs":{"script":{"type":"script","primary":true,"semantic":"narration_script","description":"A concise narration script based on the supplied brief."}},"permissions":{"project":[],"capabilities":["text.generate"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"text","port":"prompt"}]},"capability":{"schemaVersion":1,"operation":"text.generate","prompt":{"$input":"prompt"},"system":"Write a concise narration script. Return only the script text.","maxTokens":1200,"output":"script"},"tests":[{"name":"A short opening narration","input":{"prompt":"Write two narration sentences about a quiet forest at sunrise."},"expectations":{"script":{"kind":"script","minLength":20,"maxLength":6000}}}]}.
12818
+ For hosted text generation use {manifest,capability,tests}, runtime:"capability", entry:"src/capability.json", permissions.capabilities:["text.generate"]. Do not write fetch or async calls in JavaScript. The host owns model, provider, BYOK, credits and explicit run consent; never put those fields or keys in package source. One required primary input text|script|brief (structured values require text), one primary output text|script. capability:{schemaVersion:1,operation:"text.generate",prompt:{"$input":"promptPort"},system:"instructions",maxTokens:1200,output:"outputPort"}. Prompt max 32000 characters, system max 8000, maxTokens integer 1..4096. Include 1..3 tests with concrete input and expectations:{outputPort:{kind:"text" or "script",minLength:1,maxLength:12000,includes:["optional required literal"]}} instead of exact expected text. Hosted behavior tests require a separately confirmed model/payment quote; never claim they ran while authoring. Example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.script-draft","action":{"label":"Write script","running":"Writing script…"},"version":"1.0.0","name":"Draft a short script","description":"Turn a production brief into a short narration draft using an approved text-generation call.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"prompt":{"type":"text","primary":true,"semantic":"production_brief","required":true,"description":"Production brief that guides the narration draft."}},"outputs":{"script":{"type":"script","primary":true,"semantic":"narration_script","description":"A concise narration script based on the supplied brief."}},"permissions":{"project":[],"capabilities":["text.generate"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"text","port":"prompt"}]},"capability":{"schemaVersion":1,"operation":"text.generate","prompt":{"$input":"prompt"},"system":"Write a concise narration script. Return only the script text.","maxTokens":1200,"output":"script"},"tests":[{"name":"A short opening narration","input":{"prompt":"Write two narration sentences about a quiet forest at sunrise."},"expectations":{"script":{"kind":"script","minLength":20,"maxLength":6000}}}]}.
12656
12819
 
12657
12820
  ### Hosted media operations
12658
12821
 
12659
- For audio transcription, use runtime:"capability", operation:"audio.transcribe" and permissions.capabilities:["audio.transcribe"]. Declare one primary audio input with an asset control, one text language input defaulting to "auto", and one primary transcript output. Bind the two inputs through capability.audio and capability.language. Provider, model, payment and credentials belong to the host. Fixtures use transcript word-count bounds, never invented provider text. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.transcribe-audio","version":"1.0.0","name":"Transcribe audio","description":"Turn one persistent audio file into reviewed text with word timings.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"audio":{"type":"audio","primary":true},"language":{"type":"text","default":"auto"}},"outputs":{"transcript":{"type":"transcript","primary":true}},"permissions":{"project":[],"capabilities":["audio.transcribe"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"asset","port":"audio"},{"control":"select","port":"language","options":["auto","en","es","fr","de","it","pt","ja","ko","zh"]}]},"capability":{"schemaVersion":1,"operation":"audio.transcribe","audio":{"$input":"audio"},"language":{"$input":"language"},"output":"transcript"},"tests":[{"name":"timed speech","input":{"audio":{"kind":"audio","assetId":"audio-1","versionId":"version-1","url":"/api/media/example/audio.mp3","mimeType":"audio/mpeg"},"language":"en"},"expectations":{"transcript":{"kind":"transcript","minWords":1,"maxWords":1000}}}]}.
12660
- For narration or speech synthesis, use runtime:"capability", operation:"audio.speech" and permissions.capabilities:["audio.speech"]. One required primary text or script input feeds capability.text via {$input:"portName"}; a script value contains schemaVersion:1 and text. One primary audio output is named by capability.output. Text must be at most 3800 characters. The host owns the voice, model, provider, billing and BYOK. Do not put those choices in package code. Tests use audio expectations (WAV, duration and byte bounds), never invented exact audio. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.narrate-script","version":"1.0.0","name":"Narrate a script","description":"Turn a short script into a reviewed speech recording using a host-selected voice.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"script":{"type":"script","primary":true,"semantic":"narration_script","required":true,"description":"Narration script to render as speech."}},"outputs":{"audio":{"type":"audio","primary":true,"semantic":"speech_audio","description":"Speech audio generated from the narration script."}},"permissions":{"project":[],"capabilities":["audio.speech"],"network":[],"filesystem":[],"secrets":[]},"ui":[]},"capability":{"schemaVersion":1,"operation":"audio.speech","text":{"$input":"script"},"output":"audio"},"tests":[{"name":"Read a short welcome","input":{"script":{"schemaVersion":1,"text":"Welcome to the quiet forest."}},"expectations":{"audio":{"kind":"audio","format":"wav","minDuration":0.1,"maxDuration":30,"minBytes":46,"maxBytes":1500000}}}]}.
12661
- For image generation, use runtime:"capability", operation:"image.generate" and permissions.capabilities:["image.generate"]. One required primary text input feeds capability.prompt via {$input:"portName"}; one primary image output is named by capability.output. Prompt limit 32000 characters. The supported output is PNG 1024x1024, at most 12000000 bytes. Tests use image expectations, never fabricated generated URLs or pixels. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.generate-image","version":"1.0.0","name":"Generate an image","description":"Generate a square PNG from a short visual prompt using an approved host request.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"prompt":{"type":"text","primary":true,"semantic":"image_prompt","required":true,"description":"Visual description of the image to generate."}},"outputs":{"image":{"type":"image","primary":true,"semantic":"generated_image","description":"The generated square PNG image."}},"permissions":{"project":[],"capabilities":["image.generate"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"text","port":"prompt"}]},"capability":{"schemaVersion":1,"operation":"image.generate","prompt":{"$input":"prompt"},"output":"image"},"tests":[{"name":"A simple forest illustration","input":{"prompt":"A simple illustration of a quiet forest with clear dark outlines and soft green colors."},"expectations":{"image":{"kind":"image","format":"png","width":1024,"height":1024,"minBytes":67,"maxBytes":12000000}}}]}.
12662
- For image or video analysis (what a photo shows, which photos show different angles, the words on a menu or sign), use runtime:"capability", operation:"media.analyze" and permissions.capabilities:["media.analyze"]: StillMade credits pay for it, while image.describe runs only on the person's own OpenRouter key, so never use it. Declare one primary image input, one image[] input of one to four images, or one video input (with optional start and end number inputs, bound through capability.range:{start:{"$input":"start"},end:{"$input":"end"}}), and one primary text or json output. capability:{schemaVersion:1,operation:"media.analyze",media:{"$input":"photo"},question:"what to look for, at most 2,000 characters",output:"notes"}; a text output gets each picture's summary, a json output {schemaVersion:1,items}. For a quick rating of photos (sorting or picking), add detail:"check": images only, one short answer each, one credit per call of up to four photos instead of four credits per picture. The host loads only owned media and controls provider, model, payment and approval. Tests give saved references and expect json that includes summary, or text length bounds, never invented live answers. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.check-clip","version":"1.0.0","name":"Check a clip","description":"Answer a production question about a saved video clip, with timestamps.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"clip":{"type":"video","primary":true,"semantic":"source_video","required":true,"description":"Saved video to check."},"start":{"type":"number","required":false,"min":0,"semantic":"range_start","description":"Optional start of the range to look at closely, in seconds."},"end":{"type":"number","required":false,"min":0,"semantic":"range_end","description":"Optional end of the range, in seconds (at most 12 seconds after the start)."}},"outputs":{"report":{"type":"json","primary":true,"semantic":"media_findings","description":"Summary, timeline, on-screen text and issues found."}},"permissions":{"project":[],"capabilities":["media.analyze"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"asset","port":"clip"},{"control":"number","port":"start"},{"control":"number","port":"end"}]},"capability":{"schemaVersion":1,"operation":"media.analyze","media":{"$input":"clip"},"question":"Is the product logo clearly visible, and when? List any on-screen text and visible defects.","range":{"start":{"$input":"start"},"end":{"$input":"end"}},"output":"report"},"tests":[{"name":"A saved clip","input":{"clip":{"kind":"video","assetId":"clip-1","versionId":"v1","url":"/api/media/owner/clip.mp4"}},"expectations":{"report":{"kind":"json","includes":["summary"]}}}]}.
12663
- For AI-directed editing, use runtime:"capability", operation:"timeline.propose" and permissions.capabilities:["timeline.propose"]. Declare one current timeline input, up to three additional typed context inputs, and one timeline-edit output. Bind every input exactly once through capability.context; declare context.timeline.read and timeline.propose. StillMade controls the provider, strict JSON validation, stale-before checks, preview and Apply. Tests declare timeline-edit command bounds, never fabricated provider results. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.timeline-polish","version":"1.0.0","name":"Timeline polish","description":"Turn a timeline and editing direction into a bounded proposal that remains reviewable before Apply.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"timeline":{"type":"timeline","context":"timeline","primary":true},"direction":{"type":"text","default":"Polish this cut conservatively."}},"outputs":{"edit":{"type":"timeline-edit","primary":true}},"permissions":{"project":["context.timeline.read","timeline.propose"],"capabilities":["timeline.propose"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"text","port":"direction"}]},"capability":{"schemaVersion":1,"operation":"timeline.propose","context":{"timeline":{"$input":"timeline"},"direction":{"$input":"direction"}},"instruction":"Use only supported timeline-edit commands, exact before snapshots, and the current activeTimelineId. Preserve media and locked items. Return strict JSON only.","maxTokens":2000,"output":"edit"},"tests":[{"name":"one restrained edit","input":{"timeline":{"schemaVersion":1,"activeTimelineId":"timeline-1","tracks":[{"id":"video"}],"clips":[{"id":"clip-1","trackId":"video","start":0,"duration":4}],"audioItems":[],"captions":[]},"direction":"Add a soft transition."},"expectations":{"edit":{"kind":"timeline-edit","minCommands":1,"maxCommands":10}}}]}.
12664
- For video generation use runtime:"capability", operation:"video.generate", permissions.capabilities:["video.generate"], one primary text input and one primary video output. capability.prompt references the input and capability.output names the output. Prompt limit 32000. Tests declare MP4 duration, dimensions and byte bounds; never fabricate video URLs. The enabled host selects its supported model, duration, resolution, payment and approved quote; packages cannot choose provider settings or dispatch jobs. Shipped example: {"manifest":{"schemaVersion":1,"id":"example.generate-video","name":"Generate video","version":"1.0.0","sdkVersion":"0.1.0","description":"Turn a production prompt into a short video using an approved host provider.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"prompt":{"type":"text","primary":true,"required":true}},"outputs":{"video":{"type":"video","primary":true}},"permissions":{"project":[],"capabilities":["video.generate"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"port":"prompt","control":"text"}]},"capability":{"schemaVersion":1,"operation":"video.generate","prompt":{"$input":"prompt"},"output":"video"},"tests":[{"name":"Produces a bounded MP4 sample","input":{"prompt":"A paper boat floating across a calm blue pond. Gentle camera movement."},"expectations":{"video":{"kind":"video","format":"mp4","minDuration":1,"maxDuration":60,"minBytes":32,"maxBytes":67108864,"minWidth":1,"maxWidth":3840,"minHeight":1,"maxHeight":3840}}}]}.
12822
+ For audio transcription, use runtime:"capability", operation:"audio.transcribe" and permissions.capabilities:["audio.transcribe"]. Declare one primary audio input with an asset control, one text language input defaulting to "auto", and one primary transcript output. Bind the two inputs through capability.audio and capability.language. Provider, model, payment and credentials belong to the host. Fixtures use transcript word-count bounds, never invented provider text. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.transcribe-audio","action":{"label":"Transcribe audio","running":"Transcribing…"},"version":"1.0.0","name":"Transcribe audio","description":"Turn one persistent audio file into reviewed text with word timings.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"audio":{"type":"audio","primary":true},"language":{"type":"text","default":"auto"}},"outputs":{"transcript":{"type":"transcript","primary":true}},"permissions":{"project":[],"capabilities":["audio.transcribe"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"asset","port":"audio"},{"control":"select","port":"language","options":["auto","en","es","fr","de","it","pt","ja","ko","zh"]}]},"capability":{"schemaVersion":1,"operation":"audio.transcribe","audio":{"$input":"audio"},"language":{"$input":"language"},"output":"transcript"},"tests":[{"name":"timed speech","input":{"audio":{"kind":"audio","assetId":"audio-1","versionId":"version-1","url":"/api/media/example/audio.mp3","mimeType":"audio/mpeg"},"language":"en"},"expectations":{"transcript":{"kind":"transcript","minWords":1,"maxWords":1000}}}]}.
12823
+ For narration or speech synthesis, use runtime:"capability", operation:"audio.speech" and permissions.capabilities:["audio.speech"]. One required primary text or script input feeds capability.text via {$input:"portName"}; a script value contains schemaVersion:1 and text. One primary audio output is named by capability.output. Text must be at most 3800 characters. The host owns the voice, model, provider, billing and BYOK. Do not put those choices in package code. Tests use audio expectations (WAV, duration and byte bounds), never invented exact audio. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.narrate-script","action":{"label":"Generate voiceover","running":"Generating voiceover…"},"version":"1.0.0","name":"Narrate a script","description":"Turn a short script into a reviewed speech recording using a host-selected voice.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"script":{"type":"script","primary":true,"semantic":"narration_script","required":true,"description":"Narration script to render as speech."}},"outputs":{"audio":{"type":"audio","primary":true,"semantic":"speech_audio","description":"Speech audio generated from the narration script."}},"permissions":{"project":[],"capabilities":["audio.speech"],"network":[],"filesystem":[],"secrets":[]},"ui":[]},"capability":{"schemaVersion":1,"operation":"audio.speech","text":{"$input":"script"},"output":"audio"},"tests":[{"name":"Read a short welcome","input":{"script":{"schemaVersion":1,"text":"Welcome to the quiet forest."}},"expectations":{"audio":{"kind":"audio","format":"wav","minDuration":0.1,"maxDuration":30,"minBytes":46,"maxBytes":1500000}}}]}.
12824
+ For image generation, use runtime:"capability", operation:"image.generate" and permissions.capabilities:["image.generate"]. One required primary text input feeds capability.prompt via {$input:"portName"}; one primary image output is named by capability.output. Prompt limit 32000 characters. The supported output is PNG 1024x1024, at most 12000000 bytes. Tests use image expectations, never fabricated generated URLs or pixels. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.generate-image","action":{"label":"Generate image","running":"Generating image…"},"version":"1.0.0","name":"Generate an image","description":"Generate a square PNG from a short visual prompt using an approved host request.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"prompt":{"type":"text","primary":true,"semantic":"image_prompt","required":true,"description":"Visual description of the image to generate."}},"outputs":{"image":{"type":"image","primary":true,"semantic":"generated_image","description":"The generated square PNG image."}},"permissions":{"project":[],"capabilities":["image.generate"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"text","port":"prompt"}]},"capability":{"schemaVersion":1,"operation":"image.generate","prompt":{"$input":"prompt"},"output":"image"},"tests":[{"name":"A simple forest illustration","input":{"prompt":"A simple illustration of a quiet forest with clear dark outlines and soft green colors."},"expectations":{"image":{"kind":"image","format":"png","width":1024,"height":1024,"minBytes":67,"maxBytes":12000000}}}]}.
12825
+ For image or video analysis (what a photo shows, which photos show different angles, the words on a menu or sign), use runtime:"capability", operation:"media.analyze" and permissions.capabilities:["media.analyze"]: StillMade credits pay for it, while image.describe runs only on the person's own OpenRouter key, so never use it. Declare one primary image input, one image[] input of one to four images, or one video input (with optional start and end number inputs, bound through capability.range:{start:{"$input":"start"},end:{"$input":"end"}}), and one primary text or json output. capability:{schemaVersion:1,operation:"media.analyze",media:{"$input":"photo"},question:"what to look for, at most 2,000 characters",output:"notes"}; a text output gets each picture's summary, a json output {schemaVersion:1,items}. For a quick rating of photos (sorting or picking), add detail:"check": images only, one short answer each, one credit per call of up to four photos instead of four credits per picture. The host loads only owned media and controls provider, model, payment and approval. Tests give saved references and expect json that includes summary, or text length bounds, never invented live answers. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.check-clip","action":{"label":"Check clip","running":"Checking clip…"},"version":"1.0.0","name":"Check a clip","description":"Answer a production question about a saved video clip, with timestamps.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"clip":{"type":"video","primary":true,"semantic":"source_video","required":true,"description":"Saved video to check."},"start":{"type":"number","required":false,"min":0,"semantic":"range_start","description":"Optional start of the range to look at closely, in seconds."},"end":{"type":"number","required":false,"min":0,"semantic":"range_end","description":"Optional end of the range, in seconds (at most 12 seconds after the start)."}},"outputs":{"report":{"type":"json","primary":true,"semantic":"media_findings","description":"Summary, timeline, on-screen text and issues found."}},"permissions":{"project":[],"capabilities":["media.analyze"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"asset","port":"clip"},{"control":"number","port":"start"},{"control":"number","port":"end"}]},"capability":{"schemaVersion":1,"operation":"media.analyze","media":{"$input":"clip"},"question":"Is the product logo clearly visible, and when? List any on-screen text and visible defects.","range":{"start":{"$input":"start"},"end":{"$input":"end"}},"output":"report"},"tests":[{"name":"A saved clip","input":{"clip":{"kind":"video","assetId":"clip-1","versionId":"v1","url":"/api/media/owner/clip.mp4"}},"expectations":{"report":{"kind":"json","includes":["summary"]}}}]}.
12826
+ For AI-directed editing, use runtime:"capability", operation:"timeline.propose" and permissions.capabilities:["timeline.propose"]. Declare one current timeline input, up to three additional typed context inputs, and one timeline-edit output. Bind every input exactly once through capability.context; declare context.timeline.read and timeline.propose. StillMade controls the provider, strict JSON validation, stale-before checks, preview and Apply. Tests declare timeline-edit command bounds, never fabricated provider results. Shipped example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.timeline-polish","action":{"label":"Suggest edit","running":"Suggesting edit…"},"version":"1.0.0","name":"Timeline polish","description":"Turn a timeline and editing direction into a bounded proposal that remains reviewable before Apply.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"timeline":{"type":"timeline","context":"timeline","primary":true},"direction":{"type":"text","default":"Polish this cut conservatively."}},"outputs":{"edit":{"type":"timeline-edit","primary":true}},"permissions":{"project":["context.timeline.read","timeline.propose"],"capabilities":["timeline.propose"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"control":"text","port":"direction"}]},"capability":{"schemaVersion":1,"operation":"timeline.propose","context":{"timeline":{"$input":"timeline"},"direction":{"$input":"direction"}},"instruction":"Use only supported timeline-edit commands, exact before snapshots, and the current activeTimelineId. Preserve media and locked items. Return strict JSON only.","maxTokens":2000,"output":"edit"},"tests":[{"name":"one restrained edit","input":{"timeline":{"schemaVersion":1,"activeTimelineId":"timeline-1","tracks":[{"id":"video"}],"clips":[{"id":"clip-1","trackId":"video","start":0,"duration":4}],"audioItems":[],"captions":[]},"direction":"Add a soft transition."},"expectations":{"edit":{"kind":"timeline-edit","minCommands":1,"maxCommands":10}}}]}.
12827
+ For video generation use runtime:"capability", operation:"video.generate", permissions.capabilities:["video.generate"], one primary text input and one primary video output. capability.prompt references the input and capability.output names the output. Prompt limit 32000. Tests declare MP4 duration, dimensions and byte bounds; never fabricate video URLs. The enabled host selects its supported model, duration, resolution, payment and approved quote; packages cannot choose provider settings or dispatch jobs. Shipped example: {"manifest":{"schemaVersion":1,"id":"example.generate-video","action":{"label":"Generate video","running":"Generating video…"},"name":"Generate video","version":"1.0.0","sdkVersion":"0.1.0","description":"Turn a production prompt into a short video using an approved host provider.","kind":"task","runtime":"capability","entry":"src/capability.json","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"prompt":{"type":"text","primary":true,"required":true}},"outputs":{"video":{"type":"video","primary":true}},"permissions":{"project":[],"capabilities":["video.generate"],"network":[],"filesystem":[],"secrets":[]},"ui":[{"port":"prompt","control":"text"}]},"capability":{"schemaVersion":1,"operation":"video.generate","prompt":{"$input":"prompt"},"output":"video"},"tests":[{"name":"Produces a bounded MP4 sample","input":{"prompt":"A paper boat floating across a calm blue pond. Gentle camera movement."},"expectations":{"video":{"kind":"video","format":"mp4","minDuration":1,"maxDuration":60,"minBytes":32,"maxBytes":67108864,"minWidth":1,"maxWidth":3840,"minHeight":1,"maxHeight":3840}}}]}.
12665
12828
  A capability package performs exactly one supported operation. A job that needs several (transcribe a recording, then find what is said in it; write words, then voice them), or code between two operations, is one module Block that calls each with stillmade.hosted.run (Module Blocks); never split one job into part Blocks, and never invent a combined capability runtime. Hosted image, speech and video source can be statically validated while authoring, but real fixture/sample generation requires the user's subsequent model/payment selection and quote confirmation. Do not claim those calls ran. Deterministic image transformations should remain sandboxed recipe or JavaScript code when supported; do not generate a new image as a substitute for processing an existing one.
12666
12829
 
12667
12830
  ### Module Blocks
@@ -12688,7 +12851,7 @@ To propose changes to an existing blueprint, panels, board, canvas, or animation
12688
12851
 
12689
12852
  *When:* StillMade's builder adds this section when the request needs memory, counting or persistence, or refines a stateful Block.
12690
12853
 
12691
- For memory use runtime:"javascript", manifest.state:{scope:"step",version:1,initial:{...}}, permissions.project including "state.step". Code receives mutable plain-object state separately from input. Mutate state and return only declared output bindings; never return a state envelope as an undeclared output. Each test needs expectedState:{version:1,value:{...}}; a test may supply state:{version:1,value:{...}} to verify continuation. Memory is bounded to 64 KiB and scoped to a placement. The host saves it only with accepted successful output; previews use disposable memory. No localStorage, files, global or account-shared state. Interactive selections support successive memory; unattended future-media execution is not supported for stateful Blocks. Preserve the state schema/version during refinement unless the user requests a schema change. For an explicit upgrade, the new version may declare manifest.state.migrations:[{fromVersion:1,operations:[{op:"rename",from:"oldField",to:"newField"},{op:"default",key:"labels",value:[]}]}], targeting its enclosing state.version (for example 2). Use only ordered top-level rename/default/remove operations; remove uses {op:"remove",key:"field"}. Renames require an existing source and absent destination, defaults never overwrite, removals require an existing field. At most 16 distinct older fromVersion routes, 64 operations each, and 64 KiB combined declarations and intermediate state. No chains, downgrade, arbitrary code or automatic application. Bump the Block version when source or migrations change, retain unrelated state, and never invent an old field layout. Owners preview and explicitly apply migrations to exact archived source-bound state through the project host; authoring does not mutate existing projects. New execution fixtures use the target state version. Exact example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.numbered-takes","version":"1.0.0","name":"Numbered takes","description":"Label successive creative takes with an independent counter for each production placement.","kind":"task","runtime":"javascript","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"text":{"type":"text","primary":true,"semantic":"draft_text","required":true,"description":"Creative take text to label with the next number."}},"outputs":{"text":{"type":"text","primary":true,"semantic":"numbered_take","description":"The supplied take prefixed with its saved sequence number."}},"permissions":{"project":["state.step"]},"state":{"scope":"step","version":1,"initial":{"count":0}},"ui":[{"port":"text","control":"text"}]},"code":"state.count += 1; return {text: \"Take \" + state.count + \": \" + input.text.trim()};","tests":[{"name":"First take","input":{"text":" Opening scene "},"expected":{"text":"Take 1: Opening scene"},"expectedState":{"version":1,"value":{"count":1}}},{"name":"Continues saved numbering","input":{"text":"Alternate ending"},"state":{"version":1,"value":{"count":4}},"expected":{"text":"Take 5: Alternate ending"},"expectedState":{"version":1,"value":{"count":5}}}]}.
12854
+ For memory use runtime:"javascript", manifest.state:{scope:"step",version:1,initial:{...}}, permissions.project including "state.step". Code receives mutable plain-object state separately from input. Mutate state and return only declared output bindings; never return a state envelope as an undeclared output. Each test needs expectedState:{version:1,value:{...}}; a test may supply state:{version:1,value:{...}} to verify continuation. Memory is bounded to 64 KiB and scoped to a placement. The host saves it only with accepted successful output; previews use disposable memory. No localStorage, files, global or account-shared state. Interactive selections support successive memory; unattended future-media execution is not supported for stateful Blocks. Preserve the state schema/version during refinement unless the user requests a schema change. For an explicit upgrade, the new version may declare manifest.state.migrations:[{fromVersion:1,operations:[{op:"rename",from:"oldField",to:"newField"},{op:"default",key:"labels",value:[]}]}], targeting its enclosing state.version (for example 2). Use only ordered top-level rename/default/remove operations; remove uses {op:"remove",key:"field"}. Renames require an existing source and absent destination, defaults never overwrite, removals require an existing field. At most 16 distinct older fromVersion routes, 64 operations each, and 64 KiB combined declarations and intermediate state. No chains, downgrade, arbitrary code or automatic application. Bump the Block version when source or migrations change, retain unrelated state, and never invent an old field layout. Owners preview and explicitly apply migrations to exact archived source-bound state through the project host; authoring does not mutate existing projects. New execution fixtures use the target state version. Exact example: {"manifest":{"schemaVersion":1,"sdkVersion":"0.1.0","id":"example.numbered-takes","action":{"label":"Number takes","running":"Numbering takes…"},"version":"1.0.0","name":"Numbered takes","description":"Label successive creative takes with an independent counter for each production placement.","kind":"task","runtime":"javascript","license":"MIT","provenance":{"notice":"MIT License\n\nCopyright (c) 2026 StillMade SDK contributors\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"},"inputs":{"text":{"type":"text","primary":true,"semantic":"draft_text","required":true,"description":"Creative take text to label with the next number."}},"outputs":{"text":{"type":"text","primary":true,"semantic":"numbered_take","description":"The supplied take prefixed with its saved sequence number."}},"permissions":{"project":["state.step"]},"state":{"scope":"step","version":1,"initial":{"count":0}},"ui":[{"port":"text","control":"text"}]},"code":"state.count += 1; return {text: \"Take \" + state.count + \": \" + input.text.trim()};","tests":[{"name":"First take","input":{"text":" Opening scene "},"expected":{"text":"Take 1: Opening scene"},"expectedState":{"version":1,"value":{"count":1}}},{"name":"Continues saved numbering","input":{"text":"Alternate ending"},"state":{"version":1,"value":{"count":4}},"expected":{"text":"Take 5: Alternate ending"},"expectedState":{"version":1,"value":{"count":5}}}]}.
12692
12855
 
12693
12856
  ### Editor timeline proposals
12694
12857
 
@@ -12714,7 +12877,7 @@ Optional custom view interfaces are supported, but generated manifest.ui control
12714
12877
 
12715
12878
  *When:* StillMade's builder adds this section when the person asks for an interface, preview or controls, or refines a Block that has one.
12716
12879
 
12717
- A custom interface is the optional package-level view:{html,css?,themedCss?,javascript?}; when refining, preserve and refine base.view. Design it by StillMade's interface principles, in order: 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. 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. Never a JSON dump, source editor, manifest or diagnostic panel unless the task is about source. One obvious next action (`sm-primary`); peers are quiet buttons or named icons. Seven or fewer choices in view. The action button names what it does ("Write", "Generate image", "Make video"), never "Run", "Run step", "Submit" or "Review cost". 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. 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. Words only when needed. Drop what nobody needs to finish the task (intros, "how it works", restating the Block name). Words that might help start collapsed (`sm-hint`, `sm-more`). Errors, spending approvals, stale inputs and destructive steps stay visible, in few words. Strong defaults; secondary settings go in `sm-more`, closed. 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. Status is a dot or a few words ("No narration yet"), never a paragraph; the reason sits behind an `sm-hint`. 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. Rare tools (update, schedule, history, reload) are named icon buttons beside the action, never sections under the work. 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. One workspace: no cards inside cards, no second title, step counter or Back/Next bar; the host owns navigation. Status sits beside the action it describes (`sm-status`), in a few words. Keep the page in normal scroll flow; no sticky media or control strips unless the editing task needs them. 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. 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. 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. 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. On a phone chip and segment rows scroll sideways instead of wrapping; long lists show their first three with "N more" (`data-peek`) and long text five lines until tapped (`sm-clamp`). Nothing is lost when a Block gets smaller: every control stays on the screen, behind an (i), in `sm-more`, or inside the item it belongs to. Compacting moves controls; it never deletes them. Text scene descriptions are planning notes, never a storyboard or an approved frame. Its DOM controller is separate from manifest runtime code. The view may also declare appearance:"original" or "host". For an imported design, preserve its colors with appearance:"original" and view.css; no themed replacement is required. Preserve base.view.appearance when refining unless the user requests a change. Omitted/host appearance retains the existing Light, Dark and White requirement: supply semantic colors in view.css or a complete replacement view.themedCss. An original-style view may optionally supply valid themedCss for a StillMade appearance preview. Use StillMade variables (--bg,--fg,--fg-muted,--border-tok,--r-3) only when opting into host styling; do not redefine host tokens in the themed variant. Appearance never relaxes sandbox constraints: no CSS escapes/filters/blending, imports/url(), or element.style mutations in JS. Use classes for UI state; media pixels retain their colors. Both CSS fields have the same 32 KiB limit; all existing shared-state, security and permission checks still apply. Declare elements in html, bind with document.getElementById/querySelector and addEventListener; use literal property access, array methods, textContent, input.value, button.disabled and canvas. Initial values: StillMade.onInput(values=>{...}); await StillMade.run(inputBindings) returns validated output bindings from the isolated package runtime; catch errors and show results. No computation in the DOM controller; put it in code/recipe. Disable the action button while pending.
12880
+ A custom interface is the optional package-level view:{html,css?,themedCss?,javascript?}; when refining, preserve and refine base.view. Design it by StillMade's interface principles, in order: 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. 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. 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. 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. 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. A picked option reads at a glance: keep the kit's ink fill on an `sm-choices` pick, never restyled to an outline, a tint or the page's background. Media that cannot show here (on another device, or it did not open) keeps its place as a quiet `sm-media-off` tile in its own shape, never words in its place. Words only when needed. Drop what nobody needs to finish the task (intros, "how it works", restating the Block name). Words that might help start collapsed (`sm-hint`, `sm-more`). Errors, spending approvals, stale inputs and destructive steps stay visible, in few words. Strong defaults; secondary settings go in `sm-more`, closed. 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. Status is a dot or a few words ("No narration yet"), never a paragraph; the reason sits behind an `sm-hint`. 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. Rare tools (update, schedule, history, reload) are named icon buttons beside the action, never sections under the work. 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. One workspace: no cards inside cards, no second title, step counter or Back/Next bar; the host owns navigation. Status sits beside the action it describes (`sm-status`), in a few words. Keep the page in normal scroll flow; no sticky media or control strips unless the editing task needs them. 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. 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. 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. 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. On a phone chip and segment rows scroll sideways instead of wrapping; long lists show their first three with "N more" (`data-peek`) and long text five lines until tapped (`sm-clamp`). Nothing is lost when a Block gets smaller: every control stays on the screen, behind an (i), in `sm-more`, or inside the item it belongs to. Compacting moves controls; it never deletes them. Text scene descriptions are planning notes, never a storyboard or an approved frame. Say nothing about how the Block works: no notes on where it runs (this device, StillMade Desktop, the cloud), saving, syncing, recovery, accounts, credits or where a file is kept. StillMade tells the person what they need as one short notification, or nothing; never a sentence on the page, and never the same line under each item. References fill your inputs: every drop area in StillMade offers "Use a reference", and the person's saved photos, videos and notes fill the Step with no typing. Media inputs fill by kind, so take `video` or `asset` wherever a clip works as well as a photo; text inputs fill by plain names and labels (`productName`, `website`, `brandColors`, `fonts`, `voice`, and `details` or `notes` for the reference's note). Never build your own reference picker or library upload. Days and times are picked, never typed: a `date` input is a calendar, with a list of times when it is about a time (`postAt`, `startsAt`, a label with Time, When or Starts). In a custom view use `<input type="date">` or `type="datetime-local"`, never a text box for a date. Posting is its own Step: sending a result to Instagram, TikTok, email or any app is a connector Step after the Block, worded by StillMade ("Post to Instagram"). A Block never posts from inside itself. Its DOM controller is separate from manifest runtime code. The view may also declare appearance:"original" or "host". For an imported design, preserve its colors with appearance:"original" and view.css; no themed replacement is required. Preserve base.view.appearance when refining unless the user requests a change. Omitted/host appearance retains the existing Light, Dark and White requirement: supply semantic colors in view.css or a complete replacement view.themedCss. An original-style view may optionally supply valid themedCss for a StillMade appearance preview. Use StillMade variables (--bg,--fg,--fg-muted,--border-tok,--r-3) only when opting into host styling; do not redefine host tokens in the themed variant. Appearance never relaxes sandbox constraints: no CSS escapes/filters/blending, imports/url(), or element.style mutations in JS. Use classes for UI state; media pixels retain their colors. Both CSS fields have the same 32 KiB limit; all existing shared-state, security and permission checks still apply. Declare elements in html, bind with document.getElementById/querySelector and addEventListener; use literal property access, array methods, textContent, input.value, button.disabled and canvas. Initial values: StillMade.onInput(values=>{...}); await StillMade.run(inputBindings) returns validated output bindings from the isolated package runtime; catch errors and show results. No computation in the DOM controller; put it in code/recipe. Disable the action button while pending.
12718
12881
  Standard custom view code (no `view.config.json` frame runtime) is checked before it runs. These rules come straight from the validator; frame views run in their own sandbox and may build the page with ordinary DOM calls such as `createElement`:
12719
12882
 
12720
12883
  - **HTML elements:** only `div`, `section`, `article`, `header`, `footer`, `main`, `aside`, `nav`, `h1`, `h2`, `h3`, `h4`, `p`, `span`, `strong`, `em`, `i`, `small`, `br`, `hr`, `label`, `input`, `textarea`, `button`, `select`, `option`, `optgroup`, `fieldset`, `legend`, `output`, `progress`, `meter`, `ul`, `ol`, `li`, `dl`, `dt`, `dd`, `figure`, `figcaption`, `img`, `video`, `audio`, `source`, `canvas`, `table`, `thead`, `tbody`, `tfoot`, `tr`, `th`, `td`, `pre`, `code`, `details`, `summary`. No scripts, iframes, SVG, forms, comments or inline event attributes; media URLs must be `data:` or `blob:`.