Shape
Responsibility
Shape is the atomic primitive for simple geometry. Its geometry lives in payload; its fill, stroke and marker semantics live in style. The supported shape kinds are rectangle, circle, ellipse, line, polyline and polygon.
Complete rectangle
The following is a complete layer-shaped record. parentLayerId, order, frame, transform and timing belong to the common layer contract; shape-specific fields are under payload and style.
{
"id": "rounded-card",
"type": "shape",
"parentLayerId": null,
"order": 0,
"frame": { "width": 640, "height": 360 },
"transform": {
"translate": { "x": 320, "y": 240, "z": 0 },
"rotate": { "x": 0, "y": 0, "z": 0 },
"scale": { "x": 1, "y": 1, "z": 1 },
"anchor": { "x": 320, "y": 180, "z": 0 },
"skew": { "x": 0, "y": 0 }
},
"timing": { "start": 0, "duration": 5000 },
"payload": {
"shape": "rectangle",
"cornerRadius": 28,
"rx": 28,
"ry": 28
},
"style": {
"fill": "#102A43",
"fillOpacity": 1,
"stroke": "#2EE6C5",
"strokeWidth": 4,
"strokeOpacity": 0.9,
"strokeJoin": "round",
"strokeCap": "round",
"vectorEffect": "none",
"paintOrder": ["fill", "stroke"]
}
}
Geometry kinds
| Kind | Geometry fields | Notes |
|---|---|---|
rectangle | cornerRadius, rx, ry | rx/ry are optional rounded-corner radii |
circle | frame width and height | The frame defines the primitive bounds |
ellipse | frame width and height | The frame defines the horizontal and vertical radii |
line | start, end | Requires both points |
polyline | points | At least two points; remains open |
polygon | points | At least three points; closes the contour |
Point coordinates are local to the shape frame. The layer transform moves the complete primitive; it does not rewrite the local points.
Line, polyline and polygon examples
[
{
"id": "divider",
"type": "shape",
"parentLayerId": null,
"order": 1,
"frame": { "width": 500, "height": 80 },
"transform": {
"translate": { "x": 40, "y": 80, "z": 0 },
"rotate": { "x": 0, "y": 0, "z": 0 },
"scale": { "x": 1, "y": 1, "z": 1 },
"anchor": { "x": 0, "y": 0, "z": 0 },
"skew": { "x": 0, "y": 0 }
},
"timing": { "start": 0, "duration": 5000 },
"payload": {
"shape": "line",
"start": { "x": 0, "y": 40 },
"end": { "x": 500, "y": 40 },
"pathLength": 500
},
"style": {
"stroke": "#FFFFFF",
"strokeWidth": 4,
"strokeCap": "round"
}
},
{
"id": "mountain",
"type": "shape",
"parentLayerId": null,
"order": 2,
"frame": { "width": 600, "height": 300 },
"transform": {
"translate": { "x": 0, "y": 0, "z": 0 },
"rotate": { "x": 0, "y": 0, "z": 0 },
"scale": { "x": 1, "y": 1, "z": 1 },
"anchor": { "x": 0, "y": 0, "z": 0 },
"skew": { "x": 0, "y": 0 }
},
"timing": { "start": 0, "duration": 5000 },
"payload": {
"shape": "polygon",
"points": [
{ "x": 0, "y": 280 },
{ "x": 140, "y": 80 },
{ "x": 260, "y": 210 },
{ "x": 390, "y": 40 },
{ "x": 600, "y": 280 }
]
},
"style": {
"fill": "#18B89A",
"stroke": "#D8FFF7",
"strokeWidth": 3,
"strokeJoin": "round"
}
}
]
Paint and stroke
Fill and stroke are independent. A paint can be a color shorthand, none, a solid object, a linear/radial/conic gradient, a pattern or a named paint reference.
{
"style": {
"fill": {
"type": "linear-gradient",
"x1": 0,
"y1": 0,
"x2": 1,
"y2": 1,
"gradientUnits": "objectBoundingBox",
"stops": [
{ "offset": 0, "color": "#2EE6C5" },
{ "offset": 1, "color": "#6257FF", "stopOpacity": 0.8 }
]
},
"stroke": "#FFFFFF",
"strokeWidth": 6,
"strokeOpacity": 0.75,
"strokeDash": { "array": [12, 8], "offset": 0 }
}
}
| Style field | Meaning |
|---|---|
fill, fillOpacity | Interior paint and alpha |
stroke, strokeWidth, strokeOpacity | Outline paint, width and alpha |
strokeJoin | miter, bevel or round |
strokeCap | butt, square or round |
strokeMiterLimit | Limit for sharp miter joins |
strokeDash | Dash array and optional offset |
paintOrder | Ordering of fill, stroke and markers |
vectorEffect | none or non-scaling-stroke |
Rounded corners are geometry semantics, not a renderer resource. The cornerRadius, rx and ry fields are valid only for rectangles.