lc Ludic Canvas0.2.0

REFERENCE / GENERATED FROM TYPESCRIPT

The public API.

Exact signatures, types and property documentation for version 0.2.0.

Generated from package declarations. Optional properties use ?. Dimensions use CSS pixels unless stated otherwise. Import these symbols from ludic-canvas. ReactNode and ComponentType refer to the standard React types. FontName is a string identifying one of your registered faces. Internal renderer, layout and GPU classes are intentionally private.

FontSource#

/** An MTSDF atlas and its metrics, produced by msdf-atlas-gen. Maximum: four faces per root. */
export interface FontSource {
    name: string;
    atlas: string;
    metrics: string | AtlasJson;
}

UITheme#

/** Visual defaults. Individual primitive styles take precedence. */
export interface UITheme {
    textColor: string;
    emphasisColor: string;
    focusRing: string;
}

FrameInfo#

/** CSS and device-pixel dimensions of the latest frame. */
export interface FrameInfo {
    width: number;
    height: number;
    dpr: number;
    cssWidth: number;
    cssHeight: number;
    drawCalls: number;
}

UIOptions#

/** Browser root configuration. Game state and image content stay application-owned. */
export interface UIOptions {
    canvas: HTMLCanvasElement;
    /** Existing WebGL 1 context. Draw UI last and restore engine state before its next pass. */
    context?: WebGLRenderingContext;
    /** WebAssembly URL or bytes. Defaults to the bundled Yoga reactor. */
    layout?: string | ArrayBuffer | Uint8Array;
    /** First face is the default. Omit to use bundled Barlow Condensed. */
    fonts?: readonly FontSource[];
    assets?: ImageAssets | AssetResolver;
    theme?: Partial<UITheme>;
    /** Defaults to true. Set false and call frame() from the game's loop. */
    autoStart?: boolean;
    /** Resize backing canvas to CSS dimensions. Defaults to false for a supplied context. */
    manageCanvasSize?: boolean;
    /** Device-pixel ratio cap when managing canvas size. Default: 2. */
    maxDpr?: number;
    /** Clear before drawing. Omit for transparent overlay or shared-context rendering. */
    clearColor?: string;
    /** Existing overlay aligned with the canvas. Otherwise created inside its parent. */
    accessibilityContainer?: HTMLElement;
    /** Positive text measurement multiplier. Default: 1. */
    textScale?: number;
    /** Defaults to the browser's prefers-reduced-motion setting. */
    reducedMotion?: boolean;
    /** Soft cache budget in bytes. Currently visible textures may exceed it. */
    textureBudgetBytes?: number;
    onError?: (error: unknown) => void;
}

UIRoot#

/** A mounted React interface and its layout, input and GPU resources. */
export interface UIRoot {
    /** Schedule an update. State, context and ordinary React hooks work inside the tree. */
    render(element: ReactNode): void;
    /** Draw a frame; now is a requestAnimationFrame timestamp in milliseconds. */
    frame(now?: number): FrameInfo;
    /** Start or resume automatic drawing. Idempotent. */
    start(): void;
    /** Pause automatic drawing; the React tree stays mounted. */
    stop(): void;
    /** Unmount React, cancel frames, remove listeners and free resources. Idempotent. */
    destroy(): void;
    setTextScale(scale: number): void;
    setReducedMotion(enabled: boolean): void;
    setTheme(theme: Partial<UITheme>): void;
    /** Preload image identifiers. Rejects on unknown assets or failed requests. */
    preloadImages(ids: readonly string[]): Promise<void>;
    /** Host tree with computed boxes for development tools. */
    inspect(): unknown;
}

createUI#

/** Create a React → Yoga WebAssembly → WebGL interface on a browser canvas. */
export declare function createUI(options: UIOptions): Promise<UIRoot>;

View#

export declare const View: ComponentType<ViewProps>;

Text#

export declare const Text: ComponentType<TextProps>;

Image#

export declare const Image: ComponentType<ImageProps>;

Line#

export declare const Line: ComponentType<LineProps>;

ImageAsset#

/** An image URL and optional rasterization metadata. SVGs use `kind: 'vector'`. */
export interface ImageAsset {
    url: string;
    width?: number;
    height?: number;
    kind?: 'raster' | 'vector';
}

AssetResolver#

/** Resolves application image identifiers. Return undefined for an unknown identifier. */
export type AssetResolver = (id: string) => ImageAsset | undefined;

ImageAssets#

/** A catalog of application-owned images. Keys are used by the Image primitive. */
export type ImageAssets = Readonly<Record<string, ImageAsset>>;

createAssetResolver#

/** Builds a resolver from a catalog. Omitting the catalog treats `src` as a URL. */
export declare function createAssetResolver(assets?: ImageAssets | AssetResolver): AssetResolver;

defaultAssets#

/** Bundler-resolved URLs for the included layout reactor and OFL font atlas. */
export declare const defaultAssets: {
    layout: string;
    fontAtlas: string;
    fontMetrics: string;
};

Dim#

export type Dim = number | `${number}%` | 'auto';

LayoutStyle#

