frameyard 0.0.0-stage → 0.2.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 (131) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/GLOSSARY.md +145 -0
  3. package/LICENSE +21 -0
  4. package/README.md +311 -2
  5. package/dist/assets/executable.d.ts +16 -0
  6. package/dist/assets/executable.d.ts.map +1 -0
  7. package/dist/assets/executable.js +59 -0
  8. package/dist/assets/executable.js.map +1 -0
  9. package/dist/assets/files.d.ts +4 -0
  10. package/dist/assets/files.d.ts.map +1 -0
  11. package/dist/assets/files.js +30 -0
  12. package/dist/assets/files.js.map +1 -0
  13. package/dist/assets/integrations.d.ts +15 -0
  14. package/dist/assets/integrations.d.ts.map +1 -0
  15. package/dist/assets/integrations.js +15 -0
  16. package/dist/assets/integrations.js.map +1 -0
  17. package/dist/assets/process.d.ts +29 -0
  18. package/dist/assets/process.d.ts.map +1 -0
  19. package/dist/assets/process.js +97 -0
  20. package/dist/assets/process.js.map +1 -0
  21. package/dist/assets/provenance.d.ts +77 -0
  22. package/dist/assets/provenance.d.ts.map +1 -0
  23. package/dist/assets/provenance.js +302 -0
  24. package/dist/assets/provenance.js.map +1 -0
  25. package/dist/assets/transcribe.d.ts +38 -0
  26. package/dist/assets/transcribe.d.ts.map +1 -0
  27. package/dist/assets/transcribe.js +357 -0
  28. package/dist/assets/transcribe.js.map +1 -0
  29. package/dist/assets/tts.d.ts +29 -0
  30. package/dist/assets/tts.d.ts.map +1 -0
  31. package/dist/assets/tts.js +180 -0
  32. package/dist/assets/tts.js.map +1 -0
  33. package/dist/cli.d.ts +3 -0
  34. package/dist/cli.d.ts.map +1 -0
  35. package/dist/cli.js +795 -0
  36. package/dist/cli.js.map +1 -0
  37. package/dist/contracts.d.ts +106 -0
  38. package/dist/contracts.d.ts.map +1 -0
  39. package/dist/contracts.js +297 -0
  40. package/dist/contracts.js.map +1 -0
  41. package/dist/doctor.d.ts +56 -0
  42. package/dist/doctor.d.ts.map +1 -0
  43. package/dist/doctor.js +476 -0
  44. package/dist/doctor.js.map +1 -0
  45. package/dist/errors.d.ts +10 -0
  46. package/dist/errors.d.ts.map +1 -0
  47. package/dist/errors.js +18 -0
  48. package/dist/errors.js.map +1 -0
  49. package/dist/index.d.ts +8 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +5 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/preview/main.d.ts +19 -0
  54. package/dist/preview/main.d.ts.map +1 -0
  55. package/dist/preview/main.js +480 -0
  56. package/dist/preview/main.js.map +1 -0
  57. package/dist/project.d.ts +16 -0
  58. package/dist/project.d.ts.map +1 -0
  59. package/dist/project.js +88 -0
  60. package/dist/project.js.map +1 -0
  61. package/dist/renderer/audio.d.ts +31 -0
  62. package/dist/renderer/audio.d.ts.map +1 -0
  63. package/dist/renderer/audio.js +88 -0
  64. package/dist/renderer/audio.js.map +1 -0
  65. package/dist/renderer/browser.d.ts +22 -0
  66. package/dist/renderer/browser.d.ts.map +1 -0
  67. package/dist/renderer/browser.js +175 -0
  68. package/dist/renderer/browser.js.map +1 -0
  69. package/dist/renderer/ffmpeg.d.ts +58 -0
  70. package/dist/renderer/ffmpeg.d.ts.map +1 -0
  71. package/dist/renderer/ffmpeg.js +268 -0
  72. package/dist/renderer/ffmpeg.js.map +1 -0
  73. package/dist/renderer/index.d.ts +72 -0
  74. package/dist/renderer/index.d.ts.map +1 -0
  75. package/dist/renderer/index.js +281 -0
  76. package/dist/renderer/index.js.map +1 -0
  77. package/dist/renderer/transcripts.d.ts +30 -0
  78. package/dist/renderer/transcripts.d.ts.map +1 -0
  79. package/dist/renderer/transcripts.js +86 -0
  80. package/dist/renderer/transcripts.js.map +1 -0
  81. package/dist/runtime/clock.d.ts +5 -0
  82. package/dist/runtime/clock.d.ts.map +1 -0
  83. package/dist/runtime/clock.js +16 -0
  84. package/dist/runtime/clock.js.map +1 -0
  85. package/dist/runtime/index.d.ts +29 -0
  86. package/dist/runtime/index.d.ts.map +1 -0
  87. package/dist/runtime/index.js +289 -0
  88. package/dist/runtime/index.js.map +1 -0
  89. package/dist/runtime/random.d.ts +8 -0
  90. package/dist/runtime/random.d.ts.map +1 -0
  91. package/dist/runtime/random.js +21 -0
  92. package/dist/runtime/random.js.map +1 -0
  93. package/dist/scaffold.d.ts +3 -0
  94. package/dist/scaffold.d.ts.map +1 -0
  95. package/dist/scaffold.js +176 -0
  96. package/dist/scaffold.js.map +1 -0
  97. package/dist/server/preview-html.d.ts +2 -0
  98. package/dist/server/preview-html.d.ts.map +1 -0
  99. package/dist/server/preview-html.js +229 -0
  100. package/dist/server/preview-html.js.map +1 -0
  101. package/dist/server/server.d.ts +17 -0
  102. package/dist/server/server.d.ts.map +1 -0
  103. package/dist/server/server.js +237 -0
  104. package/dist/server/server.js.map +1 -0
  105. package/dist/transcript.d.ts +44 -0
  106. package/dist/transcript.d.ts.map +1 -0
  107. package/dist/transcript.js +130 -0
  108. package/dist/transcript.js.map +1 -0
  109. package/dist/version.d.ts +2 -0
  110. package/dist/version.d.ts.map +1 -0
  111. package/dist/version.js +2 -0
  112. package/dist/version.js.map +1 -0
  113. package/docs/adr/0001-keep-composition-authoring-web-native.md +3 -0
  114. package/docs/adr/0002-make-frame-and-props-the-only-animation-state.md +3 -0
  115. package/docs/adr/0003-render-browser-frames-offline.md +3 -0
  116. package/docs/adr/0004-produce-local-ai-assets-outside-rendering.md +3 -0
  117. package/docs/v0.1-design.md +238 -0
  118. package/examples/demo/README.md +24 -0
  119. package/examples/demo/assets/chime.wav +0 -0
  120. package/examples/demo/compositions/demo.js +206 -0
  121. package/examples/demo/props/demo.json +5 -0
  122. package/examples/demo/video.config.js +5 -0
  123. package/package.json +73 -3
  124. package/skills/frameyard/README.md +35 -0
  125. package/skills/frameyard/SKILL.md +60 -0
  126. package/skills/frameyard/references/audio-assets.md +86 -0
  127. package/skills/frameyard/references/deterministic-authoring.md +107 -0
  128. package/skills/frameyard/references/failure-recovery.md +57 -0
  129. package/skills/frameyard/references/json-results.md +203 -0
  130. package/skills/frameyard/references/subtitles-karaoke.md +95 -0
  131. package/skills/frameyard/scripts/frameyard.mjs +60 -0
