import { type PropertyDriver, type MotionConfig, type TweenConfig, type SpringConfig } from '@vectojs/animation'; import type { PreparedContentGrid } from '@vectojs/text'; /** A numeric transform/visual property that participates in the animation system. */ export type AnimatableProp = 'x' | 'y' | 'scaleX' | 'scaleY' | 'rotation' | 'opacity'; /** * A 2-D coordinate in canvas/world space. */ export interface Point { x: number; y: number; } /** Six-scalar 2D affine transform matching CanvasRenderingContext2D. */ export interface AffineTransform { a: number; b: number; c: number; d: number; e: number; f: number; } /** * An axis-aligned bounding box in an entity's local coordinate space. * * Returned from {@link Entity.getBounds} to enable viewport culling. */ export interface Bounds { x: number; y: number; width: number; height: number; } /** Half-open child index range selected for the current render traversal. */ export interface RenderChildRange { /** Index of the first child to visit. */ start: number; /** Index after the last child to visit. */ end: number; } /** * Describes an entity that renders as a single filled circle at its local * origin, returned from {@link Entity.getBatchCircle} to opt into the renderer's * draw-call batching fast-path. */ export interface BatchCircle { /** Circle radius in the entity's local space. */ radius: number; /** CSS fill color. */ color: string; } /** * Describes an entity that renders as a single filled rectangle from its local * origin, returned from {@link Entity.getBatchRect} to opt into the GPU * instanced-rectangle fast-path (WebGL `pointBackend` only). */ export interface BatchRect { /** Rectangle width in the entity's local space. */ width: number; /** Rectangle height in the entity's local space. */ height: number; /** CSS fill color. */ color: string; } /** * Static text an {@link Entity} exposes for DOM content projection, returned * from {@link Entity.getContentProjection}. The Scene mirrors it as a * transparent, position-synced DOM node so browser-native text machinery — * find-in-page, screen readers, SEO crawlers, translation, `#:~:text=` * fragments — operates on canvas-rendered text. */ export interface ContentProjectionRun { /** Text written with one CSS font inside a projected visual line. */ text: string; /** CSS font shorthand matching the canvas run. */ font?: string; /** * Absolute local x of this run within the entity. Set it (with {@link width}) * for justified or otherwise non-naturally-spaced text: the Scene then places * each run as a positioned carrier (`inline-block` + relative `left`) at the * exact canvas x, so the DOM selection box overlaps the drawn glyphs instead * of drifting under the browser's own inter-word spacing. When omitted, runs * flow naturally (the default for left-aligned text). */ x?: number; /** * Advance (width in px) the canvas used for this run, including any widened * trailing gap for justify. Used only alongside {@link x} to size the * positioned carrier so the next run starts flush at its own `x`. */ width?: number; } export interface ContentProjectionLine { /** Text for browser find-in-page and native selection. */ text: string; /** * Logical source content between this visual line and the next one. Use a * space for a consumed soft-wrap separator, `"\n"` for a hard break, or an * empty string for a space-less wrap. Omit to retain the legacy newline * fallback between non-final lines. */ separatorAfter?: string; /** Local origin of the visual line inside the entity. */ x: number; y: number; /** Canvas baseline relative to `y`. */ baseline: number; /** CSS font used for the line when it has no styled runs. */ font?: string; /** Explicit line height for this line. */ lineHeight?: number; /** Styled text runs in visual order. */ runs?: ContentProjectionRun[]; /** * Emit one flow-relative carrier per grapheme cluster on this line instead * of a single text node. Used by natural-order (non-bidi, non-justified) text * to correct the residual ~0.3% per-character Gecko grid-fit drift that causes * selection highlight boxes to lag or lead painted glyphs. * * Only meaningful when `runs` is absent or empty. Setting it on a line that * already has positioned runs is a no-op — those lines use their own * flow-relative carriers already. * * Must NOT be set for bidi/RTL lines: per-glyph carriers break logical caret * hit-mapping when DOM order != visual order (PR #146 revert). */ perGraphemeCarriers?: boolean; /** * The canvas painted this line's ink as ONE shaped `fillText(line.text)`, so * the ink includes the browser's kerning and ligatures. Per-grapheme * carriers must then be measured as shaped PREFIX DIFFERENCES of the whole * line — isolated grapheme advances would omit exactly the kerning/ligature * contraction the paint applied, widening the DOM line past the ink. * * Leave unset for per-glyph painters (glyphs placed at summed isolated * advances, e.g. RichText and TextEntity): there the ink is unkerned, and * shaped prefixes would drift the carriers ahead of it by the accumulated * kerning delta instead. * * Only meaningful alongside {@link perGraphemeCarriers}. */ shapedPaint?: boolean; } /** * Advice from the {@link Scene} about which part of an entity is worth * describing in {@link Entity.getContentProjection}. * * **Purely an optimization, and ignoring it is always correct.** The Scene * windows the DOM itself, so an entity that returns its whole document still * behaves correctly — it just pays to build lines that get discarded. An entity * whose projection is O(glyphs) can use this to make that build O(visible) * instead, which is the difference between per-frame cost that scales with the * document and cost that scales with the viewport. * * Why a hint rather than a strict window: the entity owns the mapping from its * own text to visual lines, and only it knows things like where a wrapped * paragraph begins. Handing it a band and letting it round outward keeps that * knowledge in one place. An entity may return more than asked — never less * than it can, because text absent from the projection is invisible to * find-in-page, copy and, for static text, the screen reader. */ export interface ContentProjectionHint { /** * Inclusive band of entity-local y worth projecting, already expanded by the * scene's `contentProjectionMargin` and intersected with every clipping * ancestor. Absent when no useful bound exists (a rotated or skewed * transform, a boundless entity), in which case project everything. */ minY?: number; maxY?: number; /** * When `true`, the caller only needs {@link ContentProjection.text} — no * `lines`, no `grid`. Entities receiving this should return the full source * text without building per-line or per-glyph structures, which avoids the * O(glyphs) layout walk that the coarse resident tier would discard anyway. * * Entities may ignore this hint and still return `lines`; the caller will * simply not use them. Returning fewer than all lines is **not** safe under * this hint: if `lines` is non-empty, Scene interprets it as the line * window, which must cover the whole text for correctness. */ textOnly?: boolean; } /** * Whether a line at `y` of height `height` is worth projecting under `hint`. * * Shared so every consumer rounds the same way: a line is kept when its box * overlaps the band at all, which retains a line straddling the edge whole * rather than clipping it mid-glyph. Returns `true` when the hint carries no * band, so the default is always "project it". */ export declare function contentLineInHint(hint: ContentProjectionHint | undefined, y: number, height: number): boolean; export interface ContentProjection { /** The logical source text exposed to find, selection, copy, and assistive technology. */ text: string; /** CSS font shorthand matching the drawn glyphs, e.g. `'24px sans-serif'`. */ font?: string; /** Line height in px, when it differs from the font's default. */ lineHeight?: number; /** * Allow native mouse selection on the projected text. Off by default so the * projection never intercepts pointer input meant for the canvas. */ selectable?: boolean; /** Local x-origin of the rendered text inside the owning entity. */ contentX?: number; /** Local y-origin of the rendered text inside the owning entity. */ contentY?: number; /** * Canvas baseline relative to `contentY` for the first line. When supplied, * Scene aligns the DOM line box baseline instead of assuming both engines * interpret the entity top as a text baseline. */ baseline?: number; /** Explicit visual lines for mixed-style or internally inset text. */ lines?: ContentProjectionLine[]; /** * Set to `'none'` for grid-drawn monospace content (code blocks, editors): * the Scene disables OpenType ligatures and kerning on the projected DOM * text so its selection geometry matches canvas text drawn cell-by-cell. * Firefox otherwise ligates sequences like `ffi` in the DOM copy and the * highlight drifts off the drawn glyphs. */ ligatures?: 'normal' | 'none'; /** * Retained source-aware grid geometry for code-like content. Canvas paint * and semantic projection share this plan so grapheme, tab, wide-character, * shaping, and bidi boundaries cannot drift between the two surfaces. */ grid?: PreparedContentGrid; /** * Confine the projected text's paint to the projection element's own box. * * Opt in when the entity's `render()` clips its own drawing, so the two * surfaces agree on where the content ends. Without it the canvas clips and * the DOM copy does not, and a selection highlight over content wider than * the box paints past the entity onto whatever is drawn beside it — the * defect a horizontally scrollable code block exhibits. * * Off by default, because the projection element is deliberately unclipped: * `Scene` relies on that so selection can start in an entity's blank/padding * regions and extend beyond its bounds. */ clipToBounds?: boolean; } /** Typography for a native input projected by the accessibility layer. */ export interface TextInputStyle { /** CSS font shorthand shared with the canvas mirror. */ font: string; /** Explicit line advance in CSS pixels. */ lineHeight: number; /** Inner text inset in CSS pixels. */ padding: number; } /** * Semantic attributes an {@link Entity} can project into the accessibility / * automation shadow layer maintained by {@link Scene}. * * Returned from {@link Entity.getA11yAttributes}; consumed by `Scene.syncA11y` * to create and label the shadow DOM node (e.g. a real `