export interface LayoutStyle {
    display?: 'flex' | 'none';
    position?: 'relative' | 'absolute';
    flexDirection?: 'row' | 'column' | 'row-reverse' | 'column-reverse';
    justifyContent?: 'flex-start' | 'center' | 'flex-end' | 'space-between' | 'space-around' | 'space-evenly';
    alignItems?: 'flex-start' | 'center' | 'flex-end' | 'stretch' | 'baseline';
    alignSelf?: 'auto' | 'flex-start' | 'center' | 'flex-end' | 'stretch' | 'baseline';
    alignContent?: 'flex-start' | 'center' | 'flex-end' | 'stretch' | 'space-between' | 'space-around';
    flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse';
    overflow?: 'visible' | 'hidden' | 'scroll';
    flex?: number;
    flexGrow?: number;
    flexShrink?: number;
    flexBasis?: Dim;
    aspectRatio?: number;
    width?: Dim;
    height?: Dim;
    minWidth?: Dim;
    minHeight?: Dim;
    maxWidth?: Dim;
    maxHeight?: Dim;
    top?: Dim;
    left?: Dim;
    right?: Dim;
    bottom?: Dim;
    margin?: Dim;
    marginX?: Dim;
    marginY?: Dim;
    marginTop?: Dim;
    marginBottom?: Dim;
    marginLeft?: Dim;
    marginRight?: Dim;
    padding?: Dim;
    paddingX?: Dim;
    paddingY?: Dim;
    paddingTop?: Dim;
    paddingBottom?: Dim;
    paddingLeft?: Dim;
    paddingRight?: Dim;
    gap?: number;
    rowGap?: number;
    columnGap?: number;
}

GlowStyle#

export interface GlowStyle {
    color: string;
    spread?: number;
    falloff?: number;
    pulse?: number;
}

VisualStyle#

export interface VisualStyle {
    opacity?: number;
    translateX?: number;
    translateY?: number;
    scale?: number;
    background?: string | [string, string];
    borderColor?: string;
    borderWidth?: number;
    borderRadius?: number;
    glow?: GlowStyle;
    breathe?: number;
}

TextVisualStyle#

export interface TextVisualStyle {
    color?: string;
    emphasisColor?: string;
    fontFamily?: FontName;
    fontSize?: number;
    lineHeight?: number;
    letterSpacing?: number;
    textAlign?: 'left' | 'center' | 'right';
    textTransform?: 'none' | 'uppercase';
    weight?: number;
    shadow?: boolean;
    maxLines?: number;
}

ImageVisualStyle#

export interface ImageVisualStyle {
    tint?: string;
    fit?: 'cover' | 'contain' | 'fill';
    flipX?: boolean;
    flipY?: boolean;
    focusX?: number;
    focusY?: number;
    desaturate?: number;
    darken?: number;
}

ViewStyle#

export type ViewStyle = LayoutStyle & VisualStyle;

TextStyleProp#

export type TextStyleProp = LayoutStyle & VisualStyle & TextVisualStyle;

ImageStyleProp#

export type ImageStyleProp = LayoutStyle & VisualStyle & ImageVisualStyle;

Enter#

export interface Enter {
    opacity?: number;
    translateX?: number;
    translateY?: number;
    scale?: number;
    delay?: number;
    duration?: number;
}

Interactive#

export interface Interactive {
    onPress?: () => void;
    onHover?: (hovered: boolean) => void;
    /** Style overrides blended in while hovered / pressed / focused. */
    hoverStyle?: Partial<VisualStyle & TextVisualStyle & ImageVisualStyle>;
    pressStyle?: Partial<VisualStyle>;
    disabled?: boolean;
    /** Accessible name; pressable nodes get an invisible DOM button mirror. */
    label?: string;
    hotkey?: string;
    pointerEvents?: 'auto' | 'none' | 'box-none';
    /** Swallow presses/hover over this box (modal panels above a scrim). */
    block?: boolean;
    cursor?: 'pointer' | 'default';
}

CommonProps#

export interface CommonProps extends Interactive {
    /** Called (asynchronously) when the node's laid-out size or position changes. */
    onLayout?: (box: {
        x: number;
        y: number;
        width: number;
        height: number;
    }) => void;
    /** Milliseconds; animates opacity/transform/colour changes. */
    transition?: number;
    enter?: Enter;
    /** Draw order among siblings (higher on top). */
    zIndex?: number;
    children?: ReactNode;
}

ViewProps#

export interface ViewProps extends CommonProps {
    style?: ViewStyle;
    /** 0..1 horizontal fill drawn inside the box (bars). Animated with `transition`. */
    fill?: number;
    fillColor?: string;
}

TextProps#

export interface TextProps extends CommonProps {
    style?: TextStyleProp;
    /** Parse **emphasis** markup. */
    rich?: boolean;
    /** Announce changes to screen readers (aria-live). */
    announce?: boolean;
}

ImageProps#

export interface ImageProps extends CommonProps {
    src: string | undefined;
    /** Optional second image cross-faded on top by `mix` (0..1). */
    src2?: string | undefined;
    mix?: number;
    style?: ImageStyleProp;
}

LineProps#

export interface LineProps extends CommonProps {
    from: [number, number];
    to: [number, number];
    /** Interpret from/to as fractions of the parent's box instead of pixels. */
    relative?: boolean;
    width?: number;
    color?: string;
    dash?: number;
    speed?: number;
}

AtlasJson#

interface Bounds { left: number; top: number; right: number; bottom: number; }

export interface AtlasJson {
    atlas: {
        distanceRange: number;
        size: number;
        width: number;
        height: number;
    };
    metrics: {
        emSize: number;
        lineHeight: number;
        ascender: number;
        descender: number;
    };
    glyphs: {
        unicode: number;
        advance: number;
        planeBounds?: Bounds;
        atlasBounds?: Bounds;
    }[];
}