* fix(core): let fill text share an auto-layout row Fill frames grow and shrink from a zero flex basis, so fill siblings split a row's free space. Fill text only got flexGrow, and its measure function capped it at its stored width, 100px for new text, so seven fill labels in a 280px row each kept 100px and overflowed. Without a measurer, the fallback pinned that width and set no grow at all. Fill text now uses the same zero basis as fill frames on both paths. * fix(design-jsx): read repeat() and minmax() in grid tracks Track lists were split on whitespace, so columns="repeat(7, 1fr)" became the tracks repeat(7, and 1fr), read as fixed 0px and 1px columns that collapsed the grid. Tokens inside parentheses now stay together, repeat() expands its tracks, minmax() grows like its maximum, and a track the grid cannot express sizes to its content instead of to 0. * refactor(scene-graph): parse CSS grid tracks with postcss-value-parser design-jsx read repeat() and minmax() with a hand-written tokenizer and regexes, while dom-css already parses CSS values with postcss-value-parser. Track lists are now parsed in @open-pencil/scene-graph/css on that library, where both packages can use it, and design-jsx calls it. dom-css's hand-written declaration of the library's types is replaced by the types the library ships, which the shared module needs. The Scene Graph guide records that CSS values are parsed there.
3.4 KiB
3.4 KiB
Scene Graph
Framework-neutral document model. Owns node types, primitives, geometry, matrices, copy/snap/undo helpers, variables, instances, hit testing, and checkpoint recovery.
- Nodes live in a flat
Map<string, SceneNode>; runtime hierarchy usesparentIdandchildIds. Frames do not clip by default. - Geometry is built on the matrices in
packages/scene-graph/src/matrix.tsandpackages/scene-graph/src/coordinate.ts(getWorldMatrix,getAxisAlignedWorldBounds,getNodeLocalMatrix). Add new transform, bounds, or inverse helpers here beside them; do not interpret ancestor rotations or reflections independently elsewhere. LINE pivots remain at the origin; other nodes rotate around their centers. - Bounds accumulation goes through the helpers in
packages/scene-graph/src/geometry.ts(computeBounds,computeAbsoluteBounds,computeVisualBounds); do not add another min/max loop. - Reparenting preserves child world positions; groups preserve them too. Sort children geometrically before creating auto-layout. Consumers such as layer trees must react to reparenting rather than retaining stale child references.
- Use the copy helpers in
packages/scene-graph/src/copy.tsfor nested values (fills, strokes, effects); never hand-copy node properties. - Instance children map to component children through
componentId; runtime overrides use the structuredInstanceOverrideState(selfanddescendantsmaps) inpackages/scene-graph/src/instance-overrides.ts. - A bound numeric field records its unit conversion in
variableBindingScales; preserve it through clone, copy, and transfer so a binding keeps meaning in its new scope. Core reconciles bindings and layout together inpackages/core/src/layout/variables.ts, which the editor and the Figma API both call rather than reimplementing. componentScalerecords an occurrence's coordinates relative to its component definition. Shared rescaling lives inpackages/scene-graph/src/scaling/; Core's Figma API delegates there instead of scaling nodes itself.- Shared primitives that format packages need live here: color conversion and management under
@open-pencil/scene-graph/colorand text/layout direction under@open-pencil/scene-graph/text-direction. - CSS values that become scene-graph types, such as grid track lists, are parsed in
@open-pencil/scene-graph/cssonpostcss-value-parser; design-jsx and dom-css call it instead of splitting or matching CSS by hand (packages/scene-graph/tests/css). - Every plugin-data key OpenPencil writes is a field of
OPEN_PENCIL_PLUGIN_DATAinpackages/scene-graph/src/plugin-data/fields.ts, with the Valibot schema that reads it; read and replace entries withreadPluginDataandwithPluginDatainstead of matchingpluginIdandkeyby hand. The fields test checks that keys stay unique. - Vector network types live here; the reverse-engineered
vectorNetworkBlobcodecs live inpackages/core/src/vector/. packages/scene-graph/src/checkpoint.tsowns transaction checkpoint recovery, including hierarchy and indexes; Core's atomic tool execution relies on it.- Export named types and primitives (
Color,Vector,Rect,SceneNode,Effect,Fill,Stroke) from the public entry; downstream packages reuse them instead of respelling shapes. StrokeextendsFill, so a stroke is a paint plus its geometry; add a paint field toFilland both get it, and copy it incopyFill, whichcopyStrokereuses (packages/scene-graph/src/copy.ts).