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
package/dist/policy.js ADDED
@@ -0,0 +1,361 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { isPlainObject } from "./contracts.js";
5
+ import { FrameyardError } from "./errors.js";
6
+ /** Project-local resource policy file discovered from the working directory upward. */
7
+ export const POLICY_FILE_NAME = "fy.policy.json";
8
+ export const POLICY_TIERS = ["light", "authoring", "full"];
9
+ export const RESOURCE_PROFILES = ["shared-cpu"];
10
+ export const MAX_STILL_FRAMES = 32;
11
+ export const SHARED_CPU_MAX_WORKERS = 2;
12
+ export const SHARED_CPU_MAX_CONCURRENCY = 1;
13
+ const POLICY_VERSION = 1;
14
+ const POLICY_FIELDS = new Set(["version", "policy", "profile", "maxStillFrames", "allowOverwrite"]);
15
+ export const TIER_DEFAULTS = {
16
+ light: { maxStillFrames: 1, allowOverwrite: false },
17
+ authoring: { maxStillFrames: 4, allowOverwrite: false },
18
+ full: { maxStillFrames: MAX_STILL_FRAMES, allowOverwrite: true },
19
+ };
20
+ function isPolicyTier(value) {
21
+ return typeof value === "string" && POLICY_TIERS.includes(value);
22
+ }
23
+ function isResourceProfile(value) {
24
+ return typeof value === "string" && RESOURCE_PROFILES.includes(value);
25
+ }
26
+ function policyError(message, details) {
27
+ throw new FrameyardError("POLICY_INVALID", message, { details });
28
+ }
29
+ async function isFile(filePath) {
30
+ try {
31
+ return (await stat(filePath)).isFile();
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
37
+ /** Walks up from a directory until it finds fy.policy.json. */
38
+ export async function findPolicyFile(start = process.cwd()) {
39
+ let current = path.resolve(start);
40
+ try {
41
+ if (!(await stat(current)).isDirectory()) {
42
+ current = path.dirname(current);
43
+ }
44
+ }
45
+ catch {
46
+ return undefined;
47
+ }
48
+ while (true) {
49
+ const candidate = path.join(current, POLICY_FILE_NAME);
50
+ if (await isFile(candidate)) {
51
+ return candidate;
52
+ }
53
+ const parent = path.dirname(current);
54
+ if (parent === current) {
55
+ return undefined;
56
+ }
57
+ current = parent;
58
+ }
59
+ }
60
+ function validatePolicyFile(value, filePath) {
61
+ if (!isPlainObject(value)) {
62
+ policyError(`${POLICY_FILE_NAME} must contain a JSON object.`, {
63
+ path: filePath,
64
+ suggestion: `Write a policy file such as { "version": 1, "policy": "authoring" }.`,
65
+ });
66
+ }
67
+ for (const key of Object.keys(value)) {
68
+ if (!POLICY_FIELDS.has(key)) {
69
+ policyError(`${POLICY_FILE_NAME} contains an unknown field "${key}".`, {
70
+ path: filePath,
71
+ jsonPath: `$.${key}`,
72
+ allowed: [...POLICY_FIELDS],
73
+ suggestion: "Remove the field or use one of the documented policy fields.",
74
+ });
75
+ }
76
+ }
77
+ if (value.version !== POLICY_VERSION) {
78
+ policyError(`${POLICY_FILE_NAME} must declare "version": ${POLICY_VERSION}.`, {
79
+ path: filePath,
80
+ jsonPath: "$.version",
81
+ value: value.version,
82
+ allowed: [POLICY_VERSION],
83
+ });
84
+ }
85
+ if (!isPolicyTier(value.policy)) {
86
+ policyError(`${POLICY_FILE_NAME} must declare policy as "light", "authoring", or "full".`, {
87
+ path: filePath,
88
+ jsonPath: "$.policy",
89
+ value: value.policy,
90
+ allowed: [...POLICY_TIERS],
91
+ });
92
+ }
93
+ const tier = value.policy;
94
+ const defaults = TIER_DEFAULTS[tier];
95
+ if (value.profile !== undefined && !isResourceProfile(value.profile)) {
96
+ policyError(`${POLICY_FILE_NAME} profile must be "shared-cpu".`, {
97
+ path: filePath,
98
+ jsonPath: "$.profile",
99
+ value: value.profile,
100
+ allowed: [...RESOURCE_PROFILES],
101
+ });
102
+ }
103
+ let maxStillFrames = defaults.maxStillFrames;
104
+ if (value.maxStillFrames !== undefined) {
105
+ if (!Number.isInteger(value.maxStillFrames) ||
106
+ value.maxStillFrames < 1 ||
107
+ value.maxStillFrames > MAX_STILL_FRAMES) {
108
+ policyError(`${POLICY_FILE_NAME} maxStillFrames must be an integer from 1 to ${MAX_STILL_FRAMES}.`, {
109
+ path: filePath,
110
+ jsonPath: "$.maxStillFrames",
111
+ value: value.maxStillFrames,
112
+ allowed: { min: 1, max: MAX_STILL_FRAMES },
113
+ });
114
+ }
115
+ if (value.maxStillFrames > defaults.maxStillFrames) {
116
+ policyError(`${POLICY_FILE_NAME} maxStillFrames cannot exceed the ${tier} default of ${defaults.maxStillFrames}.`, {
117
+ path: filePath,
118
+ jsonPath: "$.maxStillFrames",
119
+ value: value.maxStillFrames,
120
+ limit: defaults.maxStillFrames,
121
+ suggestion: "A policy file can only tighten the tier limits.",
122
+ });
123
+ }
124
+ maxStillFrames = value.maxStillFrames;
125
+ }
126
+ let allowOverwrite = defaults.allowOverwrite;
127
+ if (value.allowOverwrite !== undefined) {
128
+ if (typeof value.allowOverwrite !== "boolean") {
129
+ policyError(`${POLICY_FILE_NAME} allowOverwrite must be a boolean.`, {
130
+ path: filePath,
131
+ jsonPath: "$.allowOverwrite",
132
+ value: value.allowOverwrite,
133
+ });
134
+ }
135
+ if (value.allowOverwrite === true && !defaults.allowOverwrite) {
136
+ policyError(`${POLICY_FILE_NAME} allowOverwrite cannot be true in the ${tier} tier.`, {
137
+ path: filePath,
138
+ jsonPath: "$.allowOverwrite",
139
+ value: value.allowOverwrite,
140
+ suggestion: "A policy file can only tighten the tier limits; use FRAMEYARD_POLICY=full to allow overwrites.",
141
+ });
142
+ }
143
+ allowOverwrite = value.allowOverwrite;
144
+ }
145
+ return {
146
+ tier,
147
+ ...(value.profile !== undefined ? { profile: value.profile } : {}),
148
+ maxStillFrames,
149
+ allowOverwrite,
150
+ };
151
+ }
152
+ async function loadPolicyFile(filePath) {
153
+ let text;
154
+ try {
155
+ text = await readFile(filePath, "utf8");
156
+ }
157
+ catch (error) {
158
+ throw new FrameyardError("POLICY_INVALID", `Could not read ${filePath}.`, {
159
+ cause: error,
160
+ details: { path: filePath },
161
+ });
162
+ }
163
+ let value;
164
+ try {
165
+ value = JSON.parse(text);
166
+ }
167
+ catch (error) {
168
+ policyError(`${filePath} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`, {
169
+ path: filePath,
170
+ });
171
+ }
172
+ return {
173
+ ...validatePolicyFile(value, filePath),
174
+ source: "file",
175
+ path: filePath,
176
+ };
177
+ }
178
+ /**
179
+ * Loads the resource policy for the current workspace.
180
+ *
181
+ * `FRAMEYARD_POLICY` replaces the policy file entirely, so an explicit human
182
+ * override also resets the file's profile and tightened limits. Without the
183
+ * variable, the nearest `fy.policy.json` from `cwd` upward wins; without
184
+ * a file, the default is `full`.
185
+ */
186
+ export async function loadResourcePolicy(options = {}) {
187
+ const env = options.env ?? process.env;
188
+ const requested = env.FRAMEYARD_POLICY;
189
+ if (requested !== undefined) {
190
+ const value = requested.trim();
191
+ if (!isPolicyTier(value)) {
192
+ policyError(`FRAMEYARD_POLICY must be "light", "authoring", or "full"; received "${requested}".`, {
193
+ source: "env",
194
+ value: requested,
195
+ allowed: [...POLICY_TIERS],
196
+ });
197
+ }
198
+ const defaults = TIER_DEFAULTS[value];
199
+ return {
200
+ tier: value,
201
+ ...defaults,
202
+ source: "env",
203
+ };
204
+ }
205
+ const filePath = await findPolicyFile(options.cwd ?? process.cwd());
206
+ if (filePath === undefined) {
207
+ const defaults = TIER_DEFAULTS.full;
208
+ return {
209
+ tier: "full",
210
+ ...defaults,
211
+ source: "default",
212
+ };
213
+ }
214
+ return loadPolicyFile(filePath);
215
+ }
216
+ /** Resolves the effective profile from the CLI flag and the policy file. */
217
+ export function resolveProfile(policy, requested) {
218
+ if (requested === undefined) {
219
+ return policy.profile;
220
+ }
221
+ if (!isResourceProfile(requested)) {
222
+ throw new FrameyardError("USAGE", `--profile must be "shared-cpu"; received "${requested}".`);
223
+ }
224
+ return requested;
225
+ }
226
+ /** Returns the operation allowlist for a tier. */
227
+ export function allowedOperations(tier) {
228
+ const operations = ["lint", "context", "doctor", "init", "dev", "still", "font"];
229
+ if (tier !== "light") {
230
+ operations.push("check");
231
+ }
232
+ if (tier === "full") {
233
+ operations.push("tts", "transcribe", "render");
234
+ }
235
+ return operations;
236
+ }
237
+ export function operationAllowed(tier, operation) {
238
+ return allowedOperations(tier).includes(operation);
239
+ }
240
+ function operationSuggestion(operation, tier) {
241
+ if (operation === "check") {
242
+ return "Use lint and still in the light tier, or run check from authoring or full.";
243
+ }
244
+ if (operation === "render" || operation === "tts" || operation === "transcribe") {
245
+ return `Run the command with --dry-run to produce a handoff plan, or set FRAMEYARD_POLICY=full when the user explicitly asks for the heavy operation.`;
246
+ }
247
+ if (operation === "font") {
248
+ return `Font list and verify are available in every tier; adding fonts requires authoring or full.`;
249
+ }
250
+ return `The ${tier} policy does not allow ${operation}.`;
251
+ }
252
+ export function assertOperationAllowed(policy, operation, options = {}) {
253
+ if (options.dryRun === true) {
254
+ return;
255
+ }
256
+ if (operationAllowed(policy.tier, operation)) {
257
+ return;
258
+ }
259
+ throw new FrameyardError("RESOURCE_POLICY_BLOCKED", `"${operation}" is blocked by the ${policy.tier} resource policy.`, {
260
+ details: {
261
+ policy: policy.tier,
262
+ operation,
263
+ allowed: allowedOperations(policy.tier),
264
+ suggestion: operationSuggestion(operation, policy.tier),
265
+ },
266
+ });
267
+ }
268
+ const TIER_ORDER = { light: 0, authoring: 1, full: 2 };
269
+ /** Requires a minimum tier for subcommands that share one policy operation. */
270
+ export function assertPolicyTier(policy, required, operation) {
271
+ if (TIER_ORDER[policy.tier] >= TIER_ORDER[required]) {
272
+ return;
273
+ }
274
+ throw new FrameyardError("RESOURCE_POLICY_BLOCKED", `"${operation}" requires the ${required} resource policy; the active policy is ${policy.tier}.`, {
275
+ details: {
276
+ policy: policy.tier,
277
+ required,
278
+ operation,
279
+ allowed: allowedOperations(policy.tier),
280
+ suggestion: `Ask the user to run the command with FRAMEYARD_POLICY=${required} when it is intended.`,
281
+ },
282
+ });
283
+ }
284
+ export function assertStillFrameLimit(policy, requested) {
285
+ if (requested <= policy.maxStillFrames) {
286
+ return;
287
+ }
288
+ throw new FrameyardError("RESOURCE_POLICY_LIMIT", `Still requested ${requested} frames; the ${policy.tier} policy allows at most ${policy.maxStillFrames}.`, {
289
+ details: {
290
+ policy: policy.tier,
291
+ limit: policy.maxStillFrames,
292
+ requested,
293
+ suggestion: `Capture at most ${policy.maxStillFrames} frames per invocation, or use FRAMEYARD_POLICY=full for a larger inspection batch.`,
294
+ },
295
+ });
296
+ }
297
+ export function assertOverwriteAllowed(policy, operation) {
298
+ if (policy.allowOverwrite) {
299
+ return;
300
+ }
301
+ throw new FrameyardError("RESOURCE_POLICY_BLOCKED", `--${operation} is blocked by the ${policy.tier} resource policy.`, {
302
+ details: {
303
+ policy: policy.tier,
304
+ operation,
305
+ allowed: false,
306
+ suggestion: "Use a new output path, or ask the user to run the command with FRAMEYARD_POLICY=full when replacement is intended.",
307
+ },
308
+ });
309
+ }
310
+ export function assertProfileLimit(profile, option, requested, limit) {
311
+ if (requested <= limit) {
312
+ return;
313
+ }
314
+ throw new FrameyardError("RESOURCE_PROFILE_CONFLICT", `--${option} ${requested} exceeds the ${profile} profile limit of ${limit}.`, {
315
+ details: {
316
+ profile,
317
+ option,
318
+ requested,
319
+ limit,
320
+ suggestion: "Lower the value, or omit --profile when the machine is not shared with a local model.",
321
+ },
322
+ });
323
+ }
324
+ export function shouldLowerPriority(policy, profile, requested) {
325
+ return requested || profile === "shared-cpu" || policy.tier === "authoring" || policy.tier === "light";
326
+ }
327
+ /**
328
+ * Lowers the current process priority so it yields to a local model. Children
329
+ * inherit the nice value on Unix. This is best effort on platforms that do not
330
+ * expose process priorities.
331
+ */
332
+ export function lowerProcessPriority() {
333
+ try {
334
+ const priority = process.platform === "win32" ? os.constants.priority.PRIORITY_BELOW_NORMAL : os.constants.priority.PRIORITY_LOW;
335
+ os.setPriority(0, priority);
336
+ }
337
+ catch {
338
+ // Priority changes are advisory; rendering still proceeds when unsupported.
339
+ }
340
+ }
341
+ /** Serializable policy details for JSON results and diagnostics. */
342
+ export function policyDetails(policy) {
343
+ return {
344
+ policy: policy.tier,
345
+ ...(policy.profile !== undefined ? { profile: policy.profile } : {}),
346
+ maxStillFrames: policy.maxStillFrames,
347
+ allowOverwrite: policy.allowOverwrite,
348
+ source: policy.source,
349
+ ...(policy.path !== undefined ? { path: policy.path } : {}),
350
+ };
351
+ }
352
+ export function describePolicy(policy) {
353
+ const parts = [policy.tier];
354
+ if (policy.profile !== undefined) {
355
+ parts.push(policy.profile);
356
+ }
357
+ parts.push(`still ≤${policy.maxStillFrames}`);
358
+ parts.push(policy.allowOverwrite ? "overwrite allowed" : "overwrite blocked");
359
+ return parts.join(", ");
360
+ }
361
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,uFAAuF;AACvF,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;AAEjD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,CAAU,CAAC;AAGpE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,YAAY,CAAU,CAAC;AAGzD,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACxC,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC;AAE5C,MAAM,cAAc,GAAG,CAAC,CAAC;AACzB,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAEpG,MAAM,CAAC,MAAM,aAAa,GAMtB;IACF,KAAK,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE;IACnD,SAAS,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE;IACvD,IAAI,EAAE,EAAE,cAAc,EAAE,gBAAgB,EAAE,cAAc,EAAE,IAAI,EAAE;CACjE,CAAC;AAkCF,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,YAAkC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC1F,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,iBAAuC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC/F,CAAC;AAED,SAAS,WAAW,CAAC,OAAe,EAAE,OAAgC;IACpE,MAAM,IAAI,cAAc,CAAC,gBAAgB,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;AACnE,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,QAAgB;IACpC,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE;IACxD,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAElC,IAAI,CAAC;QACH,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACzC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;QACvD,IAAI,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc,EAAE,QAAgB;IAC1D,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,WAAW,CAAC,GAAG,gBAAgB,8BAA8B,EAAE;YAC7D,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,sEAAsE;SACnF,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,WAAW,CAAC,GAAG,gBAAgB,+BAA+B,GAAG,IAAI,EAAE;gBACrE,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,KAAK,GAAG,EAAE;gBACpB,OAAO,EAAE,CAAC,GAAG,aAAa,CAAC;gBAC3B,UAAU,EAAE,8DAA8D;aAC3E,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,KAAK,cAAc,EAAE,CAAC;QACrC,WAAW,CAAC,GAAG,gBAAgB,4BAA4B,cAAc,GAAG,EAAE;YAC5E,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,WAAW;YACrB,KAAK,EAAE,KAAK,CAAC,OAAO;YACpB,OAAO,EAAE,CAAC,cAAc,CAAC;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QAChC,WAAW,CAAC,GAAG,gBAAgB,0DAA0D,EAAE;YACzF,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,UAAU;YACpB,KAAK,EAAE,KAAK,CAAC,MAAM;YACnB,OAAO,EAAE,CAAC,GAAG,YAAY,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;IAC1B,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IAErC,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACrE,WAAW,CAAC,GAAG,gBAAgB,gCAAgC,EAAE;YAC/D,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,WAAW;YACrB,KAAK,EAAE,KAAK,CAAC,OAAO;YACpB,OAAO,EAAE,CAAC,GAAG,iBAAiB,CAAC;SAChC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,cAAc,GAAG,QAAQ,CAAC,cAAc,CAAC;IAC7C,IAAI,KAAK,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QACvC,IACE,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,cAAc,CAAC;YACtC,KAAK,CAAC,cAAyB,GAAG,CAAC;YACnC,KAAK,CAAC,cAAyB,GAAG,gBAAgB,EACnD,CAAC;YACD,WAAW,CAAC,GAAG,gBAAgB,gDAAgD,gBAAgB,GAAG,EAAE;gBAClG,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,kBAAkB;gBAC5B,KAAK,EAAE,KAAK,CAAC,cAAc;gBAC3B,OAAO,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,gBAAgB,EAAE;aAC3C,CAAC,CAAC;QACL,CAAC;QACD,IAAK,KAAK,CAAC,cAAyB,GAAG,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC/D,WAAW,CACT,GAAG,gBAAgB,qCAAqC,IAAI,eAAe,QAAQ,CAAC,cAAc,GAAG,EACrG;gBACE,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,kBAAkB;gBAC5B,KAAK,EAAE,KAAK,CAAC,cAAc;gBAC3B,KAAK,EAAE,QAAQ,CAAC,cAAc;gBAC9B,UAAU,EAAE,iDAAiD;aAC9D,CACF,CAAC;QACJ,CAAC;QACD,cAAc,GAAG,KAAK,CAAC,cAAwB,CAAC;IAClD,CAAC;IAED,IAAI,cAAc,GAAG,QAAQ,CAAC,cAAc,CAAC;IAC7C,IAAI,KAAK,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QACvC,IAAI,OAAO,KAAK,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;YAC9C,WAAW,CAAC,GAAG,gBAAgB,oCAAoC,EAAE;gBACnE,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,kBAAkB;gBAC5B,KAAK,EAAE,KAAK,CAAC,cAAc;aAC5B,CAAC,CAAC;QACL,CAAC;QACD,IAAI,KAAK,CAAC,cAAc,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC9D,WAAW,CAAC,GAAG,gBAAgB,yCAAyC,IAAI,QAAQ,EAAE;gBACpF,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,kBAAkB;gBAC5B,KAAK,EAAE,KAAK,CAAC,cAAc;gBAC3B,UAAU,EAAE,gGAAgG;aAC7G,CAAC,CAAC;QACL,CAAC;QACD,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;IACxC,CAAC;IAED,OAAO;QACL,IAAI;QACJ,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAA0B,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrF,cAAc;QACd,cAAc;KACf,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,QAAgB;IAC5C,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,cAAc,CAAC,gBAAgB,EAAE,kBAAkB,QAAQ,GAAG,EAAE;YACxE,KAAK,EAAE,KAAK;YACZ,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,WAAW,CAAC,GAAG,QAAQ,uBAAuB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE;YACtG,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,GAAG,kBAAkB,CAAC,KAAK,EAAE,QAAQ,CAAC;QACtC,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,QAAQ;KACf,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAO,GAGH,EAAE;IAEN,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,SAAS,GAAG,GAAG,CAAC,gBAAgB,CAAC;IACvC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,WAAW,CAAC,uEAAuE,SAAS,IAAI,EAAE;gBAChG,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,SAAS;gBAChB,OAAO,EAAE,CAAC,GAAG,YAAY,CAAC;aAC3B,CAAC,CAAC;QACL,CAAC;QACD,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QACtC,OAAO;YACL,IAAI,EAAE,KAAK;YACX,GAAG,QAAQ;YACX,MAAM,EAAE,KAAK;SACd,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACpE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC;QACpC,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,GAAG,QAAQ;YACX,MAAM,EAAE,SAAS;SAClB,CAAC;IACJ,CAAC;IAED,OAAO,cAAc,CAAC,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,cAAc,CAC5B,MAA4B,EAC5B,SAA6B;IAE7B,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,MAAM,CAAC,OAAO,CAAC;IACxB,CAAC;IACD,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,cAAc,CAAC,OAAO,EAAE,6CAA6C,SAAS,IAAI,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,iBAAiB,CAAC,IAAgB;IAChD,MAAM,UAAU,GAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACpG,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAgB,EAAE,SAA0B;IAC3E,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,mBAAmB,CAAC,SAA0B,EAAE,IAAgB;IACvE,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;QAC1B,OAAO,4EAA4E,CAAC;IACtF,CAAC;IACD,IAAI,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,KAAK,IAAI,SAAS,KAAK,YAAY,EAAE,CAAC;QAChF,OAAO,+IAA+I,CAAC;IACzJ,CAAC;IACD,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QACzB,OAAO,4FAA4F,CAAC;IACtG,CAAC;IACD,OAAO,OAAO,IAAI,0BAA0B,SAAS,GAAG,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,MAA4B,EAC5B,SAA0B,EAC1B,OAAO,GAAyB,EAAE;IAElC,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;QAC5B,OAAO;IACT,CAAC;IACD,IAAI,gBAAgB,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC;QAC7C,OAAO;IACT,CAAC;IACD,MAAM,IAAI,cAAc,CACtB,yBAAyB,EACzB,IAAI,SAAS,uBAAuB,MAAM,CAAC,IAAI,mBAAmB,EAClE;QACE,OAAO,EAAE;YACP,MAAM,EAAE,MAAM,CAAC,IAAI;YACnB,SAAS;YACT,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC;YACvC,UAAU,EAAE,mBAAmB,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC;SACxD;KACF,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,GAA+B,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AAEnF,+EAA+E;AAC/E,MAAM,UAAU,gBAAgB,CAAC,MAA4B,EAAE,QAAoB,EAAE,SAAiB;IACpG,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpD,OAAO;IACT,CAAC;IACD,MAAM,IAAI,cAAc,CACtB,yBAAyB,EACzB,IAAI,SAAS,kBAAkB,QAAQ,0CAA0C,MAAM,CAAC,IAAI,GAAG,EAC/F;QACE,OAAO,EAAE;YACP,MAAM,EAAE,MAAM,CAAC,IAAI;YACnB,QAAQ;YACR,SAAS;YACT,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC;YACvC,UAAU,EAAE,yDAAyD,QAAQ,uBAAuB;SACrG;KACF,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAA4B,EAAE,SAAiB;IACnF,IAAI,SAAS,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;QACvC,OAAO;IACT,CAAC;IACD,MAAM,IAAI,cAAc,CACtB,uBAAuB,EACvB,mBAAmB,SAAS,gBAAgB,MAAM,CAAC,IAAI,0BAA0B,MAAM,CAAC,cAAc,GAAG,EACzG;QACE,OAAO,EAAE;YACP,MAAM,EAAE,MAAM,CAAC,IAAI;YACnB,KAAK,EAAE,MAAM,CAAC,cAAc;YAC5B,SAAS;YACT,UAAU,EAAE,mBAAmB,MAAM,CAAC,cAAc,qFAAqF;SAC1I;KACF,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,MAA4B,EAAE,SAAgC;IACnG,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;QAC1B,OAAO;IACT,CAAC;IACD,MAAM,IAAI,cAAc,CACtB,yBAAyB,EACzB,KAAK,SAAS,sBAAsB,MAAM,CAAC,IAAI,mBAAmB,EAClE;QACE,OAAO,EAAE;YACP,MAAM,EAAE,MAAM,CAAC,IAAI;YACnB,SAAS;YACT,OAAO,EAAE,KAAK;YACd,UAAU,EACR,oHAAoH;SACvH;KACF,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,OAAwB,EACxB,MAAiC,EACjC,SAAiB,EACjB,KAAa;IAEb,IAAI,SAAS,IAAI,KAAK,EAAE,CAAC;QACvB,OAAO;IACT,CAAC;IACD,MAAM,IAAI,cAAc,CACtB,2BAA2B,EAC3B,KAAK,MAAM,IAAI,SAAS,gBAAgB,OAAO,qBAAqB,KAAK,GAAG,EAC5E;QACE,OAAO,EAAE;YACP,OAAO;YACP,MAAM;YACN,SAAS;YACT,KAAK;YACL,UAAU,EAAE,uFAAuF;SACpG;KACF,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,MAA4B,EAC5B,OAAoC,EACpC,SAAkB;IAElB,OAAO,SAAS,IAAI,OAAO,KAAK,YAAY,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC;AACzG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,IAAI,CAAC;QACH,MAAM,QAAQ,GACZ,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC;QAClH,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;IAC9E,CAAC;AACH,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,aAAa,CAAC,MAA4B;IACxD,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,IAAI;QACnB,GAAG,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAA4B;IACzD,MAAM,KAAK,GAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,UAAU,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;IAC9C,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC;IAC9E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,93 @@
1
+ Copyright 2022 The Figtree Project Authors (https://github.com/erikdkennedy/figtree) Figtree-Italic[wght].ttf: Copyright 2022 The Figtree Project Authors (https://github.com/erikdkennedy/figtree)
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ http://scripts.sil.org/OFL
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,93 @@
1
+ Copyright 2016 The Space Mono Project Authors (https://github.com/googlefonts/spacemono) SpaceMono-Italic.ttf: Copyright 2016 The Space Mono Project Authors (https://github.com/googlefonts/spacemono) SpaceMono-Bold.ttf: Copyright 2016 The Space Mono Project Authors (https://github.com/googlefonts/spacemono) SpaceMono-BoldItalic.ttf: Copyright 2016 The Space Mono Project Authors (https://github.com/googlefonts/spacemono)
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ http://scripts.sil.org/OFL
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,23 @@
1
+ # Preview chrome fonts
2
+
3
+ These faces are bundled with the framework so the composition and timeline
4
+ preview pages render in a stable type system regardless of the project's own
5
+ font manifest. They are served from
6
+ `/__frameyard/framework/preview/fonts/` and are not exposed to compositions;
7
+ compositions keep using the project font sheet injected into their document
8
+ shell.
9
+
10
+ | Family | File | Weight | SHA-256 |
11
+ | --- | --- | --- | --- |
12
+ | Figtree | `figtree-latin-wght-normal.woff2` | 300–900 (variable) | `4ba7d3d096695818fe0686be4f1e82c6b05134e18a22260336130335027462dd` |
13
+ | Space Mono | `space-mono-latin-400-normal.woff2` | 400 | `fb4a81a2d0a893e5c38c394a7e716a1cef0b24610a0af49c96f6d529bd66bf2b` |
14
+ | Space Mono | `space-mono-latin-700-normal.woff2` | 700 | `2d46bd159b53f55c41167a4f1540a074649464194fd1e416f5b4694a6c0f282c` |
15
+
16
+ Sources (Fontsource 5.3.0):
17
+
18
+ - `https://cdn.jsdelivr.net/fontsource/fonts/figtree:vf@5.3.0/latin-wght-normal.woff2`
19
+ - `https://cdn.jsdelivr.net/fontsource/fonts/space-mono@5.3.0/latin-400-normal.woff2`
20
+ - `https://cdn.jsdelivr.net/fontsource/fonts/space-mono@5.3.0/latin-700-normal.woff2`
21
+
22
+ Both families are licensed under the SIL Open Font License 1.1; the license
23
+ texts are `LICENSE-figtree.txt` and `LICENSE-space-mono.txt`.
@@ -80,13 +80,16 @@ function updateTransport() {
80
80
  clockLabel.textContent = "0.00s";
81
81
  scrubber.max = "0";
82
82
  scrubber.value = "0";
83
+ scrubber.style.setProperty("--progress", "0%");
83
84
  return;
84
85
  }
86
+ const lastFrame = Math.max(0, metadata.durationInFrames - 1);
85
87
  frameLabel.textContent = String(currentFrame);
86
- durationLabel.textContent = String(metadata.durationInFrames - 1);
88
+ durationLabel.textContent = String(lastFrame);
87
89
  clockLabel.textContent = `${(currentFrame / metadata.fps).toFixed(2)}s`;
88
- scrubber.max = String(metadata.durationInFrames - 1);
90
+ scrubber.max = String(lastFrame);
89
91
  scrubber.value = String(currentFrame);
92
+ scrubber.style.setProperty("--progress", `${lastFrame > 0 ? (currentFrame / lastFrame) * 100 : 0}%`);
90
93
  }
91
94
  function setTransportEnabled(enabled) {
92
95
  playButton.disabled = !enabled;