Developers
Paint, effects & animation
Fills, gradient stops, color references, strokes, effects, image adjustments, blend modes and animations in the Desyn document model.
Fills#
Fills are painted bottom to top. Every fill can have its own opacity, visibility and blend mode. Gradient and image coordinates are normalized to the node's box (0..1).
type Fill =
| { type: "solid"; color: Color | ColorRef; opacity?: number; visible?: boolean; blend?: BlendMode }
| { type: "linear"; angle: number; stops: Stop[]; opacity?: number; visible?: boolean; blend?: BlendMode }
| { type: "radial"; cx: number; cy: number; rx: number; ry: number; stops: Stop[]; opacity?: number; visible?: boolean; blend?: BlendMode } // normalized 0..1 of the box
| { type: "conic"; cx: number; cy: number; angle: number; stops: Stop[]; opacity?: number; visible?: boolean; blend?: BlendMode }
| { type: "image"; assetId: Id; mode: "fill" | "fit" | "tile" | "stretch"; scale?: number; offsetX?: number; offsetY?: number; rotation?: number; opacity?: number; visible?: boolean; blend?: BlendMode; adjust?: Partial<ImageAdjust> };
interface Stop { pos: number /* 0..1 */; color: Color | ColorRef; }
type ColorRef = { $var: string } | { $style: Id };linear—anglein degrees.radial— centercx,cyand radiirx,ry.conic— center and startangle.image—modefill(cover),fit(contain),tileorstretch, with optional scale, offset, rotation and per-fill adjustments.
Colors are lowercase hex (#rrggbb or #rrggbbaa). Where noted, a color can be a ColorRef instead: { "$var": "brand.primary" } resolves through Design.styles.variables, { "$style": "<id>" } through Design.styles.colors.
Strokes#
interface Stroke { fills: Fill[]; width: number; align: "inside" | "center" | "outside"; dash?: number[]; cap: "butt" | "round" | "square"; join: "miter" | "round" | "bevel"; miterLimit?: number; visible?: boolean; }A stroke's paint is a list of fills, so strokes can be gradients or images. dash is a dash/gap pattern in pixels.
Effects#
type Effect =
| { type: "dropShadow"; x: number; y: number; blur: number; spread: number; color: Color; visible?: boolean }
| { type: "innerShadow"; x: number; y: number; blur: number; spread: number; color: Color; visible?: boolean }
| { type: "layerBlur"; radius: number; visible?: boolean }
| { type: "backgroundBlur"; radius: number; visible?: boolean }
| { type: "noise"; amount: number; scale: number; mono: boolean; visible?: boolean }
| { type: "glow"; radius: number; strength: number; color: Color; visible?: boolean };Effects render in order. backgroundBlur blurs what is behind the node within its shape; noise adds grain (mono for grayscale grain); glow is a colored blur around the node's alpha.
Image adjustments#
interface ImageAdjust {
brightness: number; contrast: number; saturation: number; hue: number; temperature: number; tint: number; // each -1..1 (hue -180..180)
exposure: number; vignette: number; blur: number /* px */; grayscale: number; sepia: number; sharpen: number; grain: number;
duotone?: [Color, Color]; filter?: string /* named preset id */;
}Every adjustment is optional in image fills (Partial<ImageAdjust>) and complete on image nodes. duotone maps shadows and highlights to two colors; filter names a preset.
Blend modes#
type BlendMode = "normal" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn"
| "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity";Animation#
interface Animation {
id: Id; preset: "fade" | "rise" | "drop" | "slide-left" | "slide-right" | "zoom-in" | "zoom-out" | "pop" | "rotate" | "wipe"
| "typewriter" | "pulse" | "float" | "shake" | "blur-in" | "none";
phase: "in" | "out" | "loop"; startMs: number; durationMs: number; easing: "linear" | "ease" | "ease-in" | "ease-out" | "ease-in-out" | "spring";
}phase decides when an animation plays: in when the page appears, out before it ends, loop continuously. startMs and durationMs are relative to the page's start. Page timing (PageNode.durationMs) and transitions (PageNode.transition) are described in the nodes reference.
Reusable styles#
Design.styles holds named colors, text styles and effect sets, plus free-form variables:
interface DesignStyles {
colors: Record<Id, { name: string; value: Color }>;
text: Record<Id, { name: string; style: TextStyle; paragraph?: Partial<ParagraphStyle> }>;
effects: Record<Id, { name: string; effects: Effect[] }>;
variables: Record<string, string | number | boolean>; // e.g. "brand.primary": "#ffb02e"; referenced as {"$var":"brand.primary"}
}Text nodes follow a text style through styleRef. Variables such as "brand.primary": "#ffb02e" are what brand kits change to restyle a whole design in one transaction (a single styles operation).