frameyard 0.8.0 → 0.10.0

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 (327) hide show
  1. package/CHANGELOG.md +177 -14
  2. package/GLOSSARY.md +112 -2
  3. package/README.md +302 -265
  4. package/dist/assets/integrations.d.ts +8 -4
  5. package/dist/assets/integrations.d.ts.map +1 -1
  6. package/dist/assets/integrations.js +8 -4
  7. package/dist/assets/integrations.js.map +1 -1
  8. package/dist/assets/provenance.d.ts +2 -2
  9. package/dist/assets/provenance.d.ts.map +1 -1
  10. package/dist/assets/provenance.js +5 -3
  11. package/dist/assets/provenance.js.map +1 -1
  12. package/dist/assets/tts-supertonic.d.ts +28 -0
  13. package/dist/assets/tts-supertonic.d.ts.map +1 -0
  14. package/dist/assets/tts-supertonic.js +156 -0
  15. package/dist/assets/tts-supertonic.js.map +1 -0
  16. package/dist/assets/tts.d.ts +18 -6
  17. package/dist/assets/tts.d.ts.map +1 -1
  18. package/dist/assets/tts.js +219 -97
  19. package/dist/assets/tts.js.map +1 -1
  20. package/dist/cli.js +1685 -93
  21. package/dist/cli.js.map +1 -1
  22. package/dist/composition/format.d.ts +1 -1
  23. package/dist/composition/format.d.ts.map +1 -1
  24. package/dist/composition/format.js +1 -1
  25. package/dist/composition/format.js.map +1 -1
  26. package/dist/context.d.ts +82 -0
  27. package/dist/context.d.ts.map +1 -0
  28. package/dist/context.js +277 -0
  29. package/dist/context.js.map +1 -0
  30. package/dist/contracts.d.ts +25 -0
  31. package/dist/contracts.d.ts.map +1 -1
  32. package/dist/contracts.js.map +1 -1
  33. package/dist/doctor.d.ts +14 -1
  34. package/dist/doctor.d.ts.map +1 -1
  35. package/dist/doctor.js +166 -7
  36. package/dist/doctor.js.map +1 -1
  37. package/dist/errors.d.ts +1 -1
  38. package/dist/errors.d.ts.map +1 -1
  39. package/dist/errors.js.map +1 -1
  40. package/dist/fonts/add.d.ts +41 -0
  41. package/dist/fonts/add.d.ts.map +1 -0
  42. package/dist/fonts/add.js +259 -0
  43. package/dist/fonts/add.js.map +1 -0
  44. package/dist/fonts/binary.d.ts +4 -0
  45. package/dist/fonts/binary.d.ts.map +1 -0
  46. package/dist/fonts/binary.js +21 -0
  47. package/dist/fonts/binary.js.map +1 -0
  48. package/dist/fonts/css.d.ts +4 -0
  49. package/dist/fonts/css.d.ts.map +1 -0
  50. package/dist/fonts/css.js +50 -0
  51. package/dist/fonts/css.js.map +1 -0
  52. package/dist/fonts/fontsource.d.ts +107 -0
  53. package/dist/fonts/fontsource.d.ts.map +1 -0
  54. package/dist/fonts/fontsource.js +565 -0
  55. package/dist/fonts/fontsource.js.map +1 -0
  56. package/dist/fonts/index.d.ts +11 -0
  57. package/dist/fonts/index.d.ts.map +1 -0
  58. package/dist/fonts/index.js +11 -0
  59. package/dist/fonts/index.js.map +1 -0
  60. package/dist/fonts/install.d.ts +24 -0
  61. package/dist/fonts/install.d.ts.map +1 -0
  62. package/dist/fonts/install.js +145 -0
  63. package/dist/fonts/install.js.map +1 -0
  64. package/dist/fonts/manifest.d.ts +21 -0
  65. package/dist/fonts/manifest.d.ts.map +1 -0
  66. package/dist/fonts/manifest.js +96 -0
  67. package/dist/fonts/manifest.js.map +1 -0
  68. package/dist/fonts/options.d.ts +9 -0
  69. package/dist/fonts/options.d.ts.map +1 -0
  70. package/dist/fonts/options.js +66 -0
  71. package/dist/fonts/options.js.map +1 -0
  72. package/dist/fonts/schema.d.ts +4 -0
  73. package/dist/fonts/schema.d.ts.map +1 -0
  74. package/dist/fonts/schema.js +316 -0
  75. package/dist/fonts/schema.js.map +1 -0
  76. package/dist/fonts/summary.d.ts +16 -0
  77. package/dist/fonts/summary.d.ts.map +1 -0
  78. package/dist/fonts/summary.js +22 -0
  79. package/dist/fonts/summary.js.map +1 -0
  80. package/dist/fonts/types.d.ts +56 -0
  81. package/dist/fonts/types.d.ts.map +1 -0
  82. package/dist/fonts/types.js +8 -0
  83. package/dist/fonts/types.js.map +1 -0
  84. package/dist/fonts/verify.d.ts +33 -0
  85. package/dist/fonts/verify.d.ts.map +1 -0
  86. package/dist/fonts/verify.js +200 -0
  87. package/dist/fonts/verify.js.map +1 -0
  88. package/dist/html/validate.d.ts.map +1 -1
  89. package/dist/html/validate.js +59 -0
  90. package/dist/html/validate.js.map +1 -1
  91. package/dist/index.d.ts +3 -3
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +1 -1
  94. package/dist/index.js.map +1 -1
  95. package/dist/inspect.d.ts +61 -0
  96. package/dist/inspect.d.ts.map +1 -0
  97. package/dist/inspect.js +325 -0
  98. package/dist/inspect.js.map +1 -0
  99. package/dist/lint.d.ts +63 -0
  100. package/dist/lint.d.ts.map +1 -0
  101. package/dist/lint.js +265 -0
  102. package/dist/lint.js.map +1 -0
  103. package/dist/policy.d.ts +69 -0
  104. package/dist/policy.d.ts.map +1 -0
  105. package/dist/policy.js +361 -0
  106. package/dist/policy.js.map +1 -0
  107. package/dist/preview/fonts/LICENSE-figtree.txt +93 -0
  108. package/dist/preview/fonts/LICENSE-space-mono.txt +93 -0
  109. package/dist/preview/fonts/README.md +23 -0
  110. package/dist/preview/fonts/figtree-latin-wght-normal.woff2 +0 -0
  111. package/dist/preview/fonts/space-mono-latin-400-normal.woff2 +0 -0
  112. package/dist/preview/fonts/space-mono-latin-700-normal.woff2 +0 -0
  113. package/dist/preview/main.js +5 -2
  114. package/dist/preview/main.js.map +1 -1
  115. package/dist/preview/timeline-data.d.ts +17 -69
  116. package/dist/preview/timeline-data.d.ts.map +1 -1
  117. package/dist/preview/timeline-host.d.ts.map +1 -1
  118. package/dist/preview/timeline-host.js +70 -45
  119. package/dist/preview/timeline-host.js.map +1 -1
  120. package/dist/preview/timeline-main.d.ts.map +1 -1
  121. package/dist/preview/timeline-main.js +88 -27
  122. package/dist/preview/timeline-main.js.map +1 -1
  123. package/dist/project.d.ts +10 -3
  124. package/dist/project.d.ts.map +1 -1
  125. package/dist/project.js +20 -17
  126. package/dist/project.js.map +1 -1
  127. package/dist/renderer/audio.d.ts +6 -0
  128. package/dist/renderer/audio.d.ts.map +1 -1
  129. package/dist/renderer/audio.js +3 -1
  130. package/dist/renderer/audio.js.map +1 -1
  131. package/dist/renderer/browser.d.ts.map +1 -1
  132. package/dist/renderer/browser.js +13 -0
  133. package/dist/renderer/browser.js.map +1 -1
  134. package/dist/renderer/concurrency.d.ts +6 -0
  135. package/dist/renderer/concurrency.d.ts.map +1 -0
  136. package/dist/renderer/concurrency.js +27 -0
  137. package/dist/renderer/concurrency.js.map +1 -0
  138. package/dist/renderer/ffmpeg.d.ts +104 -5
  139. package/dist/renderer/ffmpeg.d.ts.map +1 -1
  140. package/dist/renderer/ffmpeg.js +580 -67
  141. package/dist/renderer/ffmpeg.js.map +1 -1
  142. package/dist/renderer/index.js +1 -1
  143. package/dist/renderer/index.js.map +1 -1
  144. package/dist/renderer/keyframe-expressions.d.ts +39 -0
  145. package/dist/renderer/keyframe-expressions.d.ts.map +1 -0
  146. package/dist/renderer/keyframe-expressions.js +180 -0
  147. package/dist/renderer/keyframe-expressions.js.map +1 -0
  148. package/dist/renderer/session-pool.d.ts +28 -0
  149. package/dist/renderer/session-pool.d.ts.map +1 -0
  150. package/dist/renderer/session-pool.js +91 -0
  151. package/dist/renderer/session-pool.js.map +1 -0
  152. package/dist/renderer/timeline.d.ts +2 -0
  153. package/dist/renderer/timeline.d.ts.map +1 -1
  154. package/dist/renderer/timeline.js +600 -147
  155. package/dist/renderer/timeline.js.map +1 -1
  156. package/dist/renderer/timings.d.ts +13 -0
  157. package/dist/renderer/timings.d.ts.map +1 -0
  158. package/dist/renderer/timings.js +29 -0
  159. package/dist/renderer/timings.js.map +1 -0
  160. package/dist/runtime/host.d.ts.map +1 -1
  161. package/dist/runtime/host.js +4 -0
  162. package/dist/runtime/host.js.map +1 -1
  163. package/dist/scaffold.d.ts +3 -0
  164. package/dist/scaffold.d.ts.map +1 -1
  165. package/dist/scaffold.js +48 -320
  166. package/dist/scaffold.js.map +1 -1
  167. package/dist/server/composition-html.d.ts +2 -0
  168. package/dist/server/composition-html.d.ts.map +1 -1
  169. package/dist/server/composition-html.js +7 -0
  170. package/dist/server/composition-html.js.map +1 -1
  171. package/dist/server/preview-html.d.ts.map +1 -1
  172. package/dist/server/preview-html.js +74 -188
  173. package/dist/server/preview-html.js.map +1 -1
  174. package/dist/server/preview-style.d.ts +11 -0
  175. package/dist/server/preview-style.d.ts.map +1 -0
  176. package/dist/server/preview-style.js +298 -0
  177. package/dist/server/preview-style.js.map +1 -0
  178. package/dist/server/server.d.ts.map +1 -1
  179. package/dist/server/server.js +31 -1
  180. package/dist/server/server.js.map +1 -1
  181. package/dist/server/timeline-preview-data.d.ts.map +1 -1
  182. package/dist/server/timeline-preview-data.js +12 -34
  183. package/dist/server/timeline-preview-data.js.map +1 -1
  184. package/dist/server/timeline-preview-html.d.ts.map +1 -1
  185. package/dist/server/timeline-preview-html.js +140 -148
  186. package/dist/server/timeline-preview-html.js.map +1 -1
  187. package/dist/templates.d.ts +16 -0
  188. package/dist/templates.d.ts.map +1 -0
  189. package/dist/templates.js +186 -0
  190. package/dist/templates.js.map +1 -0
  191. package/dist/timeline/easing.d.ts +36 -0
  192. package/dist/timeline/easing.d.ts.map +1 -0
  193. package/dist/timeline/easing.js +225 -0
  194. package/dist/timeline/easing.js.map +1 -0
  195. package/dist/timeline/keyframes.d.ts +23 -0
  196. package/dist/timeline/keyframes.d.ts.map +1 -0
  197. package/dist/timeline/keyframes.js +95 -0
  198. package/dist/timeline/keyframes.js.map +1 -0
  199. package/dist/timeline/plan.d.ts +6 -12
  200. package/dist/timeline/plan.d.ts.map +1 -1
  201. package/dist/timeline/plan.js +17 -30
  202. package/dist/timeline/plan.js.map +1 -1
  203. package/dist/timeline/resolve.d.ts +12 -0
  204. package/dist/timeline/resolve.d.ts.map +1 -1
  205. package/dist/timeline/resolve.js +105 -9
  206. package/dist/timeline/resolve.js.map +1 -1
  207. package/dist/timeline/scene.d.ts +126 -0
  208. package/dist/timeline/scene.d.ts.map +1 -0
  209. package/dist/timeline/scene.js +109 -0
  210. package/dist/timeline/scene.js.map +1 -0
  211. package/dist/timeline/schema.d.ts +31 -0
  212. package/dist/timeline/schema.d.ts.map +1 -1
  213. package/dist/timeline/schema.js +240 -9
  214. package/dist/timeline/schema.js.map +1 -1
  215. package/dist/timeline/transitions.d.ts +21 -0
  216. package/dist/timeline/transitions.d.ts.map +1 -0
  217. package/dist/timeline/transitions.js +23 -0
  218. package/dist/timeline/transitions.js.map +1 -0
  219. package/dist/version.d.ts +1 -1
  220. package/dist/version.d.ts.map +1 -1
  221. package/dist/version.js +1 -1
  222. package/dist/version.js.map +1 -1
  223. package/docs/adr/0007-make-html-documents-the-composition-unit.md +1 -1
  224. package/docs/adr/0010-make-timelines-the-render-unit.md +3 -2
  225. package/docs/adr/0012-render-timelines-with-segmented-lossless-clip-intermediates.md +1 -1
  226. package/docs/adr/0014-compose-timeline-clips-with-css-blend-modes.md +2 -1
  227. package/docs/adr/0015-inherit-composition-format-from-the-project.md +2 -2
  228. package/docs/adr/0016-author-compositions-as-html-fragments.md +1 -1
  229. package/docs/adr/0018-animate-timeline-clips-with-keyframes.md +35 -0
  230. package/docs/adr/0019-make-same-track-overlap-the-transition-window.md +36 -0
  231. package/docs/adr/0020-crossfade-audio-clips-on-audio-tracks.md +27 -0
  232. package/docs/adr/0021-project-timeline-scenes-once.md +32 -0
  233. package/docs/adr/0022-gate-heavy-operations-with-a-workspace-resource-policy.md +35 -0
  234. package/docs/adr/0023-pin-fonts-as-project-assets.md +98 -0
  235. package/docs/adr/0024-stream-composition-captures-and-skip-trivial-composites.md +86 -0
  236. package/docs/adr/0025-capture-timeline-layers-in-parallel-with-a-global-limit.md +67 -0
  237. package/docs/adr/0026-reuse-loaded-composition-sessions-across-segments.md +70 -0
  238. package/docs/adr/0027-encode-two-full-frame-layers-through-dual-pipes.md +76 -0
  239. package/docs/adr/0028-encode-full-frame-video-segments-directly.md +65 -0
  240. package/docs/migration-0.4.md +2 -2
  241. package/docs/preview-testing.md +27 -6
  242. package/docs/{v0.1-design.md → v0.x-design.md} +57 -32
  243. package/examples/blend/README.md +3 -3
  244. package/examples/demo/README.md +2 -2
  245. package/examples/intro/README.md +71 -0
  246. package/examples/intro/assets/fonts/figtree/LICENSE.txt +93 -0
  247. package/examples/intro/assets/fonts/figtree/figtree-latin-wght-normal.woff2 +0 -0
  248. package/examples/intro/assets/fonts/instrument-serif/LICENSE.txt +93 -0
  249. package/examples/intro/assets/fonts/instrument-serif/instrument-serif-latin-400-italic.woff2 +0 -0
  250. package/examples/intro/assets/fonts/space-mono/LICENSE.txt +93 -0
  251. package/examples/intro/assets/fonts/space-mono/space-mono-latin-400-normal.woff2 +0 -0
  252. package/examples/intro/assets/fonts/space-mono/space-mono-latin-700-normal.woff2 +0 -0
  253. package/examples/intro/assets/grain.png +0 -0
  254. package/examples/intro/assets/score.ogg +0 -0
  255. package/examples/intro/compositions/brand.html +412 -0
  256. package/examples/intro/compositions/chrome.controller.js +63 -0
  257. package/examples/intro/compositions/chrome.html +256 -0
  258. package/examples/intro/compositions/lattice.controller.js +148 -0
  259. package/examples/intro/compositions/lattice.html +308 -0
  260. package/examples/intro/compositions/opening.html +504 -0
  261. package/examples/intro/compositions/studio.html +930 -0
  262. package/examples/intro/compositions/theme.css +218 -0
  263. package/examples/intro/fy.config.js +13 -0
  264. package/examples/intro/fy.fonts.json +100 -0
  265. package/examples/intro/scripts/make-grain.mjs +79 -0
  266. package/examples/intro/scripts/make-score.mjs +702 -0
  267. package/examples/intro/timelines/intro.timeline.json +60 -0
  268. package/examples/keyframes/README.md +76 -0
  269. package/examples/keyframes/compositions/backdrop.html +60 -0
  270. package/examples/keyframes/compositions/card.html +99 -0
  271. package/examples/keyframes/fy.config.js +10 -0
  272. package/examples/keyframes/timelines/keyframes.timeline.json +60 -0
  273. package/examples/nested/README.md +112 -0
  274. package/examples/nested/assets/pulse.wav +0 -0
  275. package/examples/nested/compositions/backdrop.html +84 -0
  276. package/examples/nested/compositions/card.html +275 -0
  277. package/examples/nested/compositions/overlay.html +307 -0
  278. package/examples/nested/fy.config.js +13 -0
  279. package/examples/nested/scripts/make-pulse.sh +20 -0
  280. package/examples/nested/timelines/chapter-a.timeline.json +39 -0
  281. package/examples/nested/timelines/chapter-b.timeline.json +39 -0
  282. package/examples/nested/timelines/nested-reel.timeline.json +52 -0
  283. package/examples/static/README.md +2 -2
  284. package/examples/transitions/README.md +128 -0
  285. package/examples/transitions/assets/alpha.wav +0 -0
  286. package/examples/transitions/assets/beta.wav +0 -0
  287. package/examples/transitions/assets/gamma.wav +0 -0
  288. package/examples/transitions/compositions/alpha.html +56 -0
  289. package/examples/transitions/compositions/beta.html +56 -0
  290. package/examples/transitions/compositions/gamma.html +56 -0
  291. package/examples/transitions/fy.config.js +12 -0
  292. package/examples/transitions/timelines/audio-crossfade.timeline.json +44 -0
  293. package/examples/transitions/timelines/transitions.timeline.json +31 -0
  294. package/examples/video/README.md +4 -4
  295. package/examples/webgl/README.md +1 -1
  296. package/package.json +13 -6
  297. package/scaffolds/init/AGENTS.md +131 -0
  298. package/scaffolds/init/README.md +56 -0
  299. package/scaffolds/init/compositions/hello.html +79 -0
  300. package/scaffolds/init/fy.config.js +9 -0
  301. package/scaffolds/init/gitignore.template +1 -0
  302. package/scaffolds/init/package.json +11 -0
  303. package/scaffolds/init/props/hello.json +4 -0
  304. package/scaffolds/init/props/main.json +6 -0
  305. package/scaffolds/init/timelines/main.timeline.json +20 -0
  306. package/scaffolds/local-models/LOCAL-MODELS.md +77 -0
  307. package/scaffolds/local-models/fy.policy.json +5 -0
  308. package/scaffolds/local-models/opencode/opencode.jsonc +17 -0
  309. package/scaffolds/local-models/pi/APPEND_SYSTEM.md +21 -0
  310. package/scaffolds/local-models/pi/sandbox.json +15 -0
  311. package/scaffolds/local-models/pi/settings.json +15 -0
  312. package/skills/frameyard/README.md +1 -0
  313. package/skills/frameyard/SKILL.md +59 -61
  314. package/skills/frameyard/references/audio-assets.md +32 -3
  315. package/skills/frameyard/references/common-mistakes.md +53 -2
  316. package/skills/frameyard/references/deterministic-authoring.md +10 -3
  317. package/skills/frameyard/references/diagnostics.md +31 -1
  318. package/skills/frameyard/references/failure-recovery.md +32 -6
  319. package/skills/frameyard/references/fonts.md +132 -0
  320. package/skills/frameyard/references/json-results.md +119 -6
  321. package/skills/frameyard/references/quick-reference.md +222 -0
  322. package/skills/frameyard/references/timelines.md +97 -7
  323. /package/examples/blend/{video.config.js → fy.config.js} +0 -0
  324. /package/examples/demo/{video.config.js → fy.config.js} +0 -0
  325. /package/examples/static/{video.config.js → fy.config.js} +0 -0
  326. /package/examples/video/{video.config.js → fy.config.js} +0 -0
  327. /package/examples/webgl/{video.config.js → fy.config.js} +0 -0