@@ -0,0 +1,229 @@
1
+ const IMPORT_MAP = JSON.stringify({
2
+ imports: {
3
+ frameyard: "/__frameyard/framework/index.js",
4
+ "frameyard/runtime": "/__frameyard/framework/runtime/index.js",
5
+ },
6
+ }, null, 2);
7
+ export function renderPreviewHtml() {
8
+ return `<!doctype html>
9
+ <html lang="en">
10
+ <head>
11
+ <meta charset="utf-8" />
12
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
13
+ <title>Frameyard Preview</title>
14
+ <script type="importmap">${IMPORT_MAP}</script>
15
+ <style>
16
+ :root {
17
+ color-scheme: dark;
18
+ --bg: #0b0d10;
19
+ --panel: #11151a;
20
+ --panel-2: #171c23;
21
+ --line: #252c35;
22
+ --text: #e8edf3;
23
+ --muted: #8a97a6;
24
+ --accent: #b8f36b;
25
+ --accent-ink: #101408;
26
+ --danger: #ff8a8a;
27
+ --mono: "SFMono-Regular", ui-monospace, "Cascadia Code", "Liberation Mono", monospace;
28
+ --sans: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
29
+ }
30
+ * { box-sizing: border-box; }
31
+ html, body { height: 100%; }
32
+ body {
33
+ margin: 0;
34
+ background: var(--bg);
35
+ color: var(--text);
36
+ font-family: var(--sans);
37
+ font-size: 13px;
38
+ overflow: hidden;
39
+ }
40
+ #app {
41
+ display: grid;
42
+ grid-template-columns: 340px minmax(0, 1fr);
43
+ grid-template-rows: 54px minmax(0, 1fr) 58px;
44
+ height: 100vh;
45
+ }
46
+ .topbar {
47
+ grid-column: 1 / -1;
48
+ display: flex;
49
+ align-items: center;
50
+ gap: 22px;
51
+ padding: 0 18px;
52
+ border-bottom: 1px solid var(--line);
53
+ background: linear-gradient(180deg, #11151a, #0d1014);
54
+ }
55
+ .brand { display: flex; align-items: center; gap: 9px; font-weight: 650; letter-spacing: -0.01em; }
56
+ .mark {
57
+ width: 17px; height: 17px; border-radius: 4px;
58
+ background: linear-gradient(135deg, var(--accent), #5fd6ff);
59
+ box-shadow: 0 0 18px rgba(184, 243, 107, 0.3);
60
+ }
61
+ .tag { color: var(--muted); font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.1em; }
62
+ .comp { display: flex; align-items: center; gap: 8px; color: var(--muted); }
63
+ select, textarea, input { font: inherit; }
64
+ select {
65
+ background: var(--panel-2);
66
+ color: var(--text);
67
+ border: 1px solid var(--line);
68
+ border-radius: 6px;
69
+ padding: 6px 9px;
70
+ min-width: 160px;
71
+ }
72
+ .meta { margin-left: auto; color: var(--muted); font-family: var(--mono); font-size: 11px; }
73
+ .panel {
74
+ grid-row: 2 / 4;
75
+ display: flex;
76
+ flex-direction: column;
77
+ gap: 12px;
78
+ padding: 16px;
79
+ border-right: 1px solid var(--line);
80
+ background: var(--panel);
81
+ min-height: 0;
82
+ }
83
+ .field { display: flex; flex-direction: column; gap: 7px; min-height: 0; flex: 1; }
84
+ .field-head { display: flex; align-items: center; justify-content: space-between; color: var(--muted); }
85
+ .field-head label { font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; }
86
+ textarea {
87
+ flex: 1;
88
+ min-height: 160px;
89
+ resize: none;
90
+ background: var(--bg);
91
+ color: var(--text);
92
+ border: 1px solid var(--line);
93
+ border-radius: 7px;
94
+ padding: 11px;
95
+ font-family: var(--mono);
96
+ font-size: 12px;
97
+ line-height: 1.55;
98
+ tab-size: 2;
99
+ }
100
+ textarea:focus, select:focus, input:focus-visible, button:focus-visible {
101
+ outline: 2px solid color-mix(in srgb, var(--accent) 65%, transparent);
102
+ outline-offset: 1px;
103
+ }
104
+ button {
105
+ border: 1px solid var(--line);
106
+ background: var(--panel-2);
107
+ color: var(--text);
108
+ border-radius: 6px;
109
+ padding: 8px 12px;
110
+ cursor: pointer;
111
+ }
112
+ button:hover { border-color: #3a4654; }
113
+ button:disabled { opacity: 0.45; cursor: default; }
114
+ .primary {
115
+ background: var(--accent);
116
+ border-color: var(--accent);
117
+ color: var(--accent-ink);
118
+ font-weight: 700;
119
+ }
120
+ .ghost { background: transparent; border-color: transparent; color: var(--muted); }
121
+ .ghost:hover { color: var(--text); border-color: var(--line); }
122
+ .small { padding: 3px 7px; font-size: 11px; }
123
+ .error {
124
+ border: 1px solid color-mix(in srgb, var(--danger) 42%, var(--line));
125
+ background: color-mix(in srgb, var(--danger) 9%, var(--panel));
126
+ color: var(--danger);
127
+ border-radius: 7px;
128
+ padding: 10px 11px;
129
+ font-family: var(--mono);
130
+ font-size: 11px;
131
+ line-height: 1.5;
132
+ white-space: pre-wrap;
133
+ max-height: 30vh;
134
+ overflow: auto;
135
+ }
136
+ .hint { color: var(--muted); font-size: 11px; line-height: 1.5; }
137
+ .hint code { font-family: var(--mono); color: #b9c5d2; }
138
+ .viewport {
139
+ grid-row: 2;
140
+ grid-column: 2;
141
+ display: flex;
142
+ align-items: center;
143
+ justify-content: center;
144
+ overflow: hidden;
145
+ padding: 24px;
146
+ background:
147
+ radial-gradient(circle at 50% 40%, #161b22 0%, transparent 55%),
148
+ repeating-conic-gradient(#0d1014 0% 25%, #0b0d10 0% 50%) 50% / 24px 24px;
149
+ }
150
+ .stage-wrap { position: relative; flex: 0 0 auto; }
151
+ .stage { transform-origin: top left; overflow: hidden; background: #000; }
152
+ .transport {
153
+ grid-row: 3;
154
+ grid-column: 2;
155
+ display: flex;
156
+ align-items: center;
157
+ gap: 14px;
158
+ padding: 0 18px;
159
+ border-top: 1px solid var(--line);
160
+ background: var(--panel);
161
+ }
162
+ .play {
163
+ width: 34px; height: 34px; padding: 0; border-radius: 50%;
164
+ background: var(--text); color: var(--bg); font-size: 12px; font-weight: 800;
165
+ }
166
+ .scrub { flex: 1; accent-color: var(--accent); }
167
+ .readout { display: flex; align-items: baseline; gap: 5px; font-family: var(--mono); font-size: 11px; white-space: nowrap; }
168
+ .readout .dim { color: #5c6875; }
169
+ .clock { margin-left: 8px; color: var(--accent); }
170
+ .audio { display: flex; align-items: center; gap: 7px; color: var(--muted); font-family: var(--mono); font-size: 11px; }
171
+ .audio input[type="range"] { width: 72px; accent-color: var(--accent); }
172
+
173
+ body.render #app { display: block; height: auto; }
174
+ body.render .topbar, body.render .panel, body.render .transport { display: none; }
175
+ body.render .viewport {
176
+ position: fixed;
177
+ inset: 0;
178
+ display: block;
179
+ padding: 0;
180
+ overflow: hidden;
181
+ background: #000;
182
+ }
183
+ body.render .stage-wrap { position: absolute; inset: 0; width: auto !important; height: auto !important; }
184
+ body.render .stage { transform: none !important; }
185
+ </style>
186
+ </head>
187
+ <body>
188
+ <div id="app">
189
+ <header class="topbar">
190
+ <div class="brand"><span class="mark"></span>frameyard <span class="tag">preview</span></div>
191
+ <label class="comp">Composition <select id="composition"></select></label>
192
+ <div id="meta" class="meta"></div>
193
+ </header>
194
+ <aside id="panel" class="panel">
195
+ <div class="field">
196
+ <div class="field-head">
197
+ <label for="props">Props (JSON)</label>
198
+ <button id="format" class="ghost small" type="button">Format</button>
199
+ </div>
200
+ <textarea id="props" spellcheck="false" autocomplete="off"></textarea>
201
+ </div>
202
+ <button id="apply" class="primary" type="button">Apply props</button>
203
+ <div id="error" class="error" role="alert" hidden></div>
204
+ <div class="hint">
205
+ Frames are derived from <code>frame</code> and <code>props</code> only.
206
+ Wall-clock animation and unseeded randomness are not deterministic.
207
+ </div>
208
+ </aside>
209
+ <main id="viewport" class="viewport">
210
+ <div id="stage-wrap" class="stage-wrap"><div id="stage" class="stage"></div></div>
211
+ </main>
212
+ <footer class="transport">
213
+ <button id="play" class="play" type="button" aria-label="Play">&#9654;</button>
214
+ <input id="scrub" class="scrub" type="range" min="0" max="0" value="0" step="1" aria-label="Frame" />
215
+ <div class="readout">
216
+ <span id="frame">0</span><span class="dim">/</span><span id="duration">0</span><span class="dim">f</span>
217
+ <span id="clock" class="clock">0.00s</span>
218
+ </div>
219
+ <label class="audio">
220
+ <input id="mute" type="checkbox" /> mute
221
+ <input id="volume" type="range" min="0" max="1" step="0.01" value="0.8" aria-label="Audio volume" />
222
+ </label>
223
+ </footer>
224
+ </div>
225
+ <script type="module" src="/__frameyard/framework/preview/main.js"></script>
226
+ </body>
227
+ </html>`;
228
+ }
229
+ //# sourceMappingURL=preview-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-html.js","sourceRoot":"","sources":["../../src/server/preview-html.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAC/B;IACE,OAAO,EAAE;QACP,SAAS,EAAE,iCAAiC;QAC5C,mBAAmB,EAAE,yCAAyC;KAC/D;CACF,EACD,IAAI,EACJ,CAAC,CACF,CAAC;AAEF,MAAM,UAAU,iBAAiB;IAC/B,OAAO;;;;;;2BAMkB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAqN7B,CAAC;AACT,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { type Project } from "../project.js";
2
+ export interface PreviewServer {
3
+ readonly url: string;
4
+ readonly port: number;
5
+ readonly host: string;
6
+ readonly project: Project;
7
+ close(): Promise<void>;
8
+ }
9
+ export interface PreviewServerOptions {
10
+ projectRoot: string;
11
+ port?: number;
12
+ host?: string;
13
+ /** Overrides the directory containing built framework browser modules. */
14
+ frameworkDir?: string;
15
+ }
16
+ export declare function startPreviewServer(options: PreviewServerOptions): Promise<PreviewServer>;
17
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAMA,OAAO,EAAe,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAG1D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA+JD,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CAmG9F"}
@@ -0,0 +1,237 @@
1
+ import { createReadStream } from "node:fs";
2
+ import { stat } from "node:fs/promises";
3
+ import { createServer } from "node:http";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { FrameyardError } from "../errors.js";
7
+ import { loadProject } from "../project.js";
8
+ import { renderPreviewHtml } from "./preview-html.js";
9
+ const MIME_TYPES = {
10
+ ".avif": "image/avif",
11
+ ".css": "text/css; charset=utf-8",
12
+ ".gif": "image/gif",
13
+ ".html": "text/html; charset=utf-8",
14
+ ".ico": "image/x-icon",
15
+ ".jpeg": "image/jpeg",
16
+ ".jpg": "image/jpeg",
17
+ ".js": "text/javascript; charset=utf-8",
18
+ ".json": "application/json; charset=utf-8",
19
+ ".m4a": "audio/mp4",
20
+ ".map": "application/json; charset=utf-8",
21
+ ".mjs": "text/javascript; charset=utf-8",
22
+ ".mp3": "audio/mpeg",
23
+ ".mp4": "video/mp4",
24
+ ".ogg": "audio/ogg",
25
+ ".otf": "font/otf",
26
+ ".png": "image/png",
27
+ ".srt": "application/x-subrip; charset=utf-8",
28
+ ".svg": "image/svg+xml",
29
+ ".ttf": "font/ttf",
30
+ ".txt": "text/plain; charset=utf-8",
31
+ ".vtt": "text/vtt; charset=utf-8",
32
+ ".wav": "audio/wav",
33
+ ".webm": "video/webm",
34
+ ".webp": "image/webp",
35
+ ".woff": "font/woff",
36
+ ".woff2": "font/woff2",
37
+ };
38
+ function contentType(filePath) {
39
+ return MIME_TYPES[path.extname(filePath).toLowerCase()] ?? "application/octet-stream";
40
+ }
41
+ function resolveInside(base, relativePath) {
42
+ if (relativePath.includes("\0")) {
43
+ return null;
44
+ }
45
+ const absolute = path.resolve(base, relativePath);
46
+ if (absolute !== base && !absolute.startsWith(base + path.sep)) {
47
+ return null;
48
+ }
49
+ return absolute;
50
+ }
51
+ function sendJson(response, status, value) {
52
+ const body = `${JSON.stringify(value)}\n`;
53
+ response.writeHead(status, {
54
+ "Content-Type": "application/json; charset=utf-8",
55
+ "Content-Length": Buffer.byteLength(body),
56
+ "Cache-Control": "no-store",
57
+ });
58
+ response.end(body);
59
+ }
60
+ function parseRange(header, size) {
61
+ if (!header) {
62
+ return null;
63
+ }
64
+ const match = /^bytes=(\d*)-(\d*)$/.exec(header.trim());
65
+ if (!match) {
66
+ return "invalid";
67
+ }
68
+ const [, rawStart, rawEnd] = match;
69
+ let start;
70
+ let end;
71
+ if (rawStart === "") {
72
+ const suffix = Number(rawEnd);
73
+ if (!Number.isInteger(suffix) || suffix <= 0) {
74
+ return "invalid";
75
+ }
76
+ start = Math.max(0, size - suffix);
77
+ end = size - 1;
78
+ }
79
+ else {
80
+ start = Number(rawStart);
81
+ end = rawEnd === "" ? size - 1 : Number(rawEnd);
82
+ }
83
+ if (!Number.isInteger(start) || !Number.isInteger(end) || start < 0 || end < start || start >= size) {
84
+ return "invalid";
85
+ }
86
+ return { start, end: Math.min(end, size - 1) };
87
+ }
88
+ async function serveFile(request, response, base, relativePath) {
89
+ let filePath = resolveInside(base, relativePath);
90
+ if (!filePath) {
91
+ sendJson(response, 404, { error: "Not found" });
92
+ return;
93
+ }
94
+ let fileStat;
95
+ try {
96
+ fileStat = await stat(filePath);
97
+ if (fileStat.isDirectory()) {
98
+ filePath = path.join(filePath, "index.html");
99
+ fileStat = await stat(filePath);
100
+ }
101
+ }
102
+ catch {
103
+ sendJson(response, 404, { error: "Not found" });
104
+ return;
105
+ }
106
+ if (!fileStat.isFile()) {
107
+ sendJson(response, 404, { error: "Not found" });
108
+ return;
109
+ }
110
+ const range = parseRange(request.headers.range, fileStat.size);
111
+ if (range === "invalid") {
112
+ response.writeHead(416, {
113
+ "Content-Range": `bytes */${fileStat.size}`,
114
+ "Cache-Control": "no-store",
115
+ });
116
+ response.end();
117
+ return;
118
+ }
119
+ const headers = {
120
+ "Content-Type": contentType(filePath),
121
+ "Accept-Ranges": "bytes",
122
+ "Cache-Control": "no-store",
123
+ };
124
+ if (range) {
125
+ headers["Content-Range"] = `bytes ${range.start}-${range.end}/${fileStat.size}`;
126
+ headers["Content-Length"] = range.end - range.start + 1;
127
+ response.writeHead(206, headers);
128
+ if (request.method === "HEAD") {
129
+ response.end();
130
+ return;
131
+ }
132
+ createReadStream(filePath, { start: range.start, end: range.end })
133
+ .on("error", () => response.destroy())
134
+ .pipe(response);
135
+ return;
136
+ }
137
+ headers["Content-Length"] = fileStat.size;
138
+ response.writeHead(200, headers);
139
+ if (request.method === "HEAD") {
140
+ response.end();
141
+ return;
142
+ }
143
+ createReadStream(filePath)
144
+ .on("error", () => response.destroy())
145
+ .pipe(response);
146
+ }
147
+ export async function startPreviewServer(options) {
148
+ const project = await loadProject(options.projectRoot);
149
+ const frameworkDir = options.frameworkDir ?? path.join(fileURLToPath(new URL("../../", import.meta.url)), "dist");
150
+ const host = options.host ?? "127.0.0.1";
151
+ const html = renderPreviewHtml();
152
+ const projectJson = {
153
+ compositions: Array.from(project.compositions.values(), ({ id, entry }) => ({ id, entry })),
154
+ };
155
+ const server = createServer((request, response) => {
156
+ void (async () => {
157
+ if (request.method !== "GET" && request.method !== "HEAD") {
158
+ response.writeHead(405, { Allow: "GET, HEAD" });
159
+ response.end();
160
+ return;
161
+ }
162
+ let pathname;
163
+ try {
164
+ pathname = decodeURIComponent(new URL(request.url ?? "/", "http://localhost").pathname);
165
+ }
166
+ catch {
167
+ sendJson(response, 400, { error: "Invalid URL" });
168
+ return;
169
+ }
170
+ if (pathname === "/") {
171
+ response.writeHead(302, { Location: "/__frameyard/", "Cache-Control": "no-store" });
172
+ response.end();
173
+ return;
174
+ }
175
+ if (pathname === "/__frameyard") {
176
+ response.writeHead(302, { Location: "/__frameyard/", "Cache-Control": "no-store" });
177
+ response.end();
178
+ return;
179
+ }
180
+ if (pathname === "/__frameyard/") {
181
+ response.writeHead(200, {
182
+ "Content-Type": "text/html; charset=utf-8",
183
+ "Content-Length": Buffer.byteLength(html),
184
+ "Cache-Control": "no-store",
185
+ });
186
+ response.end(request.method === "HEAD" ? undefined : html);
187
+ return;
188
+ }
189
+ if (pathname === "/__frameyard/project.json") {
190
+ sendJson(response, 200, projectJson);
191
+ return;
192
+ }
193
+ if (pathname.startsWith("/__frameyard/framework/")) {
194
+ await serveFile(request, response, frameworkDir, pathname.slice("/__frameyard/framework/".length));
195
+ return;
196
+ }
197
+ await serveFile(request, response, project.root, pathname.slice(1));
198
+ })().catch((error) => {
199
+ if (!response.headersSent) {
200
+ sendJson(response, 500, {
201
+ error: error instanceof Error ? error.message : String(error),
202
+ });
203
+ }
204
+ else {
205
+ response.destroy();
206
+ }
207
+ });
208
+ });
209
+ await new Promise((resolve, reject) => {
210
+ server.once("error", reject);
211
+ server.listen(options.port ?? 5173, host, () => {
212
+ server.off("error", reject);
213
+ resolve();
214
+ });
215
+ });
216
+ const address = server.address();
217
+ if (!address || typeof address === "string") {
218
+ server.close();
219
+ throw new FrameyardError("INTERNAL", "Preview server did not expose a TCP address.");
220
+ }
221
+ const displayHost = host === "0.0.0.0" || host === "::" ? "127.0.0.1" : host;
222
+ const url = `http://${displayHost}:${address.port}/`;
223
+ return {
224
+ url,
225
+ port: address.port,
226
+ host,
227
+ project,
228
+ close: async () => {
229
+ const closed = new Promise((resolve, reject) => {
230
+ server.close((error) => (error ? reject(error) : resolve()));
231
+ });
232
+ server.closeAllConnections();
233
+ await closed;
234
+ },
235
+ };
236
+ }
237
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ export declare const TRANSCRIPT_SCHEMA_VERSION = 1;
2
+ export interface TranscriptSource {
3
+ /** Project-relative path when the source is inside the project; otherwise an absolute path. */
4
+ path: string;
5
+ sha256: string;
6
+ bytes: number;
7
+ }
8
+ export interface TranscriptSegment {
9
+ /** Integer milliseconds from the start of the source audio. */
10
+ startMs: number;
11
+ /** Integer milliseconds from the start of the source audio. */
12
+ endMs: number;
13
+ text: string;
14
+ }
15
+ export interface WordTiming {
16
+ /** Integer milliseconds from the start of the source audio. */
17
+ startMs: number;
18
+ /** Integer milliseconds from the start of the source audio. */
19
+ endMs: number;
20
+ text: string;
21
+ }
22
+ export interface Transcript {
23
+ schemaVersion: typeof TRANSCRIPT_SCHEMA_VERSION;
24
+ text: string;
25
+ language?: string;
26
+ source: TranscriptSource;
27
+ segments: TranscriptSegment[];
28
+ /** Measured word timings. Never interpolated from segment timings. */
29
+ words?: WordTiming[];
30
+ }
31
+ export interface ParseTranscriptOptions {
32
+ /** Fail when the transcript has no actual word timings. */
33
+ requireWords?: boolean;
34
+ }
35
+ /**
36
+ * Validates a canonical Frameyard transcript and returns a normalized copy.
37
+ * Timestamps stay in integer milliseconds relative to the source audio.
38
+ */
39
+ export declare function parseTranscript(value: unknown, options?: ParseTranscriptOptions): Transcript;
40
+ /** Renders the canonical transcript's segment timings as SRT. */
41
+ export declare function transcriptToSrt(transcript: Transcript): string;
42
+ /** Renders the canonical transcript's segment timings as WebVTT. */
43
+ export declare function transcriptToVtt(transcript: Transcript): string;
44
+ //# sourceMappingURL=transcript.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript.d.ts","sourceRoot":"","sources":["../src/transcript.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAC/B,+FAA+F;IAC/F,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,OAAO,yBAAyB,CAAC;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,gBAAgB,CAAC;IACzB,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,sEAAsE;IACtE,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,2DAA2D;IAC3D,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AA0DD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,sBAA2B,GAAG,UAAU,CA6DhG;AAYD,iEAAiE;AACjE,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAW9D;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAM9D"}