stillmade-sdk 0.1.42 → 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.
Files changed (262) hide show
  1. package/.stillmade/sdk-baseline.json +6 -8
  2. package/AGENTS.md +15 -10
  3. package/FRAME_VIEWS.md +113 -0
  4. package/INTERFACE_DESIGN.md +62 -22
  5. package/MOBILE_UI.md +4 -2
  6. package/MODULES.md +152 -6
  7. package/PASTE_TO_LLM.md +35 -25
  8. package/README.md +3 -2
  9. package/SDK.md +994 -550
  10. package/UI_AESTHETIC.md +22 -2
  11. package/blocks/generate/package.js +1 -0
  12. package/blocks/generate/versions/1.0.0/package.js +463 -0
  13. package/docs/build/audio-to-editor.md +36 -0
  14. package/docs/build/block-builder-contract.md +150 -0
  15. package/docs/build/comfyui.md +227 -0
  16. package/docs/build/concepts.md +40 -0
  17. package/docs/build/context.md +159 -0
  18. package/docs/build/cookbook.md +57 -0
  19. package/docs/build/custom-interface.md +617 -0
  20. package/docs/build/data-types.md +83 -0
  21. package/docs/build/frame-views.md +259 -0
  22. package/docs/build/generate-media.md +59 -0
  23. package/docs/build/github-applications.md +314 -0
  24. package/docs/build/hosted-images.md +214 -0
  25. package/docs/build/hosted-music.md +39 -0
  26. package/docs/build/hosted-speech.md +157 -0
  27. package/docs/build/hosted-text.md +246 -0
  28. package/docs/build/image-description.md +49 -0
  29. package/docs/build/interface-design.md +343 -0
  30. package/docs/build/javascript.md +63 -0
  31. package/docs/build/local-preview.md +61 -0
  32. package/docs/build/media-analysis.md +27 -0
  33. package/docs/build/media.md +400 -0
  34. package/docs/build/mobile-ui.md +106 -0
  35. package/docs/build/modules.md +487 -0
  36. package/docs/build/original-blocks.md +70 -0
  37. package/docs/build/outside-apis.md +128 -0
  38. package/docs/build/production-context-templates.md +12 -0
  39. package/docs/build/project-storage.md +94 -0
  40. package/docs/build/quickstart.md +48 -0
  41. package/docs/build/recipes.md +103 -0
  42. package/docs/build/script-handoff.md +45 -0
  43. package/docs/build/script-writer.md +34 -0
  44. package/docs/build/state.md +223 -0
  45. package/docs/build/testing.md +112 -0
  46. package/docs/build/timeline-edits.md +116 -0
  47. package/docs/build/timeline-proposals.md +76 -0
  48. package/docs/build/transcription.md +59 -0
  49. package/docs/build/triggers.md +59 -0
  50. package/docs/build/tutorial.md +52 -0
  51. package/docs/build/typescript.md +34 -0
  52. package/docs/build/video-generation.md +61 -0
  53. package/docs/build/web-reading.md +37 -0
  54. package/docs/build/with-your-ai.md +27 -0
  55. package/docs/changelog.md +9 -0
  56. package/docs/creators.md +21 -0
  57. package/docs/distribute/discovery.md +43 -0
  58. package/docs/distribute/imports.md +58 -0
  59. package/docs/distribute/publishing.md +29 -0
  60. package/docs/distribute/sdk-versions.md +36 -0
  61. package/docs/distribute/selling.md +14 -0
  62. package/docs/distribute/teams.md +60 -0
  63. package/docs/distribute/versioning.md +28 -0
  64. package/docs/examples.md +23 -0
  65. package/docs/gallery.md +26 -0
  66. package/docs/index.md +50 -0
  67. package/docs/native-mcp.md +307 -0
  68. package/docs/project-types/automation.md +43 -0
  69. package/docs/project-types/batches.md +50 -0
  70. package/docs/project-types/build.md +42 -0
  71. package/docs/project-types/completion.md +15 -0
  72. package/docs/project-types/conditions.md +21 -0
  73. package/docs/project-types/hosted-review.md +115 -0
  74. package/docs/project-types/onboarding.md +75 -0
  75. package/docs/project-types/running.md +309 -0
  76. package/docs/project-types/testing.md +72 -0
  77. package/docs/reference/application-artifacts.md +87 -0
  78. package/docs/reference/authoring-guide.md +134 -0
  79. package/docs/reference/browser-applications.md +267 -0
  80. package/docs/reference/capabilities.md +45 -0
  81. package/docs/reference/cli.md +71 -0
  82. package/docs/reference/connection-api.md +59 -0
  83. package/docs/reference/cooperative-jobs.md +13 -0
  84. package/docs/reference/desktop-capabilities.md +172 -0
  85. package/docs/reference/desktop-execution.md +77 -0
  86. package/docs/reference/errors.md +233 -0
  87. package/docs/reference/execution.md +800 -0
  88. package/docs/reference/first-party-blocks.md +40 -0
  89. package/docs/reference/generation-models.md +59 -0
  90. package/docs/reference/limits.md +306 -0
  91. package/docs/reference/manifest-kinds-controls.md +36 -0
  92. package/docs/reference/manifest.md +181 -0
  93. package/docs/reference/operations.md +36 -0
  94. package/docs/reference/package-jobs.md +35 -0
  95. package/docs/reference/parity.md +55 -0
  96. package/docs/reference/permissions.md +86 -0
  97. package/docs/reference/ports.md +26 -0
  98. package/docs/reference/types.md +268 -0
  99. package/docs/reference/universal-resolver.md +303 -0
  100. package/docs/reference/view-bridge.md +60 -0
  101. package/docs/reference/view-rules.md +15 -0
  102. package/docs/reference/workspace-sync.md +25 -0
  103. package/docs/sdk.md +34 -0
  104. package/docs/tools/block-remix.md +211 -0
  105. package/docs/tools/llm.md +2213 -0
  106. package/docs/tools/repository-adaptation.md +613 -0
  107. package/examples/check-clip.stillmade.json +4 -1
  108. package/examples/generate-video.stillmade.json +6 -2
  109. package/examples/research-topic.stillmade.json +5 -1
  110. package/examples/text-workflow.stillmade.json +3 -32
  111. package/examples/timeline-polish.stillmade.json +11 -3
  112. package/examples/transcribe-audio.stillmade.json +11 -3
  113. package/package.json +1 -1
  114. package/packages/block-cli/cli.js +13 -6
  115. package/packages/block-cli/dev-host/assets/host.js +76 -38
  116. package/packages/block-cli/dev-host/assets/index.css +1 -1
  117. package/packages/block-cli/format.js +1 -1
  118. package/packages/block-cli/templates.js +31 -13
  119. package/packages/block-cli/type-packages.js +119 -0
  120. package/packages/block-platform/block-readiness.js +5 -0
  121. package/packages/block-platform/canvas.js +2 -1
  122. package/packages/block-platform/catalog.js +27 -48
  123. package/packages/block-platform/native-host-inventory.js +0 -226
  124. package/packages/block-platform/plain-descriptions.js +1 -25
  125. package/packages/block-platform/project-type-starters.js +13 -53
  126. package/packages/block-platform/script-handoff.js +2 -4
  127. package/packages/block-platform/type-workspace.js +2 -0
  128. package/packages/block-sdk/appearance.js +3 -1
  129. package/packages/block-sdk/block-tier.js +1 -1
  130. package/packages/block-sdk/builder-contract.js +10 -8
  131. package/packages/block-sdk/capabilities.js +1 -1
  132. package/packages/block-sdk/contracts.js +6 -2
  133. package/packages/block-sdk/first-party-identities.js +1 -84
  134. package/packages/block-sdk/first-party-packages.js +3 -85
  135. package/packages/block-sdk/generation-catalog.js +15 -3
  136. package/packages/block-sdk/index.d.ts +2 -1
  137. package/packages/block-sdk/media-analysis-example.js +1 -1
  138. package/packages/block-sdk/mock-host.js +7 -1
  139. package/packages/block-sdk/module-host-calls.js +35 -10
  140. package/packages/block-sdk/module-hosted.js +15 -2
  141. package/packages/block-sdk/module-media-access.js +71 -0
  142. package/packages/block-sdk/module-node.js +1 -1
  143. package/packages/block-sdk/portable-media-actions.js +1 -1
  144. package/packages/block-sdk/runtime.js +1 -1
  145. package/packages/block-sdk/timeline-proposal-example.js +1 -1
  146. package/packages/block-sdk/transcription-example.js +1 -1
  147. package/packages/block-sdk/video-generation-example.js +1 -1
  148. package/packages/block-sdk/view-bridge.js +4 -1
  149. package/packages/block-sdk/view-design.js +17 -14
  150. package/packages/block-sdk/web-example.js +1 -1
  151. package/packages/design-system/block-kit.css +48 -12
  152. package/packages/design-system/block-kit.html +3 -2
  153. package/blocks/mcp-motion-planner/versions/1.1.0/package.js +0 -97
  154. package/blocks/motion-designer/versions/1.0.1/package.js +0 -173318
  155. package/blocks/motion-designer/versions/1.0.2/package.js +0 -173318
  156. package/blocks/motion-frame-review/versions/1.1.1/package.js +0 -465
  157. package/blocks/motion-frame-review/versions/1.1.2/package.snapshot.js +0 -572
  158. package/blocks/narration/package.js +0 -1
  159. package/blocks/narration/versions/1.0.0/package.js +0 -221
  160. package/blocks/narration/versions/1.0.1/package.js +0 -221
  161. package/blocks/native/sm.animated-scene/versions/2.0.0/package.js +0 -475
  162. package/blocks/native/sm.animated-scene/versions/2.1.0/package.js +0 -498
  163. package/blocks/native/sm.animated-scene/versions/2.2.0/package.js +0 -524
  164. package/blocks/native/sm.animated-scene/versions/2.3.0/package.js +0 -618
  165. package/blocks/native/sm.animated-scene/versions/2.3.1/package.js +0 -618
  166. package/blocks/native/sm.animated-scene/versions/2.3.2/package.js +0 -723
  167. package/blocks/native/sm.animated-scene/versions/2.3.3/package.js +0 -723
  168. package/blocks/native/sm.animated-scene/versions/2.3.4/package.js +0 -676
  169. package/blocks/native/sm.animated-scene/versions/2.3.5/package.js +0 -693
  170. package/blocks/native/sm.animated-scene/versions/2.3.6/package.js +0 -700
  171. package/blocks/native/sm.animated-scene/versions/2.3.7/package.js +0 -747
  172. package/blocks/native/sm.animated-scene/versions/2.3.8/package.js +0 -769
  173. package/blocks/native/sm.animated-scene/versions/2.3.9/package.js +0 -769
  174. package/blocks/native/sm.animated-scene-assistant/versions/1.0.0/package.js +0 -183
  175. package/blocks/native/sm.blueprint/versions/2.0.0/package.js +0 -358
  176. package/blocks/native/sm.blueprint/versions/2.1.0/package.js +0 -358
  177. package/blocks/native/sm.blueprint/versions/2.1.1/package.js +0 -358
  178. package/blocks/native/sm.blueprint/versions/2.1.2/package.js +0 -358
  179. package/blocks/native/sm.blueprint/versions/2.1.3/package.js +0 -381
  180. package/blocks/native/sm.blueprint/versions/2.1.4/package.js +0 -381
  181. package/blocks/native/sm.blueprint/versions/2.1.5/package.js +0 -339
  182. package/blocks/native/sm.blueprint/versions/2.1.6/package.js +0 -356
  183. package/blocks/native/sm.blueprint/versions/2.1.7/package.js +0 -363
  184. package/blocks/native/sm.blueprint/versions/2.1.8/package.js +0 -410
  185. package/blocks/native/sm.blueprint/versions/2.1.9/package.js +0 -422
  186. package/blocks/native/sm.blueprint-assistant/versions/1.0.0/package.js +0 -172
  187. package/blocks/native/sm.chat/versions/2.0.0/package.js +0 -144
  188. package/blocks/native/sm.chat/versions/2.0.1/package.js +0 -97
  189. package/blocks/native/sm.chat/versions/2.0.2/package.js +0 -100
  190. package/blocks/native/sm.chat/versions/2.0.3/package.js +0 -100
  191. package/blocks/native/sm.continue-if/versions/1.0.0/package.js +0 -168
  192. package/blocks/native/sm.describe-media/versions/2.0.0/package.js +0 -153
  193. package/blocks/native/sm.describe-media/versions/2.0.1/package.js +0 -156
  194. package/blocks/native/sm.describe-media/versions/2.1.0/package.js +0 -140
  195. package/blocks/native/sm.image-editor/versions/2.0.0/package.js +0 -183
  196. package/blocks/native/sm.image-editor/versions/2.0.1/package.js +0 -190
  197. package/blocks/native/sm.new-items/versions/1.0.0/package.js +0 -191
  198. package/blocks/native/sm.pick-photos/versions/1.0.0/package.js +0 -334
  199. package/blocks/native/sm.quality-audit/versions/1.0.0/package.js +0 -192
  200. package/blocks/native/sm.quality-audit/versions/1.0.1/package.js +0 -192
  201. package/blocks/native/sm.quality-audit/versions/1.0.2/package.js +0 -195
  202. package/blocks/native/sm.research/versions/2.0.0/package.js +0 -175
  203. package/blocks/native/sm.research/versions/2.0.1/package.js +0 -184
  204. package/blocks/native/sm.research/versions/2.0.2/package.js +0 -187
  205. package/blocks/native/sm.script/versions/2.0.0/package.js +0 -144
  206. package/blocks/native/sm.script/versions/2.1.0/package.js +0 -144
  207. package/blocks/native/sm.script/versions/2.1.1/package.js +0 -144
  208. package/blocks/native/sm.script/versions/2.1.2/package.js +0 -105
  209. package/blocks/native/sm.script/versions/2.1.3/package.js +0 -152
  210. package/blocks/native/sm.script/versions/2.1.4/package.js +0 -156
  211. package/blocks/native/sm.script/versions/2.1.5/package.js +0 -156
  212. package/blocks/native/sm.shot-plan/versions/2.0.0/package.js +0 -301
  213. package/blocks/native/sm.shot-plan/versions/2.1.0/package.js +0 -528
  214. package/blocks/native/sm.shot-plan/versions/2.1.1/package.js +0 -528
  215. package/blocks/native/sm.shot-plan/versions/2.1.2/package.js +0 -528
  216. package/blocks/native/sm.shot-plan/versions/2.1.3/package.js +0 -536
  217. package/blocks/native/sm.shot-plan/versions/2.2.0/package.js +0 -800
  218. package/blocks/native/sm.shot-plan/versions/2.2.1/package.js +0 -920
  219. package/blocks/native/sm.shot-plan-assistant/versions/1.0.0/package.js +0 -173
  220. package/blocks/native/sm.stock-search/versions/2.0.0/package.js +0 -174
  221. package/blocks/native/sm.thumbnail/versions/2.0.0/package.js +0 -137
  222. package/blocks/native/sm.thumbnail/versions/2.0.1/package.js +0 -140
  223. package/blocks/native/sm.transcribe/versions/2.0.0/package.js +0 -163
  224. package/blocks/native/sm.transcribe/versions/2.0.1/package.js +0 -168
  225. package/blocks/native/sm.whiteboard-assistant/versions/1.0.0/package.js +0 -175
  226. package/blocks/native/sm.youtube/versions/2.0.0/package.js +0 -217
  227. package/blocks/occasion-story/package.js +0 -1
  228. package/blocks/occasion-story/versions/1.0.0/package.js +0 -1658
  229. package/blocks/occasion-story/versions/1.0.1/package.js +0 -1699
  230. package/blocks/occasion-story/versions/1.0.2/package.js +0 -1682
  231. package/blocks/photo-reel-composer/versions/1.0.0/package.js +0 -3043
  232. package/blocks/photo-reel-composer/versions/1.0.1/package.js +0 -3026
  233. package/blocks/photo-reel-composer/versions/1.0.2/package.js +0 -4149
  234. package/blocks/product-ad-variants/versions/1.0.0/package.js +0 -2911
  235. package/blocks/product-launch-director/versions/1.0.0/package.js +0 -103
  236. package/blocks/release-visuals/package.js +0 -1
  237. package/blocks/release-visuals/versions/1.0.0/package.js +0 -1492
  238. package/blocks/release-visuals/versions/1.0.1/package.js +0 -1517
  239. package/blocks/release-visuals/versions/1.0.2/package.js +0 -1500
  240. package/blocks/screen-recorder/package.js +0 -1
  241. package/blocks/screen-recorder/versions/1.0.0/package.js +0 -223
  242. package/blocks/screen-recorder/versions/1.0.1/package.js +0 -223
  243. package/blocks/short-form-finish/package.js +0 -1
  244. package/blocks/short-form-finish/versions/1.0.0/package.js +0 -1043
  245. package/blocks/short-form-finish/versions/1.0.1/package.js +0 -1043
  246. package/blocks/short-form-finish/versions/1.0.2/package.js +0 -1043
  247. package/blocks/short-form-finish/versions/1.0.3/package.js +0 -1026
  248. package/examples/saas-product-launch-reviewed-source.stillmade.json +0 -383
  249. package/examples/saas-product-launch.stillmade.json +0 -304
  250. package/packages/block-platform/dealer-inventory-video-project-type.js +0 -38
  251. package/packages/block-platform/first-revenue-project-types.js +0 -46
  252. package/packages/block-platform/fixture-starters.js +0 -13
  253. package/packages/block-platform/launch-project-source.js +0 -10
  254. package/packages/block-platform/launch-project.js +0 -30
  255. package/packages/block-platform/motion-project-types.js +0 -55
  256. package/packages/block-platform/motion-starters.js +0 -14
  257. package/packages/block-platform/product-ad-variants-project-type.js +0 -30
  258. package/packages/block-platform/product-launch-updated.js +0 -90
  259. package/packages/block-platform/revenue-review-project-types.js +0 -36
  260. package/packages/block-platform/revenue-review-starters.js +0 -13
  261. package/packages/block-platform/script-writer.js +0 -29
  262. package/packages/block-platform/website-source-block.js +0 -14
