@odori/cli 0.0.2 → 0.0.4

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 (41) hide show
  1. package/dist/{chunk-7XJL2BYO.js → chunk-NYXWEZU2.js} +717 -348
  2. package/dist/cli.js +1 -1
  3. package/dist/index.d.ts +63 -8
  4. package/dist/index.js +3 -3
  5. package/dist/registry-snapshot-MSH2EA36.js +4867 -0
  6. package/package.json +3 -3
  7. package/src/assets.ts +90 -0
  8. package/src/brand-file.ts +16 -4
  9. package/src/chunk-cache.ts +6 -0
  10. package/src/cli.ts +22 -12
  11. package/src/commands/add.ts +33 -8
  12. package/src/commands/dev.ts +114 -12
  13. package/src/commands/doctor.ts +47 -2
  14. package/src/commands/exportVideo.ts +39 -5
  15. package/src/commands/{still.ts → frame.ts} +23 -9
  16. package/src/commands/init.ts +1 -1
  17. package/src/commands/new.ts +1 -1
  18. package/src/cues.ts +34 -21
  19. package/src/discovery.ts +85 -5
  20. package/src/formats.ts +67 -8
  21. package/src/index.ts +1 -1
  22. package/src/jobs.ts +6 -2
  23. package/src/registry-snapshot.json +1530 -328
  24. package/src/registry-source.ts +87 -5
  25. package/src/render.ts +48 -13
  26. package/src/server.ts +55 -13
  27. package/studio/src/Studio.tsx +19 -22
  28. package/studio/src/components/ExportPanel.tsx +124 -90
  29. package/studio/src/components/Inspector.tsx +221 -0
  30. package/studio/src/components/Navigator.tsx +145 -0
  31. package/studio/src/components/Thumbnail.tsx +65 -23
  32. package/studio/src/components/ui.tsx +9 -2
  33. package/studio/src/lib/highlight.ts +85 -0
  34. package/studio/src/studio.css +435 -20
  35. package/studio/src/views/AssetsView.tsx +14 -1
  36. package/studio/src/views/BrandsView.tsx +74 -26
  37. package/studio/src/views/ComponentsView.tsx +206 -55
  38. package/studio/src/views/HomeView.tsx +44 -19
  39. package/studio/src/views/VideosView.tsx +53 -48
  40. package/studio/src/virtual.d.ts +4 -1
  41. package/dist/registry-snapshot-NIH2JMQ6.js +0 -3559
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  checkFlags,
3
3
  parseArgs,
4
4
  run
5
- } from "./chunk-7XJL2BYO.js";
5
+ } from "./chunk-NYXWEZU2.js";
6
6
  export {
7
7
  checkFlags,
8
8
  parseArgs,
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ViteDevServer } from 'vite';
2
2
  import * as odori from 'odori';
3
- import { VideoEntry, RenderManifest, AudioCue, ManifestAudioCue, ExportJob } from 'odori';
3
+ import { VideoEntry, RenderManifest, AudioCue, ManifestAudioCue, ExportJob, Duration } from 'odori';
4
4
  import { Browser, Page } from 'playwright-core';
5
5
  export { parseArgs, run } from './cli.js';
6
6
 
@@ -72,6 +72,8 @@ type DiscoveredPreview = {
72
72
  relativeFile: string;
73
73
  importPath: string;
74
74
  identifier: string;
75
+ /** Video ids whose composition imports this component. Derived, not declared. */
76
+ usedBy?: string[];
75
77
  };
