@mekuru/protocol 0.1.3 → 0.1.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.
package/README.jp.md CHANGED
@@ -1,3 +1,13 @@
1
1
  # @mekuru/protocol
2
2
 
3
- コンパイラ出力とサーバー状態を共有するTypeScript型です。実行時依存はありません。cliとviewerがこの通信契約を参照します。
3
+ コンパイラ出力とサーバー状態を共有するTypeScript型です。実行時依存はありません。compilerパッケージとviewerがこの通信契約を参照します。
4
+
5
+ `TimelineCompilation` は整数フレーム区間、有理数 `FrameRate`、台本ID、反復情報を表します。プレビューの同期には `PreviewEvent` の `snapshot`・`status`・`patch` を使います。
6
+
7
+ 単発・常駐プレビューの文字は内容・配置・スタイルを持つ `TextOp` で、viewer が HTML/CSS で描画します。`fontSrc` と `fontRevision` はプロジェクト内のフォントを識別します。画像・動画・音声もリビジョンを持ちます。動画書き出しには従来の Rust 組版・パス描画を使います。コンパイラと埋め込み viewer は同時に更新してください。
8
+
9
+ ワーカー要求は `knownResources` の列挙から `baseVersion` の受理通知へ変わりました。応答は `previewVersion` と `update`(snapshot・patch・null)、Rust の差分生成時間 `stats.diffMs` を持ちます。`previewVersion: null` はコンパイル失敗、成功してシーンが同じなら受理済みの版を維持し更新を送りません。ワーカーは受理済みシーンと候補1件を保持し、破棄した応答を差分の基準にしません。再起動・不明な基準では snapshot を返します。以前の全体シーン応答を置き換えるためコンパイラと外部ツール を同時更新してください。ブラウザの `PreviewEvent` と単発の `Compilation` は維持します。
10
+
11
+ ネイティブの `--serve` は同一プロセス内でコンパイルし、`PreviewEvent` を直接 WebSocket 配信します。ビューアはコンパイラへ埋め込んで同時に配布します。JSON Lines のワーカー型は外部ツール・計測用です。
12
+
13
+ `/api/ws` の WebSocket で、1メッセージにつき1件の `PreviewEvent` JSON テキストを送ります。基準バージョンが合わない場合、viewer は `PreviewCommand` の `{"type":"resync"}` を送り、同じ接続で snapshot を再取得します。切断・再同期のタイムアウト時は再接続します。旧 `/api/events` SSE エンドポイントは廃止し、コンパイラと埋め込みビューアを同時更新してください。
package/README.md CHANGED
@@ -2,4 +2,16 @@
2
2
 
3
3
  Preview transport types.
4
4
 
5
- Shared TypeScript types for compiler output and server state. This package has no runtime dependencies. CLI and viewer both depend on this contract.
5
+ Shared TypeScript types for compiler output and server state. This package has no runtime dependencies. The browser viewer and authoring adapters depend on this contract; the native server implements it in Rust.
6
+
7
+ `Compilation` describes the standalone `--emit-preview` output. `WorkerRequest` and `WorkerCompilation` describe the resident compiler's JSON Lines exchange. Shared elements reference ordered SHA-256 drawing IDs, one per original `ViewOp`; preview keys identify elements independently of their drawing content and sequential compiler IDs.
8
+
9
+ `PreviewEvent` is sent as one JSON text message per WebSocket message at `/api/ws`: `snapshot` supplies the current scene and resources, `status` supplies only server state, and `patch` supplies a base/next version, keyed collection edits, ordering and resource changes. The viewer sends `PreviewCommand` (`{"type":"resync"}`) to request a snapshot on the same connection if a patch's base version does not match. A lost connection or three-second resync timeout reconnects the viewer. The old `/api/events` SSE endpoint is removed. The viewer is embedded in the compiler, so they ship together.
10
+
11
+ `TimelineCompilation` exposes integer frame intervals, rational `FrameRate`, source IDs, and compact repeat chains. Preview synchronization uses the `snapshot`, `status`, and `patch` variants of `PreviewEvent`.
12
+
13
+ Text is a `TextOp` (content, layout and style) in both standalone and worker previews. The viewer renders it as HTML/CSS. `fontSrc` and `fontRevision` identify project fonts; images and media carry their own revision. Export still uses Rust text shaping and path rendering.
14
+
15
+ Worker requests now acknowledge `baseVersion` instead of listing `knownResources`. Responses carry `previewVersion` and `update` (snapshot, patch, or null), with `stats.diffMs` measuring Rust diff generation. `previewVersion: null` means compilation failure; a successful unchanged scene keeps the acknowledged version and sends no update. The worker retains an acknowledged scene plus one candidate, so discarded responses never become a patch base. Restarting or receiving an unknown base forces a snapshot. This replaces the previous full-scene worker response; update tool clients together with the compiler. Browser `PreviewEvent` and standalone `Compilation` are unchanged.
16
+
17
+ The native `--serve` path calls the compiler in process and sends `PreviewEvent` directly over WebSocket. JSON Lines worker types remain for external tools and benchmarks.
package/package.json CHANGED
@@ -1,6 +1,12 @@
1
1
  {
2
2
  "name": "@mekuru/protocol",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/kanade-k-1228/mekuru.git",
7
+ "directory": "pkgs/protocol"
8
+ },
9
+ "homepage": "https://github.com/kanade-k-1228/mekuru/blob/main/pkgs/protocol/README.md",
4
10
  "type": "module",