@@ -1,3043 +0,0 @@
1
- // Generated from the owned 1.0.0 manifest, runtime and fixtures.
2
- export default {
3
- "manifest": {
4
- "schemaVersion": 1,
5
- "sdkVersion": "0.1.0",
6
- "id": "stillmade.photo-reel-composer",
7
- "version": "1.0.0",
8
- "name": "Photo Reel Composer",
9
- "kind": "task",
10
- "runtime": "javascript",
11
- "entry": "src/run.js",
12
- "license": "MIT",
13
- "description": "Arrange original property or product photos and approved copy into a restrained, editable 20–30 second reel. No generated imagery or model calls.",
14
- "inputs": {
15
- "assets": {
16
- "type": "asset[]",
17
- "primary": true,
18
- "default": [],
19
- "description": "Ordered original photo references. Property: 6–8 photos. Product: 3–10. Exact versions and measured dimensions are required.",
20
- "semantic": "legacy.asset-list.assets",
21
- "required": true,
22
- "sources": [
23
- "upstream",
24
- "user"
25
- ]
26
- },
27
- "purpose": {
28
- "type": "text",
29
- "default": "property",
30
- "description": "Property or product photo reel.",
31
- "semantic": "stillmade.photo_reel.purpose",
32
- "required": false,
33
- "sources": [
34
- "user",
35
- "default"
36
- ]
37
- },
38
- "title": {
39
- "type": "text",
40
- "default": "",
41
- "description": "Approved title, up to 64 characters. Use only facts supplied and reviewed by the customer.",
42
- "semantic": "stillmade.photo_reel.title",
43
- "required": true,
44
- "sources": [
45
- "user",
46
- "default"
47
- ]
48
- },
49
- "captions": {
50
- "type": "text",
51
- "default": "",
52
- "description": "One approved short caption per photo, one line each, up to 64 characters per line. Leave all empty for an uncaptioned sequence.",
53
- "semantic": "stillmade.photo_reel.captions",
54
- "required": false,
55
- "sources": [
56
- "user",
57
- "default"
58
- ]
59
- },
60
- "cta": {
61
- "type": "text",
62
- "default": "",
63
- "description": "Approved call to action, up to 56 characters.",
64
- "semantic": "stillmade.photo_reel.cta",
65
- "required": true,
66
- "sources": [
67
- "user",
68
- "default"
69
- ]
70
- },
71
- "contact": {
72
- "type": "text",
73
- "default": "",
74
- "description": "Exact contact or short destination to display, up to 64 characters.",
75
- "semantic": "stillmade.photo_reel.contact",
76
- "required": false,
77
- "sources": [
78
- "user",
79
- "default"
80
- ]
81
- },
82
- "demoDisclosure": {
83
- "type": "text",
84
- "default": "",
85
- "description": "Optional exact disclosure shown throughout, such as Stock-photo demonstration · not a live listing.",
86
- "semantic": "stillmade.photo_reel.demodisclosure",
87
- "required": false,
88
- "sources": [
89
- "user",
90
- "default"
91
- ]
92
- },
93
- "duration": {
94
- "type": "number",
95
- "default": 24,
96
- "min": 20,
97
- "max": 30,
98
- "description": "Total reel duration in seconds, including the four-second closing card.",
99
- "semantic": "stillmade.photo_reel.duration",
100
- "required": false,
101
- "sources": [
102
- "user",
103
- "default"
104
- ]
105
- },
106
- "aspect": {
107
- "type": "text",
108
- "default": "9:16",
109
- "description": "Output frame shape; photos always retain their full original rectangle.",
110
- "semantic": "stillmade.photo_reel.aspect",
111
- "required": false,
112
- "sources": [
113
- "user",
114
- "default"
115
- ]
116
- },
117
- "logo": {
118
- "type": "asset[]",
119
- "default": [],
120
- "description": "Optional single original logo image with exact version and measured dimensions.",
121
- "semantic": "stillmade.photo_reel.logo",
122
- "required": false,
123
- "sources": [
124
- "user",
125
- "default"
126
- ]
127
- },
128
- "music": {
129
- "type": "asset[]",
130
- "default": [],
131
- "description": "Optional single licensed audio track with measured duration covering the reel. Otherwise output is silent.",
132
- "semantic": "stillmade.photo_reel.music",
133
- "required": false,
134
- "sources": [
135
- "user",
136
- "default"
137
- ]
138
- },
139
- "rightsConfirmed": {
140
- "type": "boolean",
141
- "default": false,
142
- "description": "I have permission to use the supplied photos, logo, music, and exact statements. This is my confirmation, not independent legal verification.",
143
- "semantic": "stillmade.photo_reel.rightsconfirmed",
144
- "required": true,
145
- "sources": [
146
- "user"
147
- ]
148
- }
149
- },
150
- "outputs": {
151
- "timeline": {
152
- "type": "timeline",
153
- "primary": true,
154
- "semantic": "legacy.timeline.updatededitor",
155
- "description": "Editable complete Editor timeline containing original photo clips, approved text, optional music and logo."
156
- },
157
- "review": {
158
- "type": "json",
159
- "description": "Structural checks and remaining human review. Does not authorize export or certify claims or rights.",
160
- "semantic": "stillmade.photo_reel.review",
161
- "schema": {
162
- "schemaVersion": "integer",
163
- "state": "string",
164
- "durationSec": "number",
165
- "aspect": "string",
166
- "photoCount": "integer",
167
- "checks": [
168
- {
169
- "id": "string",
170
- "passed": "boolean",
171
- "note": "string"
172
- }
173
- ],
174
- "warnings": "string[]",
175
- "humanApproved": "boolean",
176
- "exportAuthorized": "boolean",
177
- "cost": {
178
- "providerCalls": "integer",
179
- "generationCredits": "integer",
180
- "note": "string"
181
- }
182
- }
183
- },
184
- "provenance": {
185
- "type": "json",
186
- "description": "Versioned source references, supplied copy and bounded transformation record.",
187
- "semantic": "stillmade.photo_reel.provenance",
188
- "schema": {
189
- "schemaVersion": "integer",
190
- "kind": "string",
191
- "block": {
192
- "id": "string",
193
- "version": "string"
194
- },
195
- "purpose": "string",
196
- "sourcePhotos": [
197
- {
198
- "index": "integer",
199
- "assetId": "string",
200
- "versionId": "string",
201
- "width": "number",
202
- "height": "number"
203
- }
204
- ],
205
- "logo": "json",
206
- "music": "json",
207
- "approvedCopy": {
208
- "title": "string",
209
- "captions": "string[]",
210
- "cta": "string",
211
- "contact": "string",
212
- "demoDisclosure": "string"
213
- },
214
- "rights": {
215
- "userConfirmed": "boolean",
216
- "independentlyVerified": "boolean"
217
- },
218
- "transformations": "string[]",
219
- "generativeMedia": "boolean",
220
- "providerCalls": "integer"
221
- }
222
- }
223
- },
224
- "permissions": {
225
- "project": [
226
- "asset.read"
227
- ],
228
- "network": [],
229
- "filesystem": [],
230
- "secrets": []
231
- },
232
- "ui": [
233
- {
234
- "port": "purpose",
235
- "control": "select",
236
- "options": [
237
- "property",
238
- "product"
239
- ]
240
- },
241
- {
242
- "port": "aspect",
243
- "control": "select",
244
- "options": [
245
- "9:16",
246
- "16:9",
247
- "1:1"
248
- ]
249
- },
250
- {
251
- "port": "duration",
252
- "control": "slider",
253
- "min": 20,
254
- "max": 30,
255
- "step": 1
256
- }
257
- ],
258
- "platforms": {
259
- "phone": {
260
- "supported": true
261
- },
262
- "browser": {
263
- "supported": true
264
- },
265
- "desktop": {
266
- "supported": true
267
- }
268
- },
269
- "provenance": {
270
- "notice": "Original source (authorship declared by the packager)\nLicense: MIT\nChanges: Original implementation declared by the packager; no reused repository or dependency code.\nFiles: LICENSE, src/run.js\n\nMIT License\n\nCopyright (c) <year> <copyright holders>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and \nassociated documentation files (the \"Software\"), to deal in the Software without restriction, including \nwithout limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell \ncopies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the \nfollowing conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial \nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT \nLIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO \nEVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER \nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE \nUSE OR OTHER DEALINGS IN THE SOFTWARE.\n",
271
- "portableSources": [
272
- {
273
- "kind": "original",
274
- "license": "MIT",
275
- "paths": [
276
- "LICENSE",
277
- "src/run.js"
278
- ],
279
- "evidence": [
280
- "upstream/0/LICENSE",
281
- "upstream/0/src/run.js"
282
- ],
283
- "changes": "Original implementation declared by the packager; no reused repository or dependency code."
284
- }
285
- ]
286
- },
287
- "semantics": [
288
- {
289
- "name": "stillmade.photo_reel.purpose",
290
- "description": "Property or product photo reel.",
291
- "parents": []
292
- },
293
- {
294
- "name": "stillmade.photo_reel.title",
295
- "description": "Approved title, up to 64 characters. Use only facts supplied and reviewed by the customer.",
296
- "parents": []
297
- },
298
- {
299
- "name": "stillmade.photo_reel.captions",
300
- "description": "One approved short caption per photo, one line each, up to 64 characters per line. Leave all empty for an uncaptioned sequence.",
301
- "parents": []
302
- },
303
- {
304
- "name": "stillmade.photo_reel.cta",
305
- "description": "Approved call to action, up to 56 characters.",
306
- "parents": []
307
- },
308
- {
309
- "name": "stillmade.photo_reel.contact",
310
- "description": "Exact contact or short destination to display, up to 64 characters.",
311
- "parents": []
312
- },
313
- {
314
- "name": "stillmade.photo_reel.demodisclosure",
315
- "description": "Optional exact disclosure shown throughout, such as Stock-photo demonstration · not a live listing.",
316
- "parents": []
317
- },
318
- {
319
- "name": "stillmade.photo_reel.duration",
320
- "description": "Total reel duration in seconds, including the four-second closing card.",
321
- "parents": []
322
- },
323
- {
324
- "name": "stillmade.photo_reel.aspect",
325
- "description": "Output frame shape; photos always retain their full original rectangle.",
326
- "parents": []
327
- },
328
- {
329
- "name": "stillmade.photo_reel.logo",
330
- "description": "Optional single original logo image with exact version and measured dimensions.",
331
- "parents": []
332
- },
333
- {
334
- "name": "stillmade.photo_reel.music",
335
- "description": "Optional single licensed audio track with measured duration covering the reel. Otherwise output is silent.",
336
- "parents": []
337
- },
338
- {
339
- "name": "stillmade.photo_reel.rightsconfirmed",
340
- "description": "I have permission to use the supplied photos, logo, music, and exact statements. This is my confirmation, not independent legal verification.",
341
- "parents": []
342
- },
343
- {
344
- "name": "stillmade.photo_reel.review",
345
- "description": "Structural checks and remaining human review. Does not authorize export or certify claims or rights.",
346
- "parents": []
347
- },
348
- {
349
- "name": "stillmade.photo_reel.provenance",
350
- "description": "Versioned source references, supplied copy and bounded transformation record.",
351
- "parents": []
352
- }
353
- ]
354
- },
355
- "code": "// Photo Reel Composer 1.0.0. Runs only inside the isolated SDK JavaScript runtime.\n// References and supplied copy are data; this Block never reads media bytes,\n// calls a model, changes a photo, authorizes an export, or verifies legal rights.\nconst clone = value => JSON.parse(JSON.stringify(value));\nconst fail = (ok, message) => { if (!ok) throw new Error(message); };\nconst clean = (value, label, maximum, required = false) => {\n fail(value === undefined || typeof value === 'string', label + ' must be text.');\n const text = (value || '').trim();\n fail((!required || text.length > 0) && text.length <= maximum, label + ' must contain ' + (required ? '1' : '0') + ' to ' + maximum + ' characters.');\n fail(!/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]/.test(text), label + ' contains unsupported control characters.');\n fail(text.split(/\\s+/).every(word => word.length <= 28), label + ' contains a word or link too long to fit. Use a shorter display label.');\n return text;\n};\nconst purpose = input.purpose || 'property';\nfail(['property', 'product'].includes(purpose), 'Choose property or product.');\nconst assets = input.assets;\nconst minimum = purpose === 'property' ? 6 : 3;\nconst maximum = purpose === 'property' ? 8 : 10;\nfail(Array.isArray(assets) && assets.length >= minimum && assets.length <= maximum, 'Choose ' + minimum + ' to ' + maximum + ' original photos, in the order they should appear.');\nconst validMedia = (asset, kind, label) => {\n fail(asset && typeof asset === 'object' && !Array.isArray(asset) && asset.kind === kind, label + ' must be a ' + kind + ' reference.');\n fail(typeof asset.assetId === 'string' && asset.assetId.length > 0 && asset.assetId.length <= 240 && typeof asset.versionId === 'string' && asset.versionId.length > 0 && asset.versionId.length <= 240, label + ' needs its exact asset and version identities.');\n const mediaUrl = asset.url;\n const supportedUrl = typeof mediaUrl === 'string' && mediaUrl.length > 0 && mediaUrl.length <= 200000 && (\n /^\\/api\\/media\\/[A-Za-z0-9_-]+\\/[A-Za-z0-9_-][A-Za-z0-9._-]*$/.test(mediaUrl) ||\n /^(https:\\/\\/|http:\\/\\/(127\\.0\\.0\\.1|localhost)(:\\d+)?\\/|data:(image\\/(png|jpeg|webp)|audio\\/[a-z0-9.+-]+);base64,|blob:|sm-media:)/i.test(mediaUrl)\n ) && !/^https?:\\/\\/[^/?#]*@/i.test(mediaUrl);\n fail(supportedUrl, label + ' needs an authorized media reference.');\n if (kind === 'image') fail(Number.isFinite(asset.width) && asset.width > 0 && asset.width <= 40000 && Number.isFinite(asset.height) && asset.height > 0 && asset.height <= 40000, label + ' needs its measured original width and height. Upload this original photo again to record its dimensions.');\n return clone(asset);\n};\nconst photos = assets.map((asset, index) => validMedia(asset, 'image', 'Photo ' + (index + 1)));\nfail(new Set(photos.map(asset => asset.assetId + '\\n' + asset.versionId)).size === photos.length, 'Remove duplicate photo versions before composing.');\nconst title = clean(input.title, 'Approved title', 64, true);\nconst cta = clean(input.cta, 'Approved call to action', 56, true);\nconst contact = clean(input.contact, 'Contact or destination', 64);\nconst demoDisclosure = clean(input.demoDisclosure, 'Demo disclosure', 72);\nconst captionsText = input.captions || '';\nfail(typeof captionsText === 'string' && captionsText.length <= 1600, 'Use one short approved caption per photo.');\nconst captions = captionsText.trim() ? captionsText.replace(/\\r/g, '').split('\\n').map((line, index) => clean(line, 'Photo caption ' + (index + 1), 64)) : [];\nfail(captions.length === 0 || captions.length === photos.length, 'Supply exactly one caption line per photo, or leave captions empty. Blank lines keep a photo uncaptioned.');\nfail(input.rightsConfirmed === true, 'Confirm that you may use these photos, logo, music and exact supplied statements before building.');\nconst duration = input.duration === undefined ? 24 : input.duration;\nfail(Number.isFinite(duration) && duration >= 20 && duration <= 30, 'Choose a duration from 20 to 30 seconds.');\nconst aspect = input.aspect || '9:16';\nfail(['9:16', '16:9', '1:1'].includes(aspect), 'Choose 9:16, 16:9 or 1:1.');\nconst extra = (value, kind, label) => {\n fail(value === undefined || Array.isArray(value) && value.length <= 1, 'Choose at most one ' + label + '.');\n return value && value.length ? validMedia(value[0], kind, label) : null;\n};\nconst logo = extra(input.logo, 'image', 'logo');\nconst music = extra(input.music, 'audio', 'music track');\nif (music) fail(Number.isFinite(music.duration) && music.duration >= duration, 'The music track must have a measured duration covering the complete reel. Upload a supported MP3 or WAV again to record its duration, choose a longer track, or omit music.');\nconst [aw, ah] = aspect.split(':').map(Number);\nconst frameWidth = aw / ah * 369;\nconst portrait = aspect === '9:16';\nconst square = aspect === '1:1';\nconst backgroundColor = '#101714';\nconst foreground = '#F7F0DB';\nconst accent = '#CEB88B';\nconst overlays = [];\nconst clips = [];\nconst stickers = [];\nconst round = value => Math.round(value * 1000000) / 1000000;\nconst text = (id, value, start, end, y, size, color = foreground, width = .82) => {\n if (!value) return;\n // The shared renderer wraps between words only. Conservatively shrink a\n // single unusually long unbroken word; ordinary short-copy layouts stay put.\n const longest = Math.max(...value.split(/\\s+/).map(word => word.length));\n if (longest > 18) size = Math.min(size, (frameWidth * width - 12) / longest);\n overlays.push({ id, trackId: 'text', type: 'text', text: value, font: 'Hanken Grotesk', size, color, background: 'none', backgroundPadding: 0, width, x: 50, y, position: 'center', start: round(start), end: round(end), duration: round(end - start), animation: 'fade', animIn: .25, animOut: .2, rotation: 0 });\n};\nconst introEnd = 3.5;\nconst cardStart = duration - 4;\nconst sceneDuration = (cardStart - introEnd) / (photos.length - 1);\n// Fit the FULL measured photo inside a reserved rectangle, then add at most 3%\n// optical zoom. No crop, stretching, retouching, or synthetic pixels are requested.\nconst photoClip = (asset, index, start, length, endCard = false) => {\n const rawFit = Math.min(frameWidth / asset.width, 369 / asset.height);\n const fittedWidth = asset.width * rawFit;\n const fittedHeight = asset.height * rawFit;\n const regionWidth = frameWidth * (endCard ? .64 : .9);\n const regionHeight = 369 * (endCard ? .31 : portrait ? .48 : square ? .48 : .49);\n const scale = Math.min(regionWidth / fittedWidth, regionHeight / fittedHeight) / 1.03;\n const center = endCard ? .34 : .5;\n return {\n id: (endCard ? 'end-card-photo-' : 'photo-') + (index + 1), kind: 'image', trackId: 'video',\n asset: clone(asset), assetId: asset.assetId, versionId: asset.versionId, url: asset.url,\n title: asset.name || 'Photo ' + (index + 1), start: round(start), duration: round(length), trimStart: 0, speed: 1, volume: 0,\n transform: { fit: 'contain', scale, x: 0, y: (center - .5) * 369, rotation: 0, opacity: 1 },\n motion: { type: endCard ? 'none' : 'zoom', intensity: 100, zoomAmount: 1.03, zoomDirection: index % 2 ? 'out' : 'in', zoomAnchor: 'center', easing: 'ease-in-out', loop: false, ['window']: [0, 100] },\n transition: { type: endCard ? 'Cut' : 'Cross dissolve', duration: .3 },\n };\n};\nphotos.forEach((asset, index) => {\n const start = index === 0 ? 0 : introEnd + (index - 1) * sceneDuration;\n const end = index === 0 ? introEnd : index === photos.length - 1 ? cardStart : introEnd + index * sceneDuration;\n clips.push(photoClip(asset, index, start, end - start));\n text('photo-caption-' + (index + 1), captions[index], start + .2, end - .1, 79, portrait ? 11 : 14);\n text('photo-number-' + (index + 1), String(index + 1).padStart(2, '0') + ' / ' + String(photos.length).padStart(2, '0'), start, end - .01, 88, portrait ? 6.5 : 8, accent);\n});\nclips.push(photoClip(photos.at(-1), photos.length - 1, cardStart, 4, true));\n// The opening and closing compositions share an editorial rhythm while the\n// photographs remain full, unaltered, independently editable timeline items.\ntext('opening-title', title, 0, introEnd - .1, 18, portrait ? 16 : 22);\ntext('sequence-title', title, introEnd, cardStart, 16, portrait ? 10 : 14, foreground);\ntext('closing-title', title, cardStart, duration, 13, portrait ? 10 : 14, accent);\ntext('closing-cta', cta, cardStart + .1, duration, 65, portrait ? 17 : 23);\ntext('closing-contact', contact, cardStart + .25, duration, 79, portrait ? 9 : 12);\ntext('demo-disclosure', demoDisclosure, 0, duration, 94, portrait ? 6.5 : 8, '#D4D9D0', .84);\nstickers.push({ id: 'editorial-rule', trackId: 'overlay', shape: 'underline', color: accent, x: 50, y: 25, scale: .2, stretchX: 1.1, stretchY: .24, opacity: .85, rotation: 0, start: 0, end: cardStart });\nstickers.push({ id: 'closing-rule', trackId: 'overlay', shape: 'underline', color: accent, x: 50, y: 55, scale: .2, stretchX: 1.1, stretchY: .24, opacity: .85, rotation: 0, start: cardStart, end: duration });\nif (logo) {\n // Use an ordinary image clip on its own upper track. This avoids the GIF\n // sticker renderer's minimum-height distortion for unusually wide wordmarks.\n const fitted = Math.min(frameWidth / logo.width, 369 / logo.height);\n const scale = Math.min(frameWidth * .2 / (logo.width * fitted), 369 * .06 / (logo.height * fitted));\n clips.push({ id: 'brand-logo', kind: 'image', trackId: 'logo', asset: clone(logo), assetId: logo.assetId, versionId: logo.versionId, url: logo.url, start: cardStart, duration: 4, trimStart: 0, speed: 1, volume: 0, transform: { fit: 'contain', scale, x: 0, y: 369 * .39, rotation: 0, opacity: 1 }, motion: { type: 'none' }, transition: { type: 'Cut', duration: 0 } });\n}\nconst audioItems = music ? [{ id: 'music', trackId: 'audio', asset: clone(music), assetId: music.assetId, versionId: music.versionId, url: music.url, start: 0, duration, trimStart: 0, sourceOffset: 0, speed: 1, volume: 35, fadeIn: .5, fadeOut: .8 }] : [];\nconst provenance = {\n schemaVersion: 1, kind: 'photo-reel-source-record', block: { id: 'stillmade.photo-reel-composer', version: '1.0.0' }, purpose,\n sourcePhotos: photos.map((asset, index) => ({ index, assetId: asset.assetId, versionId: asset.versionId, width: asset.width, height: asset.height })),\n logo: logo ? { assetId: logo.assetId, versionId: logo.versionId } : null,\n music: music ? { assetId: music.assetId, versionId: music.versionId } : null,\n approvedCopy: { title, captions, cta, contact, demoDisclosure },\n rights: { userConfirmed: true, independentlyVerified: false },\n transformations: ['contain fit', 'uniform scale', 'at most three percent optical zoom'],\n generativeMedia: false, providerCalls: 0,\n};\nconst timeline = {\n schemaVersion: 1, activeTimelineId: 'photo-reel', name: title, aspect, aspectRatio: aspect, previewH: 369, backgroundColor,\n tracks: [{ id: 'video', type: 'video', label: 'Original photos' }, ...(logo ? [{ id: 'logo', type: 'video', label: 'Original logo' }] : []), { id: 'text', type: 'text', label: 'Approved copy' }, { id: 'overlay', type: 'overlay', label: 'Graphic details' }, { id: 'audio', type: 'audio', label: 'Music' }],\n trackOrder: ['video', 'logo', 'text', 'overlay', 'audio'], clips, audioItems, textOverlays: overlays, captions: [], stickers, effects: [],\n // The device renderer consumes these legacy aliases; Editor keeps the normal\n // editable lanes above. Both refer to the same content at creation time.\n audio: clone(audioItems), overlays: clone(overlays), targetDuration: duration,\n exportSettings: { aspect, fps: 30, resolution: '1080p', quality: 'high' },\n photoReel: clone(provenance),\n};\nconst lowResolution = photos.filter(asset => asset.width < 1080 || asset.height < 720).map(asset => asset.assetId);\nreturn {\n timeline,\n review: {\n schemaVersion: 1, state: 'needs-human-review', durationSec: duration, aspect, photoCount: photos.length,\n checks: [\n { id: 'original-source-versions', passed: true, note: 'Every photo retains its supplied asset/version and full source rectangle.' },\n { id: 'approved-copy-only', passed: true, note: 'No property features, prices, availability or product claims are generated.' },\n { id: 'bounded-local-composition', passed: true, note: 'No provider call or credit spend occurs in this Block.' },\n { id: 'complete-timing', passed: true, note: 'All source photos and a four-second closing card fit the requested duration.' },\n ],\n warnings: [\n 'Review the full export for photo quality, exact facts, readable copy, licensing and the displayed contact before delivering.',\n ...(!music ? ['Silent reel. Add rights-cleared music in this Block or the Editor if wanted.'] : []),\n ...(lowResolution.length ? ['Small source images may look soft in a 1080p export: ' + lowResolution.join(', ')] : []),\n ...(demoDisclosure ? ['This is labeled demonstration material and is not evidence of a real property or product offer.'] : []),\n ],\n humanApproved: false, exportAuthorized: false, cost: { providerCalls: 0, generationCredits: 0, note: 'Host storage, export access and any separately added services use their own policy.' },\n },\n provenance,\n};\n",
356
- "tests": [
357
- {
358
- "name": "Compose exact original property photos and approved copy",
359
- "input": {
360
- "assets": [
361
- {
362
- "kind": "image",
363
- "assetId": "photo-1",
364
- "versionId": "original-v1",
365
- "url": "https://media.example/photo-1.jpg",
366
- "width": 1600,
367
- "height": 1067,
368
- "name": "Approved photo 1"
369
- },
370
- {
371
- "kind": "image",
372
- "assetId": "photo-2",
373
- "versionId": "original-v1",
374
- "url": "https://media.example/photo-2.jpg",
375
- "width": 1600,
376
- "height": 1067,
377
- "name": "Approved photo 2"
378
- },
379
- {
380
- "kind": "image",
381
- "assetId": "photo-3",
382
- "versionId": "original-v1",
383
- "url": "https://media.example/photo-3.jpg",
384
- "width": 1600,
385
- "height": 1067,
386
- "name": "Approved photo 3"
387
- },
388
- {
389
- "kind": "image",
390
- "assetId": "photo-4",
391
- "versionId": "original-v1",
392
- "url": "https://media.example/photo-4.jpg",
393
- "width": 1600,
394
- "height": 1067,
395
- "name": "Approved photo 4"
396
- },
397
- {
398
- "kind": "image",
399
- "assetId": "photo-5",
400
- "versionId": "original-v1",
401
- "url": "https://media.example/photo-5.jpg",
402
- "width": 1600,
403
- "height": 1067,
404
- "name": "Approved photo 5"
405
- },
406
- {
407
- "kind": "image",
408
- "assetId": "photo-6",
409
- "versionId": "original-v1",
410
- "url": "https://media.example/photo-6.jpg",
411
- "width": 1600,
412
- "height": 1067,
413
- "name": "Approved photo 6"
414
- }
415
- ],
416
- "purpose": "property",
417
- "title": "An interior photo collection",
418
- "captions": "Entry\nLiving area\nDining area\nKitchen\nBedroom\nDetail",
419
- "cta": "Ask for the details",
420
- "contact": "Example contact",
421
- "demoDisclosure": "Sample only · not a live listing",
422
- "duration": 24,
423
- "aspect": "9:16",
424
- "logo": [],
425
- "music": [],
426
- "rightsConfirmed": true
427
- },
428
- "expected": {
429
- "timeline": {
430
- "schemaVersion": 1,
431
- "activeTimelineId": "photo-reel",
432
- "name": "An interior photo collection",
433
- "aspect": "9:16",
434
- "aspectRatio": "9:16",
435
- "previewH": 369,
436
- "backgroundColor": "#101714",
437
- "tracks": [
438
- {
439
- "id": "video",
440
- "type": "video",
441
- "label": "Original photos"
442
- },
443
- {
444
- "id": "text",
445
- "type": "text",
446
- "label": "Approved copy"
447
- },
448
- {
449
- "id": "overlay",
450
- "type": "overlay",
451
- "label": "Graphic details"
452
- },
453
- {
454
- "id": "audio",
455
- "type": "audio",
456
- "label": "Music"
457
- }
458
- ],
459
- "trackOrder": [
460
- "video",
461
- "logo",
462
- "text",
463
- "overlay",
464
- "audio"
465
- ],
466
- "clips": [
467
- {
468
- "id": "photo-1",
469
- "kind": "image",
470
- "trackId": "video",
471
- "asset": {
472
- "kind": "image",
473
- "assetId": "photo-1",
474
- "versionId": "original-v1",
475
- "url": "https://media.example/photo-1.jpg",
476
- "width": 1600,
477
- "height": 1067,
478
- "name": "Approved photo 1"
479
- },
480
- "assetId": "photo-1",
481
- "versionId": "original-v1",
482
- "url": "https://media.example/photo-1.jpg",
483
- "title": "Approved photo 1",
484
- "start": 0,
485
- "duration": 3.5,
486
- "trimStart": 0,
487
- "speed": 1,
488
- "volume": 0,
489
- "transform": {
490
- "fit": "contain",
491
- "scale": 0.8737864077669902,
492
- "x": 0,
493
- "y": 0,
494
- "rotation": 0,
495
- "opacity": 1
496
- },
497
- "motion": {
498
- "type": "zoom",
499
- "intensity": 100,
500
- "zoomAmount": 1.03,
501
- "zoomDirection": "in",
502
- "zoomAnchor": "center",
503
- "easing": "ease-in-out",
504
- "loop": false,
505
- "window": [
506
- 0,
507
- 100
508
- ]
509
- },
510
- "transition": {
511
- "type": "Cross dissolve",
512
- "duration": 0.3
513
- }
514
- },
515
- {
516
- "id": "photo-2",
517
- "kind": "image",
518
- "trackId": "video",
519
- "asset": {
520
- "kind": "image",
521
- "assetId": "photo-2",
522
- "versionId": "original-v1",
523
- "url": "https://media.example/photo-2.jpg",
524
- "width": 1600,
525
- "height": 1067,
526
- "name": "Approved photo 2"
527
- },
528
- "assetId": "photo-2",
529
- "versionId": "original-v1",
530
- "url": "https://media.example/photo-2.jpg",
531
- "title": "Approved photo 2",
532
- "start": 3.5,
533
- "duration": 3.3,
534
- "trimStart": 0,
535
- "speed": 1,
536
- "volume": 0,
537
- "transform": {
538
- "fit": "contain",
539
- "scale": 0.8737864077669902,
540
- "x": 0,
541
- "y": 0,
542
- "rotation": 0,
543
- "opacity": 1
544
- },
545
- "motion": {
546
- "type": "zoom",
547
- "intensity": 100,
548
- "zoomAmount": 1.03,
549
- "zoomDirection": "out",
550
- "zoomAnchor": "center",
551
- "easing": "ease-in-out",
552
- "loop": false,
553
- "window": [
554
- 0,
555
- 100
556
- ]
557
- },
558
- "transition": {
559
- "type": "Cross dissolve",
560
- "duration": 0.3
561
- }
562
- },
563
- {
564
- "id": "photo-3",
565
- "kind": "image",
566
- "trackId": "video",
567
- "asset": {
568
- "kind": "image",
569
- "assetId": "photo-3",
570
- "versionId": "original-v1",
571
- "url": "https://media.example/photo-3.jpg",
572
- "width": 1600,
573
- "height": 1067,
574
- "name": "Approved photo 3"
575
- },
576
- "assetId": "photo-3",
577
- "versionId": "original-v1",
578
- "url": "https://media.example/photo-3.jpg",
579
- "title": "Approved photo 3",
580
- "start": 6.8,
581
- "duration": 3.3,
582
- "trimStart": 0,
583
- "speed": 1,
584
- "volume": 0,
585
- "transform": {
586
- "fit": "contain",
587
- "scale": 0.8737864077669902,
588
- "x": 0,
589
- "y": 0,
590
- "rotation": 0,
591
- "opacity": 1
592
- },
593
- "motion": {
594
- "type": "zoom",
595
- "intensity": 100,
596
- "zoomAmount": 1.03,
597
- "zoomDirection": "in",
598
- "zoomAnchor": "center",
599
- "easing": "ease-in-out",
600
- "loop": false,
601
- "window": [
602
- 0,
603
- 100
604
- ]
605
- },
606
- "transition": {
607
- "type": "Cross dissolve",
608
- "duration": 0.3
609
- }
610
- },
611
- {
612
- "id": "photo-4",
613
- "kind": "image",
614
- "trackId": "video",
615
- "asset": {
616
- "kind": "image",
617
- "assetId": "photo-4",
618
- "versionId": "original-v1",
619
- "url": "https://media.example/photo-4.jpg",
620
- "width": 1600,
621
- "height": 1067,
622
- "name": "Approved photo 4"
623
- },
624
- "assetId": "photo-4",
625
- "versionId": "original-v1",
626
- "url": "https://media.example/photo-4.jpg",
627
- "title": "Approved photo 4",
628
- "start": 10.1,
629
- "duration": 3.3,
630
- "trimStart": 0,
631
- "speed": 1,
632
- "volume": 0,
633
- "transform": {
634
- "fit": "contain",
635
- "scale": 0.8737864077669902,
636
- "x": 0,
637
- "y": 0,
638
- "rotation": 0,
639
- "opacity": 1
640
- },
641
- "motion": {
642
- "type": "zoom",
643
- "intensity": 100,
644
- "zoomAmount": 1.03,
645
- "zoomDirection": "out",
646
- "zoomAnchor": "center",
647
- "easing": "ease-in-out",
648
- "loop": false,
649
- "window": [
650
- 0,
651
- 100
652
- ]
653
- },
654
- "transition": {
655
- "type": "Cross dissolve",
656
- "duration": 0.3
657
- }
658
- },
659
- {
660
- "id": "photo-5",
661
- "kind": "image",
662
- "trackId": "video",
663
- "asset": {
664
- "kind": "image",
665
- "assetId": "photo-5",
666
- "versionId": "original-v1",
667
- "url": "https://media.example/photo-5.jpg",
668
- "width": 1600,
669
- "height": 1067,
670
- "name": "Approved photo 5"
671
- },
672
- "assetId": "photo-5",
673
- "versionId": "original-v1",
674
- "url": "https://media.example/photo-5.jpg",
675
- "title": "Approved photo 5",
676
- "start": 13.4,
677
- "duration": 3.3,
678
- "trimStart": 0,
679
- "speed": 1,
680
- "volume": 0,
681
- "transform": {
682
- "fit": "contain",
683
- "scale": 0.8737864077669902,
684
- "x": 0,
685
- "y": 0,
686
- "rotation": 0,
687
- "opacity": 1
688
- },
689
- "motion": {
690
- "type": "zoom",
691
- "intensity": 100,
692
- "zoomAmount": 1.03,
693
- "zoomDirection": "in",
694
- "zoomAnchor": "center",
695
- "easing": "ease-in-out",
696
- "loop": false,
697
- "window": [
698
- 0,
699
- 100
700
- ]
701
- },
702
- "transition": {
703
- "type": "Cross dissolve",
704
- "duration": 0.3
705
- }
706
- },
707
- {
708
- "id": "photo-6",
709
- "kind": "image",
710
- "trackId": "video",
711
- "asset": {
712
- "kind": "image",
713
- "assetId": "photo-6",
714
- "versionId": "original-v1",
715
- "url": "https://media.example/photo-6.jpg",
716
- "width": 1600,
717
- "height": 1067,
718
- "name": "Approved photo 6"
719
- },
720
- "assetId": "photo-6",
721
- "versionId": "original-v1",
722
- "url": "https://media.example/photo-6.jpg",
723
- "title": "Approved photo 6",
724
- "start": 16.7,
725
- "duration": 3.3,
726
- "trimStart": 0,
727
- "speed": 1,
728
- "volume": 0,
729
- "transform": {
730
- "fit": "contain",
731
- "scale": 0.8737864077669902,
732
- "x": 0,
733
- "y": 0,
734
- "rotation": 0,
735
- "opacity": 1
736
- },
737
- "motion": {
738
- "type": "zoom",
739
- "intensity": 100,
740
- "zoomAmount": 1.03,
741
- "zoomDirection": "out",
742
- "zoomAnchor": "center",
743
- "easing": "ease-in-out",
744
- "loop": false,
745
- "window": [
746
- 0,
747
- 100
748
- ]
749
- },
750
- "transition": {
751
- "type": "Cross dissolve",
752
- "duration": 0.3
753
- }
754
- },
755
- {
756
- "id": "end-card-photo-6",
757
- "kind": "image",
758
- "trackId": "video",
759
- "asset": {
760
- "kind": "image",
761
- "assetId": "photo-6",
762
- "versionId": "original-v1",
763
- "url": "https://media.example/photo-6.jpg",
764
- "width": 1600,
765
- "height": 1067,
766
- "name": "Approved photo 6"
767
- },
768
- "assetId": "photo-6",
769
- "versionId": "original-v1",
770
- "url": "https://media.example/photo-6.jpg",
771
- "title": "Approved photo 6",
772
- "start": 20,
773
- "duration": 4,
774
- "trimStart": 0,
775
- "speed": 1,
776
- "volume": 0,
777
- "transform": {
778
- "fit": "contain",
779
- "scale": 0.6213592233009708,
780
- "x": 0,
781
- "y": -59.03999999999999,
782
- "rotation": 0,
783
- "opacity": 1
784
- },
785
- "motion": {
786
- "type": "none",
787
- "intensity": 100,
788
- "zoomAmount": 1.03,
789
- "zoomDirection": "out",
790
- "zoomAnchor": "center",
791
- "easing": "ease-in-out",
792
- "loop": false,
793
- "window": [
794
- 0,
795
- 100
796
- ]
797
- },
798
- "transition": {
799
- "type": "Cut",
800
- "duration": 0.3
801
- }
802
- }
803
- ],
804
- "audioItems": [],
805
- "textOverlays": [
806
- {
807
- "id": "photo-caption-1",
808
- "trackId": "text",
809
- "type": "text",
810
- "text": "Entry",
811
- "font": "Hanken Grotesk",
812
- "size": 11,
813
- "color": "#F7F0DB",
814
- "background": "none",
815
- "backgroundPadding": 0,
816
- "width": 0.82,
817
- "x": 50,
818
- "y": 79,
819
- "position": "center",
820
- "start": 0.2,
821
- "end": 3.4,
822
- "duration": 3.2,
823
- "animation": "fade",
824
- "animIn": 0.25,
825
- "animOut": 0.2,
826
- "rotation": 0
827
- },
828
- {
829
- "id": "photo-number-1",
830
- "trackId": "text",
831
- "type": "text",
832
- "text": "01 / 06",
833
- "font": "Hanken Grotesk",
834
- "size": 6.5,
835
- "color": "#CEB88B",
836
- "background": "none",
837
- "backgroundPadding": 0,
838
- "width": 0.82,
839
- "x": 50,
840
- "y": 88,
841
- "position": "center",
842
- "start": 0,
843
- "end": 3.49,
844
- "duration": 3.49,
845
- "animation": "fade",
846
- "animIn": 0.25,
847
- "animOut": 0.2,
848
- "rotation": 0
849
- },
850
- {
851
- "id": "photo-caption-2",
852
- "trackId": "text",
853
- "type": "text",
854
- "text": "Living area",
855
- "font": "Hanken Grotesk",
856
- "size": 11,
857
- "color": "#F7F0DB",
858
- "background": "none",
859
- "backgroundPadding": 0,
860
- "width": 0.82,
861
- "x": 50,
862
- "y": 79,
863
- "position": "center",
864
- "start": 3.7,
865
- "end": 6.7,
866
- "duration": 3,
867
- "animation": "fade",
868
- "animIn": 0.25,
869
- "animOut": 0.2,
870
- "rotation": 0
871
- },
872
- {
873
- "id": "photo-number-2",
874
- "trackId": "text",
875
- "type": "text",
876
- "text": "02 / 06",
877
- "font": "Hanken Grotesk",
878
- "size": 6.5,
879
- "color": "#CEB88B",
880
- "background": "none",
881
- "backgroundPadding": 0,
882
- "width": 0.82,
883
- "x": 50,
884
- "y": 88,
885
- "position": "center",
886
- "start": 3.5,
887
- "end": 6.79,
888
- "duration": 3.29,
889
- "animation": "fade",
890
- "animIn": 0.25,
891
- "animOut": 0.2,
892
- "rotation": 0
893
- },
894
- {
895
- "id": "photo-caption-3",
896
- "trackId": "text",
897
- "type": "text",
898
- "text": "Dining area",
899
- "font": "Hanken Grotesk",
900
- "size": 11,
901
- "color": "#F7F0DB",
902
- "background": "none",
903
- "backgroundPadding": 0,
904
- "width": 0.82,
905
- "x": 50,
906
- "y": 79,
907
- "position": "center",
908
- "start": 7,
909
- "end": 10,
910
- "duration": 3,
911
- "animation": "fade",
912
- "animIn": 0.25,
913
- "animOut": 0.2,
914
- "rotation": 0
915
- },
916
- {
917
- "id": "photo-number-3",
918
- "trackId": "text",
919
- "type": "text",
920
- "text": "03 / 06",
921
- "font": "Hanken Grotesk",
922
- "size": 6.5,
923
- "color": "#CEB88B",
924
- "background": "none",
925
- "backgroundPadding": 0,
926
- "width": 0.82,
927
- "x": 50,
928
- "y": 88,
929
- "position": "center",
930
- "start": 6.8,
931
- "end": 10.09,
932
- "duration": 3.29,
933
- "animation": "fade",
934
- "animIn": 0.25,
935
- "animOut": 0.2,
936
- "rotation": 0
937
- },
938
- {
939
- "id": "photo-caption-4",
940
- "trackId": "text",
941
- "type": "text",
942
- "text": "Kitchen",
943
- "font": "Hanken Grotesk",
944
- "size": 11,
945
- "color": "#F7F0DB",
946
- "background": "none",
947
- "backgroundPadding": 0,
948
- "width": 0.82,
949
- "x": 50,
950
- "y": 79,
951
- "position": "center",
952
- "start": 10.3,
953
- "end": 13.3,
954
- "duration": 3,
955
- "animation": "fade",
956
- "animIn": 0.25,
957
- "animOut": 0.2,
958
- "rotation": 0
959
- },
960
- {
961
- "id": "photo-number-4",
962
- "trackId": "text",
963
- "type": "text",
964
- "text": "04 / 06",
965
- "font": "Hanken Grotesk",
966
- "size": 6.5,
967
- "color": "#CEB88B",
968
- "background": "none",
969
- "backgroundPadding": 0,
970
- "width": 0.82,
971
- "x": 50,
972
- "y": 88,
973
- "position": "center",
974
- "start": 10.1,
975
- "end": 13.39,
976
- "duration": 3.29,
977
- "animation": "fade",
978
- "animIn": 0.25,
979
- "animOut": 0.2,
980
- "rotation": 0
981
- },
982
- {
983
- "id": "photo-caption-5",
984
- "trackId": "text",
985
- "type": "text",
986
- "text": "Bedroom",
987
- "font": "Hanken Grotesk",
988
- "size": 11,
989
- "color": "#F7F0DB",
990
- "background": "none",
991
- "backgroundPadding": 0,
992
- "width": 0.82,
993
- "x": 50,
994
- "y": 79,
995
- "position": "center",
996
- "start": 13.6,
997
- "end": 16.6,
998
- "duration": 3,
999
- "animation": "fade",
1000
- "animIn": 0.25,
1001
- "animOut": 0.2,
1002
- "rotation": 0
1003
- },
1004
- {
1005
- "id": "photo-number-5",
1006
- "trackId": "text",
1007
- "type": "text",
1008
- "text": "05 / 06",
1009
- "font": "Hanken Grotesk",
1010
- "size": 6.5,
1011
- "color": "#CEB88B",
1012
- "background": "none",
1013
- "backgroundPadding": 0,
1014
- "width": 0.82,
1015
- "x": 50,
1016
- "y": 88,
1017
- "position": "center",
1018
- "start": 13.4,
1019
- "end": 16.69,
1020
- "duration": 3.29,
1021
- "animation": "fade",
1022
- "animIn": 0.25,
1023
- "animOut": 0.2,
1024
- "rotation": 0
1025
- },
1026
- {
1027
- "id": "photo-caption-6",
1028
- "trackId": "text",
1029
- "type": "text",
1030
- "text": "Detail",
1031
- "font": "Hanken Grotesk",
1032
- "size": 11,
1033
- "color": "#F7F0DB",
1034
- "background": "none",
1035
- "backgroundPadding": 0,
1036
- "width": 0.82,
1037
- "x": 50,
1038
- "y": 79,
1039
- "position": "center",
1040
- "start": 16.9,
1041
- "end": 19.9,
1042
- "duration": 3,
1043
- "animation": "fade",
1044
- "animIn": 0.25,
1045
- "animOut": 0.2,
1046
- "rotation": 0
1047
- },
1048
- {
1049
- "id": "photo-number-6",
1050
- "trackId": "text",
1051
- "type": "text",
1052
- "text": "06 / 06",
1053
- "font": "Hanken Grotesk",
1054
- "size": 6.5,
1055
- "color": "#CEB88B",
1056
- "background": "none",
1057
- "backgroundPadding": 0,
1058
- "width": 0.82,
1059
- "x": 50,
1060
- "y": 88,
1061
- "position": "center",
1062
- "start": 16.7,
1063
- "end": 19.99,
1064
- "duration": 3.29,
1065
- "animation": "fade",
1066
- "animIn": 0.25,
1067
- "animOut": 0.2,
1068
- "rotation": 0
1069
- },
1070
- {
1071
- "id": "opening-title",
1072
- "trackId": "text",
1073
- "type": "text",
1074
- "text": "An interior photo collection",
1075
- "font": "Hanken Grotesk",
1076
- "size": 16,
1077
- "color": "#F7F0DB",
1078
- "background": "none",
1079
- "backgroundPadding": 0,
1080
- "width": 0.82,
1081
- "x": 50,
1082
- "y": 18,
1083
- "position": "center",
1084
- "start": 0,
1085
- "end": 3.4,
1086
- "duration": 3.4,
1087
- "animation": "fade",
1088
- "animIn": 0.25,
1089
- "animOut": 0.2,
1090
- "rotation": 0
1091
- },
1092
- {
1093
- "id": "sequence-title",
1094
- "trackId": "text",
1095
- "type": "text",
1096
- "text": "An interior photo collection",
1097
- "font": "Hanken Grotesk",
1098
- "size": 10,
1099
- "color": "#F7F0DB",
1100
- "background": "none",
1101
- "backgroundPadding": 0,
1102
- "width": 0.82,
1103
- "x": 50,
1104
- "y": 16,
1105
- "position": "center",
1106
- "start": 3.5,
1107
- "end": 20,
1108
- "duration": 16.5,
1109
- "animation": "fade",
1110
- "animIn": 0.25,
1111
- "animOut": 0.2,
1112
- "rotation": 0
1113
- },
1114
- {
1115
- "id": "closing-title",
1116
- "trackId": "text",
1117
- "type": "text",
1118
- "text": "An interior photo collection",
1119
- "font": "Hanken Grotesk",
1120
- "size": 10,
1121
- "color": "#CEB88B",
1122
- "background": "none",
1123
- "backgroundPadding": 0,
1124
- "width": 0.82,
1125
- "x": 50,
1126
- "y": 13,
1127
- "position": "center",
1128
- "start": 20,
1129
- "end": 24,
1130
- "duration": 4,
1131
- "animation": "fade",
1132
- "animIn": 0.25,
1133
- "animOut": 0.2,
1134
- "rotation": 0
1135
- },
1136
- {
1137
- "id": "closing-cta",
1138
- "trackId": "text",
1139
- "type": "text",
1140
- "text": "Ask for the details",
1141
- "font": "Hanken Grotesk",
1142
- "size": 17,
1143
- "color": "#F7F0DB",
1144
- "background": "none",
1145
- "backgroundPadding": 0,
1146
- "width": 0.82,
1147
- "x": 50,
1148
- "y": 65,
1149
- "position": "center",
1150
- "start": 20.1,
1151
- "end": 24,
1152
- "duration": 3.9,
1153
- "animation": "fade",
1154
- "animIn": 0.25,
1155
- "animOut": 0.2,
1156
- "rotation": 0
1157
- },
1158
- {
1159
- "id": "closing-contact",
1160
- "trackId": "text",
1161
- "type": "text",
1162
- "text": "Example contact",
1163
- "font": "Hanken Grotesk",
1164
- "size": 9,
1165
- "color": "#F7F0DB",
1166
- "background": "none",
1167
- "backgroundPadding": 0,
1168
- "width": 0.82,
1169
- "x": 50,
1170
- "y": 79,
1171
- "position": "center",
1172
- "start": 20.25,
1173
- "end": 24,
1174
- "duration": 3.75,
1175
- "animation": "fade",
1176
- "animIn": 0.25,
1177
- "animOut": 0.2,
1178
- "rotation": 0
1179
- },
1180
- {
1181
- "id": "demo-disclosure",
1182
- "trackId": "text",
1183
- "type": "text",
1184
- "text": "Sample only · not a live listing",
1185
- "font": "Hanken Grotesk",
1186
- "size": 6.5,
1187
- "color": "#D4D9D0",
1188
- "background": "none",
1189
- "backgroundPadding": 0,
1190
- "width": 0.84,
1191
- "x": 50,
1192
- "y": 94,
1193
- "position": "center",
1194
- "start": 0,
1195
- "end": 24,
1196
- "duration": 24,
1197
- "animation": "fade",
1198
- "animIn": 0.25,
1199
- "animOut": 0.2,
1200
- "rotation": 0
1201
- }
1202
- ],
1203
- "captions": [],
1204
- "stickers": [
1205
- {
1206
- "id": "editorial-rule",
1207
- "trackId": "overlay",
1208
- "shape": "underline",
1209
- "color": "#CEB88B",
1210
- "x": 50,
1211
- "y": 25,
1212
- "scale": 0.2,
1213
- "stretchX": 1.1,
1214
- "stretchY": 0.24,
1215
- "opacity": 0.85,
1216
- "rotation": 0,
1217
- "start": 0,
1218
- "end": 20
1219
- },
1220
- {
1221
- "id": "closing-rule",
1222
- "trackId": "overlay",
1223
- "shape": "underline",
1224
- "color": "#CEB88B",
1225
- "x": 50,
1226
- "y": 55,
1227
- "scale": 0.2,
1228
- "stretchX": 1.1,
1229
- "stretchY": 0.24,
1230
- "opacity": 0.85,
1231
- "rotation": 0,
1232
- "start": 20,
1233
- "end": 24
1234
- }
1235
- ],
1236
- "effects": [],
1237
- "audio": [],
1238
- "overlays": [
1239
- {
1240
- "id": "photo-caption-1",
1241
- "trackId": "text",
1242
- "type": "text",
1243
- "text": "Entry",
1244
- "font": "Hanken Grotesk",
1245
- "size": 11,
1246
- "color": "#F7F0DB",
1247
- "background": "none",
1248
- "backgroundPadding": 0,
1249
- "width": 0.82,
1250
- "x": 50,
1251
- "y": 79,
1252
- "position": "center",
1253
- "start": 0.2,
1254
- "end": 3.4,
1255
- "duration": 3.2,
1256
- "animation": "fade",
1257
- "animIn": 0.25,
1258
- "animOut": 0.2,
1259
- "rotation": 0
1260
- },
1261
- {
1262
- "id": "photo-number-1",
1263
- "trackId": "text",
1264
- "type": "text",
1265
- "text": "01 / 06",
1266
- "font": "Hanken Grotesk",
1267
- "size": 6.5,
1268
- "color": "#CEB88B",
1269
- "background": "none",
1270
- "backgroundPadding": 0,
1271
- "width": 0.82,
1272
- "x": 50,
1273
- "y": 88,
1274
- "position": "center",
1275
- "start": 0,
1276
- "end": 3.49,
1277
- "duration": 3.49,
1278
- "animation": "fade",
1279
- "animIn": 0.25,
1280
- "animOut": 0.2,
1281
- "rotation": 0
1282
- },
1283
- {
1284
- "id": "photo-caption-2",
1285
- "trackId": "text",
1286
- "type": "text",
1287
- "text": "Living area",
1288
- "font": "Hanken Grotesk",
1289
- "size": 11,
1290
- "color": "#F7F0DB",
1291
- "background": "none",
1292
- "backgroundPadding": 0,
1293
- "width": 0.82,
1294
- "x": 50,
1295
- "y": 79,
1296
- "position": "center",
1297
- "start": 3.7,
1298
- "end": 6.7,
1299
- "duration": 3,
1300
- "animation": "fade",
1301
- "animIn": 0.25,
1302
- "animOut": 0.2,
1303
- "rotation": 0
1304
- },
1305
- {
1306
- "id": "photo-number-2",
1307
- "trackId": "text",
1308
- "type": "text",
1309
- "text": "02 / 06",
1310
- "font": "Hanken Grotesk",
1311
- "size": 6.5,
1312
- "color": "#CEB88B",
1313
- "background": "none",
1314
- "backgroundPadding": 0,
1315
- "width": 0.82,
1316
- "x": 50,
1317
- "y": 88,
1318
- "position": "center",
1319
- "start": 3.5,
1320
- "end": 6.79,
1321
- "duration": 3.29,
1322
- "animation": "fade",
1323
- "animIn": 0.25,
1324
- "animOut": 0.2,
1325
- "rotation": 0
1326
- },
1327
- {
1328
- "id": "photo-caption-3",
1329
- "trackId": "text",
1330
- "type": "text",
1331
- "text": "Dining area",
1332
- "font": "Hanken Grotesk",
1333
- "size": 11,
1334
- "color": "#F7F0DB",
1335
- "background": "none",
1336
- "backgroundPadding": 0,
1337
- "width": 0.82,
1338
- "x": 50,
1339
- "y": 79,
1340
- "position": "center",
1341
- "start": 7,
1342
- "end": 10,
1343
- "duration": 3,
1344
- "animation": "fade",
1345
- "animIn": 0.25,
1346
- "animOut": 0.2,
1347
- "rotation": 0
1348
- },
1349
- {
1350
- "id": "photo-number-3",
1351
- "trackId": "text",
1352
- "type": "text",
1353
- "text": "03 / 06",
1354
- "font": "Hanken Grotesk",
1355
- "size": 6.5,
1356
- "color": "#CEB88B",
1357
- "background": "none",
1358
- "backgroundPadding": 0,
1359
- "width": 0.82,
1360
- "x": 50,
1361
- "y": 88,
1362
- "position": "center",
1363
- "start": 6.8,
1364
- "end": 10.09,
1365
- "duration": 3.29,
1366
- "animation": "fade",
1367
- "animIn": 0.25,
1368
- "animOut": 0.2,
1369
- "rotation": 0
1370
- },
1371
- {
1372
- "id": "photo-caption-4",
1373
- "trackId": "text",
1374
- "type": "text",
1375
- "text": "Kitchen",
1376
- "font": "Hanken Grotesk",
1377
- "size": 11,
1378
- "color": "#F7F0DB",
1379
- "background": "none",
1380
- "backgroundPadding": 0,
1381
- "width": 0.82,
1382
- "x": 50,
1383
- "y": 79,
1384
- "position": "center",
1385
- "start": 10.3,
1386
- "end": 13.3,
1387
- "duration": 3,
1388
- "animation": "fade",
1389
- "animIn": 0.25,
1390
- "animOut": 0.2,
1391
- "rotation": 0
1392
- },
1393
- {
1394
- "id": "photo-number-4",
1395
- "trackId": "text",
1396
- "type": "text",
1397
- "text": "04 / 06",
1398
- "font": "Hanken Grotesk",
1399
- "size": 6.5,
1400
- "color": "#CEB88B",
1401
- "background": "none",
1402
- "backgroundPadding": 0,
1403
- "width": 0.82,
1404
- "x": 50,
1405
- "y": 88,
1406
- "position": "center",
1407
- "start": 10.1,
1408
- "end": 13.39,
1409
- "duration": 3.29,
1410
- "animation": "fade",
1411
- "animIn": 0.25,
1412
- "animOut": 0.2,
1413
- "rotation": 0
1414
- },
1415
- {
1416
- "id": "photo-caption-5",
1417
- "trackId": "text",
1418
- "type": "text",
1419
- "text": "Bedroom",
1420
- "font": "Hanken Grotesk",
1421
- "size": 11,
1422
- "color": "#F7F0DB",
1423
- "background": "none",
1424
- "backgroundPadding": 0,
1425
- "width": 0.82,
1426
- "x": 50,
1427
- "y": 79,
1428
- "position": "center",
1429
- "start": 13.6,
1430
- "end": 16.6,
1431
- "duration": 3,
1432
- "animation": "fade",
1433
- "animIn": 0.25,
1434
- "animOut": 0.2,
1435
- "rotation": 0
1436
- },
1437
- {
1438
- "id": "photo-number-5",
1439
- "trackId": "text",
1440
- "type": "text",
1441
- "text": "05 / 06",
1442
- "font": "Hanken Grotesk",
1443
- "size": 6.5,
1444
- "color": "#CEB88B",
1445
- "background": "none",
1446
- "backgroundPadding": 0,
1447
- "width": 0.82,
1448
- "x": 50,
1449
- "y": 88,
1450
- "position": "center",
1451
- "start": 13.4,
1452
- "end": 16.69,
1453
- "duration": 3.29,
1454
- "animation": "fade",
1455
- "animIn": 0.25,
1456
- "animOut": 0.2,
1457
- "rotation": 0
1458
- },
1459
- {
1460
- "id": "photo-caption-6",
1461
- "trackId": "text",
1462
- "type": "text",
1463
- "text": "Detail",
1464
- "font": "Hanken Grotesk",
1465
- "size": 11,
1466
- "color": "#F7F0DB",
1467
- "background": "none",
1468
- "backgroundPadding": 0,
1469
- "width": 0.82,
1470
- "x": 50,
1471
- "y": 79,
1472
- "position": "center",
1473
- "start": 16.9,
1474
- "end": 19.9,
1475
- "duration": 3,
1476
- "animation": "fade",
1477
- "animIn": 0.25,
1478
- "animOut": 0.2,
1479
- "rotation": 0
1480
- },
1481
- {
1482
- "id": "photo-number-6",
1483
- "trackId": "text",
1484
- "type": "text",
1485
- "text": "06 / 06",
1486
- "font": "Hanken Grotesk",
1487
- "size": 6.5,
1488
- "color": "#CEB88B",
1489
- "background": "none",
1490
- "backgroundPadding": 0,
1491
- "width": 0.82,
1492
- "x": 50,
1493
- "y": 88,
1494
- "position": "center",
1495
- "start": 16.7,
1496
- "end": 19.99,
1497
- "duration": 3.29,
1498
- "animation": "fade",
1499
- "animIn": 0.25,
1500
- "animOut": 0.2,
1501
- "rotation": 0
1502
- },
1503
- {
1504
- "id": "opening-title",
1505
- "trackId": "text",
1506
- "type": "text",
1507
- "text": "An interior photo collection",
1508
- "font": "Hanken Grotesk",
1509
- "size": 16,
1510
- "color": "#F7F0DB",
1511
- "background": "none",
1512
- "backgroundPadding": 0,
1513
- "width": 0.82,
1514
- "x": 50,
1515
- "y": 18,
1516
- "position": "center",
1517
- "start": 0,
1518
- "end": 3.4,
1519
- "duration": 3.4,
1520
- "animation": "fade",
1521
- "animIn": 0.25,
1522
- "animOut": 0.2,
1523
- "rotation": 0
1524
- },
1525
- {
1526
- "id": "sequence-title",
1527
- "trackId": "text",
1528
- "type": "text",
1529
- "text": "An interior photo collection",
1530
- "font": "Hanken Grotesk",
1531
- "size": 10,
1532
- "color": "#F7F0DB",
1533
- "background": "none",
1534
- "backgroundPadding": 0,
1535
- "width": 0.82,
1536
- "x": 50,
1537
- "y": 16,
1538
- "position": "center",
1539
- "start": 3.5,
1540
- "end": 20,
1541
- "duration": 16.5,
1542
- "animation": "fade",
1543
- "animIn": 0.25,
1544
- "animOut": 0.2,
1545
- "rotation": 0
1546
- },
1547
- {
1548
- "id": "closing-title",
1549
- "trackId": "text",
1550
- "type": "text",
1551
- "text": "An interior photo collection",
1552
- "font": "Hanken Grotesk",
1553
- "size": 10,
1554
- "color": "#CEB88B",
1555
- "background": "none",
1556
- "backgroundPadding": 0,
1557
- "width": 0.82,
1558
- "x": 50,
1559
- "y": 13,
1560
- "position": "center",
1561
- "start": 20,
1562
- "end": 24,
1563
- "duration": 4,
1564
- "animation": "fade",
1565
- "animIn": 0.25,
1566
- "animOut": 0.2,
1567
- "rotation": 0
1568
- },
1569
- {
1570
- "id": "closing-cta",
1571
- "trackId": "text",
1572
- "type": "text",
1573
- "text": "Ask for the details",
1574
- "font": "Hanken Grotesk",
1575
- "size": 17,
1576
- "color": "#F7F0DB",
1577
- "background": "none",
1578
- "backgroundPadding": 0,
1579
- "width": 0.82,
1580
- "x": 50,
1581
- "y": 65,
1582
- "position": "center",
1583
- "start": 20.1,
1584
- "end": 24,
1585
- "duration": 3.9,
1586
- "animation": "fade",
1587
- "animIn": 0.25,
1588
- "animOut": 0.2,
1589
- "rotation": 0
1590
- },
1591
- {
1592
- "id": "closing-contact",
1593
- "trackId": "text",
1594
- "type": "text",
1595
- "text": "Example contact",
1596
- "font": "Hanken Grotesk",
1597
- "size": 9,
1598
- "color": "#F7F0DB",
1599
- "background": "none",
1600
- "backgroundPadding": 0,
1601
- "width": 0.82,
1602
- "x": 50,
1603
- "y": 79,
1604
- "position": "center",
1605
- "start": 20.25,
1606
- "end": 24,
1607
- "duration": 3.75,
1608
- "animation": "fade",
1609
- "animIn": 0.25,
1610
- "animOut": 0.2,
1611
- "rotation": 0
1612
- },
1613
- {
1614
- "id": "demo-disclosure",
1615
- "trackId": "text",
1616
- "type": "text",
1617
- "text": "Sample only · not a live listing",
1618
- "font": "Hanken Grotesk",
1619
- "size": 6.5,
1620
- "color": "#D4D9D0",
1621
- "background": "none",
1622
- "backgroundPadding": 0,
1623
- "width": 0.84,
1624
- "x": 50,
1625
- "y": 94,
1626
- "position": "center",
1627
- "start": 0,
1628
- "end": 24,
1629
- "duration": 24,
1630
- "animation": "fade",
1631
- "animIn": 0.25,
1632
- "animOut": 0.2,
1633
- "rotation": 0
1634
- }
1635
- ],
1636
- "targetDuration": 24,
1637
- "exportSettings": {
1638
- "aspect": "9:16",
1639
- "fps": 30,
1640
- "resolution": "1080p",
1641
- "quality": "high"
1642
- },
1643
- "photoReel": {
1644
- "schemaVersion": 1,
1645
- "kind": "photo-reel-source-record",
1646
- "block": {
1647
- "id": "stillmade.photo-reel-composer",
1648
- "version": "1.0.0"
1649
- },
1650
- "purpose": "property",
1651
- "sourcePhotos": [
1652
- {
1653
- "index": 0,
1654
- "assetId": "photo-1",
1655
- "versionId": "original-v1",
1656
- "width": 1600,
1657
- "height": 1067
1658
- },
1659
- {
1660
- "index": 1,
1661
- "assetId": "photo-2",
1662
- "versionId": "original-v1",
1663
- "width": 1600,
1664
- "height": 1067
1665
- },
1666
- {
1667
- "index": 2,
1668
- "assetId": "photo-3",
1669
- "versionId": "original-v1",
1670
- "width": 1600,
1671
- "height": 1067
1672
- },
1673
- {
1674
- "index": 3,
1675
- "assetId": "photo-4",
1676
- "versionId": "original-v1",
1677
- "width": 1600,
1678
- "height": 1067
1679
- },
1680
- {
1681
- "index": 4,
1682
- "assetId": "photo-5",
1683
- "versionId": "original-v1",
1684
- "width": 1600,
1685
- "height": 1067
1686
- },
1687
- {
1688
- "index": 5,
1689
- "assetId": "photo-6",
1690
- "versionId": "original-v1",
1691
- "width": 1600,
1692
- "height": 1067
1693
- }
1694
- ],
1695
- "logo": null,
1696
- "music": null,
1697
- "approvedCopy": {
1698
- "title": "An interior photo collection",
1699
- "captions": [
1700
- "Entry",
1701
- "Living area",
1702
- "Dining area",
1703
- "Kitchen",
1704
- "Bedroom",
1705
- "Detail"
1706
- ],
1707
- "cta": "Ask for the details",
1708
- "contact": "Example contact",
1709
- "demoDisclosure": "Sample only · not a live listing"
1710
- },
1711
- "rights": {
1712
- "userConfirmed": true,
1713
- "independentlyVerified": false
1714
- },
1715
- "transformations": [
1716
- "contain fit",
1717
- "uniform scale",
1718
- "at most three percent optical zoom"
1719
- ],
1720
- "generativeMedia": false,
1721
- "providerCalls": 0
1722
- }
1723
- },
1724
- "review": {
1725
- "schemaVersion": 1,
1726
- "state": "needs-human-review",
1727
- "durationSec": 24,
1728
- "aspect": "9:16",
1729
- "photoCount": 6,
1730
- "checks": [
1731
- {
1732
- "id": "original-source-versions",
1733
- "passed": true,
1734
- "note": "Every photo retains its supplied asset/version and full source rectangle."
1735
- },
1736
- {
1737
- "id": "approved-copy-only",
1738
- "passed": true,
1739
- "note": "No property features, prices, availability or product claims are generated."
1740
- },
1741
- {
1742
- "id": "bounded-local-composition",
1743
- "passed": true,
1744
- "note": "No provider call or credit spend occurs in this Block."
1745
- },
1746
- {
1747
- "id": "complete-timing",
1748
- "passed": true,
1749
- "note": "All source photos and a four-second closing card fit the requested duration."
1750
- }
1751
- ],
1752
- "warnings": [
1753
- "Review the full export for photo quality, exact facts, readable copy, licensing and the displayed contact before delivering.",
1754
- "Silent reel. Add rights-cleared music in this Block or the Editor if wanted.",
1755
- "This is labeled demonstration material and is not evidence of a real property or product offer."
1756
- ],
1757
- "humanApproved": false,
1758
- "exportAuthorized": false,
1759
- "cost": {
1760
- "providerCalls": 0,
1761
- "generationCredits": 0,
1762
- "note": "Host storage, export access and any separately added services use their own policy."
1763
- }
1764
- },
1765
- "provenance": {
1766
- "schemaVersion": 1,
1767
- "kind": "photo-reel-source-record",
1768
- "block": {
1769
- "id": "stillmade.photo-reel-composer",
1770
- "version": "1.0.0"
1771
- },
1772
- "purpose": "property",
1773
- "sourcePhotos": [
1774
- {
1775
- "index": 0,
1776
- "assetId": "photo-1",
1777
- "versionId": "original-v1",
1778
- "width": 1600,
1779
- "height": 1067
1780
- },
1781
- {
1782
- "index": 1,
1783
- "assetId": "photo-2",
1784
- "versionId": "original-v1",
1785
- "width": 1600,
1786
- "height": 1067
1787
- },
1788
- {
1789
- "index": 2,
1790
- "assetId": "photo-3",
1791
- "versionId": "original-v1",
1792
- "width": 1600,
1793
- "height": 1067
1794
- },
1795
- {
1796
- "index": 3,
1797
- "assetId": "photo-4",
1798
- "versionId": "original-v1",
1799
- "width": 1600,
1800
- "height": 1067
1801
- },
1802
- {
1803
- "index": 4,
1804
- "assetId": "photo-5",
1805
- "versionId": "original-v1",
1806
- "width": 1600,
1807
- "height": 1067
1808
- },
1809
- {
1810
- "index": 5,
1811
- "assetId": "photo-6",
1812
- "versionId": "original-v1",
1813
- "width": 1600,
1814
- "height": 1067
1815
- }
1816
- ],
1817
- "logo": null,
1818
- "music": null,
1819
- "approvedCopy": {
1820
- "title": "An interior photo collection",
1821
- "captions": [
1822
- "Entry",
1823
- "Living area",
1824
- "Dining area",
1825
- "Kitchen",
1826
- "Bedroom",
1827
- "Detail"
1828
- ],
1829
- "cta": "Ask for the details",
1830
- "contact": "Example contact",
1831
- "demoDisclosure": "Sample only · not a live listing"
1832
- },
1833
- "rights": {
1834
- "userConfirmed": true,
1835
- "independentlyVerified": false
1836
- },
1837
- "transformations": [
1838
- "contain fit",
1839
- "uniform scale",
1840
- "at most three percent optical zoom"
1841
- ],
1842
- "generativeMedia": false,
1843
- "providerCalls": 0
1844
- }
1845
- }
1846
- },
1847
- {
1848
- "name": "Compose a product reel without inventing product claims",
1849
- "input": {
1850
- "assets": [
1851
- {
1852
- "kind": "image",
1853
- "assetId": "photo-1",
1854
- "versionId": "original-v1",
1855
- "url": "https://media.example/photo-1.jpg",
1856
- "width": 1600,
1857
- "height": 1067,
1858
- "name": "Approved photo 1"
1859
- },
1860
- {
1861
- "kind": "image",
1862
- "assetId": "photo-2",
1863
- "versionId": "original-v1",
1864
- "url": "https://media.example/photo-2.jpg",
1865
- "width": 1600,
1866
- "height": 1067,
1867
- "name": "Approved photo 2"
1868
- },
1869
- {
1870
- "kind": "image",
1871
- "assetId": "photo-3",
1872
- "versionId": "original-v1",
1873
- "url": "https://media.example/photo-3.jpg",
1874
- "width": 1600,
1875
- "height": 1067,
1876
- "name": "Approved photo 3"
1877
- },
1878
- {
1879
- "kind": "image",
1880
- "assetId": "photo-4",
1881
- "versionId": "original-v1",
1882
- "url": "https://media.example/photo-4.jpg",
1883
- "width": 1600,
1884
- "height": 1067,
1885
- "name": "Approved photo 4"
1886
- }
1887
- ],
1888
- "purpose": "product",
1889
- "title": "An object in four views",
1890
- "captions": "Front\nSide\nTexture\nDetail",
1891
- "cta": "Explore the collection",
1892
- "contact": "Example contact",
1893
- "demoDisclosure": "Sample only · not a product offer",
1894
- "duration": 24,
1895
- "aspect": "9:16",
1896
- "logo": [],
1897
- "music": [],
1898
- "rightsConfirmed": true
1899
- },
1900
- "expected": {
1901
- "timeline": {
1902
- "schemaVersion": 1,
1903
- "activeTimelineId": "photo-reel",
1904
- "name": "An object in four views",
1905
- "aspect": "9:16",
1906
- "aspectRatio": "9:16",
1907
- "previewH": 369,
1908
- "backgroundColor": "#101714",
1909
- "tracks": [
1910
- {
1911
- "id": "video",
1912
- "type": "video",
1913
- "label": "Original photos"
1914
- },
1915
- {
1916
- "id": "text",
1917
- "type": "text",
1918
- "label": "Approved copy"
1919
- },
1920
- {
1921
- "id": "overlay",
1922
- "type": "overlay",
1923
- "label": "Graphic details"
1924
- },
1925
- {
1926
- "id": "audio",
1927
- "type": "audio",
1928
- "label": "Music"
1929
- }
1930
- ],
1931
- "trackOrder": [
1932
- "video",
1933
- "logo",
1934
- "text",
1935
- "overlay",
1936
- "audio"
1937
- ],
1938
- "clips": [
1939
- {
1940
- "id": "photo-1",
1941
- "kind": "image",
1942
- "trackId": "video",
1943
- "asset": {
1944
- "kind": "image",
1945
- "assetId": "photo-1",
1946
- "versionId": "original-v1",
1947
- "url": "https://media.example/photo-1.jpg",
1948
- "width": 1600,
1949
- "height": 1067,
1950
- "name": "Approved photo 1"
1951
- },
1952
- "assetId": "photo-1",
1953
- "versionId": "original-v1",
1954
- "url": "https://media.example/photo-1.jpg",
1955
- "title": "Approved photo 1",
1956
- "start": 0,
1957
- "duration": 3.5,
1958
- "trimStart": 0,
1959
- "speed": 1,
1960
- "volume": 0,
1961
- "transform": {
1962
- "fit": "contain",
1963
- "scale": 0.8737864077669902,
1964
- "x": 0,
1965
- "y": 0,
1966
- "rotation": 0,
1967
- "opacity": 1
1968
- },
1969
- "motion": {
1970
- "type": "zoom",
1971
- "intensity": 100,
1972
- "zoomAmount": 1.03,
1973
- "zoomDirection": "in",
1974
- "zoomAnchor": "center",
1975
- "easing": "ease-in-out",
1976
- "loop": false,
1977
- "window": [
1978
- 0,
1979
- 100
1980
- ]
1981
- },
1982
- "transition": {
1983
- "type": "Cross dissolve",
1984
- "duration": 0.3
1985
- }
1986
- },
1987
- {
1988
- "id": "photo-2",
1989
- "kind": "image",
1990
- "trackId": "video",
1991
- "asset": {
1992
- "kind": "image",
1993
- "assetId": "photo-2",
1994
- "versionId": "original-v1",
1995
- "url": "https://media.example/photo-2.jpg",
1996
- "width": 1600,
1997
- "height": 1067,
1998
- "name": "Approved photo 2"
1999
- },
2000
- "assetId": "photo-2",
2001
- "versionId": "original-v1",
2002
- "url": "https://media.example/photo-2.jpg",
2003
- "title": "Approved photo 2",
2004
- "start": 3.5,
2005
- "duration": 5.5,
2006
- "trimStart": 0,
2007
- "speed": 1,
2008
- "volume": 0,
2009
- "transform": {
2010
- "fit": "contain",
2011
- "scale": 0.8737864077669902,
2012
- "x": 0,
2013
- "y": 0,
2014
- "rotation": 0,
2015
- "opacity": 1
2016
- },
2017
- "motion": {
2018
- "type": "zoom",
2019
- "intensity": 100,
2020
- "zoomAmount": 1.03,
2021
- "zoomDirection": "out",
2022
- "zoomAnchor": "center",
2023
- "easing": "ease-in-out",
2024
- "loop": false,
2025
- "window": [
2026
- 0,
2027
- 100
2028
- ]
2029
- },
2030
- "transition": {
2031
- "type": "Cross dissolve",
2032
- "duration": 0.3
2033
- }
2034
- },
2035
- {
2036
- "id": "photo-3",
2037
- "kind": "image",
2038
- "trackId": "video",
2039
- "asset": {
2040
- "kind": "image",
2041
- "assetId": "photo-3",
2042
- "versionId": "original-v1",
2043
- "url": "https://media.example/photo-3.jpg",
2044
- "width": 1600,
2045
- "height": 1067,
2046
- "name": "Approved photo 3"
2047
- },
2048
- "assetId": "photo-3",
2049
- "versionId": "original-v1",
2050
- "url": "https://media.example/photo-3.jpg",
2051
- "title": "Approved photo 3",
2052
- "start": 9,
2053
- "duration": 5.5,
2054
- "trimStart": 0,
2055
- "speed": 1,
2056
- "volume": 0,
2057
- "transform": {
2058
- "fit": "contain",
2059
- "scale": 0.8737864077669902,
2060
- "x": 0,
2061
- "y": 0,
2062
- "rotation": 0,
2063
- "opacity": 1
2064
- },
2065
- "motion": {
2066
- "type": "zoom",
2067
- "intensity": 100,
2068
- "zoomAmount": 1.03,
2069
- "zoomDirection": "in",
2070
- "zoomAnchor": "center",
2071
- "easing": "ease-in-out",
2072
- "loop": false,
2073
- "window": [
2074
- 0,
2075
- 100
2076
- ]
2077
- },
2078
- "transition": {
2079
- "type": "Cross dissolve",
2080
- "duration": 0.3
2081
- }
2082
- },
2083
- {
2084
- "id": "photo-4",
2085
- "kind": "image",
2086
- "trackId": "video",
2087
- "asset": {
2088
- "kind": "image",
2089
- "assetId": "photo-4",
2090
- "versionId": "original-v1",
2091
- "url": "https://media.example/photo-4.jpg",
2092
- "width": 1600,
2093
- "height": 1067,
2094
- "name": "Approved photo 4"
2095
- },
2096
- "assetId": "photo-4",
2097
- "versionId": "original-v1",
2098
- "url": "https://media.example/photo-4.jpg",
2099
- "title": "Approved photo 4",
2100
- "start": 14.5,
2101
- "duration": 5.5,
2102
- "trimStart": 0,
2103
- "speed": 1,
2104
- "volume": 0,
2105
- "transform": {
2106
- "fit": "contain",
2107
- "scale": 0.8737864077669902,
2108
- "x": 0,
2109
- "y": 0,
2110
- "rotation": 0,
2111
- "opacity": 1
2112
- },
2113
- "motion": {
2114
- "type": "zoom",
2115
- "intensity": 100,
2116
- "zoomAmount": 1.03,
2117
- "zoomDirection": "out",
2118
- "zoomAnchor": "center",
2119
- "easing": "ease-in-out",
2120
- "loop": false,
2121
- "window": [
2122
- 0,
2123
- 100
2124
- ]
2125
- },
2126
- "transition": {
2127
- "type": "Cross dissolve",
2128
- "duration": 0.3
2129
- }
2130
- },
2131
- {
2132
- "id": "end-card-photo-4",
2133
- "kind": "image",
2134
- "trackId": "video",
2135
- "asset": {
2136
- "kind": "image",
2137
- "assetId": "photo-4",
2138
- "versionId": "original-v1",
2139
- "url": "https://media.example/photo-4.jpg",
2140
- "width": 1600,
2141
- "height": 1067,
2142
- "name": "Approved photo 4"
2143
- },
2144
- "assetId": "photo-4",
2145
- "versionId": "original-v1",
2146
- "url": "https://media.example/photo-4.jpg",
2147
- "title": "Approved photo 4",
2148
- "start": 20,
2149
- "duration": 4,
2150
- "trimStart": 0,
2151
- "speed": 1,
2152
- "volume": 0,
2153
- "transform": {
2154
- "fit": "contain",
2155
- "scale": 0.6213592233009708,
2156
- "x": 0,
2157
- "y": -59.03999999999999,
2158
- "rotation": 0,
2159
- "opacity": 1
2160
- },
2161
- "motion": {
2162
- "type": "none",
2163
- "intensity": 100,
2164
- "zoomAmount": 1.03,
2165
- "zoomDirection": "out",
2166
- "zoomAnchor": "center",
2167
- "easing": "ease-in-out",
2168
- "loop": false,
2169
- "window": [
2170
- 0,
2171
- 100
2172
- ]
2173
- },
2174
- "transition": {
2175
- "type": "Cut",
2176
- "duration": 0.3
2177
- }
2178
- }
2179
- ],
2180
- "audioItems": [],
2181
- "textOverlays": [
2182
- {
2183
- "id": "photo-caption-1",
2184
- "trackId": "text",
2185
- "type": "text",
2186
- "text": "Front",
2187
- "font": "Hanken Grotesk",
2188
- "size": 11,
2189
- "color": "#F7F0DB",
2190
- "background": "none",
2191
- "backgroundPadding": 0,
2192
- "width": 0.82,
2193
- "x": 50,
2194
- "y": 79,
2195
- "position": "center",
2196
- "start": 0.2,
2197
- "end": 3.4,
2198
- "duration": 3.2,
2199
- "animation": "fade",
2200
- "animIn": 0.25,
2201
- "animOut": 0.2,
2202
- "rotation": 0
2203
- },
2204
- {
2205
- "id": "photo-number-1",
2206
- "trackId": "text",
2207
- "type": "text",
2208
- "text": "01 / 04",
2209
- "font": "Hanken Grotesk",
2210
- "size": 6.5,
2211
- "color": "#CEB88B",
2212
- "background": "none",
2213
- "backgroundPadding": 0,
2214
- "width": 0.82,
2215
- "x": 50,
2216
- "y": 88,
2217
- "position": "center",
2218
- "start": 0,
2219
- "end": 3.49,
2220
- "duration": 3.49,
2221
- "animation": "fade",
2222
- "animIn": 0.25,
2223
- "animOut": 0.2,
2224
- "rotation": 0
2225
- },
2226
- {
2227
- "id": "photo-caption-2",
2228
- "trackId": "text",
2229
- "type": "text",
2230
- "text": "Side",
2231
- "font": "Hanken Grotesk",
2232
- "size": 11,
2233
- "color": "#F7F0DB",
2234
- "background": "none",
2235
- "backgroundPadding": 0,
2236
- "width": 0.82,
2237
- "x": 50,
2238
- "y": 79,
2239
- "position": "center",
2240
- "start": 3.7,
2241
- "end": 8.9,
2242
- "duration": 5.2,
2243
- "animation": "fade",
2244
- "animIn": 0.25,
2245
- "animOut": 0.2,
2246
- "rotation": 0
2247
- },
2248
- {
2249
- "id": "photo-number-2",
2250
- "trackId": "text",
2251
- "type": "text",
2252
- "text": "02 / 04",
2253
- "font": "Hanken Grotesk",
2254
- "size": 6.5,
2255
- "color": "#CEB88B",
2256
- "background": "none",
2257
- "backgroundPadding": 0,
2258
- "width": 0.82,
2259
- "x": 50,
2260
- "y": 88,
2261
- "position": "center",
2262
- "start": 3.5,
2263
- "end": 8.99,
2264
- "duration": 5.49,
2265
- "animation": "fade",
2266
- "animIn": 0.25,
2267
- "animOut": 0.2,
2268
- "rotation": 0
2269
- },
2270
- {
2271
- "id": "photo-caption-3",
2272
- "trackId": "text",
2273
- "type": "text",
2274
- "text": "Texture",
2275
- "font": "Hanken Grotesk",
2276
- "size": 11,
2277
- "color": "#F7F0DB",
2278
- "background": "none",
2279
- "backgroundPadding": 0,
2280
- "width": 0.82,
2281
- "x": 50,
2282
- "y": 79,
2283
- "position": "center",
2284
- "start": 9.2,
2285
- "end": 14.4,
2286
- "duration": 5.2,
2287
- "animation": "fade",
2288
- "animIn": 0.25,
2289
- "animOut": 0.2,
2290
- "rotation": 0
2291
- },
2292
- {
2293
- "id": "photo-number-3",
2294
- "trackId": "text",
2295
- "type": "text",
2296
- "text": "03 / 04",
2297
- "font": "Hanken Grotesk",
2298
- "size": 6.5,
2299
- "color": "#CEB88B",
2300
- "background": "none",
2301
- "backgroundPadding": 0,
2302
- "width": 0.82,
2303
- "x": 50,
2304
- "y": 88,
2305
- "position": "center",
2306
- "start": 9,
2307
- "end": 14.49,
2308
- "duration": 5.49,
2309
- "animation": "fade",
2310
- "animIn": 0.25,
2311
- "animOut": 0.2,
2312
- "rotation": 0
2313
- },
2314
- {
2315
- "id": "photo-caption-4",
2316
- "trackId": "text",
2317
- "type": "text",
2318
- "text": "Detail",
2319
- "font": "Hanken Grotesk",
2320
- "size": 11,
2321
- "color": "#F7F0DB",
2322
- "background": "none",
2323
- "backgroundPadding": 0,
2324
- "width": 0.82,
2325
- "x": 50,
2326
- "y": 79,
2327
- "position": "center",
2328
- "start": 14.7,
2329
- "end": 19.9,
2330
- "duration": 5.2,
2331
- "animation": "fade",
2332
- "animIn": 0.25,
2333
- "animOut": 0.2,
2334
- "rotation": 0
2335
- },
2336
- {
2337
- "id": "photo-number-4",
2338
- "trackId": "text",
2339
- "type": "text",
2340
- "text": "04 / 04",
2341
- "font": "Hanken Grotesk",
2342
- "size": 6.5,
2343
- "color": "#CEB88B",
2344
- "background": "none",
2345
- "backgroundPadding": 0,
2346
- "width": 0.82,
2347
- "x": 50,
2348
- "y": 88,
2349
- "position": "center",
2350
- "start": 14.5,
2351
- "end": 19.99,
2352
- "duration": 5.49,
2353
- "animation": "fade",
2354
- "animIn": 0.25,
2355
- "animOut": 0.2,
2356
- "rotation": 0
2357
- },
2358
- {
2359
- "id": "opening-title",
2360
- "trackId": "text",
2361
- "type": "text",
2362
- "text": "An object in four views",
2363
- "font": "Hanken Grotesk",
2364
- "size": 16,
2365
- "color": "#F7F0DB",
2366
- "background": "none",
2367
- "backgroundPadding": 0,
2368
- "width": 0.82,
2369
- "x": 50,
2370
- "y": 18,
2371
- "position": "center",
2372
- "start": 0,
2373
- "end": 3.4,
2374
- "duration": 3.4,
2375
- "animation": "fade",
2376
- "animIn": 0.25,
2377
- "animOut": 0.2,
2378
- "rotation": 0
2379
- },
2380
- {
2381
- "id": "sequence-title",
2382
- "trackId": "text",
2383
- "type": "text",
2384
- "text": "An object in four views",
2385
- "font": "Hanken Grotesk",
2386
- "size": 10,
2387
- "color": "#F7F0DB",
2388
- "background": "none",
2389
- "backgroundPadding": 0,
2390
- "width": 0.82,
2391
- "x": 50,
2392
- "y": 16,
2393
- "position": "center",
2394
- "start": 3.5,
2395
- "end": 20,
2396
- "duration": 16.5,
2397
- "animation": "fade",
2398
- "animIn": 0.25,
2399
- "animOut": 0.2,
2400
- "rotation": 0
2401
- },
2402
- {
2403
- "id": "closing-title",
2404
- "trackId": "text",
2405
- "type": "text",
2406
- "text": "An object in four views",
2407
- "font": "Hanken Grotesk",
2408
- "size": 10,
2409
- "color": "#CEB88B",
2410
- "background": "none",
2411
- "backgroundPadding": 0,
2412
- "width": 0.82,
2413
- "x": 50,
2414
- "y": 13,
2415
- "position": "center",
2416
- "start": 20,
2417
- "end": 24,
2418
- "duration": 4,
2419
- "animation": "fade",
2420
- "animIn": 0.25,
2421
- "animOut": 0.2,
2422
- "rotation": 0
2423
- },
2424
- {
2425
- "id": "closing-cta",
2426
- "trackId": "text",
2427
- "type": "text",
2428
- "text": "Explore the collection",
2429
- "font": "Hanken Grotesk",
2430
- "size": 17,
2431
- "color": "#F7F0DB",
2432
- "background": "none",
2433
- "backgroundPadding": 0,
2434
- "width": 0.82,
2435
- "x": 50,
2436
- "y": 65,
2437
- "position": "center",
2438
- "start": 20.1,
2439
- "end": 24,
2440
- "duration": 3.9,
2441
- "animation": "fade",
2442
- "animIn": 0.25,
2443
- "animOut": 0.2,
2444
- "rotation": 0
2445
- },
2446
- {
2447
- "id": "closing-contact",
2448
- "trackId": "text",
2449
- "type": "text",
2450
- "text": "Example contact",
2451
- "font": "Hanken Grotesk",
2452
- "size": 9,
2453
- "color": "#F7F0DB",
2454
- "background": "none",
2455
- "backgroundPadding": 0,
2456
- "width": 0.82,
2457
- "x": 50,
2458
- "y": 79,
2459
- "position": "center",
2460
- "start": 20.25,
2461
- "end": 24,
2462
- "duration": 3.75,
2463
- "animation": "fade",
2464
- "animIn": 0.25,
2465
- "animOut": 0.2,
2466
- "rotation": 0
2467
- },
2468
- {
2469
- "id": "demo-disclosure",
2470
- "trackId": "text",
2471
- "type": "text",
2472
- "text": "Sample only · not a product offer",
2473
- "font": "Hanken Grotesk",
2474
- "size": 6.5,
2475
- "color": "#D4D9D0",
2476
- "background": "none",
2477
- "backgroundPadding": 0,
2478
- "width": 0.84,
2479
- "x": 50,
2480
- "y": 94,
2481
- "position": "center",
2482
- "start": 0,
2483
- "end": 24,
2484
- "duration": 24,
2485
- "animation": "fade",
2486
- "animIn": 0.25,
2487
- "animOut": 0.2,
2488
- "rotation": 0
2489
- }
2490
- ],
2491
- "captions": [],
2492
- "stickers": [
2493
- {
2494
- "id": "editorial-rule",
2495
- "trackId": "overlay",
2496
- "shape": "underline",
2497
- "color": "#CEB88B",
2498
- "x": 50,
2499
- "y": 25,
2500
- "scale": 0.2,
2501
- "stretchX": 1.1,
2502
- "stretchY": 0.24,
2503
- "opacity": 0.85,
2504
- "rotation": 0,
2505
- "start": 0,
2506
- "end": 20
2507
- },
2508
- {
2509
- "id": "closing-rule",
2510
- "trackId": "overlay",
2511
- "shape": "underline",
2512
- "color": "#CEB88B",
2513
- "x": 50,
2514
- "y": 55,
2515
- "scale": 0.2,
2516
- "stretchX": 1.1,
2517
- "stretchY": 0.24,
2518
- "opacity": 0.85,
2519
- "rotation": 0,
2520
- "start": 20,
2521
- "end": 24
2522
- }
2523
- ],
2524
- "effects": [],
2525
- "audio": [],
2526
- "overlays": [
2527
- {
2528
- "id": "photo-caption-1",
2529
- "trackId": "text",
2530
- "type": "text",
2531
- "text": "Front",
2532
- "font": "Hanken Grotesk",
2533
- "size": 11,
2534
- "color": "#F7F0DB",
2535
- "background": "none",
2536
- "backgroundPadding": 0,
2537
- "width": 0.82,
2538
- "x": 50,
2539
- "y": 79,
2540
- "position": "center",
2541
- "start": 0.2,
2542
- "end": 3.4,
2543
- "duration": 3.2,
2544
- "animation": "fade",
2545
- "animIn": 0.25,
2546
- "animOut": 0.2,
2547
- "rotation": 0
2548
- },
2549
- {
2550
- "id": "photo-number-1",
2551
- "trackId": "text",
2552
- "type": "text",
2553
- "text": "01 / 04",
2554
- "font": "Hanken Grotesk",
2555
- "size": 6.5,
2556
- "color": "#CEB88B",
2557
- "background": "none",
2558
- "backgroundPadding": 0,
2559
- "width": 0.82,
2560
- "x": 50,
2561
- "y": 88,
2562
- "position": "center",
2563
- "start": 0,
2564
- "end": 3.49,
2565
- "duration": 3.49,
2566
- "animation": "fade",
2567
- "animIn": 0.25,
2568
- "animOut": 0.2,
2569
- "rotation": 0
2570
- },
2571
- {
2572
- "id": "photo-caption-2",
2573
- "trackId": "text",
2574
- "type": "text",
2575
- "text": "Side",
2576
- "font": "Hanken Grotesk",
2577
- "size": 11,
2578
- "color": "#F7F0DB",
2579
- "background": "none",
2580
- "backgroundPadding": 0,
2581
- "width": 0.82,
2582
- "x": 50,
2583
- "y": 79,
2584
- "position": "center",
2585
- "start": 3.7,
2586
- "end": 8.9,
2587
- "duration": 5.2,
2588
- "animation": "fade",
2589
- "animIn": 0.25,
2590
- "animOut": 0.2,
2591
- "rotation": 0
2592
- },
2593
- {
2594
- "id": "photo-number-2",
2595
- "trackId": "text",
2596
- "type": "text",
2597
- "text": "02 / 04",
2598
- "font": "Hanken Grotesk",
2599
- "size": 6.5,
2600
- "color": "#CEB88B",
2601
- "background": "none",
2602
- "backgroundPadding": 0,
2603
- "width": 0.82,
2604
- "x": 50,
2605
- "y": 88,
2606
- "position": "center",
2607
- "start": 3.5,
2608
- "end": 8.99,
2609
- "duration": 5.49,
2610
- "animation": "fade",
2611
- "animIn": 0.25,
2612
- "animOut": 0.2,
2613
- "rotation": 0
2614
- },
2615
- {
2616
- "id": "photo-caption-3",
2617
- "trackId": "text",
2618
- "type": "text",
2619
- "text": "Texture",
2620
- "font": "Hanken Grotesk",
2621
- "size": 11,
2622
- "color": "#F7F0DB",
2623
- "background": "none",
2624
- "backgroundPadding": 0,
2625
- "width": 0.82,
2626
- "x": 50,
2627
- "y": 79,
2628
- "position": "center",
2629
- "start": 9.2,
2630
- "end": 14.4,
2631
- "duration": 5.2,
2632
- "animation": "fade",
2633
- "animIn": 0.25,
2634
- "animOut": 0.2,
2635
- "rotation": 0
2636
- },
2637
- {
2638
- "id": "photo-number-3",
2639
- "trackId": "text",
2640
- "type": "text",
2641
- "text": "03 / 04",
2642
- "font": "Hanken Grotesk",
2643
- "size": 6.5,
2644
- "color": "#CEB88B",
2645
- "background": "none",
2646
- "backgroundPadding": 0,
2647
- "width": 0.82,
2648
- "x": 50,
2649
- "y": 88,
2650
- "position": "center",
2651
- "start": 9,
2652
- "end": 14.49,
2653
- "duration": 5.49,
2654
- "animation": "fade",
2655
- "animIn": 0.25,
2656
- "animOut": 0.2,
2657
- "rotation": 0
2658
- },
2659
- {
2660
- "id": "photo-caption-4",
2661
- "trackId": "text",
2662
- "type": "text",
2663
- "text": "Detail",
2664
- "font": "Hanken Grotesk",
2665
- "size": 11,
2666
- "color": "#F7F0DB",
2667
- "background": "none",
2668
- "backgroundPadding": 0,
2669
- "width": 0.82,
2670
- "x": 50,
2671
- "y": 79,
2672
- "position": "center",
2673
- "start": 14.7,
2674
- "end": 19.9,
2675
- "duration": 5.2,
2676
- "animation": "fade",
2677
- "animIn": 0.25,
2678
- "animOut": 0.2,
2679
- "rotation": 0
2680
- },
2681
- {
2682
- "id": "photo-number-4",
2683
- "trackId": "text",
2684
- "type": "text",
2685
- "text": "04 / 04",
2686
- "font": "Hanken Grotesk",
2687
- "size": 6.5,
2688
- "color": "#CEB88B",
2689
- "background": "none",
2690
- "backgroundPadding": 0,
2691
- "width": 0.82,
2692
- "x": 50,
2693
- "y": 88,
2694
- "position": "center",
2695
- "start": 14.5,
2696
- "end": 19.99,
2697
- "duration": 5.49,
2698
- "animation": "fade",
2699
- "animIn": 0.25,
2700
- "animOut": 0.2,
2701
- "rotation": 0
2702
- },
2703
- {
2704
- "id": "opening-title",
2705
- "trackId": "text",
2706
- "type": "text",
2707
- "text": "An object in four views",
2708
- "font": "Hanken Grotesk",
2709
- "size": 16,
2710
- "color": "#F7F0DB",
2711
- "background": "none",
2712
- "backgroundPadding": 0,
2713
- "width": 0.82,
2714
- "x": 50,
2715
- "y": 18,
2716
- "position": "center",
2717
- "start": 0,
2718
- "end": 3.4,
2719
- "duration": 3.4,
2720
- "animation": "fade",
2721
- "animIn": 0.25,
2722
- "animOut": 0.2,
2723
- "rotation": 0
2724
- },
2725
- {
2726
- "id": "sequence-title",
2727
- "trackId": "text",
2728
- "type": "text",
2729
- "text": "An object in four views",
2730
- "font": "Hanken Grotesk",
2731
- "size": 10,
2732
- "color": "#F7F0DB",
2733
- "background": "none",
2734
- "backgroundPadding": 0,
2735
- "width": 0.82,
2736
- "x": 50,
2737
- "y": 16,
2738
- "position": "center",
2739
- "start": 3.5,
2740
- "end": 20,
2741
- "duration": 16.5,
2742
- "animation": "fade",
2743
- "animIn": 0.25,
2744
- "animOut": 0.2,
2745
- "rotation": 0
2746
- },
2747
- {
2748
- "id": "closing-title",
2749
- "trackId": "text",
2750
- "type": "text",
2751
- "text": "An object in four views",
2752
- "font": "Hanken Grotesk",
2753
- "size": 10,
2754
- "color": "#CEB88B",
2755
- "background": "none",
2756
- "backgroundPadding": 0,
2757
- "width": 0.82,
2758
- "x": 50,
2759
- "y": 13,
2760
- "position": "center",
2761
- "start": 20,
2762
- "end": 24,
2763
- "duration": 4,
2764
- "animation": "fade",
2765
- "animIn": 0.25,
2766
- "animOut": 0.2,
2767
- "rotation": 0
2768
- },
2769
- {
2770
- "id": "closing-cta",
2771
- "trackId": "text",
2772
- "type": "text",
2773
- "text": "Explore the collection",
2774
- "font": "Hanken Grotesk",
2775
- "size": 17,
2776
- "color": "#F7F0DB",
2777
- "background": "none",
2778
- "backgroundPadding": 0,
2779
- "width": 0.82,
2780
- "x": 50,
2781
- "y": 65,
2782
- "position": "center",
2783
- "start": 20.1,
2784
- "end": 24,
2785
- "duration": 3.9,
2786
- "animation": "fade",
2787
- "animIn": 0.25,
2788
- "animOut": 0.2,
2789
- "rotation": 0
2790
- },
2791
- {
2792
- "id": "closing-contact",
2793
- "trackId": "text",
2794
- "type": "text",
2795
- "text": "Example contact",
2796
- "font": "Hanken Grotesk",
2797
- "size": 9,
2798
- "color": "#F7F0DB",
2799
- "background": "none",
2800
- "backgroundPadding": 0,
2801
- "width": 0.82,
2802
- "x": 50,
2803
- "y": 79,
2804
- "position": "center",
2805
- "start": 20.25,
2806
- "end": 24,
2807
- "duration": 3.75,
2808
- "animation": "fade",
2809
- "animIn": 0.25,
2810
- "animOut": 0.2,
2811
- "rotation": 0
2812
- },
2813
- {
2814
- "id": "demo-disclosure",
2815
- "trackId": "text",
2816
- "type": "text",
2817
- "text": "Sample only · not a product offer",
2818
- "font": "Hanken Grotesk",
2819
- "size": 6.5,
2820
- "color": "#D4D9D0",
2821
- "background": "none",
2822
- "backgroundPadding": 0,
2823
- "width": 0.84,
2824
- "x": 50,
2825
- "y": 94,
2826
- "position": "center",
2827
- "start": 0,
2828
- "end": 24,
2829
- "duration": 24,
2830
- "animation": "fade",
2831
- "animIn": 0.25,
2832
- "animOut": 0.2,
2833
- "rotation": 0
2834
- }
2835
- ],
2836
- "targetDuration": 24,
2837
- "exportSettings": {
2838
- "aspect": "9:16",
2839
- "fps": 30,
2840
- "resolution": "1080p",
2841
- "quality": "high"
2842
- },
2843
- "photoReel": {
2844
- "schemaVersion": 1,
2845
- "kind": "photo-reel-source-record",
2846
- "block": {
2847
- "id": "stillmade.photo-reel-composer",
2848
- "version": "1.0.0"
2849
- },
2850
- "purpose": "product",
2851
- "sourcePhotos": [
2852
- {
2853
- "index": 0,
2854
- "assetId": "photo-1",
2855
- "versionId": "original-v1",
2856
- "width": 1600,
2857
- "height": 1067
2858
- },
2859
- {
2860
- "index": 1,
2861
- "assetId": "photo-2",
2862
- "versionId": "original-v1",
2863
- "width": 1600,
2864
- "height": 1067
2865
- },
2866
- {
2867
- "index": 2,
2868
- "assetId": "photo-3",
2869
- "versionId": "original-v1",
2870
- "width": 1600,
2871
- "height": 1067
2872
- },
2873
- {
2874
- "index": 3,
2875
- "assetId": "photo-4",
2876
- "versionId": "original-v1",
2877
- "width": 1600,
2878
- "height": 1067
2879
- }
2880
- ],
2881
- "logo": null,
2882
- "music": null,
2883
- "approvedCopy": {
2884
- "title": "An object in four views",
2885
- "captions": [
2886
- "Front",
2887
- "Side",
2888
- "Texture",
2889
- "Detail"
2890
- ],
2891
- "cta": "Explore the collection",
2892
- "contact": "Example contact",
2893
- "demoDisclosure": "Sample only · not a product offer"
2894
- },
2895
- "rights": {
2896
- "userConfirmed": true,
2897
- "independentlyVerified": false
2898
- },
2899
- "transformations": [
2900
- "contain fit",
2901
- "uniform scale",
2902
- "at most three percent optical zoom"
2903
- ],
2904
- "generativeMedia": false,
2905
- "providerCalls": 0
2906
- }
2907
- },
2908
- "review": {
2909
- "schemaVersion": 1,
2910
- "state": "needs-human-review",
2911
- "durationSec": 24,
2912
- "aspect": "9:16",
2913
- "photoCount": 4,
2914
- "checks": [
2915
- {
2916
- "id": "original-source-versions",
2917
- "passed": true,
2918
- "note": "Every photo retains its supplied asset/version and full source rectangle."
2919
- },
2920
- {
2921
- "id": "approved-copy-only",
2922
- "passed": true,
2923
- "note": "No property features, prices, availability or product claims are generated."
2924
- },
2925
- {
2926
- "id": "bounded-local-composition",
2927
- "passed": true,
2928
- "note": "No provider call or credit spend occurs in this Block."
2929
- },
2930
- {
2931
- "id": "complete-timing",
2932
- "passed": true,
2933
- "note": "All source photos and a four-second closing card fit the requested duration."
2934
- }
2935
- ],
2936
- "warnings": [
2937
- "Review the full export for photo quality, exact facts, readable copy, licensing and the displayed contact before delivering.",
2938
- "Silent reel. Add rights-cleared music in this Block or the Editor if wanted.",
2939
- "This is labeled demonstration material and is not evidence of a real property or product offer."
2940
- ],
2941
- "humanApproved": false,
2942
- "exportAuthorized": false,
2943
- "cost": {
2944
- "providerCalls": 0,
2945
- "generationCredits": 0,
2946
- "note": "Host storage, export access and any separately added services use their own policy."
2947
- }
2948
- },
2949
- "provenance": {
2950
- "schemaVersion": 1,
2951
- "kind": "photo-reel-source-record",
2952
- "block": {
2953
- "id": "stillmade.photo-reel-composer",
2954
- "version": "1.0.0"
2955
- },
2956
- "purpose": "product",
2957
- "sourcePhotos": [
2958
- {
2959
- "index": 0,
2960
- "assetId": "photo-1",
2961
- "versionId": "original-v1",
2962
- "width": 1600,
2963
- "height": 1067
2964
- },
2965
- {
2966
- "index": 1,
2967
- "assetId": "photo-2",
2968
- "versionId": "original-v1",
2969
- "width": 1600,
2970
- "height": 1067
2971
- },
2972
- {
2973
- "index": 2,
2974
- "assetId": "photo-3",
2975
- "versionId": "original-v1",
2976
- "width": 1600,
2977
- "height": 1067
2978
- },
2979
- {
2980
- "index": 3,
2981
- "assetId": "photo-4",
2982
- "versionId": "original-v1",
2983
- "width": 1600,
2984
- "height": 1067
2985
- }
2986
- ],
2987
- "logo": null,
2988
- "music": null,
2989
- "approvedCopy": {
2990
- "title": "An object in four views",
2991
- "captions": [
2992
- "Front",
2993
- "Side",
2994
- "Texture",
2995
- "Detail"
2996
- ],
2997
- "cta": "Explore the collection",
2998
- "contact": "Example contact",
2999
- "demoDisclosure": "Sample only · not a product offer"
3000
- },
3001
- "rights": {
3002
- "userConfirmed": true,
3003
- "independentlyVerified": false
3004
- },
3005
- "transformations": [
3006
- "contain fit",
3007
- "uniform scale",
3008
- "at most three percent optical zoom"
3009
- ],
3010
- "generativeMedia": false,
3011
- "providerCalls": 0
3012
- }
3013
- }
3014
- }
3015
- ],
3016
- "portable": {
3017
- "format": "stillmade-block/1",
3018
- "dependencies": [],
3019
- "sources": [
3020
- {
3021
- "kind": "original",
3022
- "license": "MIT",
3023
- "paths": [
3024
- "LICENSE",
3025
- "src/run.js"
3026
- ],
3027
- "evidence": [
3028
- "upstream/0/LICENSE",
3029
- "upstream/0/src/run.js"
3030
- ],
3031
- "changes": "Original implementation declared by the packager; no reused repository or dependency code."
3032
- }
3033
- ],
3034
- "files": {
3035
- "upstream/0/LICENSE": "MIT License\n\nCopyright (c) <year> <copyright holders>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and \nassociated documentation files (the \"Software\"), to deal in the Software without restriction, including \nwithout limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell \ncopies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the \nfollowing conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial \nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT \nLIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO \nEVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER \nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE \nUSE OR OTHER DEALINGS IN THE SOFTWARE.\n",
3036
- "upstream/0/src/run.js": "// Photo Reel Composer 1.0.0. Runs only inside the isolated SDK JavaScript runtime.\n// References and supplied copy are data; this Block never reads media bytes,\n// calls a model, changes a photo, authorizes an export, or verifies legal rights.\nconst clone = value => JSON.parse(JSON.stringify(value));\nconst fail = (ok, message) => { if (!ok) throw new Error(message); };\nconst clean = (value, label, maximum, required = false) => {\n fail(value === undefined || typeof value === 'string', label + ' must be text.');\n const text = (value || '').trim();\n fail((!required || text.length > 0) && text.length <= maximum, label + ' must contain ' + (required ? '1' : '0') + ' to ' + maximum + ' characters.');\n fail(!/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]/.test(text), label + ' contains unsupported control characters.');\n fail(text.split(/\\s+/).every(word => word.length <= 28), label + ' contains a word or link too long to fit. Use a shorter display label.');\n return text;\n};\nconst purpose = input.purpose || 'property';\nfail(['property', 'product'].includes(purpose), 'Choose property or product.');\nconst assets = input.assets;\nconst minimum = purpose === 'property' ? 6 : 3;\nconst maximum = purpose === 'property' ? 8 : 10;\nfail(Array.isArray(assets) && assets.length >= minimum && assets.length <= maximum, 'Choose ' + minimum + ' to ' + maximum + ' original photos, in the order they should appear.');\nconst validMedia = (asset, kind, label) => {\n fail(asset && typeof asset === 'object' && !Array.isArray(asset) && asset.kind === kind, label + ' must be a ' + kind + ' reference.');\n fail(typeof asset.assetId === 'string' && asset.assetId.length > 0 && asset.assetId.length <= 240 && typeof asset.versionId === 'string' && asset.versionId.length > 0 && asset.versionId.length <= 240, label + ' needs its exact asset and version identities.');\n const mediaUrl = asset.url;\n const supportedUrl = typeof mediaUrl === 'string' && mediaUrl.length > 0 && mediaUrl.length <= 200000 && (\n /^\\/api\\/media\\/[A-Za-z0-9_-]+\\/[A-Za-z0-9_-][A-Za-z0-9._-]*$/.test(mediaUrl) ||\n /^(https:\\/\\/|http:\\/\\/(127\\.0\\.0\\.1|localhost)(:\\d+)?\\/|data:(image\\/(png|jpeg|webp)|audio\\/[a-z0-9.+-]+);base64,|blob:|sm-media:)/i.test(mediaUrl)\n ) && !/^https?:\\/\\/[^/?#]*@/i.test(mediaUrl);\n fail(supportedUrl, label + ' needs an authorized media reference.');\n if (kind === 'image') fail(Number.isFinite(asset.width) && asset.width > 0 && asset.width <= 40000 && Number.isFinite(asset.height) && asset.height > 0 && asset.height <= 40000, label + ' needs its measured original width and height. Upload this original photo again to record its dimensions.');\n return clone(asset);\n};\nconst photos = assets.map((asset, index) => validMedia(asset, 'image', 'Photo ' + (index + 1)));\nfail(new Set(photos.map(asset => asset.assetId + '\\n' + asset.versionId)).size === photos.length, 'Remove duplicate photo versions before composing.');\nconst title = clean(input.title, 'Approved title', 64, true);\nconst cta = clean(input.cta, 'Approved call to action', 56, true);\nconst contact = clean(input.contact, 'Contact or destination', 64);\nconst demoDisclosure = clean(input.demoDisclosure, 'Demo disclosure', 72);\nconst captionsText = input.captions || '';\nfail(typeof captionsText === 'string' && captionsText.length <= 1600, 'Use one short approved caption per photo.');\nconst captions = captionsText.trim() ? captionsText.replace(/\\r/g, '').split('\\n').map((line, index) => clean(line, 'Photo caption ' + (index + 1), 64)) : [];\nfail(captions.length === 0 || captions.length === photos.length, 'Supply exactly one caption line per photo, or leave captions empty. Blank lines keep a photo uncaptioned.');\nfail(input.rightsConfirmed === true, 'Confirm that you may use these photos, logo, music and exact supplied statements before building.');\nconst duration = input.duration === undefined ? 24 : input.duration;\nfail(Number.isFinite(duration) && duration >= 20 && duration <= 30, 'Choose a duration from 20 to 30 seconds.');\nconst aspect = input.aspect || '9:16';\nfail(['9:16', '16:9', '1:1'].includes(aspect), 'Choose 9:16, 16:9 or 1:1.');\nconst extra = (value, kind, label) => {\n fail(value === undefined || Array.isArray(value) && value.length <= 1, 'Choose at most one ' + label + '.');\n return value && value.length ? validMedia(value[0], kind, label) : null;\n};\nconst logo = extra(input.logo, 'image', 'logo');\nconst music = extra(input.music, 'audio', 'music track');\nif (music) fail(Number.isFinite(music.duration) && music.duration >= duration, 'The music track must have a measured duration covering the complete reel. Upload a supported MP3 or WAV again to record its duration, choose a longer track, or omit music.');\nconst [aw, ah] = aspect.split(':').map(Number);\nconst frameWidth = aw / ah * 369;\nconst portrait = aspect === '9:16';\nconst square = aspect === '1:1';\nconst backgroundColor = '#101714';\nconst foreground = '#F7F0DB';\nconst accent = '#CEB88B';\nconst overlays = [];\nconst clips = [];\nconst stickers = [];\nconst round = value => Math.round(value * 1000000) / 1000000;\nconst text = (id, value, start, end, y, size, color = foreground, width = .82) => {\n if (!value) return;\n // The shared renderer wraps between words only. Conservatively shrink a\n // single unusually long unbroken word; ordinary short-copy layouts stay put.\n const longest = Math.max(...value.split(/\\s+/).map(word => word.length));\n if (longest > 18) size = Math.min(size, (frameWidth * width - 12) / longest);\n overlays.push({ id, trackId: 'text', type: 'text', text: value, font: 'Hanken Grotesk', size, color, background: 'none', backgroundPadding: 0, width, x: 50, y, position: 'center', start: round(start), end: round(end), duration: round(end - start), animation: 'fade', animIn: .25, animOut: .2, rotation: 0 });\n};\nconst introEnd = 3.5;\nconst cardStart = duration - 4;\nconst sceneDuration = (cardStart - introEnd) / (photos.length - 1);\n// Fit the FULL measured photo inside a reserved rectangle, then add at most 3%\n// optical zoom. No crop, stretching, retouching, or synthetic pixels are requested.\nconst photoClip = (asset, index, start, length, endCard = false) => {\n const rawFit = Math.min(frameWidth / asset.width, 369 / asset.height);\n const fittedWidth = asset.width * rawFit;\n const fittedHeight = asset.height * rawFit;\n const regionWidth = frameWidth * (endCard ? .64 : .9);\n const regionHeight = 369 * (endCard ? .31 : portrait ? .48 : square ? .48 : .49);\n const scale = Math.min(regionWidth / fittedWidth, regionHeight / fittedHeight) / 1.03;\n const center = endCard ? .34 : .5;\n return {\n id: (endCard ? 'end-card-photo-' : 'photo-') + (index + 1), kind: 'image', trackId: 'video',\n asset: clone(asset), assetId: asset.assetId, versionId: asset.versionId, url: asset.url,\n title: asset.name || 'Photo ' + (index + 1), start: round(start), duration: round(length), trimStart: 0, speed: 1, volume: 0,\n transform: { fit: 'contain', scale, x: 0, y: (center - .5) * 369, rotation: 0, opacity: 1 },\n motion: { type: endCard ? 'none' : 'zoom', intensity: 100, zoomAmount: 1.03, zoomDirection: index % 2 ? 'out' : 'in', zoomAnchor: 'center', easing: 'ease-in-out', loop: false, ['window']: [0, 100] },\n transition: { type: endCard ? 'Cut' : 'Cross dissolve', duration: .3 },\n };\n};\nphotos.forEach((asset, index) => {\n const start = index === 0 ? 0 : introEnd + (index - 1) * sceneDuration;\n const end = index === 0 ? introEnd : index === photos.length - 1 ? cardStart : introEnd + index * sceneDuration;\n clips.push(photoClip(asset, index, start, end - start));\n text('photo-caption-' + (index + 1), captions[index], start + .2, end - .1, 79, portrait ? 11 : 14);\n text('photo-number-' + (index + 1), String(index + 1).padStart(2, '0') + ' / ' + String(photos.length).padStart(2, '0'), start, end - .01, 88, portrait ? 6.5 : 8, accent);\n});\nclips.push(photoClip(photos.at(-1), photos.length - 1, cardStart, 4, true));\n// The opening and closing compositions share an editorial rhythm while the\n// photographs remain full, unaltered, independently editable timeline items.\ntext('opening-title', title, 0, introEnd - .1, 18, portrait ? 16 : 22);\ntext('sequence-title', title, introEnd, cardStart, 16, portrait ? 10 : 14, foreground);\ntext('closing-title', title, cardStart, duration, 13, portrait ? 10 : 14, accent);\ntext('closing-cta', cta, cardStart + .1, duration, 65, portrait ? 17 : 23);\ntext('closing-contact', contact, cardStart + .25, duration, 79, portrait ? 9 : 12);\ntext('demo-disclosure', demoDisclosure, 0, duration, 94, portrait ? 6.5 : 8, '#D4D9D0', .84);\nstickers.push({ id: 'editorial-rule', trackId: 'overlay', shape: 'underline', color: accent, x: 50, y: 25, scale: .2, stretchX: 1.1, stretchY: .24, opacity: .85, rotation: 0, start: 0, end: cardStart });\nstickers.push({ id: 'closing-rule', trackId: 'overlay', shape: 'underline', color: accent, x: 50, y: 55, scale: .2, stretchX: 1.1, stretchY: .24, opacity: .85, rotation: 0, start: cardStart, end: duration });\nif (logo) {\n // Use an ordinary image clip on its own upper track. This avoids the GIF\n // sticker renderer's minimum-height distortion for unusually wide wordmarks.\n const fitted = Math.min(frameWidth / logo.width, 369 / logo.height);\n const scale = Math.min(frameWidth * .2 / (logo.width * fitted), 369 * .06 / (logo.height * fitted));\n clips.push({ id: 'brand-logo', kind: 'image', trackId: 'logo', asset: clone(logo), assetId: logo.assetId, versionId: logo.versionId, url: logo.url, start: cardStart, duration: 4, trimStart: 0, speed: 1, volume: 0, transform: { fit: 'contain', scale, x: 0, y: 369 * .39, rotation: 0, opacity: 1 }, motion: { type: 'none' }, transition: { type: 'Cut', duration: 0 } });\n}\nconst audioItems = music ? [{ id: 'music', trackId: 'audio', asset: clone(music), assetId: music.assetId, versionId: music.versionId, url: music.url, start: 0, duration, trimStart: 0, sourceOffset: 0, speed: 1, volume: 35, fadeIn: .5, fadeOut: .8 }] : [];\nconst provenance = {\n schemaVersion: 1, kind: 'photo-reel-source-record', block: { id: 'stillmade.photo-reel-composer', version: '1.0.0' }, purpose,\n sourcePhotos: photos.map((asset, index) => ({ index, assetId: asset.assetId, versionId: asset.versionId, width: asset.width, height: asset.height })),\n logo: logo ? { assetId: logo.assetId, versionId: logo.versionId } : null,\n music: music ? { assetId: music.assetId, versionId: music.versionId } : null,\n approvedCopy: { title, captions, cta, contact, demoDisclosure },\n rights: { userConfirmed: true, independentlyVerified: false },\n transformations: ['contain fit', 'uniform scale', 'at most three percent optical zoom'],\n generativeMedia: false, providerCalls: 0,\n};\nconst timeline = {\n schemaVersion: 1, activeTimelineId: 'photo-reel', name: title, aspect, aspectRatio: aspect, previewH: 369, backgroundColor,\n tracks: [{ id: 'video', type: 'video', label: 'Original photos' }, ...(logo ? [{ id: 'logo', type: 'video', label: 'Original logo' }] : []), { id: 'text', type: 'text', label: 'Approved copy' }, { id: 'overlay', type: 'overlay', label: 'Graphic details' }, { id: 'audio', type: 'audio', label: 'Music' }],\n trackOrder: ['video', 'logo', 'text', 'overlay', 'audio'], clips, audioItems, textOverlays: overlays, captions: [], stickers, effects: [],\n // The device renderer consumes these legacy aliases; Editor keeps the normal\n // editable lanes above. Both refer to the same content at creation time.\n audio: clone(audioItems), overlays: clone(overlays), targetDuration: duration,\n exportSettings: { aspect, fps: 30, resolution: '1080p', quality: 'high' },\n photoReel: clone(provenance),\n};\nconst lowResolution = photos.filter(asset => asset.width < 1080 || asset.height < 720).map(asset => asset.assetId);\nreturn {\n timeline,\n review: {\n schemaVersion: 1, state: 'needs-human-review', durationSec: duration, aspect, photoCount: photos.length,\n checks: [\n { id: 'original-source-versions', passed: true, note: 'Every photo retains its supplied asset/version and full source rectangle.' },\n { id: 'approved-copy-only', passed: true, note: 'No property features, prices, availability or product claims are generated.' },\n { id: 'bounded-local-composition', passed: true, note: 'No provider call or credit spend occurs in this Block.' },\n { id: 'complete-timing', passed: true, note: 'All source photos and a four-second closing card fit the requested duration.' },\n ],\n warnings: [\n 'Review the full export for photo quality, exact facts, readable copy, licensing and the displayed contact before delivering.',\n ...(!music ? ['Silent reel. Add rights-cleared music in this Block or the Editor if wanted.'] : []),\n ...(lowResolution.length ? ['Small source images may look soft in a 1080p export: ' + lowResolution.join(', ')] : []),\n ...(demoDisclosure ? ['This is labeled demonstration material and is not evidence of a real property or product offer.'] : []),\n ],\n humanApproved: false, exportAuthorized: false, cost: { providerCalls: 0, generationCredits: 0, note: 'Host storage, export access and any separately added services use their own policy.' },\n },\n provenance,\n};\n"
3037
- },
3038
- "lineage": {
3039
- "parents": [],
3040
- "changes": "Packaged original Block source for StillMade."
3041
- }
3042
- }
3043
- };