import type { AudioFadeShape } from './envelope'; export type LaneV2 = 'visual' | 'audio'; export interface OutputV2 { width: number; height: number; fps: number; look?: unknown; encoding?: unknown; [key: string]: unknown; } export interface EditSourceV2 { id: string; path: string; proxy?: string | null; chroma_key?: Record | null; } /** 同じ収録の素材時刻。先頭 member を基準 (offset_sec = 0) とする。 */ export interface SyncGroupV2 { id: string; members: Array<{ source: string; offset_sec: number; }>; } export declare function removeSourceFromSyncGroups(edit: T, sourceId: string): T; /** 音声素材を 1 つの映像素材と同期させる。解除時は映像 id を省略する。 */ export declare function setSourceSyncGroup(edit: EditV2, audioSource: string, visualSource?: string): EditV2; export interface TransformV2 { x?: number; y?: number; scale?: number; scaleX?: number; scaleY?: number; rotate?: number; } export interface CropV2 { x: number; y: number; w: number; h: number; rotate?: number; [key: string]: unknown; } export type EasingV2 = string; export interface KeyframeV2 { /** アイテム内のローカル時間(整数フレーム、item.at を 0 とする)。 */ t: number; transform?: TransformV2; crop?: CropV2; perspective?: Record; opacity?: number; gain_db?: number; animator?: Record; /** 数値の CSS 変数(例 --akari-3d-rot-y: 度)。v0 でキーを打てるのは 3D 回転の 3 本だけ。 */ vars?: Record; /** object なら "transform.x" / "opacity" / "vars.--akari-3d-rot-y" のように項目ごと。 */ easing?: EasingV2 | Record; [key: string]: unknown; } export interface KeyframesReferenceV2 { path: string; count: number; } export interface MotionV0 { in?: { preset: string; duration: number; ease?: string; amount?: number; }; out?: { preset: string; duration: number; ease?: string; amount?: number; }; loop?: { preset: string; period: number; ease?: string; amount?: number; }; } export interface AnimatorV0 { id: string; basis: 'chars' | 'words' | 'lines' | 'segments'; shape: 'ramp' | 'triangle' | 'round' | 'smooth' | 'square' | 'ramp-down'; start: number; end: number; offset: number; randomize?: { seed: number; }; amount: Record; ease?: string; } export type BlendModeV2 = 'normal' | 'screen' | 'multiply' | 'add' | 'difference' | 'darken' | 'lighten' | 'overlay' | 'hardlight' | 'softlight'; export interface MediaSourceV2 { kind: 'media'; src: string; in: number; out: number; framing?: Record; transition_out?: Record | null; freeze?: Record | null; fx?: unknown[]; speed?: number; /** 埋め込み音声(speech)の音量 dB。-60〜12・省略時 0。 */ gain_db?: number; /** 埋め込み音声(speech)のミュート。省略時 false。 */ mute?: boolean; chroma_key?: Record | null; } export interface AudioMediaSourceV2 { kind: 'media'; src: string; /** 素材ファイル内のトリム開始(秒)。省略時は 0。 */ in?: number; /** 素材ファイル内のトリム終端(秒)。省略時はファイル末尾。 */ out?: number; speed?: number; pitch_semitones?: number; formant?: 'preserve' | 'shift'; } export interface HtmlSourceV2 { kind: 'html'; path: string; part?: string; style?: Record; text?: string; elements?: Record; }>; exclude?: string[]; derivedFrom?: string; vars?: Record; params?: Record; } export type ShapeKindV0 = 'rect' | 'rounded-rect' | 'ellipse' | 'line' | 'arrow' | 'speech-bubble'; export type ShapeKindV1 = ShapeKindV0 | 'path' | 'bubble'; export type ShapePaintV1 = string | { type: 'linear' | 'radial'; angle?: number; stops: Array<{ color: string; offset: number; }>; }; export type ShapeCapV1 = 'none' | 'triangle' | 'chevron' | 'bar' | 'square' | 'circle' | 'diamond'; export interface ShapeParamsV0 { width?: number; height?: number; fill?: ShapePaintV1; stroke?: ShapePaintV1; strokeWidth?: number; cornerRadius?: number; path?: { d: string; vb: [number, number]; rule?: 'nonzero' | 'evenodd'; }; preset?: string; dash?: 'solid' | 'dash' | 'dot'; startCap?: ShapeCapV1; endCap?: ShapeCapV1; startCapScale?: number; endCapScale?: number; startCapFilled?: boolean; endCapFilled?: boolean; lineCap?: 'butt' | 'round'; style?: 'ellipse' | 'rounded' | 'rect' | 'jagged' | 'burst' | 'cloud' | 'wobble'; count?: number; depth?: number; jitter?: number; seed?: number; tail?: 'point' | 'dots' | 'none'; tailAngle?: number; tailLength?: number; tailWidth?: number; tailCurve?: number; } export interface ShapeSourceV2 { kind: 'shape'; shape: ShapeKindV1; params?: ShapeParamsV0; } export interface TelopSourceV2 { kind: 'telop'; preset: string; params?: Record; baked?: string; from?: string; } export type FilterV2 = { type: 'invert'; } | { type: 'lut'; id: string; intensity?: number; } | { type: 'saturation'; value: number; }; export interface FilterSourceV2 { kind: 'filter'; filter: FilterV2; } export interface CanvasV0 { origin: 'user' | 'plan'; durationMode: 'fixed'; intent?: string; background?: { type: 'none'; } | { type: 'color'; color: string; }; } export interface GroupSourceV2 { kind: 'group'; canvas?: CanvasV0; } export interface CaptionsSourceV2 { kind: 'captions'; path: 'captions.json'; exclude?: string[]; } export interface CaptionSourceV2 { kind: 'caption'; path: 'captions.json'; id: string; } export type SourceV2 = MediaSourceV2 | HtmlSourceV2 | ShapeSourceV2 | TelopSourceV2 | FilterSourceV2 | GroupSourceV2 | CaptionsSourceV2 | CaptionSourceV2; export interface AdjustBasicV0 { exposure?: number; contrast?: number; highlights?: number; shadows?: number; blacks?: number; whites?: number; temperature?: number; tint?: number; vibrance?: number; saturation?: number; } export interface AdjustLutV0 { lut: string; intensity?: number; } export interface AdjustCurvePointV1 { in: number; out: number; } export interface AdjustCurvesV1 { master?: AdjustCurvePointV1[]; r?: AdjustCurvePointV1[]; g?: AdjustCurvePointV1[]; b?: AdjustCurvePointV1[]; } export interface AdjustWheelV1 { r?: number; g?: number; b?: number; } export interface AdjustWheelsV1 { lift?: AdjustWheelV1; gamma?: AdjustWheelV1; gain?: AdjustWheelV1; offset?: AdjustWheelV1; } export interface AdjustHuePointV1 { hue: number; value: number; } export interface AdjustHueCurvesV1 { hue?: AdjustHuePointV1[]; sat?: AdjustHuePointV1[]; luma?: AdjustHuePointV1[]; } export type AdjustFxV1 = { id: 'vignette'; amount?: number; midpoint?: number; roundness?: number; feather?: number; } | { id: 'blur'; px?: number; } | { id: 'grain'; amount?: number; size?: number; } | { id: 'sharpen'; amount?: number; } | { id: 'glow'; intensity?: number; radius?: number; threshold?: number; warmth?: number; } | { id: 'clarity'; amount?: number; radius?: number; } | { id: 'dehaze'; amount?: number; } | { id: 'denoise'; amount?: number; } | { id: 'motion_blur'; px?: number; angle?: number; }; export interface AdjustV1 { basic?: AdjustBasicV0; lut?: AdjustLutV0 | null; curves?: AdjustCurvesV1; wheels?: AdjustWheelsV1; hue?: AdjustHueCurvesV1; fx?: AdjustFxV1[]; sections?: { basic?: boolean; lut?: boolean; curves?: boolean; wheels?: boolean; hue?: boolean; fx?: boolean; }; } /** @deprecated Use AdjustV1. */ export type AdjustV0 = AdjustV1; export interface ItemV2Base { id: string; name?: string; hidden?: boolean; locked?: boolean; /** 段直下では絶対位置、子では親相対の位置(整数フレーム)。 */ at: number; /** 表示・再生尺(整数フレーム)。 */ duration: number; anchor?: ItemAnchorV2; transform?: TransformV2; opacity?: number; blend?: BlendModeV2; crop?: CropV2; adjust?: AdjustV1; perspective?: Record; motion?: MotionV0; animator?: AnimatorV0[]; /** inline keyframes. The lazy reference spelling is exposed as InternalItem.keyframesRef. */ keyframes?: KeyframeV2[]; items?: ItemV2[]; } export type MediaItemV2 = ItemV2Base & { source: MediaSourceV2; /** 同期組の端をまたぐカットで残った映像片の元の素材端と配置。 */ cut_edge?: { in: number; out: number; at: number; }; /** この映像の間の字幕表示。省略時は通常の字幕表示に従う。 */ captions?: 'on' | 'off'; /** 省略時は埋め込み音声を供給。false は明示分離後の停止。 */ audio?: false; /** sources[].id of a gray mask video or a still-image PNG mask. */ mask?: string; maskFeather?: number; regions?: PhotoRegionV1[]; erase?: PhotoEraseStrokeV2[]; flip?: { h?: boolean; v?: boolean; }; frame?: { stroke?: { color: string; width: number; }; cornerRadius?: number; }; }; export interface PhotoRegionV1 { id: string; name?: string; maskRef: string; invert?: boolean; enabled?: boolean; adjust?: { basic?: Pick; }; filter?: AdjustLutV0; blur?: number; } export interface PhotoEraseStrokeV2 { mode: 'erase' | 'restore'; points: [number, number][]; size: number; hardness: number; } export type ItemV2 = MediaItemV2 | (ItemV2Base & { source: HtmlSourceV2; }) | (ItemV2Base & { source: ShapeSourceV2; }) | (ItemV2Base & { source: TelopSourceV2; }) | (ItemV2Base & { source: FilterSourceV2; }) | (ItemV2Base & { source: GroupSourceV2; }) | (ItemV2Base & { source: CaptionsSourceV2; }) | (ItemV2Base & { source: CaptionSourceV2; }); export type AudioRoleV2 = 'sfx' | 'narration' | 'bgm' | 'speech'; export interface NarrationProvenanceV2 { provider: string; engine?: string; voice?: string; credit?: string; generated_at?: string; [key: string]: unknown; } export interface AudioMediaItemV2 { id: string; name?: string; hidden?: boolean; locked?: boolean; /** 出力タイムライン上の絶対位置(整数フレーム)。 */ at: number; /** 出力尺(整数フレーム)。0 は実尺未解決のセンチネル。 */ duration: number; anchor?: ItemAnchorV2; /** 省略時は sfx。 */ role?: AudioRoleV2; /** 同じ edit 内の visual media id。編集上の関連であり時刻・source の正本ではない。 */ link?: string; /** カット前の音声片の素材端(秒)と配置(フレーム)。 */ cut_edge?: { in: number; out: number; at: number; }; reason?: 'silence' | 'word'; label?: string; /** item 単位のミュート。省略時は false。 */ mute?: boolean; source: AudioMediaSourceV2; gain_db?: number; denoise?: { method: 'fft' | 'nlm'; strength: number; }; lowcut_hz?: number; keyframes?: KeyframeV2[]; fade_in?: number; fade_out?: number; fade_in_shape?: AudioFadeShape; fade_out_shape?: AudioFadeShape; ducking?: boolean; duck_db?: number; duck_attack?: number; duck_release?: number; script?: string; reading?: string; caption_ref?: string; provenance?: NarrationProvenanceV2; } export interface ItemAnchorV2 { caption: string; range?: { start: number; end: number; }; offset?: number; edge?: 'start' | 'end'; attached_by?: { style_uid: string; caption: string; }; duration?: 'caption' | 'own'; } export interface CaptionTrackContentV2 { from: 'captions.json'; } export interface VisualItemsTrackV2 { id: string; lane: 'visual'; name?: string; /** トラックの音声をミュート。visual は cut の埋め込み音声、audio は item を書き出し・プレビューから除外。 */ muted?: boolean; target?: boolean; sync?: boolean; items: ItemV2[]; } export interface AudioItemsTrackV2 { id: string; lane: 'audio'; name?: string; /** トラックの音声をミュート。visual は cut の埋め込み音声、audio は item を書き出し・プレビューから除外。 */ muted?: boolean; target?: boolean; sync?: boolean; items: AudioMediaItemV2[]; } export type ItemsTrackV2 = VisualItemsTrackV2 | AudioItemsTrackV2; export interface ContentTrackV2 { id: string; lane: LaneV2; name?: string; /** トラックの音声をミュート。visual は cut の埋め込み音声、audio は item を書き出し・プレビューから除外。 */ muted?: boolean; target?: boolean; sync?: boolean; content: CaptionTrackContentV2; } export type TrackV2 = ItemsTrackV2 | ContentTrackV2; export interface EditV2 { version: 2; output: OutputV2; sources: EditSourceV2[]; sync_groups?: SyncGroupV2[]; /** 配列順が下から上の合成 z 順。 */ tracks: TrackV2[]; /** * 旧 v2 fixture が持つ top-level audio の互換 fallback。新規の SFX / narration / BGM は * audio lane の items で宣言する。 */ audio?: unknown; captions?: unknown[]; thumbnail?: Record; } export type InternalTrackV2 = TrackV2 & { /** 0 が最背面。tracks の配列添字と常に一致する。 */ z: number; }; export interface InternalEditV2 { version: 2; output: OutputV2; sources: EditSourceV2[]; sync_groups?: SyncGroupV2[]; /** 入力順を保持した下→上のトラック列。 */ tracks: InternalTrackV2[]; audio?: unknown; captions?: unknown[]; thumbnail?: Record; } /** * edit.json v2 だけを検証して内部表現へ読む。v0/v1 の変換は意図的に扱わない。 * tracks の配列順を保持し、各 track に z(0 = 最背面)を付ける。 */ export declare function readEditV2(json: unknown): InternalEditV2;