import { type CaptionRun } from './caption-runs'; import { type CaptionEmphasisMatchWord } from './caption-emphasis-match'; /** * Caption display policy v1. This is the single pure implementation used by * render-cut, preview-server, and the shell backend. It deliberately performs * no file IO and returns timeline-domain display cues; browser consumers only * select a resolved cue by output time. */ export declare const CAPTION_DISPLAY_SCHEMA: "caption-layout/v1"; export declare const CAPTION_DISPLAY_MODE: "single_line_sequential"; export declare const CAPTION_DISPLAY_ALGORITHM: "a4-ja-two-fragment-v1"; export declare function captionDefaultSizePx(output?: { width?: number; height?: number; }): number; export declare const CAPTION_RICH_LAYER_CSS = ".akari-caption--rich .akari-caption__tok{position:relative;-webkit-text-fill-color:transparent;-webkit-text-stroke:0 transparent;text-shadow:none;}.akari-caption--rich .akari-caption__run,.akari-caption--rich .akari-caption__char{position:relative;}.akari-caption--rich .akari-caption__rich-segment{position:relative;display:inline-block;vertical-align:baseline;white-space:pre;}.akari-caption--rich .akari-caption__rich-shadow,.akari-caption--rich .akari-caption__rich-stroke{position:absolute;inset:0;white-space:pre;pointer-events:none;text-decoration:none;}.akari-caption--rich .akari-caption__rich-fill{position:relative;white-space:pre;pointer-events:none;text-decoration:none;}.akari-caption--rich .akari-caption__rich-shadow{color:transparent;-webkit-text-fill-color:transparent;-webkit-text-stroke:0 transparent;text-shadow:var(--caption-text-shadow,none);}.akari-caption--rich .akari-caption__rich-stroke{color:transparent;-webkit-text-fill-color:transparent;-webkit-text-stroke:var(--caption-rich-stroke-width) var(--caption-rich-stroke-color);paint-order:stroke fill;text-shadow:none;transform:translate(var(--caption-rich-stroke-offset-x,0em),var(--caption-rich-stroke-offset-y,0em));}.akari-caption--rich .akari-caption__rich-fill{color:var(--caption-tok-rich-fill-color,var(--caption-rich-fill-color,var(--caption-color,#fff)));background-image:var(--caption-tok-rich-fill-image,var(--caption-rich-fill-image,none));background-size:var(--caption-tok-rich-fill-size,var(--caption-rich-fill-size,100% 100%));background-position:var(--caption-tok-rich-fill-position,var(--caption-rich-fill-position,0 0));-webkit-background-clip:text;-webkit-text-fill-color:var(--caption-tok-rich-fill-color,var(--caption-rich-fill-color,var(--caption-color,#fff)));-webkit-text-stroke:0 transparent;text-shadow:none;paint-order:stroke fill;}.akari-caption--rich .akari-caption__run[style*=\"color:\"] .akari-caption__rich-fill{color:inherit;background-image:none;-webkit-text-fill-color:currentColor;}.akari-caption--rich .akari-caption__run[style*=\"-webkit-text-stroke:\"][style*=\"px\"] .akari-caption__rich-stroke{display:none;}.akari-caption--rich .akari-caption__run[style*=\"-webkit-text-stroke:\"][style*=\"px\"] .akari-caption__rich-fill{-webkit-text-stroke:inherit;}.akari-caption--rich .akari-caption__tok--karaoke-done .akari-caption__rich-fill{background-image:none;-webkit-text-fill-color:var(--caption-highlight-color,#ffd94a);}.akari-caption--rich .akari-caption__tok--karaoke-smooth::after{display:none;}.akari-caption--rich .akari-caption__tok--karaoke-smooth .akari-caption__rich-fill::after{content:attr(data-karaoke-text);position:absolute;inset:0;white-space:pre;-webkit-text-stroke:0 transparent;background-image:none;color:var(--caption-highlight-color,#ffd94a);-webkit-text-fill-color:var(--caption-highlight-color,#ffd94a);animation:akari-caption-karaoke-wipe var(--akari-tok-dur,0.2s) var(--akari-tok-delay,0s) linear both paused;}"; type RichRect = { left: number; top: number; width: number; height: number; }; type RichFillNode = { getBoundingClientRect(): RichRect; style: { setProperty(name: string, value: string): void; }; }; type RichLineNode = { getBoundingClientRect(): RichRect; querySelectorAll(selector: string): Iterable; }; /** Place each token's image in the coordinate system of its complete line. */ export declare function alignCaptionRichFillPhase(root: { getAttribute(name: string): string | null; querySelectorAll(selector: string): Iterable; }): void; export declare const CAPTION_UNIT_METRIC: "ascii-half-other-one-v1"; export interface CaptionBreakHints { preferred_second_starts?: string[]; preferred_first_ends?: string[]; protected_terms?: string[]; } export interface CaptionDisplayPolicy { mode: typeof CAPTION_DISPLAY_MODE; algorithm: typeof CAPTION_DISPLAY_ALGORITHM; unit_metric: typeof CAPTION_UNIT_METRIC; max_line_units: number; minimum_fragment_duration_seconds: number; locale: string; lines?: number; wrap?: 'multi' | 'fold'; word_style?: 'none' | 'karaoke'; break_hints?: CaptionBreakHints; } export interface CaptionDisplayCue { id: string; source_cue_id: string; src: string | null; cut_index: number; occurrence_index: number; fragment_index: number; fragment_count: number; start: number; end: number; text: string; display_lines?: string[]; units: number; line_override: boolean; text_style?: Record; style_vars?: Record; layout?: ResolvedCaptionLayout; words?: CaptionDisplayWord[]; style?: 'karaoke'; karaoke_offset?: number; word_styles?: CaptionDisplayWordStyle[]; untimed_emphasis_words?: Array; runs?: CaptionRun[]; overflow?: CaptionDisplayOverflow; } export interface CaptionDisplayOverflow { code: 'NO_WORD_BOUNDARY_SPLIT' | 'INVALID_MANUAL_FRAGMENTS'; units: number; } export interface CaptionDisplayWord { start: number; end: number; text: string; line: number; untimed?: true; } export interface CaptionDisplayWordStyle { from: number; to: number; preset_id: string; style_vars: Record; } export interface CaptionBoundaryProjection { source_cue_id: string; text: string; boundaries: number[]; } export interface CaptionDisplayResult { schema: typeof CAPTION_DISPLAY_SCHEMA; policy: CaptionDisplayPolicy; source_cue_count: number; occurrence_count: number; display_cue_count: number; split_source_cue_count: number; boundary_projection: CaptionBoundaryProjection[]; display_cues: CaptionDisplayCue[]; word_book_fallbacks: Array<{ caption_id: string; dropped_terms: string[]; }>; } export interface ResolvedCaptionLayout { mode: 'reference-pixel'; reference_width_px: number; reference_height_px: number; left_px: number; width_px: number; right_px: number; center_x_px: number; bottom_px: number; text_align: 'center'; max_lines: 1; scale: number; } type UnknownRecord = Record; export interface CaptionOccurrence { source_cue_id: string; src: string | null; cut_index: number; caption_input_index: number; source_start: number; source_end: number; start: number; end: number; track: number; text: string; display_fragments?: string[]; occurrence_index?: number; text_style?: UnknownRecord; time_offset?: number; time_scale?: number; } export interface ProjectedCaptionWords { displayText: string; words: UnknownRecord[] | undefined; changed: boolean; renderable: boolean; } export declare class CaptionDisplayError extends Error { readonly code: string; constructor(code: string, message: string); } export declare function measureCaptionUnits(text: string): number; export interface CaptionWordSpan { start: number; end: number; wordLike: boolean; } /** 自動分割で採用してはいけない、Latin/数字または Segmenter 語の内部境界を判定する。 */ export declare function captionBreakBoundaryBlocked(text: string, boundary: number, wordSpans: readonly CaptionWordSpan[]): boolean; export declare function joinCaptionLines(lines: string[], locale: string): string; export declare function validateCaptionDisplayPolicy(value: unknown): CaptionDisplayPolicy; /** Read and write the global word display default without changing the caption shape. */ export declare function getCaptionDisplayWordStyle(root: unknown): 'none' | 'karaoke'; export declare function setCaptionDisplayWordStyle(root: unknown, style: 'none' | 'karaoke'): UnknownRecord; /** An explicit row style overrides the global default; null restores inheritance. */ export declare function setCaptionDisplayRowStyle(root: unknown, id: string, style: 'karaoke' | 'plain' | null): UnknownRecord; export declare function resolveCaptionDisplay(captionsRoot: unknown, edit: UnknownRecord, options?: { output?: { width: number; height: number; }; extra_protected_terms?: string[]; }): CaptionDisplayResult | null; /** * Strict captions.schema textStyle validation for the opt-in display-policy kernel. * Validation happens on each source object before merge so a valid override can never * conceal an invalid default (or vice versa). */ export declare function validateCaptionTextStyle(value: unknown, label?: string): UnknownRecord; /** Count only declared sources used by timeline media, including nested v2 items and v1 cuts. */ export declare function referencedCaptionSourceCount(edit: UnknownRecord): number; /** * `captions.json` は変更せず、keep cut から外れた語だけを描画用の本文と words から除く。 * どれかの cut と一部でも交差する語は残す(語の途中で切った場合に欠落させない)。 */ export declare function projectCaptionWords(caption: UnknownRecord, cuts: UnknownRecord[]): ProjectedCaptionWords; /** * 同じ source cue が同じ出力区間へ複数回射影された場合、下→上の trackOrder で * 最後に描かれる occurrence だけを残す。部分重複は境界で分割する。 */ export declare function dedupeCaptionOccurrences(occurrences: readonly T[], trackOrder: readonly number[]): T[]; export declare function splitCaptionFragments(text: string, policy: CaptionDisplayPolicy): { fragments: string[]; boundaries: number[]; overflow?: CaptionDisplayOverflow; }; export declare function foldCaptionLines(text: string, maxLineUnits: number, lines: number, locale?: string): string[]; export declare function scheduleCaptionFragments(start: number, end: number, fragments: string[], minimumSeconds: number): Array<{ start: number; end: number; text: string; }>; export declare function mergeCaptionDisplayStyles(base: unknown, override: unknown): UnknownRecord | undefined; /** Merge the snake_case captions.json line style vocabulary used by every renderer. */ export declare function mergeCaptionLineTextStyles(base: unknown, override: unknown): UnknownRecord | null; export declare function usesPercentageBackground(background: unknown): boolean; export declare function usesExtendedPerLineBackground(background: unknown): boolean; /** * zone 方式の px 系フィールドに掛ける scale(issue #40 §2)。`reference_height_px` が無ければ 1 * (既存出力はバイト同一)。あれば output.height / reference_height_px — 基準は高さ(文字サイズは * 縦方向の量。縦型出力でも自然)。`layout`(reference-pixel)との併用は禁止。output.height が無いと * layout 経路の INVALID_OUTPUT_GEOMETRY と同型で fail する。render-cut の captionTextStyleVars と * gpu-export page-builder はこの単一定義を使い、GPU / OSR の両経路で同じ実効 px になる。 */ export declare function resolveCaptionReferenceScale(style: unknown, output: { width?: number; height?: number; } | undefined): number; /** * 宣言 px × scale。scale === 1 なら値をそのまま返す(`${value}` の文字列が従来とバイト同一)。 * それ以外は小数 6 桁へ丸めて浮動小数の端数(0.1 × 3 = 0.30000000000000004)を CSS に漏らさない。 */ export declare function scaleCaptionPx(value: number, scale: number): number; /** * text_anchor(9 点)+ position(0..1 相対)→ プレート配置の CSS 変数。単一定義 * (プレビュー = shell captionTextStyleVars / 書き出し = render-cut captions.mjs の両消費者が * これを使う — 2026-08-26 akari-reel 実機: プレビュー側だけ text_anchor/position を落として * 明示位置付き字幕が既定の下段 7% に出る「出力とプレビューの位置不一致」の再発防止)。 * position 未指定なら anchor は zone 相当の縁寄せとして効く。position.y 指定時は * b は下端、t は上端、m は中心をその座標へ合わせる。 * 不正な anchor / vertical_align は未宣言として無視する(書き込み時検証済みが前提の防御)。 */ export declare function captionAnchorPositionVars(anchorValue: unknown, positionValue: unknown, verticalAlignValue: unknown, frameFit?: boolean): Record; /** The resolved vars and the source style are both valid entry points for preview captions. */ export declare function captionStyleFitsFrame(style: unknown, vars?: Record): boolean; export declare function deriveMetallicStops(hue: string, variant: 'gold' | 'navy'): Array<{ at: number; color: string; }>; /** A nonmetallic or edited stop sequence has no one-knob hue representation. */ export declare function readMetallicHue(stops: unknown): { hue: string; variant: 'gold' | 'navy'; } | null; export declare function resolveCaptionRichFillVars(fill: UnknownRecord, scale?: number): Record; export declare function resolveCaptionRichStrokes(style: UnknownRecord, output?: { width: number; height: number; }): Array>; /** Resolve the complete snake_case captions.json line style vocabulary to CSS variables. */ export declare function resolveCaptionLineStyleVars(style: UnknownRecord | null | undefined, output: { width: number; height: number; } | undefined): Record; export declare function resolveCaptionStyleForOutput(style: UnknownRecord, output: { width: number; height: number; } | undefined): { vars: Record; layout?: ResolvedCaptionLayout; }; export declare function resolveCaptionWordStyleVars(style: UnknownRecord, output: { width: number; height: number; } | undefined, inheritCaptionSize?: boolean): Record; export declare const CAPTION_INHERITED_EMPHASIS_VARS: { [k: string]: Record; }; export declare function captionTextShadowValue(shadow: unknown, glow: unknown, scale?: number): string | null; export declare function captionRichTextShadowValue(style: UnknownRecord, scale: number): string | null; export declare function colorWithOpacity(color: string, explicitOpacity?: number): string; export declare function formatCssNumber(value: number): string; /** Render caption outlines with round SVG joins while preserving the text nodes. */ export declare function captionOutlineRuntime(): { sync: (root: any, remeasureAll?: boolean) => number; install: (doc: any, options?: { selector?: string; }) => any; bake: (root: any) => number; affectsMutation: (record: any, selector: string) => boolean; }; export {};