@@ -0,0 +1,275 @@
1
+ <script type="application/json" data-fy="props">
2
+ {
3
+ "chapter": "01",
4
+ "kicker": "Chapter one · inner timeline",
5
+ "title": "A sequence, not a clip.",
6
+ "note": "This chapter is a timeline: a static backdrop, this animated card, and a local pulse.",
7
+ "accent": "#ffb347"
8
+ }
9
+ </script>
10
+ <style>
11
+ @keyframes rise {
12
+ from {
13
+ opacity: 0;
14
+ transform: translateY(30px);
15
+ }
16
+ to {
17
+ opacity: 1;
18
+ transform: translateY(0);
19
+ }
20
+ }
21
+ @keyframes slide {
22
+ from {
23
+ opacity: 0;
24
+ transform: translateX(28px);
25
+ }
26
+ to {
27
+ opacity: 1;
28
+ transform: translateX(0);
29
+ }
30
+ }
31
+ @keyframes dial {
32
+ from {
33
+ transform: rotate(-46deg);
34
+ }
35
+ to {
36
+ transform: rotate(314deg);
37
+ }
38
+ }
39
+ @keyframes glow {
40
+ 0%,
41
+ 100% {
42
+ opacity: 0.4;
43
+ transform: scale(0.94);
44
+ }
45
+ 50% {
46
+ opacity: 0.78;
47
+ transform: scale(1.06);
48
+ }
49
+ }
50
+ html,
51
+ body,
52
+ fy-composition {
53
+ margin: 0;
54
+ width: 100%;
55
+ height: 100%;
56
+ background: transparent;
57
+ }
58
+ fy-composition {
59
+ display: block;
60
+ overflow: hidden;
61
+ }
62
+ .scene {
63
+ position: relative;
64
+ width: 100%;
65
+ height: 100%;
66
+ overflow: hidden;
67
+ color: #eef4ff;
68
+ font-family: Inter, "Helvetica Neue", ui-sans-serif, system-ui, sans-serif;
69
+ }
70
+ .glow {
71
+ position: absolute;
72
+ right: 150px;
73
+ top: 210px;
74
+ width: 440px;
75
+ height: 440px;
76
+ border-radius: 50%;
77
+ background: radial-gradient(circle, var(--fy-prop-accent), transparent 68%);
78
+ filter: blur(90px);
79
+ opacity: 0.2;
80
+ animation: glow 1s ease-in-out both;
81
+ }
82
+ .panel {
83
+ position: absolute;
84
+ left: 84px;
85
+ top: 148px;
86
+ width: 760px;
87
+ box-sizing: border-box;
88
+ padding: 38px 44px 32px;
89
+ border: 1px solid rgba(168, 204, 255, 0.22);
90
+ border-radius: 26px;
91
+ background: linear-gradient(135deg, rgba(6, 12, 24, 0.9), rgba(7, 14, 27, 0.58));
92
+ box-shadow: 0 42px 130px rgba(0, 0, 0, 0.45);
93
+ animation: rise 1s cubic-bezier(0.215, 0.61, 0.355, 1) both;
94
+ }
95
+ .panel::before {
96
+ content: "";
97
+ position: absolute;
98
+ inset: 12px;
99
+ border: 1px solid rgba(255, 255, 255, 0.05);
100
+ border-radius: 18px;
101
+ pointer-events: none;
102
+ }
103
+ .eyebrow {
104
+ color: var(--fy-prop-accent);
105
+ font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
106
+ font-size: 13px;
107
+ font-weight: 650;
108
+ letter-spacing: 0.2em;
109
+ text-transform: uppercase;
110
+ }
111
+ .title {
112
+ margin: 18px 0 0;
113
+ max-width: 660px;
114
+ font-size: 88px;
115
+ font-weight: 660;
116
+ letter-spacing: -0.055em;
117
+ line-height: 0.96;
118
+ }
119
+ .note {
120
+ margin: 22px 0 0;
121
+ max-width: 604px;
122
+ color: #a9b8d0;
123
+ font-size: 22px;
124
+ font-weight: 420;
125
+ line-height: 1.5;
126
+ }
127
+ .panel-foot {
128
+ display: flex;
129
+ justify-content: space-between;
130
+ gap: 18px;
131
+ margin-top: 30px;
132
+ color: #73839a;
133
+ font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
134
+ font-size: 11px;
135
+ letter-spacing: 0.12em;
136
+ text-transform: uppercase;
137
+ }
138
+ .progress {
139
+ height: 3px;
140
+ margin-top: 16px;
141
+ overflow: hidden;
142
+ border-radius: 99px;
143
+ background: rgba(220, 235, 255, 0.14);
144
+ }
145
+ .progress .fill {
146
+ width: calc(var(--fy-progress) * 100%);
147
+ height: 100%;
148
+ border-radius: inherit;
149
+ background: linear-gradient(90deg, var(--fy-prop-accent), #eef4ff);
150
+ box-shadow: 0 0 16px var(--fy-prop-accent);
151
+ }
152
+ .index {
153
+ position: absolute;
154
+ right: 74px;
155
+ top: 126px;
156
+ width: 300px;
157
+ text-align: right;
158
+ animation: slide 1s cubic-bezier(0.215, 0.61, 0.355, 1) both;
159
+ }
160
+ .number {
161
+ color: var(--fy-prop-accent);
162
+ font-size: 230px;
163
+ font-weight: 680;
164
+ letter-spacing: -0.08em;
165
+ line-height: 0.8;
166
+ opacity: 0.18;
167
+ }
168
+ .index-label {
169
+ margin-top: 14px;
170
+ color: #8a9ab2;
171
+ font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
172
+ font-size: 12px;
173
+ letter-spacing: 0.26em;
174
+ text-transform: uppercase;
175
+ }
176
+ .dial {
177
+ position: absolute;
178
+ right: 154px;
179
+ top: 382px;
180
+ width: 190px;
181
+ height: 190px;
182
+ border: 1px solid rgba(168, 204, 255, 0.24);
183
+ border-radius: 50%;
184
+ background: rgba(6, 12, 24, 0.4);
185
+ animation: rise 1s cubic-bezier(0.215, 0.61, 0.355, 1) both;
186
+ }
187
+ .dial::before {
188
+ content: "";
189
+ position: absolute;
190
+ inset: 22px;
191
+ border: 1px dashed rgba(168, 204, 255, 0.2);
192
+ border-radius: 50%;
193
+ }
194
+ .dial-hand {
195
+ position: absolute;
196
+ left: 50%;
197
+ top: 50%;
198
+ width: 82px;
199
+ height: 2px;
200
+ border-radius: 99px;
201
+ background: var(--fy-prop-accent);
202
+ box-shadow: 0 0 18px var(--fy-prop-accent);
203
+ transform-origin: 0 50%;
204
+ animation: dial 1s linear both;
205
+ }
206
+ .dial-core {
207
+ position: absolute;
208
+ inset: 0;
209
+ display: flex;
210
+ flex-direction: column;
211
+ align-items: center;
212
+ justify-content: center;
213
+ gap: 7px;
214
+ text-align: center;
215
+ }
216
+ .dial-kicker {
217
+ color: var(--fy-prop-accent);
218
+ font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
219
+ font-size: 10px;
220
+ font-weight: 650;
221
+ letter-spacing: 0.24em;
222
+ }
223
+ .dial-copy {
224
+ color: #95a5bd;
225
+ font-size: 13px;
226
+ letter-spacing: 0.02em;
227
+ }
228
+ .corner-label {
229
+ position: absolute;
230
+ left: 84px;
231
+ bottom: 60px;
232
+ color: #73839a;
233
+ font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
234
+ font-size: 12px;
235
+ letter-spacing: 0.18em;
236
+ text-transform: uppercase;
237
+ }
238
+ .corner-label b {
239
+ color: var(--fy-prop-accent);
240
+ font-weight: 600;
241
+ }
242
+ </style>
243
+ <fy-composition width="1280" height="720" fps="30" duration-in-frames="120">
244
+ <div class="scene">
245
+ <div class="glow" data-fy-anim-start="0" data-fy-anim-duration="120"></div>
246
+ <div
247
+ class="panel"
248
+ data-fy-anim-start="0"
249
+ data-fy-anim-duration="18"
250
+ data-fy-anim-easing="cubic-bezier(0.215, 0.61, 0.355, 1)"
251
+ >
252
+ <div class="eyebrow" data-fy-text="kicker"></div>
253
+ <h1 class="title" data-fy-text="title"></h1>
254
+ <p class="note" data-fy-text="note"></p>
255
+ <div class="panel-foot">
256
+ <span>Inner timeline</span>
257
+ <span>120 frames · 4.00 s</span>
258
+ <span>Local clock</span>
259
+ </div>
260
+ <div class="progress"><div class="fill"></div></div>
261
+ </div>
262
+ <div class="index" data-fy-anim-start="6" data-fy-anim-duration="24">
263
+ <div class="number" data-fy-text="chapter"></div>
264
+ <div class="index-label">Chapter</div>
265
+ </div>
266
+ <div class="dial" data-fy-anim-start="8" data-fy-anim-duration="28">
267
+ <div class="dial-hand" data-fy-anim-start="18" data-fy-anim-duration="102"></div>
268
+ <div class="dial-core">
269
+ <span class="dial-kicker">Nested</span>
270
+ <span class="dial-copy">one level deeper</span>
271
+ </div>
272
+ </div>
273
+ <div class="corner-label">A <b>timeline</b> inside a timeline</div>
274
+ </div>
275
+ </fy-composition>
@@ -0,0 +1,307 @@
1
+ <script type="application/json" data-fy="props">
2
+ {
3
+ "kicker": "Frameyard / Nested timelines",
4
+ "meta": "Reel 02 · 12.0 s · 30 fps",
5
+ "pipLabel": "01 · same nested timeline · 480×270 group",
6
+ "pipNote": "sourceIn 0 · 120 frames · audio muted",
7
+ "accent": "#ffb347"
8
+ }
9
+ </script>
10
+ <style>
11
+ @keyframes pip-in {
12
+ from {
13
+ opacity: 0;
14
+ transform: translateY(14px);
15
+ }
16
+ to {
17
+ opacity: 1;
18
+ transform: translateY(0);
19
+ }
20
+ }
21
+ html,
22
+ body,
23
+ fy-composition {
24
+ margin: 0;
25
+ width: 100%;
26
+ height: 100%;
27
+ background: transparent;
28
+ }
29
+ fy-composition {
30
+ display: block;
31
+ overflow: hidden;
32
+ }
33
+ .scene {
34
+ position: relative;
35
+ width: 100%;
36
+ height: 100%;
37
+ overflow: hidden;
38
+ color: #eef4ff;
39
+ font-family: Inter, "Helvetica Neue", ui-sans-serif, system-ui, sans-serif;
40
+ }
41
+ .kicker {
42
+ position: absolute;
43
+ left: 64px;
44
+ top: 50px;
45
+ display: flex;
46
+ align-items: center;
47
+ gap: 14px;
48
+ color: #7fd6ff;
49
+ font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
50
+ font-size: 13px;
51
+ font-weight: 650;
52
+ letter-spacing: 0.24em;
53
+ text-transform: uppercase;
54
+ }
55
+ .kicker::before {
56
+ content: "";
57
+ width: 8px;
58
+ height: 8px;
59
+ background: var(--fy-prop-accent);
60
+ box-shadow: 0 0 16px var(--fy-prop-accent);
61
+ }
62
+ .segments {
63
+ position: absolute;
64
+ right: 64px;
65
+ top: 44px;
66
+ display: flex;
67
+ align-items: center;
68
+ gap: 20px;
69
+ font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
70
+ font-size: 11px;
71
+ letter-spacing: 0.14em;
72
+ text-transform: uppercase;
73
+ }
74
+ .segment {
75
+ display: flex;
76
+ align-items: center;
77
+ gap: 8px;
78
+ color: #8696ae;
79
+ }
80
+ .segment::before {
81
+ content: "";
82
+ width: 18px;
83
+ height: 2px;
84
+ background: currentColor;
85
+ opacity: 0.55;
86
+ }
87
+ .segment b {
88
+ color: #eef4ff;
89
+ font-weight: 600;
90
+ }
91
+ .segment.a {
92
+ color: var(--fy-prop-accent);
93
+ }
94
+ .segment.b {
95
+ color: #7fd6ff;
96
+ }
97
+ .rule {
98
+ position: absolute;
99
+ left: 64px;
100
+ right: 64px;
101
+ top: 92px;
102
+ height: 1px;
103
+ background: linear-gradient(
104
+ 90deg,
105
+ rgba(168, 204, 255, 0.32),
106
+ rgba(168, 204, 255, 0.12) 48%,
107
+ rgba(168, 204, 255, 0.28)
108
+ );
109
+ }
110
+ .pip-chrome {
111
+ position: absolute;
112
+ inset: 0;
113
+ animation: pip-in 1s cubic-bezier(0.215, 0.61, 0.355, 1) both;
114
+ }
115
+ .pip-label {
116
+ position: absolute;
117
+ left: 760px;
118
+ top: 348px;
119
+ padding: 8px 12px 9px;
120
+ border-left: 2px solid var(--fy-prop-accent);
121
+ background: rgba(5, 7, 13, 0.72);
122
+ color: #ffd9a3;
123
+ font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
124
+ font-size: 11px;
125
+ letter-spacing: 0.14em;
126
+ text-transform: uppercase;
127
+ white-space: nowrap;
128
+ }
129
+ .pip-label small {
130
+ display: block;
131
+ margin-top: 6px;
132
+ color: #7f90a8;
133
+ font-size: 10px;
134
+ letter-spacing: 0.12em;
135
+ }
136
+ .pip-box {
137
+ position: absolute;
138
+ left: 760px;
139
+ top: 405px;
140
+ width: 480px;
141
+ height: 270px;
142
+ box-sizing: border-box;
143
+ border: 1px solid rgba(238, 244, 255, 0.42);
144
+ box-shadow:
145
+ 0 30px 90px rgba(0, 0, 0, 0.42),
146
+ 0 0 0 6px rgba(5, 7, 13, 0.18);
147
+ pointer-events: none;
148
+ }
149
+ .pip-box::before,
150
+ .pip-box::after {
151
+ content: "";
152
+ position: absolute;
153
+ width: 26px;
154
+ height: 26px;
155
+ border: 2px solid var(--fy-prop-accent);
156
+ }
157
+ .pip-box::before {
158
+ left: -2px;
159
+ top: -2px;
160
+ border-right: 0;
161
+ border-bottom: 0;
162
+ }
163
+ .pip-box::after {
164
+ right: -2px;
165
+ bottom: -2px;
166
+ border-left: 0;
167
+ border-top: 0;
168
+ }
169
+ .foot {
170
+ position: absolute;
171
+ left: 64px;
172
+ bottom: 38px;
173
+ color: #73839a;
174
+ font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
175
+ font-size: 12px;
176
+ letter-spacing: 0.14em;
177
+ text-transform: uppercase;
178
+ }
179
+ .outro {
180
+ position: absolute;
181
+ left: 64px;
182
+ top: 196px;
183
+ width: 580px;
184
+ animation: pip-in 1s cubic-bezier(0.215, 0.61, 0.355, 1) both;
185
+ }
186
+ .outro-kicker {
187
+ color: var(--fy-prop-accent);
188
+ font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
189
+ font-size: 12px;
190
+ font-weight: 650;
191
+ letter-spacing: 0.2em;
192
+ text-transform: uppercase;
193
+ }
194
+ .outro h2 {
195
+ margin: 16px 0 0;
196
+ color: #eef4ff;
197
+ font-size: 58px;
198
+ font-weight: 660;
199
+ letter-spacing: -0.045em;
200
+ line-height: 0.97;
201
+ }
202
+ .outro p {
203
+ width: 540px;
204
+ margin: 20px 0 0;
205
+ color: #a9b8d0;
206
+ font-size: 20px;
207
+ font-weight: 420;
208
+ line-height: 1.5;
209
+ }
210
+ .outro-stats {
211
+ display: flex;
212
+ flex-direction: column;
213
+ gap: 0;
214
+ width: 540px;
215
+ margin-top: 26px;
216
+ color: #73839a;
217
+ font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
218
+ font-size: 11px;
219
+ letter-spacing: 0.12em;
220
+ text-transform: uppercase;
221
+ }
222
+ .outro-stats div {
223
+ display: flex;
224
+ justify-content: space-between;
225
+ gap: 18px;
226
+ padding: 8px 0;
227
+ border-top: 1px solid rgba(168, 204, 255, 0.14);
228
+ }
229
+ .outro-stats b {
230
+ color: #eef4ff;
231
+ font-weight: 600;
232
+ }
233
+ .foot b {
234
+ color: #eef4ff;
235
+ font-weight: 600;
236
+ }
237
+ .clock {
238
+ position: absolute;
239
+ right: 64px;
240
+ top: 68px;
241
+ color: #7f90a8;
242
+ font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
243
+ font-size: 11px;
244
+ letter-spacing: 0.14em;
245
+ text-transform: uppercase;
246
+ }
247
+ .clock b {
248
+ color: var(--fy-prop-accent);
249
+ font-weight: 600;
250
+ }
251
+ .frame-counter::after {
252
+ counter-reset: fy-frame var(--fy-frame);
253
+ content: counter(fy-frame);
254
+ }
255
+ .progress {
256
+ position: absolute;
257
+ left: 64px;
258
+ right: 64px;
259
+ bottom: 20px;
260
+ height: 2px;
261
+ overflow: hidden;
262
+ background: rgba(220, 235, 255, 0.12);
263
+ }
264
+ .progress .fill {
265
+ width: calc(var(--fy-progress) * 100%);
266
+ height: 100%;
267
+ background: linear-gradient(90deg, var(--fy-prop-accent), #7fd6ff);
268
+ box-shadow: 0 0 14px var(--fy-prop-accent);
269
+ }
270
+ </style>
271
+ <fy-composition width="1280" height="720" fps="30" duration-in-frames="360">
272
+ <div class="scene">
273
+ <div class="kicker" data-fy-text="kicker"></div>
274
+ <div class="segments">
275
+ <span class="segment a"><b>01</b> full</span>
276
+ <span class="segment b"><b>02</b> full</span>
277
+ <span class="segment a"><b>01</b> group</span>
278
+ </div>
279
+ <div class="rule"></div>
280
+
281
+ <div class="pip-chrome" data-fy-anim-start="240" data-fy-anim-duration="24">
282
+ <div class="pip-label">
283
+ <span data-fy-text="pipLabel"></span>
284
+ <small data-fy-text="pipNote"></small>
285
+ </div>
286
+ <div class="pip-box"></div>
287
+ </div>
288
+
289
+ <div class="outro" data-fy-anim-start="246" data-fy-anim-duration="24">
290
+ <div class="outro-kicker">Chapter A · third placement</div>
291
+ <h2>One timeline,<br />inside another.</h2>
292
+ <p>
293
+ The two inner chapters play full frame first. Here chapter A returns as a 480×270 group on track v3, with its
294
+ pulse muted.
295
+ </p>
296
+ <div class="outro-stats">
297
+ <div><span>Group transform</span><b>480×270</b></div>
298
+ <div><span>Source range</span><b>0–119</b></div>
299
+ <div><span>Nested audio</span><b>Muted</b></div>
300
+ </div>
301
+ </div>
302
+
303
+ <div class="foot">One outer timeline · <b>two inner timelines</b> · three placements</div>
304
+ <div class="clock">Project frame <b class="frame-counter"></b> / 359</div>
305
+ <div class="progress"><div class="fill"></div></div>
306
+ </div>
307
+ </fy-composition>
@@ -0,0 +1,13 @@
1
+ export default {
2
+ format: { width: 1280, height: 720, fps: 30 },
3
+ compositions: {
4
+ backdrop: "./compositions/backdrop.html",
5
+ card: "./compositions/card.html",
6
+ overlay: "./compositions/overlay.html",
7
+ },
8
+ timelines: {
9
+ "chapter-a": "./timelines/chapter-a.timeline.json",
10
+ "chapter-b": "./timelines/chapter-b.timeline.json",
11
+ "nested-reel": "./timelines/nested-reel.timeline.json",
12
+ },
13
+ };
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
+ out="${1:-$root/assets/pulse.wav}"
6
+ mkdir -p "$(dirname "$out")"
7
+
8
+ ffmpeg -y -v error \
9
+ -f lavfi \
10
+ -i "sine=frequency=659.25:duration=1.8:sample_rate=24000" \
11
+ -f lavfi \
12
+ -i "sine=frequency=987.77:duration=1.8:sample_rate=24000" \
13
+ -filter_complex "[0:a]volume=1.6,afade=t=in:st=0:d=0.012,afade=t=out:st=0.18:d=1.62[a0];[1:a]volume=0.7,afade=t=in:st=0:d=0.012,afade=t=out:st=0.3:d=1.5[a1];[a0][a1]amix=inputs=2:normalize=0,alimiter=limit=0.9[out]" \
14
+ -map "[out]" \
15
+ -ac 1 \
16
+ -ar 24000 \
17
+ -c:a pcm_s16le \
18
+ "$out"
19
+
20
+ printf 'Wrote %s\n' "$out"
@@ -0,0 +1,39 @@
1
+ {
2
+ "version": 1,
3
+ "name": "Chapter A: a reusable inner timeline",
4
+ "tracks": [
5
+ { "id": "v1", "kind": "video", "name": "Backdrop" },
6
+ { "id": "v2", "kind": "video", "name": "Card" },
7
+ { "id": "a1", "kind": "audio", "name": "Pulse" }
8
+ ],
9
+ "clips": [
10
+ {
11
+ "id": "backdrop",
12
+ "track": "v1",
13
+ "source": { "kind": "composition", "id": "backdrop" },
14
+ "start": 0,
15
+ "duration": 120
16
+ },
17
+ {
18
+ "id": "card",
19
+ "track": "v2",
20
+ "source": { "kind": "composition", "id": "card" },
21
+ "start": 0,
22
+ "duration": 120,
23
+ "props": {
24
+ "chapter": "01",
25
+ "kicker": "Chapter one · inner timeline",
26
+ "title": "A sequence, not a clip.",
27
+ "note": "This chapter is a timeline: a static backdrop, this animated card, and a local pulse.",
28
+ "accent": "#ffb347"
29
+ }
30
+ },
31
+ {
32
+ "id": "pulse",
33
+ "track": "a1",
34
+ "source": { "kind": "audio", "src": "assets/pulse.wav" },
35
+ "start": 12,
36
+ "audio": { "gain": 0.5 }
37
+ }
38
+ ]
39
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "version": 1,
3
+ "name": "Chapter B: the same structure, different props",
4
+ "tracks": [
5
+ { "id": "v1", "kind": "video", "name": "Backdrop" },
6
+ { "id": "v2", "kind": "video", "name": "Card" },
7
+ { "id": "a1", "kind": "audio", "name": "Pulse" }
8
+ ],
9
+ "clips": [
10
+ {
11
+ "id": "backdrop",
12
+ "track": "v1",
13
+ "source": { "kind": "composition", "id": "backdrop" },
14
+ "start": 0,
15
+ "duration": 120
16
+ },
17
+ {
18
+ "id": "card",
19
+ "track": "v2",
20
+ "source": { "kind": "composition", "id": "card" },
21
+ "start": 0,
22
+ "duration": 120,
23
+ "props": {
24
+ "chapter": "02",
25
+ "kicker": "Chapter two · inner timeline",
26
+ "title": "Nested, then reused.",
27
+ "note": "The same chapter plays again as a 480×270 group, and every layer moves together.",
28
+ "accent": "#7fd6ff"
29
+ }
30
+ },
31
+ {
32
+ "id": "pulse",
33
+ "track": "a1",
34
+ "source": { "kind": "audio", "src": "assets/pulse.wav" },
35
+ "start": 24,
36
+ "audio": { "gain": 0.45 }
37
+ }
38
+ ]
39
+ }