5
11
  "exports": {
6
12
  ".": "./src/index.ts"
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ export interface Compilation {
8
8
  preview: PreviewDto | null;
9
9
  diagnostics: Diagnostic[];
10
10
  }
11
+ /** Compilation status; it never contains drawing data. */
11
12
  export interface StateDto {
12
13
  path: string;
13
14
  version: number;
@@ -15,9 +16,65 @@ export interface StateDto {
15
16
  status: "building" | "ready" | "error";
16
17
  error: string | null;
17
18
  diagnostics: Diagnostic[];
18
- preview: PreviewDto | null;
19
19
  }
20
20
 
21
+ export type Keyed<T> = T & { key: string };
22
+ export interface SharedPreviewDto extends Omit<PreviewDto, "elements" | "timeline"> {
23
+ version: number;
24
+ elements: SharedElement[];
25
+ timeline: { nodes: Keyed<TimelineNode>[]; clips: Keyed<TimelineClip>[] };
26
+ }
27
+ export interface SharedElement extends Omit<SceneElement, "ops" | "chunks"> {
28
+ key: string;
29
+ drawings: string[];
30
+ }
31
+ export type Resources = Record<string, DrawOp[]>;
32
+ export interface WorkerRequest {
33
+ version: number;
34
+ xml: string;
35
+ /** Last scene accepted by the CLI, never an intermediate discarded result. */
36
+ baseVersion: number | null;
37
+ }
38
+ export interface WorkerCompilation {
39
+ version: number;
40
+ /** null on compilation failure; unchanged scenes retain the acknowledged version. */
41
+ previewVersion: number | null;
42
+ diagnostics: Diagnostic[];
43
+ update: PreviewUpdate | null;
44
+ stats: { drawHits: number; drawMisses: number; compileMs: number; diffMs: number };
45
+ }
46
+ export type PreviewUpdate = Omit<SnapshotEvent, "state"> | Omit<PatchEvent, "state">;
47
+ export interface CollectionPatch<T> {
48
+ upsert: T[];
49
+ remove: string[];
50
+ order?: string[];
51
+ }
52
+ export interface SnapshotEvent {
53
+ type: "snapshot";
54
+ state: StateDto;
55
+ preview: SharedPreviewDto | null;
56
+ resources: Resources;
57
+ }
58
+ export interface StatusEvent {
59
+ type: "status";
60
+ state: StateDto;
61
+ }
62
+ export interface PatchEvent {
63
+ type: "patch";
64
+ state: StateDto;
65
+ baseVersion: number;
66
+ version: number;
67
+ scene: Pick<PreviewDto, "width" | "height" | "fps" | "duration">;
68
+ elements: CollectionPatch<SharedElement>;
69
+ nodes: CollectionPatch<Keyed<TimelineNode>>;
70
+ clips: CollectionPatch<Keyed<TimelineClip>>;
71
+ resources: Resources;
72
+ removedResources: string[];
73
+ }
74
+ export type PreviewEvent = SnapshotEvent | StatusEvent | PatchEvent;
75
+ /** Browser-to-server JSON message over /api/ws. */
76
+ export type PreviewCommand = { type: "resync" };
77
+
21
78
  export interface PreviewDto {
22
79
  width: number;
23
80
  height: number;
@@ -28,20 +85,41 @@ export interface PreviewDto {
28
85
  }
29
86
  export type Bounds = [number, number, number, number];
30
87
  export type Fade = [start: number, end: number, fadeIn: number, fadeOut: number, level: number];
88
+ export interface TextOp {
89
+ kind: "text";
90
+ text: string;
91
+ x: number;
92
+ y: number;
93
+ width: number | null;
94
+ font: string;
95
+ fontSrc: string | null;
96
+ fontRevision: string | null;
97
+ size: number;
98
+ color: string;
99
+ bold: boolean;
100
+ align: "left" | "center" | "right";
101
+ lineHeight: number;
102
+ stroke: string | null;
103
+ strokeWidth: number;
104
+ transform: [number, number, number, number, number, number] | null;
105
+ }
31
106
  export type DrawOp =
107
+ | TextOp
32
108
  | {
33
109
  kind: "path";
34
110
  d: string;
35
111
  color: string;
36
112
  stroke: { width: number; lineCap: "butt" | "round" | "square"; lineJoin: "miter" | "round" | "bevel"; dash: number[] } | null;
37
113
  }
38
- | { kind: "image"; src: string; bounds: Bounds; transform: [number, number, number, number, number, number] | null };
114
+ | { kind: "image"; src: string; revision?: string; bounds: Bounds; transform: [number, number, number, number, number, number] | null };
39
115
  export interface MediaMap {
40
116
  from: number;
41
117
  end: number;
42
118
  segments: [outStart: number, outEnd: number, srcStart: number, rate: number][];
43
119
  }
44
120
  export interface SceneElement {
121
+ key?: string;
122
+ chunks?: { id: string; ops: DrawOp[] }[];
45
123
  id: number;
46
124
  kind: "view" | "video" | "audio";
47
125
  start: number;
@@ -50,12 +128,13 @@ export interface SceneElement {
50
128
  fades: Fade[];
51
129
  ops: DrawOp[];
52
130
  bounds: Bounds | null;
53
- media: { src: string; gain: number; map: MediaMap } | null;
131
+ media: { src: string; revision?: string; gain: number; map: MediaMap } | null;
54
132
  repeat: [from: number, period: number, until: number][];
55
133
  hidden: [start: number, end: number][];
56
134
  }
57
135
 
58
136
  export interface TimelineNode {
137
+ key?: string;
59
138
  id: number;
60
139
  parent: number | null;
61
140
  depth: number;
@@ -71,6 +150,7 @@ export interface TimelineNode {
71
150
  export type ClipLane = "speech" | "visual" | "video" | "audio";
72
151
 
73
152
  export interface TimelineClip {
153
+ key?: string;
74
154
  tag: string;
75
155
  lane: ClipLane;
76
156
  line: number;
@@ -85,3 +165,29 @@ export interface TimelineDto {
85
165
  nodes: TimelineNode[];
86
166
  clips: TimelineClip[];
87
167
  }
168
+
169
+ export interface FrameRate {
170
+ num: number;
171
+ den: number;
172
+ }
173
+ export interface FrameInterval {
174
+ startFrame: number;
175
+ endFrame: number;
176
+ }
177
+ export interface TimelineEntry extends FrameInterval {
178
+ id: string;
179
+ parent: string | null;
180
+ sourceId: string | null;
181
+ kind: "seq" | "par" | "repeat" | "view" | "video" | "audio";
182
+ repeat: { fromFrame: number; periodFrames: number; untilFrame: number }[];
183
+ }
184
+ export interface ResolvedTimeline {
185
+ fps: FrameRate;
186
+ frames: number;
187
+ estimated: boolean;
188
+ entries: TimelineEntry[];
189
+ }
190
+ export interface TimelineCompilation {
191
+ timeline: ResolvedTimeline | null;
192
+ diagnostics: Diagnostic[];
193
+ }