///
///
import type { Gradient } from "./color"
import type { ProgramId, TextureId } from "flux:gpu"
import type { TextInputHints } from "flux:rendertree"
import type { Element } from "solid-js"
export type { TextInputHints }
// The "srt:*" lattice runner modules are declared in ./runtime-modules.d.ts
// (referenced above) - ambient `declare module` only reaches consumers from a
// non-module declaration file, and this file is a module.
declare global {
interface ImportMeta {
/**
* Build-mode constants, substituted textually by the srt bundler (Vite
* vocabulary). `DEV` is true in dev bundles and false in production
* bundles, where the substituted constant lets the minifier fold
* dev-only code away entirely.
*/
readonly env: { readonly DEV: boolean }
}
let speech: {
start(options: {
model: Uint8Array, vadModel: Uint8Array, lang?: string, microphone?: number,
continuous?: boolean, interimResults?: boolean, wakeWord?: Uint8Array | string | string[], wakeThreshold?: number,
}): Promise<{ handle: number }>
setResultCallback(handle: number, callback: (result: { transcript: string, isFinal: boolean }) => void): void
setSpeechStartCallback(handle: number, callback: () => void): void
setSpeechEndCallback(handle: number, callback: () => void): void
setWakeCallback(handle: number, callback: () => void): void
stop(handle: number): void
}
}
// JSX value model. The element type is solid-js's (its control-flow components
// like return it, so JSX.Element must match). @solidjs/signals ships no
// JSX namespace and solid-js defines no ElementChildrenAttribute, so we supply
// that here - its single key tells TS which prop receives JSX children.
export type { Element }
export interface ElementChildrenAttribute {
children: {}
}
type Children = Element
// Doc-comment policy for this file: JSX props mostly mirror CSS/DOM, which any
// developer or agent already knows, so a comment restating standard semantics
// is noise. Add one only where a prop deviates from that standard, is bespoke
// to this engine, or has an interaction that isn't decidable from the type
// alone (e.g. shorthand-vs-longhand precedence, a subsetted value range).
interface FlexboxProps {
gap?: LengthPercentage
rowGap?: LengthPercentage
columnGap?: LengthPercentage
/** Shorthand; overridden by flexGrow/flexShrink/flexBasis when they're also set. */
flex?: number | "none" | "auto" | (string & {})
flexGrow?: number
flexShrink?: number
flexBasis?: Dimension
flexDirection?: "row" | "column" | "row-reverse" | "column-reverse"
flexWrap?: "nowrap" | "wrap" | "wrap-reverse"
alignSelf?: "start" | "end" | "flex-start" | "flex-end" | "center" | "baseline" | "stretch"
alignItems?: "start" | "end" | "flex-start" | "flex-end" | "center" | "baseline" | "stretch"
alignContent?: "start" | "end" | "flex-start" | "flex-end" | "center" | "stretch" | "space-between" | "space-evenly" | "space-around"
justifyContent?: "start" | "end" | "flex-start" | "flex-end" | "center" | "stretch" | "space-between" | "space-evenly" | "space-around"
}
/** CSS grid subset: line-based placement only, no named lines, no grid-template-areas, and auto tracks take a fixed size (no minmax/fr/keyword). */
interface GridProps {
gridAutoFlow?: "row" | "column" | "row-dense" | "column-dense"
gridAutoColumns?: number
gridAutoRows?: number
gridColumnStart?: number
gridColumnEnd?: number
gridRowStart?: number
gridRowEnd?: number
gridTemplateColumns?: string
gridTemplateRows?: string
}
/**
* A layout length: a bare number is pixels, `pct(n)` is a percentage of the
* containing block, plus "auto" and the `"50%"` string form (kept for paste).
*/
type Dimension = number | Pct | "auto" | `${number}%`
/** Like {@link Dimension} without "auto" (e.g. gap, which has no auto value). */
type LengthPercentage = number | Pct | `${number}%`
export interface LayoutProps extends FlexboxProps, GridProps {
display?: "block" | "flex" | "grid" | "none"
/**
* No "fixed" or "sticky". Unlike CSS, `absolute` does not itself become a
* containing block: an absolute element resolves against the nearest
* ancestor with `position: relative`, so a chain of absolute elements
* resolves against whatever relative element is above all of them.
*/
position?: "relative" | "absolute"
top?: Dimension
right?: Dimension
bottom?: Dimension
left?: Dimension
width?: Dimension
height?: Dimension
minWidth?: Dimension
minHeight?: Dimension
maxWidth?: Dimension
maxHeight?: Dimension
aspectRatio?: number | (string & {})
padding?: Dimension
paddingTop?: Dimension
paddingRight?: Dimension
paddingBottom?: Dimension
paddingLeft?: Dimension
margin?: Dimension
marginTop?: Dimension
marginRight?: Dimension
marginBottom?: Dimension
marginLeft?: Dimension
overflow?: "visible" | "clip" | "hidden" | "scroll"
overflowX?: "visible" | "clip" | "hidden" | "scroll"
overflowY?: "visible" | "clip" | "hidden" | "scroll"
/**
* As an inline atom (an element child of ): leave the flow and sit
* against that side of the text, at the top of the line where the atom
* occurs; the lines it overlaps wrap around its margin box. Same-side
* floats overlapping vertically sit beside each other. The text's height
* includes the float. Meaningless outside a .
*/
float?: "left" | "right"
/**
* As an inline atom: start a new line below the text's earlier floats on
* that side (a floated atom goes below them instead of beside). An empty
* `` is the section break after an image.
*/
clear?: "left" | "right" | "both"
}
/** Colors are CSS color strings, parsed to a packed u32 by `parseColor`. */
export type Color = string
export interface PaintProps {
// A solid color, or a gradient from createLinearGradient/createRadialGradient.
color?: Color | Gradient
blendMode?: "clear" | "source" | "destination" | "source-over" | "destination-over" | "source-in" | "destination-in" | "source-out" | "destination-out" | "source-atop" | "destination-atop" | "xor" | "plus" | "modulate" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "multiply" | "hue" | "saturation" | "color" | "luminosity"
drawStyle?: "fill" | "stroke" | "stroke-and-fill"
strokeCap?: "butt" | "round" | "square"
strokeJoin?: "miter" | "round" | "bevel"
strokeMiter?: number
strokeWidth?: number
}
/** A percentage value, from `pct(50)`. Resolves against the element box. */
export type Pct = { readonly __unit: "pct"; v: number }
// One axis of the transform origin (the point rotate/scale/3D pivot around),
// split per axis to match the engine's x/y prop convention. A bare number is
// pixels; `pct(50)` is a fraction of the box, so a percentage origin tracks the
// layout size with no reactive wiring. Unset defaults to the axis center on a
// laid-out view; on a d-view (no box of its own) it defaults to the view's
// local (0,0) - the origin its children's coordinates are authored against, so
// the pivot never depends on the inherited box. To pivot a d-view around its
// content's center, set the origin explicitly in pixels; pct()/keywords on a
// d-view resolve against the inherited box, which is rarely what you want.
type OriginX = number | Pct | "left" | "center" | "right"
type OriginY = number | Pct | "top" | "center" | "bottom"
export interface TransformProps {
rotate?: number
scale?: number
// Per-axis scale; overrides `scale` on that axis (e.g. scaleX for a flip).
scaleX?: number
scaleY?: number
// 3D rotation about the horizontal axis, in radians (a top/bottom tilt). Like
// rotateY, reads as 3D only with `perspective` set.
rotateX?: number
// 3D rotation about the vertical axis, in radians, for a card-flip. Reads as a
// real flip only with `perspective` set; on its own it is an orthographic
// squash (like scaleX).
rotateY?: number
// Perspective viewing distance in pixels (CSS `perspective`). Enables the 3D
// depth for rotateY; larger values give a shallower effect.
perspective?: number
// Subtree translation in pixels, composited post-layout (no re-record, no
// layout). Unlike the draw primitives' detached-only x/y, these exist on
// layout views too - the drag/thumb idiom animates them freely.
x?: number
y?: number
originX?: OriginX
originY?: OriginY
// Group opacity in 0..1: children are composited together, then faded as a
// whole (CSS `opacity`). Does not affect hit testing. Costs a compositing
// layer (save_layer around the subtree) while below 1, except on a
// repaintBoundary view, where it is hoisted to composite time for free. To
// fade a single primitive, put the alpha in its `color` (rgba) instead -
// paint alpha costs nothing.
opacity?: number
scrollX?: number
scrollY?: number
}
// Window-relative pointer coordinates are reported as clientX/clientY (matching
// the DOM MouseEvent). pointerType distinguishes mouse from touch; button is the
// pressed button on down/up (0 = primary); the modifier flags mirror the DOM.
export interface PointerEvent {
clientX: number
clientY: number
/**
* Pointer position in the coordinate frame of the node whose handler is
* running (its transform chain undone), so it differs per node as the event
* bubbles. Exact even when the pointer is not over the node: a drag routed
* along the frozen down-path keeps reporting true local coordinates after
* leaving it.
*/
localX: number
localY: number
/**
* Pointer position in the frame the running node's own x/y coordinates live
* in: its parent on the hit path (the window for the root). The drag idiom
* is `x = parentX - grab offset`, with the grab offset taken from
* localX/localY at pointer down. The path parent skips
* pointerEvents="none" ancestors, so it is the layout parent in ordinary
* trees.
*/
parentX: number
parentY: number
/**
* Pointer movement since the previous move event, in logical pixels. Mouse
* reports hardware deltas (summed, never lost, and the only motion signal
* while the pointer is locked); touch reports position diffs. 0 on
* non-move events.
*/
movementX: number
movementY: number
/** Node id whose handler is currently running (bubbling changes it per call). */
currentTarget: number
/** Deepest node id of the event's path (the hit leaf). */
target: number
pointerId: number
pointerType: "mouse" | "touch" | "pen" | (string & {})
button?: number
shiftKey: boolean
ctrlKey: boolean
altKey: boolean
metaKey: boolean
// Stops the event from reaching ancestor handlers. Events dispatch leaf->root
// (bubbling), so calling this in a child prevents the enclosing node from
// seeing it (e.g. a slider claiming a drag so an ancestor scroller ignores it).
stopPropagation: () => void
}
export interface WheelEvent extends PointerEvent {
deltaX: number
deltaY: number
}
// Key events use the W3C UI Events vocabulary: `key` is the logical,
// layout-dependent value ("a", "!", "Enter", "ArrowLeft"); `code` is the
// physical, layout-independent key position ("KeyA", "Digit1", "NumpadEnter").
// Printable characters for text entry arrive via onTextInput, not here.
// Routing: keydown/keyup dispatch along the focused node's ancestor chain,
// leaf->root, always ending at the window root; with nothing focused they go
// to the window root alone. is therefore the app-global
// shortcut point.
export interface KeyEvent {
key: string
code: string
repeat: boolean
shiftKey: boolean
ctrlKey: boolean
altKey: boolean
metaKey: boolean
/** Node id whose handler is currently running (bubbling changes it per call). */
currentTarget: number
/** Node id the dispatch started at: the focused node, or the window root when nothing is focused. */
target: number
/**
* Stops the event from reaching ancestor handlers. A component that consumed
* the key calls this so enclosing handlers (and app-global shortcuts on the
* window) do not also act on it.
*/
stopPropagation: () => void
}
export interface TextEvent {
text: string
}
export interface PointerProps {
onPointerDown?: (event: PointerEvent) => void
onPointerUp?: (event: PointerEvent) => void
onPointerMove?: (event: PointerEvent) => void
onPointerEnter?: (event: PointerEvent) => void
onPointerLeave?: (event: PointerEvent) => void
onWheel?: (event: WheelEvent) => void
onFocus?: () => void
onBlur?: () => void
onKeyDown?: (event: KeyEvent) => void
onKeyUp?: (event: KeyEvent) => void
onTextInput?: (event: TextEvent) => void
/**
* IME behavior for this node's text-entry sessions (keyboard type,
* capitalization, autocorrect); read when a session starts. Without it the
* OS defaults apply - notably sentence auto-capitalization, which
* identifier fields and terminals want off:
* `textInputHints={{ capitalize: "none", autocorrect: false }}`.
*/
textInputHints?: TextInputHints
/**
* Declares the element a candidate for focus navigation, enumerable via
* getFocusables(). Candidacy only - it changes no behavior by itself; focus
* still moves through setFocus.
*/
focusable?: boolean
pointerEvents?: "auto" | "none" | "all"
}
/**
* Detached-only geometry, in paint-space pixels. Never affects layout: these
* props exist only on the d-* forms, where there is no layout box and the
* element owns its geometry. The layout forms of the draw primitives derive
* their geometry from the layout box instead (size it with width/height).
*/
export interface PositionProps {
/** Horizontal offset of the drawn geometry; defaults to 0. */
x?: number
/** Vertical offset of the drawn geometry; defaults to 0. */
y?: number
}
/** See {@link PositionProps}: detached-only, never affects layout. */
export interface GeometryProps extends PositionProps {
/** Drawn width; defaults to the inherited box width. */
w?: number
/** Drawn height; defaults to the inherited box height. */
h?: number
}
/** See {@link PositionProps}: detached-only, never affects layout. */
export interface OvalGeometryProps extends PositionProps {
/** Bounding box width of the ellipse (not a radius); defaults to the inherited box. */
w?: number
/** Bounding box height of the ellipse (not a radius); defaults to the inherited box. */
h?: number
}
/** See {@link PositionProps}: detached-only, never affects layout. */
export interface TextGeometryProps extends PositionProps {
// Shaping (wrap) width. Detached text wraps at the inherited ancestor size
// by default; set w for an unwrapped natural line or an explicit wrap width.
w?: number
// Reported-bounds height only; paragraph height always falls out of the text.
h?: number
}
/** See {@link PositionProps}: detached-only, never affects layout. */
export interface LineGeometryProps {
/** Endpoints default to spanning the box: (0,0) to (box width, box height). */
x1?: number
y1?: number
x2?: number
y2?: number
}
// Native transitions (okf/done/native-transitions.md): declared once on
// the element, applied by the runtime to every later write of the covered
// properties. JS hands over targets; Rust interpolates every frame, so a
// running animation costs no JS per frame.
/** A cubic-bezier timing curve: a CSS name or [x1, y1, x2, y2] control values. */
export type TransitionCurve = "linear" | "ease" | "ease-in" | "ease-out" | "ease-in-out" | [number, number, number, number]
/**
* A perceptual spring - the default kind: a bare `{ duration }` is a
* critically damped spring. `duration` (ms) is the perceptual settling
* time, `bounce` in (-1, 1] the springiness - 0 (the default) settles
* without overshoot, positive values overshoot, negative values settle
* sluggishly. A new target while the spring runs keeps position and
* velocity, so the motion stays continuous - use springs for anything
* retargeted while moving.
*/
export interface TransitionSpring {
duration: number
bounce?: number
/** Hold each write for this long (ms) before it applies; a newer write during the hold replaces it and restarts the delay. */
delay?: number
/**
* Mount-time enter animation: at the element's first attach the property
* snaps to this value and animates to the value it mounted with. Numbers
* for the scalar properties; the color property takes a CSS color string
* or packed number. Per-property entries only (not under `all`); a later
* move or reorder re-runs nothing.
*/
from?: number | string
/**
* Removal exit animation: an unmounted element stays visible, animates
* the property to this value (honoring `delay`), and is freed when its
* exit animations settle. Same value forms as `from`, per-property only.
* A move never plays it, the exiting element is hit-test invisible, its
* whole subtree stays painted with it, and no onTransitionEnd fires (the
* component is already disposed). An attached element keeps its layout
* slot until the exit finishes.
*/
exit?: number | string
}
/**
* A duration/curve tween, opted into by naming the curve (a tween is
* always a specific curve; without one the spec reads as a spring).
* Duration in ms. A new target while the tween runs restarts it from the
* current value with the full duration (CSS semantics) - designer-timed,
* one-shot motion.
*/
export interface TransitionTween {
duration: number
curve: TransitionCurve
/** Hold each write for this long (ms) before it applies; a newer write during the hold replaces it and restarts the delay. */
delay?: number
/**
* Mount-time enter animation: at the element's first attach the property
* snaps to this value and animates to the value it mounted with. Numbers
* for the scalar properties; the color property takes a CSS color string
* or packed number. Per-property entries only (not under `all`); a later
* move or reorder re-runs nothing.
*/
from?: number | string
/**
* Removal exit animation: an unmounted element stays visible, animates
* the property to this value (honoring `delay`), and is freed when its
* exit animations settle. Same value forms as `from`, per-property only.
* A move never plays it, the exiting element is hit-test invisible, its
* whole subtree stays painted with it, and no onTransitionEnd fires (the
* component is already disposed). An attached element keeps its layout
* slot until the exit finishes.
*/
exit?: number | string
}
/**
* The shorthand string: `"ms [curve] [ms]"` - `"300ms"` is
* a bounce-0 spring, `"300ms ease-out"` a tween, `"300ms ease-out 100ms"`
* delayed (first time value the duration, second the delay; ms only).
* Bounce, bezier control values and `from` need the object form.
*/
export type TransitionShorthand = string
export type Transition = TransitionSpring | TransitionTween | TransitionShorthand
/** The property names a transition can cover (numeric scalars). */
export type TransitionPropName =
| "x"
| "y"
| "w"
| "h"
| "x1"
| "y1"
| "x2"
| "y2"
| "opacity"
| "rotate"
| "rotateX"
| "rotateY"
| "scale"
| "scaleX"
| "scaleY"
| "strokeWidth"
| "radius"
| "color"
/** Payload of onTransitionEnd: which animated property finished. */
export interface TransitionEndEvent {
property: TransitionPropName
}
export interface TransitionProps {
/**
* A runtime-side transition of one of this element's properties reached
* its target (natural settles only; a cancelled or retargeted animation
* does not fire until it finally settles). Delivered to this element
* only, no bubbling.
*/
onTransitionEnd?: (event: TransitionEndEvent) => void
/**
* Animate later writes of the listed properties instead of snapping:
* `transition={{ x: { duration: 400, bounce: 0.2 }, opacity: "200ms ease-out" }}`.
* `all` covers every animatable property the element has, and a bare
* string is shorthand for it: `transition="300ms ease-out"`. Only
* properties the element carries animate (a d-rect has x, a view's x is
* its transform); the initial value never animates unless the entry sets
* `from` (an enter animation), and a non-numeric write (e.g. null)
* cancels the running animation and snaps. `null` clears the
* declaration; already-running animations finish.
*/
transition?:
| ({
all?: Omit | Omit | TransitionShorthand
/**
* Group stagger (ms): every descendant enter (`from`) or exit that
* begins in the same frame under this element gets `index * stagger`
* of extra delay, in occurrence order (enters and exits cascade
* separately). Nearest declaring ancestor wins; it orchestrates
* descendants only - ordinary writes and this element's own
* lifecycle are unaffected. Adds on top of a per-entry `delay`.
*/
stagger?: number
} & {
[P in TransitionPropName]?: Transition
})
| TransitionShorthand
| null
}
// Primitives
export interface WindowProps extends LayoutProps, PointerProps {
children?: Children
title?: string
fullscreen?: boolean
/**
* Run the window's finished frame through a GPU program as the last step
* before it reaches the screen. While declared, the frame renders into a
* runtime-owned layer texture the program samples; removing the prop
* restores the direct path and frees the layer. Everything else about the
* program (compiling, linking, lifetime) is the raw shading layer's:
* see compileShader/linkProgram.
*/
shader?: WindowShaderProps | null
}
/**
* A window shader declaration. The program reads the frame through
* `uniform sampler2D uSource` (top-left origin, like every sampled texture -
* so a vertex stage mapping it onto the window flips the v coordinate) and
* is drawn attributeless as triangles, `vertexCount` vertices fetched via
* gl_VertexID. `iResolution`, filled by name, is the window size in physical
* pixels (the pass covers exactly that). The window is cleared to opaque
* black first, so geometry that does not cover it still presents a defined
* frame.
*/
export interface WindowShaderProps {
/** Linked program handle from linkProgram. */
program: ProgramId
/**
* Uniforms filled by name, paced to the next real repaint. A number drives
* a scalar (`float`/`int`); a flat number array drives the declared GLSL
* type: 2/3/4 for `vec2`/`vec3`/`vec4`, 16 (column-major) for `mat4`.
*/
params?: Record
/** Extra sampler2D inputs: uniform name to texture id. */
textures?: Record
/** Vertices drawn (attributeless triangles). Default 3, the covering triangle. */
vertexCount?: number
/**
* Retain the last frame as a second layer the program samples as
* `uniform sampler2D uPrevious` (one-frame history: motion echo, frame
* differencing). Costs one extra window-sized texture while declared.
* Until a second frame exists uPrevious samples opaque black. Only declare
* the uPrevious uniform together with this flag - without it the uniform
* stays at unit 0 and aliases uSource. Default false.
*/
previous?: boolean
}
// Everything a view offers besides layout: d-view uses this directly (a
// detached view has no taffy presence, so layout props would be rejected at
// runtime); the layout `view` adds LayoutProps below.
export interface ViewOwnProps extends TransformProps, PointerProps {
children?: Children
trace?: boolean
/**
* Design-space size `[w, h]` for the children: content drawn in that
* coordinate space is uniformly scaled to fit and centered in the element's
* box (SVG's default preserveAspectRatio, generalized). A pure fit
* transform - it never sizes the element, so give the box its size with
* layout props. Composed innermost: the transform props still operate in
* box space, and pointer events on children arrive in design coordinates.
* The overflow clip and scrollX/scrollY stay box properties too: the clip
* rect is the layout box and scroll offsets are box pixels, regardless of
* fit scale. The natural wrapper for parseSvg draws, or any d-* subtree
* authored in fixed design units.
*/
viewBox?: [number, number]
/**
* Corner radii for the clip applied when overflow is non-visible (hidden,
* clip, scroll on both axes). A single number rounds all four corners; an
* array is [top-left, top-right, bottom-right, bottom-left]. Without overflow
* clipping this has no effect.
*/
clipRadius?: number | [number, number, number, number]
/**
* Marks a repaint boundary: the subtree is recorded into its own retained
* display list and reused until something inside it changes. Place around
* heavy static content that sits next to frequently changing content.
*
* "snapshot" additionally retains the rasterized pixels as a GPU texture,
* skipping rasterization entirely. Costs texture memory and re-rasterizes
* on layout-size or display-scale changes. Content painted outside the
* element's layout box is cropped, and ancestor scale animations smear the
* bitmap; best for screen-aligned, static, raster-expensive content.
*
* "snapshot-no-aa" is "snapshot" rasterized without anti-aliasing: cheaper
* (no multisampled scratch, one render pass), but vector content - svg
* paths, rounded corners, rotated edges - comes out hard-edged. Text and
* axis-aligned rects look identical, so prefer it for plain UI panels.
*/
repaintBoundary?: boolean | "snapshot" | "snapshot-no-aa"
/**
* Run this view's rasterized subtree through a GPU program and composite
* the result in its place. Requires a snapshot boundary
* (repaintBoundary="snapshot" or "snapshot-no-aa"; the cost is snapshot
* semantics, kept explicit; declared without one the shader is ignored
* with a warning). The pass is region-sized and split from content
* invalidation: a params-only change re-runs just the pass against the
* cached snapshot, so animating an effect over a static subtree never
* re-rasterizes it.
*
* The effect samples only the subtree's own pixels - grading, warping or
* dissolving the panel works; anything needing what is behind it does not.
* Sampling outside the content clamps to the edge, and the output is
* cropped to the layout box like any snapshot. Hit-testing stays on layout
* geometry: a distortion moves pixels, not hit targets. The view's own
* transform and opacity apply after the effect, so the program sees
* unrotated, opaque content.
*/
shader?: ViewShaderProps | null
}
/**
* A boundary shader declaration. The program contract matches shader targets,
* not the window pass: the subtree's rasterization binds as
* `uniform sampler2D uSource` (top-left origin, like every sampled texture)
* and the pass draws the covering triangle attributeless. `iResolution`,
* filled by name, is the boundary in physical pixels.
*/
export interface ViewShaderProps {
/** Linked program handle from linkProgram. */
program: ProgramId
/**
* Uniforms filled by name, paced to the next real repaint. A number drives
* a scalar (`float`/`int`); a flat number array drives the declared GLSL
* type: 2/3/4 for `vec2`/`vec3`/`vec4`, 16 (column-major) for `mat4`.
*/
params?: Record
/** Extra sampler2D inputs: uniform name to texture id. */
textures?: Record
/**
* Transparent margin in logical px on every side of the layout box, for
* the effect to write into - glow, drop shadow, blur that bleeds past the
* edge. Grows the rasterized canvas and the composited quad; the subtree's
* own paint stays clipped to the layout box either way. The pass sees only
* the bigger iResolution - declare an app uniform if the program needs the
* margin size. Default 0.
*/
outset?: number
/**
* Retain the prior rasterization of the subtree as
* `uniform sampler2D uPrevious`. Source history, not output history: it
* rotates when the content actually re-rasterizes, not per frame - on a
* content change uPrevious holds exactly the old look (transition
* material: cross-dissolve old into new), while for a static subtree with
* animated params uPrevious equals uSource. Feedback/accumulation is not
* this; that stays with manual targets. Costs one extra canvas-sized
* texture while declared; transparent until the first rotation, and reset
* to transparent by a size or scale change. Only declare the uPrevious
* uniform together with this flag - without it the uniform stays at unit 0
* and aliases uSource. Default false.
*/
previous?: boolean
}
export interface ViewProps extends ViewOwnProps, LayoutProps {}
// draw primitives
// A stroked rect paints inside its box, like a CSS border: the stroke's outer
// edge sits on the box edge rather than straddling it, so nothing bleeds past
// the box for a clip to cut. `path` and `line` strokes stay centered on their
// geometry - there the geometry is the stroke, not a box.
export interface RectProps extends PaintProps, PointerProps {
// Corner radius, measured on the box (the stroke's outer edge). A single
// number applies to all four corners; an array is [top-left, top-right,
// bottom-right, bottom-left] (CSS border-radius order).
radius?: number | [number, number, number, number]
}
// Strokes paint inside the box, same as `RectProps`.
export interface OvalProps extends PaintProps, PointerProps {}
// A line's geometry is numbers, not a path string: the segment primitive to
// reach for when endpoints move (each endpoint is one property write; a path
// animates by rebuilding its `d` string). Endpoints (x1/y1/x2/y2) exist on
// the detached `d-line` only. A laid-out `` is practically a rule -
// give it a thin box (length x strokeWidth); in general it draws its layout
// box's top-left-to-bottom-right diagonal. For arbitrary angles and
// connectors use `d-line`; for polylines and curves, a path.
export interface LineProps extends PaintProps, PointerProps {
/** Dash pattern in local units: the drawn segment length. Both onLength and offLength must be set to dash; with either unset the line is solid. */
onLength?: number
/** Dash pattern in local units: the gap length. Both onLength and offLength must be set to dash; with either unset the line is solid. */
offLength?: number
}
export interface PathProps extends PaintProps, PointerProps {
d?: string
fillRule?: "nonzero" | "evenodd"
}
/**
* Per-run text style: the paragraph default on , an override on .
* The cascade is intra-paragraph only: a span inherits from its enclosing
* span, then from the ; nothing inherits across the tree.
*/
export interface TextRunProps {
fontFamily?: "sans" | "serif" | "mono" | (string & {})
fontSize?: number
/**
* Line height as a MULTIPLIER of fontSize, not pixels (the theme uses
* 1.3-1.6). A CSS-reflex pixel value like 22 makes each line box 22x the
* font size, rendering the text as blank space.
*/
lineHeight?: number
fontStyle?: "normal" | "italic"
fontWeight?: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
/**
* Underline in the run's own color, drawn straight through descenders
* (no skip-ink). Position and thickness come from the font's own metrics
* unless overridden; a font Impeller resolves through the system fallback
* gets the shipped Noto values.
*/
textDecoration?: "none" | "underline"
/** Pixels from the baseline to the top of the underline. */
textUnderlineOffset?: number
/** Underline thickness in pixels. */
textDecorationThickness?: number
}
/**
* A styled run inside . Inline text only: children are text and other
* spans. `color` takes what a text's color takes (solid or gradient).
* Pointer handlers fire for the boxes of the run's own text on each line it
* spans and bubble to the enclosing spans and text.
*/
export interface SpanProps extends TextRunProps, PointerProps {
children?: Children
color?: Color | Gradient
}
export interface TextProps extends PaintProps, PointerProps, TextRunProps {
children?: Children
textAlign?: "left" | "right" | "center" | "justify"
maxLines?: number
/**
* What happens to text cut off by maxLines: "clip" (default), "ellipsis"
* (a U+2026 at the end of the last line), or any other string to use as
* the ellipsis. Drawn in the paragraph's default style.
*/
textOverflow?: "clip" | "ellipsis" | (string & {})
/**
* A word (wrap unit) wider than the line: "anywhere" (default) splits it
* at grapheme boundaries so it stays inside the box, "normal" keeps it
* whole and lets it overflow (CSS's default).
*/
overflowWrap?: "normal" | "anywhere"
/**
* First-line indent in pixels. Negative hangs: the first line starts at 0
* and every following line is indented by the magnitude. A hard break does
* not start a new first line.
*/
textIndent?: number
/**
* How lines are chosen beyond greedy fitting (CSS text-wrap): "wrap"
* (default) is greedy; "balance" evens the line lengths while keeping the
* line count (headings, captions); "pretty" is greedy except that a lone
* word on the last line pulls one down from the line above. Neither
* applies once maxLines truncates.
*/
textWrap?: "wrap" | "balance" | "pretty"
}
/**
* A raster draw uses only part of a paint. `blendMode` applies, which is how
* two GPU layers composite in the tree (a solid pass plus an additive pass)
* without a hand-written compositing shader. `color` contributes its alpha
* only, as an opacity multiplier; its RGB does not tint, and a gradient does
* not replace the texture. `drawStyle` and the stroke props have no effect.
* Texture alpha is premultiplied, so additive modes need no manual
* premultiplication.
*/
export interface TextureProps extends PaintProps, PointerProps {
src?: TextureId
/**
* How the texture's pixels map to the element box (CSS object-fit).
* "fill" (default) stretches; "cover" and "none" crop; "contain" and
* "scale-down" letterbox. Everything centers - there is no object-position.
* Paint-only: the element box itself is unaffected, so "contain" letterbox
* bars and "cover" cropped edges still hit-test as part of the element.
*/
fit?: "fill" | "cover" | "contain" | "none" | "scale-down"
srcX?: number
srcY?: number
srcW?: number
srcH?: number
// Shader uniform values, when src names a render target: the same channel
// setTargetParams drives, written through it directly - prop and
// imperative writes validate and error identically (an unknown name
// throws, and set src before params: a write with no src to route to
// throws). However often a signal writes, the target renders once per
// frame at the raster flush. A number drives a scalar (`float`/`int`); a
// flat number array drives the declared GLSL type: 2/3/4 for
// `vec2`/`vec3`/`vec4`, 16 (column-major) for `mat4`.
params?: Record
}