/** * A Blobatar style composed from silhouette definitions. * * The band table chooses and weights silhouettes. Each silhouette owns its * geometry and safe face region; this module owns the shared body, eyes and SVG * serialization. The seam is private, so it can deepen when a future shape * proves the current definition insufficient without committing consumers to * its lifecycle. */ import type { Palette } from "../color"; import type { Traits } from "../traits"; import type { Body, Ellipse, Shape } from "./shapes"; export interface Eye { cx: number; cy: number; rx: number; ry: number; n: number; rot: number; } export type Fit = (t: Traits, b: Body, face: Ellipse) => Eye[]; /** Fits the eye cluster against the silhouette's face region on both axes. */ export declare const faceFit: Fit; /** `[shape, upper edge of its band in [0, 1)]`, in order. */ export type Band = readonly [Shape, number]; export declare function compose(bands: Band[], fit: Fit): { layout: (t: Traits) => { shape: string; draw: ((b: Body) => string) | undefined; body: Body; face: Ellipse; petals: { cx: number; cy: number; r: number; }[]; extra: string[]; eyes: Eye[]; }; render: (l: ReturnType<(t: Traits) => { shape: string; draw: ((b: Body) => string) | undefined; body: Body; face: Ellipse; petals: { cx: number; cy: number; r: number; }[]; extra: string[]; eyes: Eye[]; }>, p: Palette, mo?: boolean) => string; background: false; }; /** * One drawn primitive, as data rather than as markup. * * This is the other half of `render`, and it exists because `react-native-svg` * has no `innerHTML` to hand a string to, so an adapter there builds real * elements or it builds nothing. Serializing here and parsing there would put * an XML parser between the renderer and the screen, which is a place output * can change, and ADR-0009 is explicit that an adapter adds no geometry of its * own. * * The fill rides on every mark rather than on a group. `render` groups by fill * because SVG attribute inheritance makes that cheaper on the wire; nothing * downstream of this reads a group, so grouping here would only be structure * the adapter has to walk back out. */ export type Mark = { kind: "path"; d: string; fill: string; } | { kind: "circle"; cx: number; cy: number; r: number; fill: string; }; /** * The same figure `render` draws, as marks. * * **A standalone function, deliberately not a method on the object `compose` * returns.** A property of a live object literal can never be dropped by a * bundler, so putting it there would charge every web consumer for a seam only * React Native reads. That is the same reasoning that keeps `animate.ts` out of static * bundles by passing the motion factory in rather than importing it. * * Kept beside `render` rather than derived from it, or it from this. Both * directions were available and both tax the static path everyone is already * on: an emitter puts an indirection in it, and making marks primary makes it * allocate an array of objects before stringifying. So there are two small * traversals of one layout, and the drift that invites is *caught* rather than * prevented: `test/marks.test.ts` asserts these serialize to exactly what * `render` emits, over the golden corpus, and `packages/harness` compares the * React Native adapter against React on every case in its table. * * No `mo` parameter. React Native never animates (the motion layer is CSS), so * there is no motion grouping to emit and no class to carry. */ export declare function marks(l: Layout, p: Palette): Mark[]; /** * What a composed `layout` returns. * * `shape` is a `string` here rather than a union of names, because which names * are possible is a property of the band table and not of the composer. The * public `blob` entry narrows this to the package major's known vocabulary. */ export type Layout = ReturnType["layout"]>; //# sourceMappingURL=compose.d.ts.map