@vosjs/studio-core 0.4.0 → 0.4.1

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 (2) hide show
  1. package/README.md +69 -52
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -1,69 +1,86 @@
1
- # @vosso/studio-core
1
+ # @vosjs/studio-core
2
2
 
3
- The studio's editing model. This package holds the product opinions that turn a raw
4
- screen recording into an editable, re-renderable video: the `ProjectDoc` schema,
5
- the element-aware auto-zoom planner, and the lowering that compiles a doc down to
6
- a vos composition.
3
+ > The document model of a screen recording: the `ProjectDoc` schema, the planners that read a cursor track (auto-zoom, speed, tilt), the digest that lets an agent see a recording, and the lowering from a document to a vos program.
7
4
 
8
- It is pure logic — no DOM, no React, no vos-render dependency. The generic
9
- editing mechanisms (patch store, edit classifier, editor-bridge client, timeline
10
- view-model) live in the open-source [`@vosjs/editor`](https://www.npmjs.com/package/@vosjs/editor);
11
- what stays here is studio-specific. Consumed in-source by the vosso web app and bundled
12
- into [`@vosso/vos-plugin`](../vos-plugin). MIT.
5
+ [![npm](https://img.shields.io/npm/v/@vosjs/studio-core.svg)](https://www.npmjs.com/package/@vosjs/studio-core)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/vosjs/vos/blob/main/LICENSE)
7
+
8
+ Part of [vos](https://github.com/vosjs/vos), the open programmatic video engine behind [vos.so](https://vos.so). This package holds the opinions that turn raw footage plus a cursor track into an editable, re-renderable video. It is pure logic: no DOM, no React, no engine import at run time (`@vosjs/core` is a peer for types). The generic editing mechanics (patch store, edit classifier, bridge client, view-model math) live in [`@vosjs/editor`](../editor); the time math in [`@vosjs/timeline`](../timeline). The `vos` CLI and the vos.so studio both build on this package, so a document cut on the command line opens in the studio with every span intact.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ pnpm add @vosjs/studio-core
14
+ ```
13
15
 
14
16
  ## The pipeline
15
17
 
16
18
  ```
17
- RecordingArtifact ──projectFromArtifact──▶ ProjectDoc ──lowerToComposition──▶ { config, data, duration }
18
- (footage + (normalize capture (editable (constant program +
19
- cursor track) space, plan zoom) document) ctx.data live edits)
19
+ RecordingArtifact ──projectFromArtifact──▶ ProjectDoc ──lowerStudioDoc──▶ { config, data, stack, duration }
20
+ (footage + cursor track) normalize capture space, (doc.json: the constant program + ctx.data,
21
+ plan zoom / speed / tilt editable surface) so every edit is live
20
22
  ```
21
23
 
22
- - **`projectFromArtifact(artifact)`** build the initial `ProjectDoc` from a
23
- recording: normalize the capture space (`normalizeCaptureSpace`, viewport crop
24
- for window takes), then seed auto-zoom.
25
- - **`planAutoZoom(doc, options)`** — element-aware zoom planner. Emits
26
- `source: 'auto'` spans from click/dwell clusters; honors the wand contract
27
- (never touches `source: 'manual'` spans). Camera dynamics come from a named
28
- style preset (`ZOOM_STYLES` glide / focus / cinema / snappy / cut).
29
- - **`lowerToComposition(doc)`** — lower the doc to a **constant** vos program
30
- plus a `ctx.data` payload. Zoom spans expand into an output-time keyframe
31
- track; trims, speed, cursor follow, click effects, and audio envelopes all bake
32
- into `data`. Because the program string is constant, edits replay live via
33
- `SET_DATA`/`SET_DURATION` — nothing recompiles for a retime or a zoom tweak.
34
-
35
- ## Key exports
36
-
37
- | Area | Exports |
38
- | -------------- | ----------------------------------------------------------------------------------------------------------------------------- |
39
- | Ingest | `projectFromArtifact` |
40
- | Capture space | `normalizeCaptureSpace`, `deriveViewportCrop`, `docToCropSpace`, `docToFullSpace`, `CAPTURE_COVERAGE_MIN`, `WINDOW_FOCUS_MIN` |
41
- | Planner | `planAutoZoom`, `smoothCursor` |
42
- | Zoom styles | `ZOOM_STYLES`, `DEFAULT_ZOOM_STYLE`, `resolveZoomStyle` |
43
- | Lowering | `lowerToComposition`, `zoomTrackFromDoc`, `followFocusEvents`, `extractClicks`, `ratedSegments` |
44
- | Layout / focus | `computeCardLayout`, `docCardLayout`, `focusBounds`, `clampFocus`, `recommendedExportResolution` |
45
- | Audio | `clipEnvelope`, `duckCurve`, `computePeaks`, `computeMicRms` |
46
- | Timeline lanes | `zoomLane`, `speedLane`, `camLane`, `audioLane`, `videoLane` |
47
-
48
- See [`src/types.ts`](src/types.ts) for the full `ProjectDoc` shape.
24
+ - **`projectFromArtifact(artifact, videoUrl, { frame? })`** builds the initial `ProjectDoc` from a recording: normalize the capture space (`normalizeCaptureSpace`; a viewport crop for window takes via `deriveViewportCrop`, fail-closed below `CAPTURE_COVERAGE_MIN`), then seed the automatic spans. Returns `{ doc, videoUrl }`.
25
+ - **The planners** read the cursor track, never the pixels. `planAutoZoom(track, { width, height, style?, params? })` emits `source: 'auto'` zoom spans from click clusters (`z…`), typing sessions (`k…`) and dwells (`d…`); `planAutoSpeed` proposes speed-ups over idle gaps and scroll runs; `planAutoTilt` leans the card toward each zoom's focus. Every planner honors the wand contract: `source: 'manual'` spans are never touched, and a deleted proposal stays deleted (`rejectSpan` writes `doc.rejected`, `isRejected` filters the next plan).
26
+ - **`lowerStudioDoc(doc)`** lowers a document to a constant vos program plus a `ctx.data` payload. Zoom, tilt and cam-motion spans expand into output-time keyframe tracks; trims, speed, cursor follow, click effects and audio envelopes all bake into data. Because the program string is constant, edits replay live through `SET_DATA` and `SET_DURATION`; nothing recompiles for a retime or a zoom tweak. `lowerToComposition` is the recording-only path underneath it.
27
+
28
+ ## Two documents, one editor
29
+
30
+ `StudioDoc = ProjectDoc | ProgramAnchorDoc`, discriminated on `source`. A `ProjectDoc` is a recording: footage, `segments` (the kept source spans), `zoom`, `speed`, `tilt`, `camMotion`, the frame and cursor styles, plus the shared layers. A `ProgramAnchorDoc` is a vos program that gained the same shared layers (text, image and video overlays, 3D objects, audio clips, speed spans, a tween-retime overlay) without those being written into its config. `anchorKindOf`, `isRecordingDoc` and `isProgramDoc` read the discriminator; `lowerProgramDoc` lowers the program kind. Hosted documents carry `docSchemaVersion` (`DOC_SCHEMA_VERSION`, currently 2) and are upgraded on read with `migrateHostedDoc`.
31
+
32
+ The shared layers lower as one engine `stack` entry, `STUDIO_ENTRY_ID` (`'vosso.studio'`), with its own data (`studioLayerData`), so either document kind hosts them and the engine's `SET_DATA { target }` updates them alone. `studioAudioPlan` turns the entry's audio clips and duck curve into the plan `@vosjs/core/audio` mixes.
33
+
34
+ ## Time and space conventions
35
+
36
+ - **Seconds everywhere.** Zoom, speed, tilt and cam-motion spans and the cursor samples are anchored in source time, so they follow footage through trims. Overlays, audio clips and click effects are anchored in output time, so a title keeps its perceived length through a speed change. `ratedSegments`, `effectiveSegments`, `docOutputDuration` and `outputRangeToSource` are the remaps.
37
+ - **Normalized coordinates.** A zoom's `cx`/`cy` and an overlay's `transform.x`/`y` are fractions of the frame in `[0, 1]`, never pixels, so a document survives an aspect-ratio switch. `focusBounds` and `clampFocus` keep a focus inside the card at a given `level`.
38
+ - **Camera styles.** `ZOOM_STYLES` names eight camera personalities (`glide`, the default, then `focus`, `cinema`, `snappy`, `cut`, `keynote`, `drift`, `none`); a style parametrizes both the planner and the camera motion, and `doc.zoomParams` layers per-document overrides.
39
+ - **The stage.** `CARD_FOV`, `CARD_Z`, `OVERLAY_Z`, `BACKGROUND_Z` and `planeSizeAtDepth` define the frustum-filling planes the program draws (background, the tiltable card, the overlay); `computeCardLayout` and `docCardLayout` are the host-side mirror of the program's card math, pinned to it by tests.
40
+ - **Backdrops.** `withBackdrop(frame, backdrop)` and `backdropMedia` put a looping video or a still behind the card, output-anchored modulo its duration. The package carries the mechanism and `BASE_FRAME_STYLE`; which loop a host opens on is the host's choice.
41
+
42
+ ## Seeing a recording: the digest
43
+
44
+ `momentsFromDoc`, `sceneChanges` and `buildDigest` derive the moments of a recording from its cursor track (click clusters, typing sessions, scroll runs, dwells, idle gaps, head, tail, frame-diff scene changes), each with source and output extents, a normalized focus rectangle a zoom span can copy, and the ids of the planner's proposals over it. `zoomCoversRect` and `zoomWindow` are the framing lint that closes the loop. The CLI's `vos digest` writes it as `digest.json` beside footage frames and crops; `STYLE_FIELDS`, `copyStyle` and `pickStyle` carry a signed-off document's look onto the next take.
45
+
46
+ ## Destinations
47
+
48
+ `DESTINATIONS` is the table of launch destinations (store listings, Product Hunt, social, OG cards, README loops) with exact pixel sizes, byte and duration ceilings, generated from `channel-specs.json` in `@vosjs/cli` and hash-gated by a test. `destinationById`, `destinationsForChannel`, `exportSizeFor(ratio, resolution)` and `resolveExportSize` size an export; `ExportResolution` is `720p | 1080p | 2k | 4k`.
49
+
50
+ ## Exports by area
51
+
52
+ | Area | Exports |
53
+ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
54
+ | Ingest | `projectFromArtifact`, `normalizeCaptureSpace`, `deriveViewportCrop`, `docToCropSpace`, `docToFullSpace`, `CAPTURE_COVERAGE_MIN`, `WINDOW_FOCUS_MIN` |
55
+ | Document | `StudioDoc`, `ProjectDoc`, `ProgramAnchorDoc`, `anchorKindOf`, `isRecordingDoc`, `isProgramDoc`, `DOC_SCHEMA_VERSION`, `migrateHostedDoc`, `DEFAULT_FRAME_STYLE`, `BASE_FRAME_STYLE`, the constants (`ZOOM_LEVELS`, `TILT_DEG_MAX`, …) |
56
+ | Planners | `planAutoZoom`, `planAutoSpeed`, `planAutoTilt`, `smoothCursor`, `idleGaps`, `scrollRuns`, `rejectSpan`, `isRejected`, `withoutRejected` |
57
+ | Camera styles | `ZOOM_STYLES`, `ZOOM_STYLE_OPTIONS`, `DEFAULT_ZOOM_STYLE`, `resolveZoomStyle` |
58
+ | Lowering | `lowerStudioDoc`, `lowerProgramDoc`, `lowerToComposition`, `zoomTrackFromDoc`, `tiltTrackFromDoc`, `camTrackFromDoc`, `motionTrack`, `followFocusEvents`, `extractClicks`, `cursorIdleFade`, `ratedSegments`, `STUDIO_ENTRY_ID`, `studioEntry`, `studioLayerData` |
59
+ | Layout | `computeCardLayout`, `docCardLayout`, `focusBounds`, `clampFocus`, `camBubbleRectAt`, `overlayRect`, `overlayHit`, `CARD_FOV`, `CARD_Z`, `planeSizeAtDepth`, `recommendedExportResolution` |
60
+ | Text | `TEXT_PRESETS`, `OVERLAY_FONT_FACES`, `resolveOverlayStyle`, `resolveOverlayBox`, `resolveText3dAsset` |
61
+ | Audio | `studioAudioPlan`, `clipEnvelope`, `duckCurve`, `computePeaks`, `computeMicRms`, `voiceKey`, `musicBedClip`, `refillAudioBeds` |
62
+ | Backdrops | `withBackdrop`, `backdropMedia` |
63
+ | Digest | `momentsFromDoc`, `planForDigest`, `buildDigest`, `sceneChanges`, `zoomCoversRect`, `zoomWindow`, `cropBox`, `frameGeometry`, `STYLE_FIELDS`, `copyStyle`, `pickStyle`, `DIGEST_VERSION` |
64
+ | Destinations | `DESTINATIONS`, `destinationById`, `destinationsForChannel`, `exportSizeFor`, `resolveExportSize`, `ASPECT_RATIOS` |
65
+ | Timeline lanes | `videoLane`, `micLane`, `camLane`, `zoomLane`, `tiltLane`, `camMoveLane`, `speedLane`, `overlaysLane`, `objectsLane`, `audioLane`; range actions `outputRangeToSource`, `removeSourceRange`, `setSpeedInRange`, `zoomSpanForRange` |
66
+
67
+ The full document shape is in [`src/types.ts`](src/types.ts); the JSON Schema that ships to users is [`doc.schema.json`](../cli/schema/doc.schema.json) in `@vosjs/cli`.
49
68
 
50
69
  ## Design rules
51
70
 
52
- - **Never bake doc values into the program string.** The program is a structural
53
- hash; all editable state travels in `ctx.data`. Baking values breaks live editing.
54
- - **Lowering is deterministic.** No stateful springs or wall-clock `seek(t)` must
55
- be a pure function of `t`, so cursor follow, click effects, and zoom are all
56
- computed from the doc up front.
57
- - **Source-anchored spans.** Zoom and speed spans are anchored in source time and
58
- follow footage through trims; the lowering remaps them to output time.
71
+ - **Never bake a document value into the program string.** The program is a structural hash; all editable state travels in `ctx.data`. Baking a value breaks live editing.
72
+ - **Lowering is deterministic.** No stateful springs, no wall clock: `seek(t)` is a pure function of `t`, so cursor follow, click effects and zoom are computed from the document up front.
73
+ - **Perception reads the recording, never the composition.** The planners and the digest read the cursor track and the footage; they never inspect a rendered frame.
59
74
 
60
75
  ## Development
61
76
 
62
77
  ```bash
63
- pnpm --filter @vosso/studio-core test # vitest
64
- pnpm --filter @vosso/studio-core typecheck
78
+ pnpm --filter @vosjs/studio-core test
79
+ pnpm --filter @vosjs/studio-core typecheck
65
80
  ```
66
81
 
67
- The `__tests__` suite pins the invariants that are easy to break capture-space
68
- fail-closed matrix, zoom keyframe expansion, click extraction, layout↔ON_FRAME
69
- parity. Extend them when touching lowering.
82
+ The test suite pins the invariants that are easy to break: the capture-space fail-closed matrix, zoom keyframe expansion, click extraction, layout-to-program parity, byte-identical lowering when a feature is absent, and the destinations hash. Extend it when touching the lowering.
83
+
84
+ ## License
85
+
86
+ [MIT](https://github.com/vosjs/vos/blob/main/LICENSE) © vosso
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vosjs/studio-core",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "The studio's editing model: the ProjectDoc schema, the element-aware auto-zoom planner and cursor smoothing, the lowering from a document to a vos composition, and the timeline lane adapters. Generic editing mechanisms live in @vosjs/editor.",
5
5
  "license": "MIT",
6
6
  "author": "vosso",
@@ -27,9 +27,9 @@
27
27
  ],
28
28
  "sideEffects": false,
29
29
  "dependencies": {
30
- "@vosjs/editor": "^1.3.0",
31
- "@vosjs/shared": "^0.4.0",
32
- "@vosjs/timeline": "^0.4.0"
30
+ "@vosjs/editor": "^1.3.1",
31
+ "@vosjs/shared": "^0.4.1",
32
+ "@vosjs/timeline": "^0.4.1"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "@vosjs/core": ">=0.10.0 <0.24.0"
@@ -40,7 +40,7 @@
40
40
  "tsup": "^8.5.0",
41
41
  "typescript": "^5",
42
42
  "vitest": "^3.0.0",
43
- "@vosjs/core": "^0.23.1"
43
+ "@vosjs/core": "^0.23.2"
44
44
  },
45
45
  "publishConfig": {
46
46
  "access": "public"