76
78
  type DiscoveredBrandModule = {
77
79
  name: string;
@@ -87,11 +89,25 @@ type DiscoveredAudio = {
87
89
  relativeFile: string;
88
90
  bytes: number;
89
91
  };
92
+ /**
93
+ * A directory naming itself, from a `category.json` beside the components it
94
+ * holds. The path is what the filesystem already says; this is only how that
95
+ * level should read and where it should sit among its siblings.
96
+ */
97
+ type DiscoveredCategory = {
98
+ /** Directory path under the components directory: `product-ui/forms`. */
99
+ path: string;
100
+ /** What to call it. Without one, the directory name is read as words. */
101
+ name?: string;
102
+ /** Sort position among siblings. Unset sorts after, alphabetically. */
103
+ order?: number;
104
+ };
90
105
  type ProjectGraph = {
91
106
  videos: DiscoveredVideo[];
92
107
  previews: DiscoveredPreview[];
93
108
  brands: DiscoveredBrandModule[];
94
109
  audio: DiscoveredAudio[];
110
+ categories: DiscoveredCategory[];
95
111
  sourceHash: string;
96
112
  };
97
113
  /**
@@ -177,6 +193,16 @@ declare const freezeManifest: (video: LoadedVideo, graph: ProjectGraph, config:
177
193
  * concatenated without re-encoding. `chunked: false` says a format has to be
178
194
  * encoded in one pass, which is slower and correct.
179
195
  */
196
+ /** Compression tiers, named for where the file is going. */
197
+ type Quality = "studio" | "social" | "web";
198
+ type EncodeOptions = {
199
+ /** x264-style speed preset. Orthogonal to quality: it trades time, not pixels. */
200
+ preset: string;
201
+ /** Compression tier. Codecs that are already lossless or mandated ignore it. */
202
+ quality: Quality;
203
+ /** Output scale multiplier. 1 is the composition's own size. */
204
+ scale: number;
205
+ };
180
206
  type VideoFormat = {
181
207
  name: string;
182
208
  extension: string;
@@ -186,8 +212,8 @@ type VideoFormat = {
186
212
  chunked: boolean;
187
213
  /** Whether the container carries an audio track at all. */
188
214
  audio: boolean;
189
- /** FFmpeg arguments for the video stream, given the requested preset. */
190
- args: (preset: string) => string[];
215
+ /** FFmpeg arguments for the video stream. */
216
+ args: (options: EncodeOptions) => string[];
191
217
  description: string;
192
218
  };
193
219
  declare const FORMATS: Record<string, VideoFormat>;
@@ -234,7 +260,10 @@ type RenderPage = {
234
260
  declare const openRenderPage: (origin: string, target: RenderTarget, config: ResolvedConfig) => Promise<RenderPage>;
235
261
  /** Seek through the readiness handshake instead of guessing with timeouts. */
236
262
  declare const seekTo: (page: Page, frame: number) => Promise<void>;
237
- declare const readTimeline: (page: Page) => Promise<odori.CompiledTimeline>;
263
+ declare const readTimeline: (page: Page) => Promise<odori.CompiledTimeline | {
264
+ scenes: never[];
265
+ durationInFrames: number;
266
+ }>;
238
267
  declare const readAudio: (page: Page) => Promise<odori.AudioTrack>;
239
268
  declare const probeSignatures: (page: Page, frames: number[]) => Promise<string[]>;
240
269
  /** Kept for callers that only want to know an encoder exists. */
@@ -254,6 +283,10 @@ type RenderTimings = {
254
283
  type RenderOptions = {
255
284
  concurrency?: number;
256
285
  preset?: string;
286
+ /** Compression tier. Defaults to studio, which is what the pipeline always was. */
287
+ quality?: Quality;
288
+ /** Output scale multiplier. Defaults to 1, the composition's own size. */
289
+ scale?: number;
257
290
  /** Container and codec. Defaults to H.264 in MP4. */
258
291
  format?: VideoFormat;
259
292
  skipUnchangedFrames?: boolean;
@@ -298,16 +331,24 @@ type CompileResult = {
298
331
  declare const compileInBrowser: (origin: string, target: RenderTarget, config: ResolvedConfig) => Promise<CompileResult>;
299
332
  declare const withServer: <Value>(config: ResolvedConfig, handler: (server: StudioServer) => Promise<Value>) => Promise<Value>;
300
333
 
334
+ /** How a job should be encoded, frozen with it so a retry cannot drift. */
335
+ type JobRender = {
336
+ format?: string;
337
+ quality?: string;
338
+ scale?: number;
339
+ preset?: string;
340
+ };
301
341
  type JobRecord = {
302
342
  job: ExportJob;
303
343
  manifest: RenderManifest;
304
344
  output: string;
345
+ render?: JobRender;
305
346
  };
306
347
  /**
307
348
  * An export job records the frozen manifest, progress, attempts, and result,
308
349
  * so a retry reuses the approved inputs instead of resolving them again.
309
350
  */
310
- declare const createJob: (config: ResolvedConfig, manifest: RenderManifest, output: string) => Promise<JobRecord>;
351
+ declare const createJob: (config: ResolvedConfig, manifest: RenderManifest, output: string, render?: JobRender) => Promise<JobRecord>;
311
352
  declare const readJob: (config: ResolvedConfig, id: string) => Promise<JobRecord>;
312
353
  declare const updateJob: (config: ResolvedConfig, job: ExportJob) => Promise<ExportJob>;
313
354
  declare const appendJobLog: (config: ResolvedConfig, id: string, message: string) => Promise<ExportJob>;
@@ -494,6 +535,8 @@ declare const cancelJob: (id: string) => boolean;
494
535
  declare const runJob: (config: ResolvedConfig, origin: string, record: JobRecord, video: LoadedVideo, options?: {
495
536
  concurrency?: number;
496
537
  preset?: string;
538
+ quality?: Quality;
539
+ scale?: number;
497
540
  format?: VideoFormat;
498
541
  skipUnchangedFrames?: boolean;
499
542
  signal?: AbortSignal;
@@ -504,6 +547,8 @@ declare const exportCommand: (id: string, options?: {
504
547
  input?: Record<string, unknown>;
505
548
  concurrency?: number;
506
549
  preset?: string;
550
+ quality?: string;
551
+ scale?: number;
507
552
  format?: string;
508
553
  skipUnchangedFrames?: boolean;
509
554
  retry?: string;
@@ -542,8 +587,18 @@ type PlanOptions = {
542
587
  declare const planChunks: ({ durationInFrames, scenes, concurrency, maxChunkFrames, }: PlanOptions) => ChunkPlan;
543
588
  declare const chunkFrames: (chunk: FrameChunk) => number[];
544
589
 
545
- declare const stillCommand: (id: string, options?: {
546
- frame?: number;
590
+ /**
591
+ * One frame of a video, as a PNG.
592
+ *
593
+ * `at` is a duration like everything else in Odori: a bare number is seconds,
594
+ * and `120f` is frame 120. Which frame that resolves to depends on the
595
+ * video's frame rate, and the frame rate belongs to the video's layout, so
596
+ * the position is checked for shape first and resolved once the video is
597
+ * loaded. A typo still costs nothing: no discovery, no dev server, no
598
+ * browser.
599
+ */
600
+ declare const frameCommand: (id: string, options?: {
601
+ at?: Duration;
547
602
  output?: string;
548
603
  input?: Record<string, unknown>;
549
604
  }) => Promise<string>;
@@ -619,4 +674,4 @@ declare const newCommand: (name: string, options?: {
619
674
  /** Add the videos source root and configuration to an existing project. */
620
675
  declare const initCommand: (root?: string) => Promise<void>;
621
676
 
622
- export { CHROME_BUILD, type ChunkPlan, type CompileResult, type ComponentStatus, type Context, type DeterminismFinding, type DiffLine, FORMATS, type FrameChunk, JobQueue, type JobRecord, type LoadedVideo, type MixInput, type OdoriConfig, type ProjectGraph, type RenderOptions, type RenderTarget, type RenderTimings, type ResolvedBinary, type ResolvedConfig, type StudioServer, type VideoFormat, addCommand, alphaWarning, appendJobLog, buildAudioFilter, cacheRoot, cancelJob, checkDeterminism, chunkFrames, clearPrepareCache, compileInBrowser, componentStatus, countChanges, createContext, createIntegrityResolver, createJob, defaultConcurrency, defineConfig, devCommand, diffCommand, diffLines, discoverProject, ensureFfmpeg, exportCommand, exportQueue, fileKey, findVideo, formatDiff, formatNames, freezeManifest, generateImports, initCommand, inspectCommand, installBrowser, installFfmpeg, jobsCommand, listCommand, listJobs, loadConfig, loadVideos, localCandidates, newCommand, openRenderPage, outputName, planChunks, prepareCacheKey, probeSignatures, readAudio, readJob, readPrepareCache, readTimeline, reconcileJobs, renderMovie, renderStill, renderToolchain, resolveBrowser, resolveChromePath, resolveCueFile, resolveFfmpeg, resolveFormat, runJob, runPrepare, seekTo, startStudioServer, stillCommand, targetFor, testCommand, updateCommand, updateJob, withServer, writeGenerated, writePrepareCache };
677
+ export { CHROME_BUILD, type ChunkPlan, type CompileResult, type ComponentStatus, type Context, type DeterminismFinding, type DiffLine, FORMATS, type FrameChunk, JobQueue, type JobRecord, type LoadedVideo, type MixInput, type OdoriConfig, type ProjectGraph, type RenderOptions, type RenderTarget, type RenderTimings, type ResolvedBinary, type ResolvedConfig, type StudioServer, type VideoFormat, addCommand, alphaWarning, appendJobLog, buildAudioFilter, cacheRoot, cancelJob, checkDeterminism, chunkFrames, clearPrepareCache, compileInBrowser, componentStatus, countChanges, createContext, createIntegrityResolver, createJob, defaultConcurrency, defineConfig, devCommand, diffCommand, diffLines, discoverProject, ensureFfmpeg, exportCommand, exportQueue, fileKey, findVideo, formatDiff, formatNames, frameCommand, freezeManifest, generateImports, initCommand, inspectCommand, installBrowser, installFfmpeg, jobsCommand, listCommand, listJobs, loadConfig, loadVideos, localCandidates, newCommand, openRenderPage, outputName, planChunks, prepareCacheKey, probeSignatures, readAudio, readJob, readPrepareCache, readTimeline, reconcileJobs, renderMovie, renderStill, renderToolchain, resolveBrowser, resolveChromePath, resolveCueFile, resolveFfmpeg, resolveFormat, runJob, runPrepare, seekTo, startStudioServer, targetFor, testCommand, updateCommand, updateJob, withServer, writeGenerated, writePrepareCache };
package/dist/index.js CHANGED
@@ -30,6 +30,7 @@ import {
30
30
  findVideo,
31
31
  formatDiff,
32
32
  formatNames,
33
+ frameCommand,
33
34
  freezeManifest,
34
35
  generateImports,
35
36
  initCommand,
@@ -67,7 +68,6 @@ import {
67
68
  runPrepare,
68
69
  seekTo,
69
70
  startStudioServer,
70
- stillCommand,
71
71
  targetFor,
72
72
  testCommand,
73
73
  updateCommand,
@@ -75,7 +75,7 @@ import {
75
75
  withServer,
76
76
  writeGenerated,
77
77
  writePrepareCache
78
- } from "./chunk-7XJL2BYO.js";
78
+ } from "./chunk-NYXWEZU2.js";
79
79
  export {
80
80
  CHROME_BUILD,
81
81
  FORMATS,
@@ -108,6 +108,7 @@ export {
108
108
  findVideo,
109
109
  formatDiff,
110
110
  formatNames,
111
+ frameCommand,
111
112
  freezeManifest,
112
113
  generateImports,
113
114
  initCommand,
@@ -145,7 +146,6 @@ export {
145
146
  runPrepare,
146
147
  seekTo,
147
148
  startStudioServer,
148
- stillCommand,
149
149
  targetFor,
150
150
  testCommand,
151
151
  updateCommand,