stillmade-sdk 0.1.41 → 0.1.43
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.
- package/.stillmade/sdk-baseline.json +19 -21
- package/AGENTS.md +17 -12
- package/FRAME_VIEWS.md +113 -0
- package/INTERFACE_DESIGN.md +67 -22
- package/MOBILE_UI.md +4 -2
- package/MODULES.md +152 -6
- package/PASTE_TO_LLM.md +42 -32
- package/README.md +3 -2
- package/SDK.md +1028 -563
- package/UI_AESTHETIC.md +30 -3
- package/blocks/generate/package.js +1 -0
- package/blocks/generate/versions/1.0.0/package.js +463 -0
- package/docs/build/audio-to-editor.md +36 -0
- package/docs/build/block-builder-contract.md +150 -0
- package/docs/build/comfyui.md +227 -0
- package/docs/build/concepts.md +40 -0
- package/docs/build/context.md +159 -0
- package/docs/build/cookbook.md +57 -0
- package/docs/build/custom-interface.md +617 -0
- package/docs/build/data-types.md +83 -0
- package/docs/build/frame-views.md +259 -0
- package/docs/build/generate-media.md +59 -0
- package/docs/build/github-applications.md +314 -0
- package/docs/build/hosted-images.md +214 -0
- package/docs/build/hosted-music.md +39 -0
- package/docs/build/hosted-speech.md +157 -0
- package/docs/build/hosted-text.md +246 -0
- package/docs/build/image-description.md +49 -0
- package/docs/build/interface-design.md +343 -0
- package/docs/build/javascript.md +63 -0
- package/docs/build/local-preview.md +61 -0
- package/docs/build/media-analysis.md +27 -0
- package/docs/build/media.md +400 -0
- package/docs/build/mobile-ui.md +106 -0
- package/docs/build/modules.md +487 -0
- package/docs/build/original-blocks.md +70 -0
- package/docs/build/outside-apis.md +128 -0
- package/docs/build/production-context-templates.md +12 -0
- package/docs/build/project-storage.md +94 -0
- package/docs/build/quickstart.md +48 -0
- package/docs/build/recipes.md +103 -0
- package/docs/build/script-handoff.md +45 -0
- package/docs/build/script-writer.md +34 -0
- package/docs/build/state.md +223 -0
- package/docs/build/testing.md +112 -0
- package/docs/build/timeline-edits.md +116 -0
- package/docs/build/timeline-proposals.md +76 -0
- package/docs/build/transcription.md +59 -0
- package/docs/build/triggers.md +59 -0
- package/docs/build/tutorial.md +52 -0
- package/docs/build/typescript.md +34 -0
- package/docs/build/video-generation.md +61 -0
- package/docs/build/web-reading.md +37 -0
- package/docs/build/with-your-ai.md +27 -0
- package/docs/changelog.md +9 -0
- package/docs/creators.md +21 -0
- package/docs/distribute/discovery.md +43 -0
- package/docs/distribute/imports.md +58 -0
- package/docs/distribute/publishing.md +29 -0
- package/docs/distribute/sdk-versions.md +36 -0
- package/docs/distribute/selling.md +14 -0
- package/docs/distribute/teams.md +60 -0
- package/docs/distribute/versioning.md +28 -0
- package/docs/examples.md +23 -0
- package/docs/gallery.md +26 -0
- package/docs/index.md +50 -0
- package/docs/native-mcp.md +307 -0
- package/docs/project-types/automation.md +43 -0
- package/docs/project-types/batches.md +50 -0
- package/docs/project-types/build.md +42 -0
- package/docs/project-types/completion.md +15 -0
- package/docs/project-types/conditions.md +21 -0
- package/docs/project-types/hosted-review.md +115 -0
- package/docs/project-types/onboarding.md +75 -0
- package/docs/project-types/running.md +309 -0
- package/docs/project-types/testing.md +72 -0
- package/docs/reference/application-artifacts.md +87 -0
- package/docs/reference/authoring-guide.md +134 -0
- package/docs/reference/browser-applications.md +267 -0
- package/docs/reference/capabilities.md +45 -0
- package/docs/reference/cli.md +71 -0
- package/docs/reference/connection-api.md +59 -0
- package/docs/reference/cooperative-jobs.md +13 -0
- package/docs/reference/desktop-capabilities.md +172 -0
- package/docs/reference/desktop-execution.md +77 -0
- package/docs/reference/errors.md +233 -0
- package/docs/reference/execution.md +800 -0
- package/docs/reference/first-party-blocks.md +40 -0
- package/docs/reference/generation-models.md +59 -0
- package/docs/reference/limits.md +306 -0
- package/docs/reference/manifest-kinds-controls.md +36 -0
- package/docs/reference/manifest.md +181 -0
- package/docs/reference/operations.md +36 -0
- package/docs/reference/package-jobs.md +35 -0
- package/docs/reference/parity.md +55 -0
- package/docs/reference/permissions.md +86 -0
- package/docs/reference/ports.md +26 -0
- package/docs/reference/types.md +268 -0
- package/docs/reference/universal-resolver.md +303 -0
- package/docs/reference/view-bridge.md +60 -0
- package/docs/reference/view-rules.md +15 -0
- package/docs/reference/workspace-sync.md +25 -0
- package/docs/sdk.md +34 -0
- package/docs/tools/block-remix.md +211 -0
- package/docs/tools/llm.md +2213 -0
- package/docs/tools/repository-adaptation.md +613 -0
- package/examples/check-clip.stillmade.json +8 -1
- package/examples/clean-text.stillmade.json +4 -0
- package/examples/custom-interface.stillmade.json +4 -0
- package/examples/describe-image.stillmade.json +4 -0
- package/examples/foley-cue.stillmade.json +4 -0
- package/examples/generate-image.stillmade.json +4 -0
- package/examples/generate-video.stillmade.json +10 -2
- package/examples/module-word-stats/stillmade.block.json +4 -0
- package/examples/narrate-script.stillmade.json +4 -0
- package/examples/numbered-takes.stillmade.json +4 -0
- package/examples/research-topic.stillmade.json +9 -1
- package/examples/score-a-scene.stillmade.json +4 -0
- package/examples/script-draft.stillmade.json +4 -0
- package/examples/summarize-page.stillmade.json +4 -0
- package/examples/text-workflow.stillmade.json +7 -32
- package/examples/thicken-lines.stillmade.json +4 -0
- package/examples/timeline-polish.stillmade.json +15 -3
- package/examples/transcribe-audio.stillmade.json +15 -3
- package/examples/word-count.stillmade.json +4 -0
- package/package.json +1 -1
- package/packages/block-cli/cli.js +13 -6
- package/packages/block-cli/dev-host/assets/host.js +81 -38
- package/packages/block-cli/dev-host/assets/index.css +1 -1
- package/packages/block-cli/format.js +1 -1
- package/packages/block-cli/ready-gate.js +4 -0
- package/packages/block-cli/templates.js +37 -19
- package/packages/block-cli/type-packages.js +119 -0
- package/packages/block-platform/block-readiness.js +8 -1
- package/packages/block-platform/canvas.js +2 -1
- package/packages/block-platform/catalog.js +27 -48
- package/packages/block-platform/native-host-inventory.js +0 -226
- package/packages/block-platform/plain-descriptions.js +1 -25
- package/packages/block-platform/project-type-starters.js +13 -53
- package/packages/block-platform/script-handoff.js +2 -4
- package/packages/block-platform/type-workspace.js +2 -0
- package/packages/block-sdk/appearance.js +3 -1
- package/packages/block-sdk/audio-generation-example.js +2 -2
- package/packages/block-sdk/block-tier.js +1 -1
- package/packages/block-sdk/builder-contract.js +13 -11
- package/packages/block-sdk/capabilities.js +1 -1
- package/packages/block-sdk/capability-example.js +1 -1
- package/packages/block-sdk/contracts.js +6 -2
- package/packages/block-sdk/examples.js +3 -3
- package/packages/block-sdk/first-party-identities.js +1 -84
- package/packages/block-sdk/first-party-packages.js +3 -85
- package/packages/block-sdk/generation-catalog.js +15 -3
- package/packages/block-sdk/image-description-example.js +1 -1
- package/packages/block-sdk/image-generation-example.js +1 -1
- package/packages/block-sdk/index.d.ts +2 -1
- package/packages/block-sdk/media-analysis-example.js +2 -2
- package/packages/block-sdk/mock-host.js +7 -1
- package/packages/block-sdk/module-example.js +1 -1
- package/packages/block-sdk/module-host-calls.js +35 -10
- package/packages/block-sdk/module-hosted.js +15 -2
- package/packages/block-sdk/module-media-access.js +71 -0
- package/packages/block-sdk/module-node.js +1 -1
- package/packages/block-sdk/portable-media-actions.js +1 -1
- package/packages/block-sdk/runtime.js +1 -1
- package/packages/block-sdk/speech-example.js +1 -1
- package/packages/block-sdk/state-example.js +1 -1
- package/packages/block-sdk/timeline-proposal-example.js +1 -1
- package/packages/block-sdk/transcription-example.js +1 -1
- package/packages/block-sdk/trigger-examples.js +2 -2
- package/packages/block-sdk/video-generation-example.js +1 -1
- package/packages/block-sdk/view-bridge.js +4 -1
- package/packages/block-sdk/view-design.js +44 -15
- package/packages/block-sdk/web-example.js +2 -2
- package/packages/design-system/block-kit.css +53 -12
- package/packages/design-system/block-kit.html +3 -2
- package/blocks/mcp-motion-planner/versions/1.1.0/package.js +0 -97
- package/blocks/motion-designer/versions/1.0.1/package.js +0 -173318
- package/blocks/motion-designer/versions/1.0.2/package.js +0 -173318
- package/blocks/motion-frame-review/versions/1.1.1/package.js +0 -465
- package/blocks/motion-frame-review/versions/1.1.2/package.snapshot.js +0 -572
- package/blocks/narration/package.js +0 -1
- package/blocks/narration/versions/1.0.0/package.js +0 -221
- package/blocks/narration/versions/1.0.1/package.js +0 -221
- package/blocks/native/sm.animated-scene/versions/2.0.0/package.js +0 -475
- package/blocks/native/sm.animated-scene/versions/2.1.0/package.js +0 -498
- package/blocks/native/sm.animated-scene/versions/2.2.0/package.js +0 -524
- package/blocks/native/sm.animated-scene/versions/2.3.0/package.js +0 -618
- package/blocks/native/sm.animated-scene/versions/2.3.1/package.js +0 -618
- package/blocks/native/sm.animated-scene/versions/2.3.2/package.js +0 -723
- package/blocks/native/sm.animated-scene/versions/2.3.3/package.js +0 -723
- package/blocks/native/sm.animated-scene/versions/2.3.4/package.js +0 -676
- package/blocks/native/sm.animated-scene/versions/2.3.5/package.js +0 -693
- package/blocks/native/sm.animated-scene/versions/2.3.6/package.js +0 -700
- package/blocks/native/sm.animated-scene/versions/2.3.7/package.js +0 -747
- package/blocks/native/sm.animated-scene/versions/2.3.8/package.js +0 -769
- package/blocks/native/sm.animated-scene/versions/2.3.9/package.js +0 -769
- package/blocks/native/sm.animated-scene-assistant/versions/1.0.0/package.js +0 -183
- package/blocks/native/sm.blueprint/versions/2.0.0/package.js +0 -358
- package/blocks/native/sm.blueprint/versions/2.1.0/package.js +0 -358
- package/blocks/native/sm.blueprint/versions/2.1.1/package.js +0 -358
- package/blocks/native/sm.blueprint/versions/2.1.2/package.js +0 -358
- package/blocks/native/sm.blueprint/versions/2.1.3/package.js +0 -381
- package/blocks/native/sm.blueprint/versions/2.1.4/package.js +0 -381
- package/blocks/native/sm.blueprint/versions/2.1.5/package.js +0 -339
- package/blocks/native/sm.blueprint/versions/2.1.6/package.js +0 -356
- package/blocks/native/sm.blueprint/versions/2.1.7/package.js +0 -363
- package/blocks/native/sm.blueprint/versions/2.1.8/package.js +0 -410
- package/blocks/native/sm.blueprint/versions/2.1.9/package.js +0 -422
- package/blocks/native/sm.blueprint-assistant/versions/1.0.0/package.js +0 -172
- package/blocks/native/sm.chat/versions/2.0.0/package.js +0 -144
- package/blocks/native/sm.chat/versions/2.0.1/package.js +0 -97
- package/blocks/native/sm.chat/versions/2.0.2/package.js +0 -100
- package/blocks/native/sm.chat/versions/2.0.3/package.js +0 -100
- package/blocks/native/sm.continue-if/versions/1.0.0/package.js +0 -168
- package/blocks/native/sm.describe-media/versions/2.0.0/package.js +0 -153
- package/blocks/native/sm.describe-media/versions/2.0.1/package.js +0 -156
- package/blocks/native/sm.describe-media/versions/2.1.0/package.js +0 -140
- package/blocks/native/sm.image-editor/versions/2.0.0/package.js +0 -183
- package/blocks/native/sm.image-editor/versions/2.0.1/package.js +0 -190
- package/blocks/native/sm.new-items/versions/1.0.0/package.js +0 -191
- package/blocks/native/sm.pick-photos/versions/1.0.0/package.js +0 -334
- package/blocks/native/sm.quality-audit/versions/1.0.0/package.js +0 -192
- package/blocks/native/sm.quality-audit/versions/1.0.1/package.js +0 -192
- package/blocks/native/sm.quality-audit/versions/1.0.2/package.js +0 -195
- package/blocks/native/sm.research/versions/2.0.0/package.js +0 -175
- package/blocks/native/sm.research/versions/2.0.1/package.js +0 -184
- package/blocks/native/sm.research/versions/2.0.2/package.js +0 -187
- package/blocks/native/sm.script/versions/2.0.0/package.js +0 -144
- package/blocks/native/sm.script/versions/2.1.0/package.js +0 -144
- package/blocks/native/sm.script/versions/2.1.1/package.js +0 -144
- package/blocks/native/sm.script/versions/2.1.2/package.js +0 -105
- package/blocks/native/sm.script/versions/2.1.3/package.js +0 -152
- package/blocks/native/sm.script/versions/2.1.4/package.js +0 -156
- package/blocks/native/sm.script/versions/2.1.5/package.js +0 -156
- package/blocks/native/sm.shot-plan/versions/2.0.0/package.js +0 -301
- package/blocks/native/sm.shot-plan/versions/2.1.0/package.js +0 -528
- package/blocks/native/sm.shot-plan/versions/2.1.1/package.js +0 -528
- package/blocks/native/sm.shot-plan/versions/2.1.2/package.js +0 -528
- package/blocks/native/sm.shot-plan/versions/2.1.3/package.js +0 -536
- package/blocks/native/sm.shot-plan/versions/2.2.0/package.js +0 -800
- package/blocks/native/sm.shot-plan/versions/2.2.1/package.js +0 -920
- package/blocks/native/sm.shot-plan-assistant/versions/1.0.0/package.js +0 -173
- package/blocks/native/sm.stock-search/versions/2.0.0/package.js +0 -174
- package/blocks/native/sm.thumbnail/versions/2.0.0/package.js +0 -137
- package/blocks/native/sm.thumbnail/versions/2.0.1/package.js +0 -140
- package/blocks/native/sm.transcribe/versions/2.0.0/package.js +0 -163
- package/blocks/native/sm.transcribe/versions/2.0.1/package.js +0 -168
- package/blocks/native/sm.whiteboard-assistant/versions/1.0.0/package.js +0 -175
- package/blocks/native/sm.youtube/versions/2.0.0/package.js +0 -217
- package/blocks/occasion-story/package.js +0 -1
- package/blocks/occasion-story/versions/1.0.0/package.js +0 -1658
- package/blocks/occasion-story/versions/1.0.1/package.js +0 -1699
- package/blocks/occasion-story/versions/1.0.2/package.js +0 -1682
- package/blocks/photo-reel-composer/versions/1.0.0/package.js +0 -3043
- package/blocks/photo-reel-composer/versions/1.0.1/package.js +0 -3026
- package/blocks/photo-reel-composer/versions/1.0.2/package.js +0 -4149
- package/blocks/product-ad-variants/versions/1.0.0/package.js +0 -2911
- package/blocks/product-launch-director/versions/1.0.0/package.js +0 -103
- package/blocks/release-visuals/package.js +0 -1
- package/blocks/release-visuals/versions/1.0.0/package.js +0 -1492
- package/blocks/release-visuals/versions/1.0.1/package.js +0 -1517
- package/blocks/release-visuals/versions/1.0.2/package.js +0 -1500
- package/blocks/screen-recorder/package.js +0 -1
- package/blocks/screen-recorder/versions/1.0.0/package.js +0 -223
- package/blocks/screen-recorder/versions/1.0.1/package.js +0 -223
- package/blocks/short-form-finish/package.js +0 -1
- package/blocks/short-form-finish/versions/1.0.0/package.js +0 -1043
- package/blocks/short-form-finish/versions/1.0.1/package.js +0 -1043
- package/blocks/short-form-finish/versions/1.0.2/package.js +0 -1043
- package/blocks/short-form-finish/versions/1.0.3/package.js +0 -1026
- package/examples/saas-product-launch-reviewed-source.stillmade.json +0 -383
- package/examples/saas-product-launch.stillmade.json +0 -304
- package/packages/block-platform/dealer-inventory-video-project-type.js +0 -38
- package/packages/block-platform/first-revenue-project-types.js +0 -46
- package/packages/block-platform/fixture-starters.js +0 -13
- package/packages/block-platform/launch-project-source.js +0 -10
- package/packages/block-platform/launch-project.js +0 -30
- package/packages/block-platform/motion-project-types.js +0 -55
- package/packages/block-platform/motion-starters.js +0 -14
- package/packages/block-platform/product-ad-variants-project-type.js +0 -30
- package/packages/block-platform/product-launch-updated.js +0 -90
- package/packages/block-platform/revenue-review-project-types.js +0 -36
- package/packages/block-platform/revenue-review-starters.js +0 -13
- package/packages/block-platform/script-writer.js +0 -29
- package/packages/block-platform/website-source-block.js +0 -14
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Module Blocks inside a Project Type, for the SDK CLI (November 3, 2026: a no-context agent's Real Estate
|
|
2
|
+
// Listing Video Type could not be tested or packed. `test` and `pack` ran its two module Blocks with no
|
|
3
|
+
// executor (RUNTIME_UNAVAILABLE), and the packed Blocks' base64 files, pasted into moduleSource, passed
|
|
4
|
+
// `validate` and failed only at run time with "main.js does not match its recorded digest").
|
|
5
|
+
//
|
|
6
|
+
// A Type carries a module Block's files as JavaScript text in `packages[].moduleSource`. In the Type file
|
|
7
|
+
// an entry of `packages` may instead be what `pack` wrote for the Block, embedded as it is
|
|
8
|
+
// (`{"format":"stillmade-module-bundle/1",...}`), or a path to it or to the Block's folder, relative to
|
|
9
|
+
// the Type file. The CLI turns each into the package with its moduleSource, checks every file against its
|
|
10
|
+
// recorded digest, and `pack` writes the Type with them embedded.
|
|
11
|
+
import {assert,plain} from '../block-sdk/contracts.js';
|
|
12
|
+
import {isModuleBundle,readModuleBundle} from '../block-sdk/module-bundle.js';
|
|
13
|
+
import {moduleFileDigest,MODULE_LIMITS} from '../block-sdk/module-runtime.js';
|
|
14
|
+
import {createNodeModuleExecutor} from '../block-sdk/module-node.js';
|
|
15
|
+
import {createMockHost,validateMocks} from '../block-sdk/mock-host.js';
|
|
16
|
+
import {testPackage} from '../block-sdk/testing.js';
|
|
17
|
+
import {runPackageAsync} from '../block-sdk/runtime.js';
|
|
18
|
+
import {textCleanup} from '../block-sdk/examples.js';
|
|
19
|
+
|
|
20
|
+
const fail=message=>{throw Object.assign(new Error(message),{code:'TYPE_PACKAGE'});};
|
|
21
|
+
const utf8=new TextDecoder('utf-8',{fatal:true});
|
|
22
|
+
const label=(pkg,index)=>`packages[${index}] (${pkg?.manifest?.id||'unnamed'}@${pkg?.manifest?.version||'?'})`;
|
|
23
|
+
|
|
24
|
+
// files: {path: Uint8Array} for the package's module descriptor. Returns the package with moduleSource.
|
|
25
|
+
function withModuleSource(pkg,files,index){
|
|
26
|
+
if(pkg?.manifest?.runtime!=='module')return pkg;
|
|
27
|
+
if(pkg.view?.files)fail(`${label(pkg,index)} has a frame view with its own files, which a Project Type cannot carry. Embed a Block whose view has no files in src/view-files/.`);
|
|
28
|
+
const moduleSource={};
|
|
29
|
+
for(const [path,file] of Object.entries(pkg.module?.files||{})){
|
|
30
|
+
if(file.mediaType!=='text/javascript')fail(`${label(pkg,index)} has ${path} (${file.mediaType}). A Project Type carries a module Block's files as JavaScript text in moduleSource, so bundle the Block into JavaScript files only (no .wasm or data files) to embed it.`);
|
|
31
|
+
const bytes=files?.[path];if(!bytes)fail(`${label(pkg,index)}: ${path} is missing from the packed Block.`);
|
|
32
|
+
try{moduleSource[path]=utf8.decode(bytes);}catch{fail(`${label(pkg,index)}: ${path} is not UTF-8 text.`);}
|
|
33
|
+
}
|
|
34
|
+
return {...pkg,moduleSource};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The Type with every `packages` entry as a package object. read(path) returns {pkg, files} for a packed
|
|
39
|
+
* Block file or a Block folder (the CLI's readPackage). folder: the Type file's folder.
|
|
40
|
+
* Returns the same object when every entry already is a package.
|
|
41
|
+
*/
|
|
42
|
+
export async function embedTypePackages(type,{folder,read,resolvePath}){
|
|
43
|
+
if(!Array.isArray(type?.packages)||type.packages.every(entry=>plain(entry)&&!isModuleBundle(entry)))return type;
|
|
44
|
+
const packages=[];
|
|
45
|
+
for(const [index,entry] of type.packages.entries()){
|
|
46
|
+
if(typeof entry==='string'){
|
|
47
|
+
let found;try{found=await read(resolvePath(folder,entry));}catch(error){fail(`packages[${index}] names ${entry}, which could not be read: ${error.message}`);}
|
|
48
|
+
assert(!found.pkg?.stages,'TYPE_PACKAGE',`packages[${index}] names ${entry}, a Project Type. Name a packed Block or a Block folder.`);
|
|
49
|
+
packages.push(found.files?withModuleSource(found.pkg,found.files,index):found.pkg);
|
|
50
|
+
}else if(isModuleBundle(entry)){
|
|
51
|
+
const bundle=await readModuleBundle(entry),files={};
|
|
52
|
+
for(const [path,file] of Object.entries(bundle.package.module?.files||{}))files[path]=bundle.files[file.sha256];
|
|
53
|
+
packages.push(withModuleSource(bundle.package,files,index));
|
|
54
|
+
}else packages.push(entry);
|
|
55
|
+
}
|
|
56
|
+
return {...type,packages};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const looksBase64=text=>text.length>=8&&text.length%4===0&&/^[A-Za-z0-9+/]+={0,2}$/.test(text.replace(/\s+/g,''));
|
|
60
|
+
/** Every module package's moduleSource must be its files' exact text: checked here, before anything runs. */
|
|
61
|
+
export async function checkTypeModuleSources(type){
|
|
62
|
+
for(const [index,pkg] of (type?.packages||[]).entries()){
|
|
63
|
+
if(pkg?.manifest?.runtime!=='module'||!plain(pkg.moduleSource)||!plain(pkg.module?.files))continue;
|
|
64
|
+
for(const [path,text] of Object.entries(pkg.moduleSource)){
|
|
65
|
+
const file=pkg.module.files[path];if(!file||typeof text!=='string')continue;
|
|
66
|
+
const bytes=new TextEncoder().encode(text);
|
|
67
|
+
if(bytes.byteLength===file.bytes&&await moduleFileDigest(bytes)===file.sha256)continue;
|
|
68
|
+
if(looksBase64(text)){
|
|
69
|
+
let decoded=null;try{decoded=new Uint8Array(Buffer.from(text,'base64'));}catch{}
|
|
70
|
+
if(decoded&&decoded.byteLength===file.bytes&&await moduleFileDigest(decoded)===file.sha256)fail(`${label(pkg,index)}: moduleSource["${path}"] holds the file as base64, the way a packed .stillmade-module.json stores it. A Project Type carries it as plain JavaScript text. Put the packed file's path in packages instead (for example "packages": ["dist/${pkg.manifest.id}-${pkg.manifest.version}.stillmade-module.json"]) and the CLI embeds it, or put the decoded text there.`);
|
|
71
|
+
}
|
|
72
|
+
fail(`${label(pkg,index)}: moduleSource["${path}"] does not match module.files["${path}"] (${file.bytes} bytes, sha256 ${file.sha256}). Pack the Block again and put the packed file's path in packages, so the text and its digest come from the same build.`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const sourceFiles=pkg=>{
|
|
78
|
+
assert(plain(pkg.moduleSource)&&Object.keys(pkg.moduleSource).length,'MODULE_FILE',`${pkg.manifest.name} carries no moduleSource, so it cannot run here. Put its packed file or folder in the Type's packages and the CLI embeds the files.`);
|
|
79
|
+
return Object.fromEntries(Object.entries(pkg.moduleSource).map(([path,text])=>[path,new TextEncoder().encode(text)]));
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* The local module runner for a Type's checks, the one `test` and `preview` use for a single module Block:
|
|
83
|
+
* the SDK's Node executor, each fixture answered by its own mocks, and with mock (--mock) the recorded
|
|
84
|
+
* stand-ins for anything else. In the connected run a module Step is answered by its first fixture's
|
|
85
|
+
* mocks when it records some, else by the stand-ins with --mock. No provider is ever called.
|
|
86
|
+
* Returns {test, run} for testProjectType/previewProjectType and calls() for the report.
|
|
87
|
+
*/
|
|
88
|
+
export function typeModuleRunner({mock=false,readLocalFile}={}){
|
|
89
|
+
const hosts=[];
|
|
90
|
+
const hostFor=(pkg,mocks,source)=>{const host=createMockHost({mocks:validateMocks(mocks),readLocalFile,manifest:pkg.manifest});hosts.push({host,source});return host.host;};
|
|
91
|
+
const executor=(pkg,host)=>createNodeModuleExecutor({files:sourceFiles(pkg),...(host?{host}:{})});
|
|
92
|
+
const test=(pkg,options={})=>{
|
|
93
|
+
if(pkg.manifest.runtime!=='module')return testPackage(pkg,options);
|
|
94
|
+
const module=executor(pkg,mock?hostFor(pkg,undefined,'recorded stand-in'):undefined);
|
|
95
|
+
return testPackage(pkg,{...options,module,moduleFor:fixture=>fixture?.mocks?executor(pkg,hostFor(pkg,fixture.mocks,'fixture mocks')):module,timeoutMs:Math.min(options.timeoutMs??MODULE_LIMITS.wallClockMs,MODULE_LIMITS.wallClockMs)});
|
|
96
|
+
};
|
|
97
|
+
const run=(pkg,input,options={})=>{
|
|
98
|
+
if(pkg.manifest.runtime!=='module')return runPackageAsync(pkg,input,options);
|
|
99
|
+
const recorded=pkg.tests?.find(fixture=>fixture?.mocks)?.mocks;
|
|
100
|
+
const host=recorded?hostFor(pkg,recorded,'fixture mocks'):mock?hostFor(pkg,undefined,'recorded stand-in'):undefined;
|
|
101
|
+
return runPackageAsync(pkg,input,{...options,module:executor(pkg,host)});
|
|
102
|
+
};
|
|
103
|
+
const calls=()=>hosts.flatMap(({host,source})=>host.calls.map(call=>({api:call.api,name:call.name,source:call.source==='mocks'?source:'recorded stand-in'})));
|
|
104
|
+
return {test,run,calls};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// What `create-type` writes: one job Step, then the Editor, which has captions and export built in, so no
|
|
108
|
+
// Export video Step follows it (builder contract, "One Step per job"). November 3, 2026: it had a second
|
|
109
|
+
// "Review clean text" Step, and a review never starts a new Step; the Editor stays because the person cuts by hand.
|
|
110
|
+
export const TYPE_SCAFFOLD=Object.freeze({
|
|
111
|
+
schemaVersion:1,id:'example.text-workflow',version:'1.0.0',name:'Text workflow',
|
|
112
|
+
description:'Clean the text, then assemble and export the video in the Editor.',
|
|
113
|
+
packages:[textCleanup],
|
|
114
|
+
stages:[
|
|
115
|
+
{id:'first',blockId:'example.clean-text',version:'1.0.0',label:'Prepare text'},
|
|
116
|
+
{id:'edit',blockId:'sm.editor',version:'1.0.0',label:'Edit and export'},
|
|
117
|
+
],
|
|
118
|
+
connections:[],
|
|
119
|
+
});
|
|
@@ -47,11 +47,18 @@ export function jobWordingNotes(pkg){
|
|
|
47
47
|
const manifest=pkg?.manifest||{},notes=[],label=manifest.action?.label;
|
|
48
48
|
const operations=pkg?.capability?.operation?[pkg.capability.operation]:(manifest.permissions?.capabilities||[]);
|
|
49
49
|
if(label&&GENERIC_ACTIONS.test(label.trim()))notes.push(`The button reads "${label}". Name what it does in the job's words in manifest.action ("Plan the tour").`);
|
|
50
|
-
|
|
50
|
+
// November 3, 2026 (owner: fix the underlying problem): StillMade draws the run button for every Block without its
|
|
51
|
+
// own screen, and for one that calls operations; such a Block names it, or StillMade can only guess from its name.
|
|
52
|
+
else if(!label&&(!pkg?.view||operations.length))notes.push('StillMade draws this Step\'s button and can only guess its words from the Block\'s name or output. Name what it does in the job\'s words in manifest.action ({label:"Animate photos",running:"Animating…"}).');
|
|
51
53
|
const bare=Object.entries(manifest.inputs||{}).filter(([name,port])=>MEDIA_PORTS.has(port?.type)&&BARE_MEDIA_NAMES.has(name.toLowerCase())).map(([name])=>name);
|
|
52
54
|
// Days and times are picked, never typed: a text input that holds one is a date input, which StillMade shows as a calendar.
|
|
53
55
|
const typedDates=Object.entries(manifest.inputs||{}).filter(([name,port])=>port?.type==='text'&&/(?:date|time|when|deadline|schedule)|(?:At|_at)$/.test(name)).map(([name])=>name);
|
|
54
56
|
if(typedDates.length)notes.push(`${typedDates.length===1?`The input ${typedDates[0]} is`:`The inputs ${typedDates.join(', ')} are`} text, so a day or time is typed. Make ${typedDates.length===1?'it':'each'} a date input: StillMade shows a calendar, and a list of times when it is about a time.`);
|
|
57
|
+
// November 3, 2026: a "one fact per line" input showed its example as one line ("Austin$549,0003 bedrooms"). Text whose
|
|
58
|
+
// examples hold line breaks declares it, so every host draws a box that keeps them. A `text` control is already a growing
|
|
59
|
+
// box on the Step page, so only an input with no control at all is noted.
|
|
60
|
+
const lined=Object.entries(manifest.inputs||{}).filter(([name,port])=>{const control=(manifest.ui||[]).find(item=>item?.port===name);return port?.type==='text'&&!control&&(pkg?.tests||[]).some(test=>typeof test?.input?.[name]==='string'&&test.input[name].includes('\n'));}).map(([name])=>name);
|
|
61
|
+
if(lined.length)notes.push(`${lined.length===1?`The input ${lined[0]} has examples`:`The inputs ${lined.join(', ')} have examples`} of several lines but ${lined.length===1?'is':'are'} not declared multi-line, so a host can draw one line and lose the line breaks. Add {"control":"text","port":"${lined[0]}","multiline":true} to manifest.ui${lined.length===1?'':' for each'}.`);
|
|
55
62
|
if(pkg?.view)notes.push(...viewWordingNotes(pkg.view));
|
|
56
63
|
if(bare.length)notes.push(`${bare.length===1?`The input ${bare[0]} is`:`The inputs ${bare.join(', ')} are`} named only by type, so the drop area reads "Drop a ${bare[0].replace(/s$/,'')} here". Name each for what the person brings (sermonVideo), unless any file of that kind does the job.`);
|
|
57
64
|
return notes;
|
|
@@ -141,7 +141,8 @@ export function connectedBlockInputs(node, nodes, edges, {context={},raw=false,a
|
|
|
141
141
|
for(const name of Object.keys(node.data?.blockValuePins||{}))if(!edges.some(edge=>edge.target===node.id&&String(edge.targetHandle||'').replace(/^in:/,'')===name)){
|
|
142
142
|
inputs[name]=undefined;errors.push(`The pinned result for ${name} no longer has a Canvas connection. Review the pin before running.`);
|
|
143
143
|
}
|
|
144
|
-
|
|
144
|
+
// Two wires from one Step that has not run say "Run it first." once, not once per wire.
|
|
145
|
+
return { inputs, errors:[...new Set(errors)], ...(allowOmissions?{omissions}:{}) };
|
|
145
146
|
}
|
|
146
147
|
|
|
147
148
|
// Called only for data edits, never for position/selection changes. Preserve old
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import {FIRST_PARTY_SDK_PACKAGES} from '../block-sdk/first-party-packages.js';
|
|
2
|
-
import {DEALER_INVENTORY_VIDEO_PROJECT_TYPE} from './dealer-inventory-video-project-type.js';
|
|
3
2
|
import { SDK_VERSION, ROOT_CHAT_ID } from '../block-sdk/contracts.js';
|
|
4
|
-
import {SCRIPT_WRITER_BLOCK} from './script-writer.js';
|
|
5
3
|
import {VIDEO_ASSETS_BLOCK} from './video-assets.js';
|
|
6
4
|
import {HOST_RELEASE_MANIFEST_SNAPSHOTS} from './host-release-manifests.js';
|
|
7
5
|
// Host releases stay available for saved projects until their complete UI and
|
|
@@ -14,13 +12,7 @@ const hostReleaseManifest=(id,version)=>{
|
|
|
14
12
|
return structuredClone(manifest);
|
|
15
13
|
};
|
|
16
14
|
const definitions = [
|
|
17
|
-
['chat', 'Production chat', 'workspace', 'brief', 'script', 'Develop a script or production decision in a scoped conversation after the protected starting chat.', 'ProductionWorkspaceNode.jsx'],
|
|
18
|
-
['research', 'Research', 'task', 'text', 'research', 'Find supporting material for a topic and return a research dossier with citations.', 'ProductionWorkspaceNode.jsx'],
|
|
19
|
-
['script', 'Script', 'workspace', 'brief', 'script', 'Develop and review a script from the project brief.', 'NarrativeCompiler.jsx'],
|
|
20
15
|
['voiceover', 'Voiceover', 'workspace', 'script', 'audio', 'Generate, record, or import narration and prepare it for timed visuals.', 'VoiceoverStep.jsx'],
|
|
21
|
-
['transcribe', 'Transcription', 'task', 'audio', 'transcript', 'Turn audio into editable timed words for captions and shot planning.', 'TranscriptionEditor.jsx'],
|
|
22
|
-
['shot-plan', 'Shot planning', 'workspace', 'transcript', 'shot-plan', 'Break narration into reviewed shots with visual intent and timing.', 'ShotMapReview.jsx'],
|
|
23
|
-
['blueprint', 'Blueprint', 'workspace', 'brief', 'bible', 'Organize the story, cast, locations, and visual style into a reusable production guide.', 'BibleEditor.jsx'],
|
|
24
16
|
['character', 'Character reference', 'workspace', 'text', 'character', 'Build a consistent character identity with reusable visual references.', 'CharacterReferenceNode.jsx'],
|
|
25
17
|
['location', 'Location reference', 'workspace', 'text', 'location', 'Build a location identity and reference images for consistent settings.', 'LocationReferenceNode.jsx'],
|
|
26
18
|
['style', 'Style reference', 'workspace', 'text', 'style', 'Create a reusable art direction and its visual examples.', 'StyleNode.jsx'],
|
|
@@ -28,14 +20,9 @@ const definitions = [
|
|
|
28
20
|
['import-media', 'Import media', 'task', null, 'asset[]', 'Bring selected images, video, and audio into the project media library.', 'MediaUploadNode.jsx'],
|
|
29
21
|
['generate-image', 'Generate image', 'task', 'text', 'image', 'Generate a new image using a prompt and selected identity or style references.', 'ImageGenNode.jsx'],
|
|
30
22
|
['generate-video', 'Generate video', 'task', 'image', 'video', 'Generate a video clip from an image, prompt, and motion settings.', 'VideoGenNode.jsx'],
|
|
31
|
-
['thumbnail', 'Thumbnail', 'task', 'text', 'image', 'Create a thumbnail image for the finished video.', 'ThumbnailNode.jsx'],
|
|
32
|
-
['describe-media', 'Describe media', 'task', 'image', 'text', 'Describe the visible content of an image for production planning.', 'ImageDescriberNode.jsx'],
|
|
33
|
-
['image-editor', 'Image editor', 'workspace', 'image', 'image', 'Crop, adjust, and composite an image while retaining its original version.', 'ProductionWorkspaceNode.jsx'],
|
|
34
23
|
['compare', 'Compare assets', 'workspace', 'asset[]', 'asset', 'Review candidate assets and choose a version for the next step.', 'CompareNode.jsx'],
|
|
35
|
-
['stock-search', 'Stock media', 'workspace', 'text', 'asset[]', 'Search real-world media and import selected licensed assets.', 'ProductionWorkspaceNode.jsx'],
|
|
36
24
|
['panel-strip', 'Image panels', 'workspace', 'audio', 'panel-document', 'Build a timed sequence of consistent images and diagrams around narration.', 'StripStep.jsx'],
|
|
37
25
|
['board-editor', 'White Board Motion', 'workspace', 'audio', 'board-document', 'Arrange and animate editable boards with text, media, and narration.', 'CanvasEditorStep.jsx'],
|
|
38
|
-
['animated-scene', 'Animated scene', 'workspace', 'shot-plan', 'scene-document', 'Compose animated scenes with object motion and camera direction.', 'AnimatedV2AssetStep.jsx'],
|
|
39
26
|
['editor', 'Video editor', 'workspace', 'asset[]', 'timeline', 'Assemble and edit video, audio, captions, and effects on a shared timeline.', 'VideoEditor.jsx'],
|
|
40
27
|
['captions', 'Captions', 'editor-extension', 'transcript', 'timeline', 'Place timed editable captions on the selected timeline.', 'editorAI.js'],
|
|
41
28
|
['grade', 'Color grade', 'editor-extension', 'timeline-range', 'timeline', 'Adjust the color and tone of selected clips without replacing originals.', 'editorAdds.js'],
|
|
@@ -48,18 +35,15 @@ const definitions = [
|
|
|
48
35
|
['export-video', 'Export video', 'task', 'timeline', 'video', 'Render an accepted timeline to a video file using available device capabilities.', 'exportRender/index.js'],
|
|
49
36
|
['export-audio', 'Export audio', 'task', 'timeline', 'audio', 'Mix and export the timeline audio to a standalone file.', 'exportRender/index.js'],
|
|
50
37
|
['export-timeline', 'Export timeline', 'task', 'timeline', 'json', 'Export the timeline structure for another editing application.', 'fcpxml.js'],
|
|
51
|
-
['youtube', 'YouTube hub', 'workspace', 'video', 'json', 'Analyze channel performance and manage an authorized video upload.', 'YouTubeScreen.jsx'],
|
|
52
38
|
];
|
|
53
39
|
const LEGACY_BLOCKS = definitions.map(([key, name, kind, input, output, description, source]) => ({
|
|
54
40
|
manifest: { schemaVersion: 1, sdkVersion: SDK_VERSION, id: `sm.${key}`, name, version: '1.0.0', kind, runtime: 'host', description, inputs: input ? { input: { type: input } } : {}, outputs: { output: { type: output } }, permissions: { project: [], network: [], filesystem: [], secrets: [] } },
|
|
55
41
|
source, summary: { text: description, origin: 'llm', generation: 'build-time', generator: 'Codex', status: 'ready' }, adapterStatus: 'legacy',
|
|
56
42
|
}));
|
|
57
43
|
const types = [
|
|
58
|
-
['guided', 'Guided', 'Plan a video from an idea, build references and footage, then edit and export.', ['script', 'voiceover', 'shot-plan', 'blueprint', 'pipeline', 'editor', 'export-video']],
|
|
59
44
|
['blank', 'Blank Canvas', 'Start with your own media and production canvas, then assemble a video.', ['import-media', 'pipeline', 'editor', 'export-video']],
|
|
60
45
|
['imagePanel', 'Image Panels', 'Turn narration into a timed visual sequence, refine the cut, and export.', ['voiceover', 'panel-strip', 'editor', 'export-video']],
|
|
61
46
|
['whiteboard', 'White Board Motion', 'Build animated boards around narration, then refine and export the video.', ['voiceover', 'board-editor', 'editor', 'export-video']],
|
|
62
|
-
['animated', 'Animated Studio', 'Plan and compose animated scenes, then assemble and export the sequence.', ['voiceover', 'shot-plan', 'animated-scene', 'editor', 'export-video']],
|
|
63
47
|
];
|
|
64
48
|
const LEGACY_TYPES = types.map(([legacyMode, name, description, stages]) => ({ schemaVersion: 1, id: `sm.${legacyMode.toLowerCase()}`, version: '1.0.0', name, description, legacyMode, stages: stages.map((id, i) => ({ id: `stage-${i + 1}`, blockId: `sm.${id}`, version: '1.0.0', label: LEGACY_BLOCKS.find(b => b.manifest.id === `sm.${id}`).manifest.name })), summary: { text: description, origin: 'llm', generation: 'build-time', generator: 'Codex', status: 'ready' } }));
|
|
65
49
|
|
|
@@ -67,15 +51,12 @@ const LEGACY_TYPES = types.map(([legacyMode, name, description, stages]) => ({ s
|
|
|
67
51
|
// adapters remain version-addressable solely for saved workflow compatibility.
|
|
68
52
|
const screens = [
|
|
69
53
|
['voiceover','Voiceover','voiceover','VoiceoverStep.jsx','Turn your script into speech, or record your own voice.',['Narration and voices','Recording and import','Transcript and timing']],
|
|
70
|
-
['shot-plan','Shots','shotMap','ShotMapReview.jsx','Plan each shot and match it to the voice.',['Shot sequence','Visual directions','Timing and versions']],
|
|
71
|
-
['blueprint','Blueprint','bible','BibleEditor.jsx','Keep your story, characters, places, and art style in one place.',['Story and scenes','Characters and locations','Visual direction']],
|
|
72
54
|
['pipeline','Canvas','canvas','WorkflowCanvas.jsx','Make images and videos, and keep your characters looking the same.',['Persistent references','Media generation','Assets and versions']],
|
|
73
55
|
['editor','Editor','editor','VideoEditor.jsx','Cut clips, add sound and text, then save your video.',['Video and audio timeline','Captions and effects','Export']],
|
|
74
56
|
['panel-strip','Image Panels','shotMap','StripStep.jsx','Turn your script into pictures that play with the voice.',['Scenes and panels','Consistent artwork','Timing and editor handoff']],
|
|
75
57
|
['board-editor','White Board Motion','canvasEditor','CanvasEditorStep.jsx','Make text and pictures move on a board with a voice.',['Boards and media','Editable animation','Narration and handoff']],
|
|
76
|
-
['animated-scene','Assets','assetGen','AnimatedV2AssetStep.jsx','Prepare pictures, objects, and camera moves for your scenes.',['Scenes and assets','Object and camera motion','Editor handoff']],
|
|
77
58
|
];
|
|
78
|
-
const HOST_WORKSPACE_BLOCKS = [
|
|
59
|
+
const HOST_WORKSPACE_BLOCKS = [...screens.map(([key,name,phase,source,description,features])=>{
|
|
79
60
|
const legacy=LEGACY_BLOCKS.find(block=>block.manifest.id===`sm.${key}`);
|
|
80
61
|
// The Editor's main release is the original one (1.0): the full video editor.
|
|
81
62
|
// Its portable 2.x releases are a separate, simpler view kept for their exact pins.
|
|
@@ -89,7 +70,7 @@ HOST_WORKSPACE_BLOCKS.splice(HOST_WORKSPACE_BLOCKS.findIndex(block=>block.manife
|
|
|
89
70
|
// Promote a portable workspace after its accepted production MVP and rendered
|
|
90
71
|
// acceptance are complete; advanced host extensions can remain on old exact pins. Exact portable releases remain usable as normal
|
|
91
72
|
// Steps before promotion; this map only controls the default production route.
|
|
92
|
-
export const CURRENT_PORTABLE_WORKSPACE_VERSIONS=Object.freeze({'sm.
|
|
73
|
+
export const CURRENT_PORTABLE_WORKSPACE_VERSIONS=Object.freeze({'sm.voiceover':'2.1.6','sm.pipeline':'2.2.6','sm.video-assets':'2.1.4','sm.panel-strip':'2.4.2','sm.board-editor':'2.2.11','sm.editor':'2.2.11'});
|
|
93
74
|
// Workspaces whose main release stays the host one: the original Editor (1.0) is
|
|
94
75
|
// the full video editor. Its accepted portable release stays discoverable for
|
|
95
76
|
// Steps that hand the Editor a prepared timeline, which only it accepts.
|
|
@@ -115,10 +96,8 @@ const historicalWorkspaceBlock=(id,version)=>{
|
|
|
115
96
|
const current=HOST_WORKSPACE_BLOCKS.find(block=>block.manifest.id===id);
|
|
116
97
|
return {...current,manifest:hostReleaseManifest(id,version)};
|
|
117
98
|
};
|
|
118
|
-
const HISTORICAL_WORKSPACE_BLOCKS = Object.freeze([
|
|
119
|
-
const
|
|
120
|
-
const YOUTUBE_HOST_1_1=(()=>{const legacy=LEGACY_BLOCKS.find(block=>block.manifest.id==='sm.youtube');return {...legacy,manifest:{...legacy.manifest,version:'1.1.0',description:'Review channel performance and upload an account-owned saved MP4 through a retained authorized session.'},adapterStatus:'workspace'};})();
|
|
121
|
-
const GENERATION_HOST_RELEASES=Object.freeze(['sm.generate-image','sm.generate-video','sm.thumbnail','sm.compare'].flatMap(id=>{
|
|
99
|
+
const HISTORICAL_WORKSPACE_BLOCKS = Object.freeze([historicalWorkspaceBlock('sm.voiceover','1.1.0'),historicalWorkspaceBlock('sm.panel-strip','1.1.0'),historicalWorkspaceBlock('sm.board-editor','1.1.0'),historicalWorkspaceBlock('sm.editor','1.1.0'),historicalWorkspaceBlock('sm.editor','1.2.0'),historicalWorkspaceBlock('sm.editor','1.3.0'),historicalWorkspaceBlock('sm.editor','1.4.0'),historicalWorkspaceBlock('sm.editor','1.5.0'),historicalWorkspaceBlock('sm.pipeline','1.1.0'),historicalWorkspaceBlock('sm.pipeline','1.2.0'),VIDEO_ASSETS_BLOCK,historicalWorkspaceBlock('sm.video-assets','1.0.0'),historicalWorkspaceBlock('sm.video-assets','1.1.0')]);
|
|
100
|
+
const GENERATION_HOST_RELEASES=Object.freeze(['sm.generate-image','sm.generate-video','sm.compare'].flatMap(id=>{
|
|
122
101
|
const legacy=LEGACY_BLOCKS.find(block=>block.manifest.id===id);
|
|
123
102
|
return ['1.1.0','1.2.0'].map(version=>({...legacy,manifest:{...legacy.manifest,version},adapterStatus:'module'}));
|
|
124
103
|
}));
|
|
@@ -145,9 +124,11 @@ export const BLOCK_TOOLS=new Set(['sm.export-video','sm.export-audio','sm.export
|
|
|
145
124
|
// The Automation (When 1.1.0) starts from an app's events or checks it every few minutes, handing each new item on
|
|
146
125
|
// once, and its Only if lets through only the items wanted (October 22, 2026, owner-approved mockup): finding new
|
|
147
126
|
// items and gating on a decision are no longer Blocks of their own. Saved projects keep running them.
|
|
148
|
-
export const AUTOMATION_PARTS=new Set([
|
|
127
|
+
export const AUTOMATION_PARTS=new Set([]);
|
|
149
128
|
// November 2, 2026 (owner): Voiceover is offered again ("voiceover was the original").
|
|
150
|
-
|
|
129
|
+
// November 4, 2026 (owner): Generate (stillmade.generate) is the one Block for every image and video model; Generate
|
|
130
|
+
// image and Generate video stay only as the Canvas's own generation nodes.
|
|
131
|
+
export const HIDDEN_BLOCKS=new Set(['sm.generate-image','sm.generate-video','sm.final-edit','sm.edit-assistant','sm.character','sm.location','sm.style','sm.compare','sm.score','sm.rough-cut',...BLOCK_TOOLS,...AUTOMATION_PARTS]);
|
|
151
132
|
// Exact releases to hide (id@version) when one release of a shown Block should not be offered; none today.
|
|
152
133
|
export const HIDDEN_RELEASES=new Set([]);
|
|
153
134
|
export const isHiddenBlock=block=>HIDDEN_BLOCKS.has(block.manifest.id)||HIDDEN_RELEASES.has(`${block.manifest.id}@${block.manifest.version}`);
|
|
@@ -167,7 +148,7 @@ export const DISCOVERABLE_BLOCKS = [STARTING_CHAT_BLOCK,...WORKSPACE_BLOCKS,...A
|
|
|
167
148
|
// not results anyone asks for, and the niche cuts that hand a finished timeline to the newer Editor are never put
|
|
168
149
|
// together by Chat; each becomes a target of an engine. They stay discoverable releases, so built-in Types and saved
|
|
169
150
|
// projects keep their pins and still get newer releases.
|
|
170
|
-
export const FOLDED_BLOCKS=new Set(['sm.
|
|
151
|
+
export const FOLDED_BLOCKS=new Set(['sm.video-assets']);
|
|
171
152
|
export const isOfferedBlock=block=>block.manifest.id!==STARTING_CHAT_BLOCK.manifest.id&&!FOLDED_BLOCKS.has(block.manifest.id);
|
|
172
153
|
// Planners pin a finished file to a Block's output port, which the Editor alias has
|
|
173
154
|
// none of, so planning keeps the newest render-only release in its place. Chat
|
|
@@ -185,39 +166,37 @@ const oneCardEach=blocks=>[...blocks.reduce((map,block)=>{
|
|
|
185
166
|
// November 2, 2026 (owner: "idc if it's called narration, just make it look and act like voiceover"): Chat
|
|
186
167
|
// still plans a narration job with Narration, and the Step it places is Voiceover (chatAutomation.js), so
|
|
187
168
|
// people only ever see Voiceover. Saved projects and Types that pin Narration keep running it.
|
|
188
|
-
export const PLACED_AS=new Map(
|
|
169
|
+
export const PLACED_AS=new Map();
|
|
189
170
|
export const LISTED_BLOCKS=Object.freeze(oneCardEach(DISCOVERABLE_BLOCKS.filter(isOfferedBlock).filter(block=>!PLACED_AS.has(block.manifest.id))));
|
|
190
171
|
// A folded Block's card, offered only to replace a saved Step of that Block (its "Update to" button).
|
|
191
172
|
export const FOLDED_CARDS=Object.freeze(oneCardEach(DISCOVERABLE_BLOCKS.filter(block=>FOLDED_BLOCKS.has(block.manifest.id))));
|
|
192
173
|
export const PLANNING_BLOCKS = DISCOVERABLE_BLOCKS.map(block=>DISCOVERED_AS_HOST.get(block.manifest.id)===block?newestRelease(block.manifest.id)||block:block);
|
|
193
|
-
export const BUILTIN_BLOCKS = [STARTING_CHAT_BLOCK,...WORKSPACE_BLOCKS,...HISTORICAL_WORKSPACE_BLOCKS
|
|
194
|
-
const flows={
|
|
174
|
+
export const BUILTIN_BLOCKS = [STARTING_CHAT_BLOCK,...WORKSPACE_BLOCKS,...HISTORICAL_WORKSPACE_BLOCKS,...GENERATION_HOST_RELEASES,...SDK_BUILTIN_BLOCKS.filter(block=>!WORKSPACE_BLOCKS.some(current=>current.manifest.id===block.manifest.id&¤t.manifest.version===block.manifest.version)),...LEGACY_BLOCKS.filter(block=>!WORKSPACE_BLOCKS.some(current=>current.manifest.id===block.manifest.id&¤t.manifest.version===block.manifest.version))];
|
|
175
|
+
const flows={blank:['pipeline','editor'],imagePanel:['voiceover','panel-strip','editor'],whiteboard:['voiceover','board-editor','editor']};
|
|
195
176
|
const typeDescriptions={
|
|
196
|
-
guided:'Turn an idea into a video, from the script to the final cut.',
|
|
197
177
|
blank:'Start with your own pictures and clips, then make a video.',
|
|
198
178
|
imagePanel:'Make a video with still pictures and a voice.',
|
|
199
179
|
whiteboard:'Make a video with moving text, pictures, and a voice.',
|
|
200
|
-
animated:'Build scenes with moving objects, then put them into a video.',
|
|
201
180
|
};
|
|
202
181
|
// Freeze the actual pre-collaboration-release catalog fallback. Historical type
|
|
203
182
|
// definitions must not follow future changes to the discoverable Block map.
|
|
204
183
|
const PINNED_TYPE_WORKSPACE_VERSIONS=Object.freeze({'voiceover':'2.1.3','shot-plan':'2.1.2','blueprint':'2.1.7','pipeline':'2.2.2','editor':'2.2.7','panel-strip':'2.3.5','board-editor':'2.2.8','animated-scene':'2.3.6'});
|
|
205
|
-
const currentBuiltinTypes=(version,pipelineVersion,scriptVersion
|
|
184
|
+
const currentBuiltinTypes=(version,pipelineVersion,scriptVersion,versions={})=>LEGACY_TYPES.map(type=>({...type,description:typeDescriptions[type.legacyMode],summary:{...type.summary,text:typeDescriptions[type.legacyMode]},version,stages:flows[type.legacyMode].map((key,i)=>{const block=WORKSPACE_BLOCKS.find(block=>block.manifest.id===`sm.${key}`);return {id:`stage-${i+1}`,blockId:block.manifest.id,version:versions[key]||(key==='pipeline'?pipelineVersion:key==='script'?scriptVersion:PINNED_TYPE_WORKSPACE_VERSIONS[key]),label:key==='editor'?'Editor':block.manifest.name};})}));
|
|
206
185
|
const PRIOR_HOST_WORKSPACE_VERSIONS={'shot-plan':'1.1.0','blueprint':'1.1.0','panel-strip':'2.3.4','board-editor':'1.1.0','animated-scene':'1.1.0'};
|
|
207
|
-
const PREVIOUS_BUILTIN_TYPES=currentBuiltinTypes('1.2.0','1.2.0',
|
|
208
|
-
const SHOTS_MIGRATED_TYPES=currentBuiltinTypes('1.3.0','1.2.0',
|
|
186
|
+
const PREVIOUS_BUILTIN_TYPES=currentBuiltinTypes('1.2.0','1.2.0',undefined,PRIOR_HOST_WORKSPACE_VERSIONS);
|
|
187
|
+
const SHOTS_MIGRATED_TYPES=currentBuiltinTypes('1.3.0','1.2.0',undefined,{'blueprint':'1.1.0','board-editor':'1.1.0','animated-scene':'1.1.0'});
|
|
209
188
|
const PRE_PROMOTION_CURRENT_TYPES = PREVIOUS_BUILTIN_TYPES.map(type=>flows[type.legacyMode].includes('shot-plan')?SHOTS_MIGRATED_TYPES.find(next=>next.id===type.id):type);
|
|
210
|
-
const PORTABLE_MVP_TYPES = currentBuiltinTypes('1.4.0','2.2.2',
|
|
211
|
-
const ADVANCED_PORTABLE_TYPES = currentBuiltinTypes('1.5.0','2.2.2',
|
|
212
|
-
const PLAYABLE_EDITOR_TYPES = currentBuiltinTypes('1.6.0','2.2.2',
|
|
213
|
-
const EDITOR_AUDIO_TYPES = currentBuiltinTypes('1.7.0','2.2.2',
|
|
214
|
-
const MEDIA_LIBRARY_TYPES = currentBuiltinTypes('1.8.0','2.2.2',
|
|
189
|
+
const PORTABLE_MVP_TYPES = currentBuiltinTypes('1.4.0','2.2.2',undefined,{'blueprint':'2.1.5','panel-strip':'2.3.4','board-editor':'2.2.6','animated-scene':'2.3.4'});
|
|
190
|
+
const ADVANCED_PORTABLE_TYPES = currentBuiltinTypes('1.5.0','2.2.2',undefined,{'blueprint':'2.1.6','panel-strip':'2.3.4','board-editor':'2.2.7','animated-scene':'2.3.5','editor':'2.2.4'});
|
|
191
|
+
const PLAYABLE_EDITOR_TYPES = currentBuiltinTypes('1.6.0','2.2.2',undefined,{'blueprint':'2.1.6','panel-strip':'2.3.4','board-editor':'2.2.7','animated-scene':'2.3.5','editor':'2.2.5'});
|
|
192
|
+
const EDITOR_AUDIO_TYPES = currentBuiltinTypes('1.7.0','2.2.2',undefined,{'blueprint':'2.1.6','panel-strip':'2.3.4','board-editor':'2.2.7','animated-scene':'2.3.5','editor':'2.2.6'});
|
|
193
|
+
const MEDIA_LIBRARY_TYPES = currentBuiltinTypes('1.8.0','2.2.2',undefined,{'panel-strip':'2.3.4'});
|
|
215
194
|
const PRIOR_SHARED_TYPES = currentBuiltinTypes('1.9.0','2.2.2');
|
|
216
|
-
const SHARED_BLUEPRINT_TYPES = currentBuiltinTypes('1.10.0','2.2.2',
|
|
217
|
-
const SHARED_CANVAS_TYPES = currentBuiltinTypes('1.11.0','2.2.3',
|
|
218
|
-
const SHARED_WORKSPACE_TYPES = currentBuiltinTypes('1.12.0','2.2.3',
|
|
219
|
-
const PRIOR_CURRENT_TYPES = currentBuiltinTypes('1.13.0','2.2.3',
|
|
220
|
-
const PREVIOUS_PORTABLE_TYPES=currentBuiltinTypes('1.14.0','2.2.4',
|
|
195
|
+
const SHARED_BLUEPRINT_TYPES = currentBuiltinTypes('1.10.0','2.2.2',undefined,{'blueprint':'2.1.8'});
|
|
196
|
+
const SHARED_CANVAS_TYPES = currentBuiltinTypes('1.11.0','2.2.3',undefined,{'blueprint':'2.1.8'});
|
|
197
|
+
const SHARED_WORKSPACE_TYPES = currentBuiltinTypes('1.12.0','2.2.3',undefined,{'blueprint':'2.1.8','panel-strip':'2.3.6','board-editor':'2.2.9','animated-scene':'2.3.7'});
|
|
198
|
+
const PRIOR_CURRENT_TYPES = currentBuiltinTypes('1.13.0','2.2.3',undefined,{'blueprint':'2.1.8','panel-strip':'2.3.6','board-editor':'2.2.9','animated-scene':'2.3.7','editor':'2.2.8'});
|
|
199
|
+
const PREVIOUS_PORTABLE_TYPES=currentBuiltinTypes('1.14.0','2.2.4',undefined,{'blueprint':'2.1.8','panel-strip':'2.3.6','board-editor':'2.2.9','animated-scene':'2.3.7','editor':'2.2.8'});
|
|
221
200
|
// 1.16.0: every built-in type ends in the original Editor (1.0), the full video editor.
|
|
222
201
|
const PORTABLE_EDITOR_TYPES=currentBuiltinTypes('1.15.0','2.2.4','2.1.4',{'voiceover':'2.1.4','shot-plan':'2.1.3','blueprint':'2.1.9','panel-strip':'2.3.7','board-editor':'2.2.10','animated-scene':'2.3.8','editor':'2.2.9'});
|
|
223
202
|
const HOST_EDITOR_TYPES=currentBuiltinTypes('1.16.0','2.2.4','2.1.4',{'voiceover':'2.1.4','shot-plan':'2.1.3','blueprint':'2.1.9','panel-strip':'2.3.7','board-editor':'2.2.10','animated-scene':'2.3.8','editor':'1.0.0'});
|
|
@@ -227,7 +206,7 @@ const HOST_EDITOR_TYPES=currentBuiltinTypes('1.16.0','2.2.4','2.1.4',{'voiceover
|
|
|
227
206
|
const narrates=type=>flows[type.legacyMode].includes('voiceover');
|
|
228
207
|
const ORIGINAL_VOICEOVER_TYPES=currentBuiltinTypes('1.17.0','2.2.4','2.1.4',{'voiceover':'1.2.0','shot-plan':'2.1.3','blueprint':'2.1.9','panel-strip':'1.2.0','board-editor':'2.2.10','animated-scene':'2.3.8','editor':'1.0.0'}).map(type=>type.legacyMode!=='imagePanel'?type:
|
|
229
208
|
{...type,connections:[{from:{stage:'stage-1',port:'output'},to:{stage:'stage-2',port:'narrationAudio'}},{from:{stage:'stage-1',port:'timing'},to:{stage:'stage-2',port:'narrationTiming'}}]});
|
|
230
|
-
export const CURRENT_BUILTIN_TYPES = [...HOST_EDITOR_TYPES.map(type=>narrates(type)?ORIGINAL_VOICEOVER_TYPES.find(next=>next.id===type.id):type)
|
|
209
|
+
export const CURRENT_BUILTIN_TYPES = [...HOST_EDITOR_TYPES.map(type=>narrates(type)?ORIGINAL_VOICEOVER_TYPES.find(next=>next.id===type.id):type)];
|
|
231
210
|
const HISTORICAL_CURRENT_TYPES=[...HOST_EDITOR_TYPES.filter(narrates),...PORTABLE_EDITOR_TYPES,...PREVIOUS_PORTABLE_TYPES,...PRIOR_CURRENT_TYPES,...SHARED_WORKSPACE_TYPES,...SHARED_CANVAS_TYPES,...SHARED_BLUEPRINT_TYPES,...PRIOR_SHARED_TYPES,...MEDIA_LIBRARY_TYPES,...EDITOR_AUDIO_TYPES,...PLAYABLE_EDITOR_TYPES,...ADVANCED_PORTABLE_TYPES,...PORTABLE_MVP_TYPES,...PRE_PROMOTION_CURRENT_TYPES,...PREVIOUS_BUILTIN_TYPES.filter(type=>flows[type.legacyMode].includes('shot-plan')),...currentBuiltinTypes('1.1.0','1.1.0','1.1.0',PRIOR_HOST_WORKSPACE_VERSIONS)];
|
|
232
211
|
export const BUILTIN_TYPES = [...CURRENT_BUILTIN_TYPES,...HISTORICAL_CURRENT_TYPES,...LEGACY_TYPES];
|
|
233
212
|
// Hidden from discovery (October 20, 2026, owner decision: keep only Guided, Image Panels, Blank
|
|
@@ -238,7 +217,7 @@ export const BUILTIN_TYPES = [...CURRENT_BUILTIN_TYPES,...HISTORICAL_CURRENT_TYP
|
|
|
238
217
|
// Ad Variants and the two photo reels are no longer built-in Types at all: their definitions stay
|
|
239
218
|
// in the repository only as acceptance fixtures (revenue-review-project-types.js and friends), a
|
|
240
219
|
// saved project carries its own copy of its Type, and the Blocks they used remain Blocks.
|
|
241
|
-
export const HIDDEN_TYPES=new Set([
|
|
220
|
+
export const HIDDEN_TYPES=new Set([]);
|
|
242
221
|
export const isHiddenType=type=>HIDDEN_TYPES.has((type?.manifest||type)?.id);
|
|
243
222
|
export const DISCOVERABLE_TYPES=Object.freeze(CURRENT_BUILTIN_TYPES.filter(type=>!isHiddenType(type)));
|
|
244
223
|
export const workspaceBlock = (id,version)=>DISCOVERABLE_BLOCKS.find(block=>block.manifest.id===id && (!version || block.manifest.version===version));
|