geometry
The 187 preset shapes and custom paths as SVG path data, with the formula evaluator, arcs and adjust handles.
The 187 preset shapes and custom paths, turned into SVG path data; drag an adjust handle and get the number to write back.
npm install @pptx-studio/geometry
What it is
DrawingML describes a shape as guides - little formulas over the width, height and adjust values - and paths built from them. @pptx-studio/geometry carries all 187 preset definitions, transcoded from the standard's own file and cross-checked, plus the evaluator, the arc mathematics and the SVG path emitter. Custom geometry goes through the same code.
Nothing is painted here. Fills, strokes and effects are the paint package's job.
30-second example
const roundRect = getPreset('roundRect');
if (roundRect === undefined) throw new Error('unknown preset');
const size = { w: 200, h: 100 };
resolveGeometry(roundRect, size).paths[0]?.d; // SVG path data, e.g. 'M16.667 0L183.333 0A16.667 16.667 …'
resolveHandles(roundRect, size)[0]?.axes[0]?.value; // the adjust value as the shape stands
const handle = roundRect.ahLst[0];
if (handle !== undefined) {
dragHandle(roundRect, size, handle, { x: 25, y: 0 }); // { adj: … } - what a:avLst should hold
}Key concepts
Adjust values merge by name
A shape's a:avLst overrides the preset's defaults guide by guide. Pass them as { adjust } and resolveGeometry evaluates the rest.
Division by zero is reachable and does not throw
At zero width many guides go non-finite. The result marks them rather than throwing, because a zero-sized shape is something a deck can contain.
Arcs are rays, not parameters
a:arcTo angles are measured against the ellipse's unskewed circle, negative sweeps run the other way, and a sweep of a whole turn is split - every case measured against what PowerPoint draws.
Dragging a handle inverts the formula
dragHandle searches the declared range for the adjust value that puts the handle where the pointer is, and returns the number to write into a:avLst. Some declared ranges do not contain the shape's own value; those are widened and say so.
API reference
80 exports of @pptx-studio/geometry 0.1.2, read from the package this site installed. Click a name for its declaration.
src/presets/manifest.gen.ts
PRESET_SOURCEconstconst PRESET_SOURCE: { readonly file: "presetShapeDefinitions.xml"; readonly sha256: "4a762444d8d85876881c02a5b1dedf6f73006fcd8acb7b4e393435615b37c780"; readonly bytes: 538970; readonly root: "presetShapeDefinitons"; };PRESET_TOTALSconstCounted on the generator side, from the parse. The suite checks the decode against these.const PRESET_TOTALS: { readonly shapes: 187; readonly avGuides: 300; readonly gdGuides: 3622; readonly handles: 243; readonly sites: 860; readonly textRects: 182; readonly paths: 320; readonly commands: 2915; };BUCKET_MEMBERSconstconst BUCKET_MEMBERS: { readonly basic: readonly ["arc", "bevel", "blockArc", "bracePair", "bracketPair", "can", "chord", "cloud", "corner", "cube", "decagon", "diagStripe", "diamond", "dodecagon", "donut", "ellipse", "foldedCorner", "frame", "halfFrame", "heart", "heptagon", "hexagon", "leftBrace", "leftBracket", "lightningBolt", "moon", "noSmoking", "octagon", "parallelogram", "pentagon", "pie", "plaque", "plus", "rect", "rightBrace", "rightBracket", "roundRect", "rtTriangle", "smileyFace", "sun", "teardrop", "trapezoid", "triangle"]; readonly arrows: readonly ["bentArrow", "bentUpArrow", "chevron", "circularArrow", "curvedDownArrow", "curvedLeftArrow", "curvedRightArrow", "curvedUpArrow", "downArrow", "downArrowCallout", "homePlate", "leftArrow", "leftArrowCallout", "leftCircularArrow", "leftRightArrow", "leftRightArrowCallout", "leftRightCircularArrow", "leftRightUpArrow", "leftUpArrow", "notchedRightArrow", "quadArrow", "quadArrowCallout", "rightArrow", "rightArrowCallout", "stripedRightArrow", "swooshArrow", "upArrowCallout", "upDownArrow", "upArrow", "upDownArrowCallout", "uturnArrow"]; readonly callouts: readonly ["accentBorderCallout1", "accentBorderCallout2", "accentBorderCallout3", "accentCallout1", "accentCallout2", "accentCallout3", "borderCallout1", "borderCallout2", "borderCallout3", "callout1", "callout2", "callout3", "cloudCallout", "wedgeEllipseCallout", "wedgeRectCallout", "wedgeRoundRectCallout"]; readonly flowchart: readonly ["flowChartAlternateProcess", "flowChartCollate", "flowChartConnector", "flowChartDecision", "flowChartDelay", "flowChartDisplay", "flowChartDocument", "flowChartExtract", "flowChartInputOutput", "flowChartInternalStorage", "flowChartMagneticDisk", "flowChartMagneticDrum", "flowChartMagneticTape", "flowChartManualInput", "flowChartManualOperation", "flowChartMerge", "flowChartMultidocument", "flowChartOfflineStorage", "flowChartOffpageConnector", "flowChartOnlineStorage", "flowChartOr", "flowChartPredefinedProcess", "flowChartPreparation", "flowChartProcess", "flowChartPunchedCard", "flowChartPunchedTape", "flowChartSort", "flowChartSummingJunction", "flowChartTerminator"]; readonly misc: readonly ["actionButtonBackPrevious", "actionButtonBeginning", "actionButtonBlank", "actionButtonDocument", "actionButtonEnd", "actionButtonForwardNext", "actionButtonHelp", "actionButtonHome", "actionButtonInformation", "actionButtonMovie", "actionButtonReturn", "actionButtonSound", "bentConnector2", "bentConnector3", "bentConnector4", "bentConnector5", "chartPlus", "chartStar", "chartX", "cornerTabs", "curvedConnector2", "curvedConnector3", "curvedConnector4", "curvedConnector5", "funnel", "gear6", "gear9", "line", "lineInv", "mathDivide", "mathEqual", "mathMinus", "mathMultiply", "mathNotEqual", "mathPlus", "nonIsoscelesTrapezoid", "pieWedge", "plaqueTabs", "round1Rect", "round2DiagRect", "round2SameRect", "snip1Rect", "snip2DiagRect", "snip2SameRect", "snipRoundRect", "squareTabs", "straightConnector1"]; readonly stars: readonly ["doubleWave", "ellipseRibbon", "ellipseRibbon2", "horizontalScroll", "irregularSeal1", "irregularSeal2", "leftRightRibbon", "ribbon", "ribbon2", "star10", "star12", "star16", "star24", "star32", "star4", "star5", "star6", "star7", "star8", "verticalScroll", "wave"]; };OVER_LONG_FORMULASconst+-takes three operands in ECMA. Eight formulas in POI's file carry four, every one of them ending in a spare0, and every one of them in the circular-arrow family. Carried through verbatim: the evaluator decides what to do with a fourth operand, not the transcoder.const OVER_LONG_FORMULAS: readonly [{ readonly shape: "circularArrow"; readonly guide: "xB"; readonly fmla: "+- xH 0 dxB 0"; }, { readonly shape: "circularArrow"; readonly guide: "yB"; readonly fmla: "+- yH 0 dyB 0"; }, { readonly shape: "leftCircularArrow"; readonly guide: "xB"; readonly fmla: "+- xH 0 dxB 0"; }, { readonly shape: "leftCircularArrow"; readonly guide: "yB"; readonly fmla: "+- yH 0 dyB 0"; }, { readonly shape: "leftRightCircularArrow"; readonly guide: "xB"; readonly fmla: "+- xH 0 dxB 0"; }, { readonly shape: "leftRightCircularArrow"; readonly guide: "yB"; readonly fmla: "+- yH 0 dyB 0"; }, { readonly shape: "leftRightCircularArrow"; readonly guide: "xJ"; readonly fmla: "+- xI 0 dxJ 0"; }, { readonly shape: "leftRightCircularArrow"; readonly guide: "yJ"; readonly fmla: "+- yI 0 dyJ 0"; }];COLLAPSED_WHITESPACEconstFormulas written with a double space. Split on runs of whitespace, so the operands are right; listed because a naive single-space split gives each of these an empty operand and an arity one too high.const COLLAPSED_WHITESPACE: readonly [{ readonly shape: "heptagon"; readonly guide: "svc"; readonly fmla: "*/ vc vf 100000"; }, { readonly shape: "leftArrow"; readonly guide: "x1"; readonly fmla: "+- x2 0 dx1"; }, { readonly shape: "pentagon"; readonly guide: "svc"; readonly fmla: "*/ vc vf 100000"; }, { readonly shape: "star5"; readonly guide: "svc"; readonly fmla: "*/ vc vf 100000"; }, { readonly shape: "star7"; readonly guide: "svc"; readonly fmla: "*/ vc vf 100000"; }, { readonly shape: "upArrow"; readonly guide: "y1"; readonly fmla: "+- y2 0 dy1"; }];
src/errors.ts
GeometryErrorCodetypeTyped failures, as everywhere else in this repository.type GeometryErrorCode = /** The generated preset data did not decode. A build bug, never a user's file. */ 'PRESET_DECODE' | /** A preset name that is not one of the 187. */ 'PRESET_UNKNOWN' | /** A `fmla` whose first token is not one of the seventeen operators. */ 'FMLA_OPERATOR' | /** An operator given the wrong number of operands. */ 'FMLA_ARITY' | /** An operand that is neither an integer literal nor a guide in scope. */ 'FMLA_OPERAND';
GeometryErrorclassclass GeometryError extends Error { readonly code: GeometryErrorCode; /** The preset being decoded when this happened, when there is one. */ readonly preset: string | null; constructor(code: GeometryErrorCode, message: string, preset?: string | null); }
src/types.ts
PresetBucketNametypeWhich generated bucket a preset lives in. A packaging fact, not a semantic one.type PresetBucketName = 'basic' | 'arrows' | 'callouts' | 'flowchart' | 'misc' | 'stars';
PresetGuidetypeOnea:gd: a named value and the formula that produces it.interface PresetGuide { readonly name: string; /** * The `fmla` attribute, split on whitespace: the operator first, then its * operands. Not a fixed arity, because the source data does not have one - * see `OVER_LONG_FORMULAS` in the generated buckets. */ readonly fmla: readonly string[]; }PresetPointtypeA point in guide space. Both coordinates are formula operands, not numbers.interface PresetPoint { readonly x: string; readonly y: string; }PointtypeA point after evaluation, in shape coordinates.interface Point { readonly x: number; readonly y: number; }PresetCommandtypeOne drawing command.type PresetCommand = { readonly kind: 'moveTo'; readonly to: PresetPoint; } | { readonly kind: 'lnTo'; readonly to: PresetPoint; } | { readonly kind: 'quadBezTo'; readonly c1: PresetPoint; readonly to: PresetPoint; } | { readonly kind: 'cubicBezTo'; readonly c1: PresetPoint; readonly c2: PresetPoint; readonly to: PresetPoint; } | { readonly kind: 'arcTo'; readonly wR: string; readonly hR: string; readonly stAng: string; readonly swAng: string; } | { readonly kind: 'close'; };PresetPathFilltypeST_PathFillMode.normis the default and is never written in the source.type PresetPathFill = 'none' | 'norm' | 'lighten' | 'lightenLess' | 'darken' | 'darkenLess';
PresetPathtypeinterface PresetPath { /** * Path-space width and height. **Zero means no scaling**, not a degenerate * path: an unscaled path is already in shape coordinates. Reading these as a * divisor without the zero check is a divide-by-zero on 270 of the 320 paths. */ readonly w: number; readonly h: number; readonly fill: PresetPathFill; readonly stroke: boolean; readonly extrusionOk: boolean; readonly commands: readonly PresetCommand[]; }PresetAdjustHandleXYtypeAn adjust handle, in one of its two coordinate systems.interface PresetAdjustHandleXY { readonly kind: 'xy'; readonly gdRefX: string | null; readonly minX: string | null; readonly maxX: string | null; readonly gdRefY: string | null; readonly minY: string | null; readonly maxY: string | null; readonly pos: PresetPoint; }PresetAdjustHandlePolartypeinterface PresetAdjustHandlePolar { readonly kind: 'polar'; readonly gdRefR: string | null; readonly minR: string | null; readonly maxR: string | null; readonly gdRefAng: string | null; readonly minAng: string | null; readonly maxAng: string | null; readonly pos: PresetPoint; }PresetAdjustHandletypetype PresetAdjustHandle = PresetAdjustHandleXY | PresetAdjustHandlePolar;
PresetConnectionSitetypeA connection site: where a connector may attach, and the angle it leaves at.interface PresetConnectionSite { readonly ang: string; readonly pos: PresetPoint; }PresetTextRecttypeThe text rectangle. Four formula operands, not a box.interface PresetTextRect { readonly l: string; readonly t: string; readonly r: string; readonly b: string; }GeometrytypeA geometry definition: one of the 187 presets, or ana:custGeomread from a slide.interface Geometry { /** The `ST_ShapeType` value from `a:prstGeom/@prst`, or `null` for an `a:custGeom`. */ readonly name: string | null; /** Adjust values, with their defaults. Overridden by name from the shape's own `avLst`. */ readonly avLst: readonly PresetGuide[]; /** Computed guides, in dependency order - the source data is already ordered. */ readonly gdLst: readonly PresetGuide[]; readonly ahLst: readonly PresetAdjustHandle[]; readonly cxnLst: readonly PresetConnectionSite[]; /** * The text rectangle, or `null` when there is none - five presets, and any * `custGeom` that omits `a:rect`. A caller that defaults a missing one to the * shape bounds is choosing a policy, which is why this is null rather than * pre-filled. */ readonly rect: PresetTextRect | null; readonly pathLst: readonly PresetPath[]; }PresetShapetypeA preset: aGeometrythat is guaranteed to have a name.interface PresetShape extends Geometry { readonly name: string; }custGeomfunctionBuild aGeometryfrom the parts ana:custGeomactually declared.function custGeom(parts?: Partial<Geometry>): Geometry;
src/formula/builtins.ts
builtinGuidesfunctionEvery built-in guide for a shape of this size.function builtinGuides(w: number, h: number): Map<string, number>;
builtinGuideNamesfunctionThe names of every built-in guide, sorted by code unit.function builtinGuideNames(): readonly string[];
src/paths/arc.ts
ARC_MAX_SWEEPconstA full turn of sweep, in 60000ths of a degree.swAngis clamped to plus or minus this.const ARC_MAX_SWEEP = 21600000;
ArcParameterstypeOnea:arcTo, after its four operands have been evaluated.interface ArcParameters { /** Horizontal radius. Note this is a radius, not a diameter: presets pass `wd2`. */ readonly wR: number; readonly hR: number; /** Start angle in 60000ths of a degree, as a ray from the centre. Not a parameter. */ readonly stAng: number; /** Swing angle. Signed: negative sweeps anticlockwise on screen. */ readonly swAng: number; }ArcGeometrytypeEverything an arc turns out to be, once its start point is known.interface ArcGeometry { readonly centre: Point; readonly start: Point; readonly end: Point; /** The radii actually used - the absolute values of `wR` and `hR`. */ readonly rx: number; readonly ry: number; /** Parametric start angle in radians. */ readonly startT: number; /** * Parametric end angle in radians, lifted rather than wrapped: it is * `startT + delta` for the true signed sweep, so it may lie outside * `[-pi, pi]` and its difference from `startT` is the parametric sweep. */ readonly endT: number; /** The swing angle actually used, after clamping. Same units as `swAng`. */ readonly sweptAngle: number; /** * True when the arc has no extent to draw: a zero radius, or a non-finite * operand. Start, end and centre are still filled in as far as they can be. */ readonly degenerate: boolean; }ArcSegmenttypeOne arc an SVGAcommand can actually draw.interface ArcSegment { readonly from: Point; readonly to: Point; readonly rx: number; readonly ry: number; /** SVG `large-arc-flag`: this piece spans more than half a turn. */ readonly largeArc: boolean; /** SVG `sweep-flag`: true when the sweep is positive, which on screen is clockwise. */ readonly sweep: boolean; }clampSweepfunctionswAngclamped to a single turn in either direction, which is what Office does.function clampSweep(swAng: number): number;
unskewAnglefunctionTurn a DrawingML ray angle into the ellipse parameter that reaches the same point:t = atan2(wR sin a, hR cos a).function unskewAngle(angle: number, wR: number, hR: number): number;
arcGeometryfunctionResolve one arc against the point the path has reached.function arcGeometry(from: Point, arc: ArcParameters): ArcGeometry;
arcEndfunctionWhere an arc leaves the pen. The only thing a path walker needs from it.function arcEnd(from: Point, arc: ArcParameters): Point;
arcPointAtfunctionThe point a given fraction of the way along the arc,0being the start and1the end. Fractions outside that range extrapolate along the same ellipse.function arcPointAt(geometry: ArcGeometry, fraction: number): Point;
arcSegmentsfunctionBreak an arc into pieces an SVGAcommand can draw, in order.function arcSegments(from: Point, arc: ArcParameters): ArcSegment[];
src/decode.ts
decodeShapefunctionDecode one shape's|-separated body. Exported so the generator can round-trip it.function decodeShape(name: string, body: string): PresetShape;
PresetBucketclassOne generated bucket, decoded on demand.class PresetBucket { #private; constructor(data: string); /** Every preset name in this bucket, in the order the source file lists them. */ get names(): readonly string[]; has(name: string): boolean; /** `undefined` when the name lives in another bucket - callers chain over the six. */ get(name: string): PresetShape | undefined; }
src/formula/formula.ts
FULL_CIRCLEconstOne full turn, in 60000ths of a degree.const FULL_CIRCLE = 21600000;
ANGLE_UNITS_PER_DEGREEconstDrawingML states angles in 60000ths of a degree, everywhere, without exception.const ANGLE_UNITS_PER_DEGREE = 60000;
FmlaOperatortypeThe operator tokens, as a type.type FmlaOperator = '*/' | '+-' | '+/' | '?:' | 'abs' | 'at2' | 'cat2' | 'cos' | 'max' | 'min' | 'mod' | 'pin' | 'sat2' | 'sin' | 'sqrt' | 'tan' | 'val';
FMLA_ARITYconstHow many operands each operator takes.const FMLA_ARITY: Readonly<Record<FmlaOperator, number>>;
isFmlaOperatorfunctionfunction isFmlaOperator(token: string): token is FmlaOperator;
angleToRadiansfunctionConvert an angle in 60000ths of a degree to radians.function angleToRadians(angle: number): number;
radiansToAnglefunctionConvert radians to 60000ths of a degree.function radiansToAngle(radians: number): number;
FormulaSitetypeWhere a formula came from, for the error message and forGeometryError.preset.interface FormulaSite { readonly preset: string | null; readonly guide: string | null; }applyOperatorfunctionApply one operator to operands that are already numbers.function applyOperator(op: string, args: readonly number[], site?: FormulaSite | null): number;
src/formula/evaluate.ts
ShapeSizetypeThe size of the shape being evaluated, in whatever unit the caller is using.interface ShapeSize { readonly w: number; readonly h: number; }AdjustOverridestypeA deck's own adjust values.type AdjustOverrides = readonly PresetGuide[] | Readonly<Record<string, number>>;
EvaluateOptionstypeinterface EvaluateOptions { /** Overrides from `a:prstGeom/a:avLst`, merged over the preset's defaults by NAME. */ readonly adjust?: AdjustOverrides; }resolveOperandfunctionResolve one operand: a guide already in scope, or an integer literal.function resolveOperand(token: string, guides: ReadonlyMap<string, number>, site?: FormulaSite | null): number;
resolvePointfunctionResolve both coordinates of a point. Used by the text rectangle, connection sites and paths.function resolvePoint(point: PresetPoint, guides: ReadonlyMap<string, number>, site?: FormulaSite | null): Point;
evaluateGuidesfunctionEvaluate every guide of a preset at a given size.function evaluateGuides(shape: Geometry, size: ShapeSize, options?: EvaluateOptions): Map<string, number>;
nonFiniteGuidesfunctionThe names of any guides that evaluated to something not finite, sorted.function nonFiniteGuides(guides: ReadonlyMap<string, number>): string[];
src/paths/handles.ts
HandleAxisKindtypeWhich scalar of a handle's position an axis moves.type HandleAxisKind = 'x' | 'y' | 'r' | 'ang';
HANDLE_SAMPLESconstHow many points the readout is sampled at before a bracket is chosen.const HANDLE_SAMPLES = 33;
HANDLE_TOLERANCEconstWhen the search stops, in adjust units.const HANDLE_TOLERANCE = 0.5;
ResolvedHandleAxistypeOne adjustable axis of one handle, resolved at a size.interface ResolvedHandleAxis { readonly kind: HandleAxisKind; /** The adjust value this axis writes: `gdRefX`, `gdRefY`, `gdRefR` or `gdRefAng`. */ readonly guide: string; /** What that guide holds as the shape currently stands. */ readonly value: number; /** * The bounds the search and the clamp use, ordered so `min <= max`. * * The declared `minX`/`maxX` pair, widened where it had to be - see `widened`. */ readonly min: number; readonly max: number; /** * True when the declared bounds did not contain the shape's own value and * were widened to admit it. 16 of the 1435 axis-and-size combinations. */ readonly widened: boolean; /** The readout at `value`: a coordinate, a radius, or an angle in 60000ths of a degree. */ readonly readout: number; }ResolvedHandletypeOnea:ahXYora:ahPolar, resolved at a size.interface ResolvedHandle { readonly kind: 'xy' | 'polar'; /** Where to draw it, in shape space. */ readonly pos: Point; /** One entry per declared `gdRef`. Zero, one or two - either axis may be absent. */ readonly axes: readonly ResolvedHandleAxis[]; /** False if the position or a bound is not finite, which a zero-sized shape reaches. */ readonly finite: boolean; }ResolveHandleOptionstypeinterface ResolveHandleOptions extends EvaluateOptions { /** The preset's name, for the message when an operand does not resolve. */ readonly name?: string | null; }handleCentrefunctionThe origin a polar handle's radius and angle are measured from.function handleCentre(size: ShapeSize): Point;
readHandleAxisfunctionRead one scalar off a handle position. Angles come back in 60000ths of a degree.function readHandleAxis(kind: HandleAxisKind, pos: Point, centre: Point): number;
resolveHandlesfunctionEvery handle of a geometry, resolved at a size.function resolveHandles(geometry: Geometry, size: ShapeSize, options?: ResolveHandleOptions): readonly ResolvedHandle[];
InvertAxisOptionstypeinterface InvertAxisOptions extends ResolveHandleOptions { /** * The value to stay near when a fold makes more than one answer possible. * Defaults to the axis's current value, which is what a drag wants. */ readonly near?: number; }invertAxisfunctionThe adjust value that puts this axis's readout attarget.function invertAxis(geometry: Geometry, size: ShapeSize, handle: PresetAdjustHandle, axis: ResolvedHandleAxis, target: number, options?: InvertAxisOptions): number;
roundAdjustfunctionRound an adjust value to something a file can hold.function roundAdjust(value: number, min: number, max: number): number;
dragHandlefunctionDrag one handle to a point, and get back the adjust values to write.function dragHandle(geometry: Geometry, size: ShapeSize, handle: PresetAdjustHandle, to: Point, options?: ResolveHandleOptions): Record<string, number>;
src/paths/path.ts
DEFAULT_PRECISIONconstDecimal places kept in an emitteddstring.const DEFAULT_PRECISION = 4;
PathSegmenttypeOne segment of a resolved path, in shape coordinates and ready to emit.type PathSegment = { readonly kind: 'move'; readonly to: Point; } | { readonly kind: 'line'; readonly to: Point; } | { readonly kind: 'quad'; readonly c1: Point; readonly to: Point; } | { readonly kind: 'cubic'; readonly c1: Point; readonly c2: Point; readonly to: Point; } | ({ readonly kind: 'arc'; } & ArcSegment) | { readonly kind: 'close'; };ResolvedPathtypeinterface ResolvedPath { /** `ST_PathFillMode`, passed through. What it means in paint is 2.6 to 2.8. */ readonly fill: PresetPathFill; readonly stroke: boolean; readonly extrusionOk: boolean; /** The factors path space was scaled by. Both 1 when the path declares none. */ readonly scaleX: number; readonly scaleY: number; readonly segments: readonly PathSegment[]; /** * SVG path data. **Empty when `finite` is false**, because a `d` holding a * `NaN` is not merely wrong, it is invalid: a browser drops the whole path * and says nothing. The numbers stay in `segments` for a caller that wants to * see what happened. */ readonly d: string; /** * False when any operand, scale factor or emitted coordinate was not finite. * * A real case rather than a corrupt-file one. At zero width 11 presets reach * a non-finite number inside a path, at zero height 16, and 19 when both * dimensions collapse - see the note on division in `evaluate.ts`. */ readonly finite: boolean; }ResolvedRecttypeThe text rectangle, resolved. Four numbers in shape coordinates.interface ResolvedRect { readonly l: number; readonly t: number; readonly r: number; readonly b: number; }ResolvedConnectionSitetypeA connection site, resolved.angstays in 60000ths of a degree.interface ResolvedConnectionSite { readonly ang: number; readonly pos: Point; }ResolvedGeometrytypeinterface ResolvedGeometry { /** The preset's name, or `null` for an `a:custGeom`, which has none. */ readonly name: string | null; /** Built-ins, adjust values and computed guides, as `evaluateGuides` returns them. */ readonly guides: ReadonlyMap<string, number>; readonly paths: readonly ResolvedPath[]; /** `null` for the five presets with no `a:rect`. Defaulting one is a policy. */ readonly textRect: ResolvedRect | null; readonly connectionSites: readonly ResolvedConnectionSite[]; }ResolvePathOptionstypeinterface ResolvePathOptions { /** Decimal places in the `d` string. Default `DEFAULT_PRECISION`. */ readonly precision?: number; /** The shape name, used only so a failed operand can say where it came from. */ readonly name?: string | null; }ResolveGeometryOptionstypetype ResolveGeometryOptions = EvaluateOptions & ResolvePathOptions;
pathScalefunctionThe factors that carry a path's own coordinate system into shape space.function pathScale(path: PresetPath, size: ShapeSize): { x: number; y: number; };pathDatafunctionSegments to an SVGdstring.function pathData(segments: readonly PathSegment[], precision?: number): string;
resolvePathfunctionResolve onea:pathagainst a set of guides and a shape size.function resolvePath(path: PresetPath, guides: ReadonlyMap<string, number>, size: ShapeSize, options?: ResolvePathOptions): ResolvedPath;
resolveGeometryfunctionEvaluate a geometry and resolve everything a renderer needs from it.function resolveGeometry(geometry: Geometry, size: ShapeSize, options?: ResolveGeometryOptions): ResolvedGeometry;
src/presets/index.ts
BUCKETSconstAll 187 presets, and the stable way to reach one.const BUCKETS: Readonly<Record<PresetBucketName, PresetBucket>>;
getPresetfunctionThe preset for ana:prstGeom/@prstvalue, orundefinedif it is not one of the 187.function getPreset(name: string): PresetShape | undefined;
presetNamesfunctionEveryST_ShapeTypename that has a definition, sorted by code unit.function presetNames(): readonly string[];
Errors
Throws GeometryError, whose code is one of:
- PRESET_DECODE
- PRESET_UNKNOWN
- FMLA_OPERATOR
- FMLA_ARITY
- FMLA_OPERAND
Try it live
Reading the deck…