A declarative SVG generator powered by yoga-layout. Describe your design as a flexbox layout tree in JSON, get positioned SVG elements back — no drag-and-drop, no visual editor.
bun run compile-layout examples/intro.json
bun run render-elements out/intro.json --pngnpm install @kuriyona/yona-svg
# or
pnpm add @kuriyona/yona-svgOptional — enables PNG output:
npm install sharp
pnpm add sharp# Compile a layout JSON into positioned elements
bun run compile-layout <layout.json> [output-dir]
# Render elements into SVG (and optionally PNG with --png)
bun run render-elements <elements.json> [output-dir] [--png]bun run compile-layout examples/intro.json
# → out/intro.json
bun run render-elements out/intro.json --png
# → out/intro.svg + out/intro.pngimport { compileLayout, compileLayoutFromFile, renderSVG, renderPNG } from '@kuriyona/yona-svg';
// Option A: from a JS object (pure function, no I/O)
const doc = compileLayout({
width: 800,
height: 400,
backgroundColor: '#1a1a2e',
children: [
{
type: 'text',
content: 'Hello',
fontSize: 48,
height: 60,
},
],
});
// Generate SVG string (pure function, no I/O)
const svg = renderSVG(doc);
// Option B: from a JSON file
const doc2 = await compileLayoutFromFile('examples/intro.json');
// Generate PNG buffer (requires sharp)
const png = await renderPNG(svg);
await Bun.write('output.png', png); // or fs.writeFile| Property | Type | Default | Description |
|---|---|---|---|
width |
number | — | Canvas width (px) |
height |
number | — | Canvas height (px) |
backgroundColor |
string | — | CSS color for background rect |
fontFamily |
string | — | Inherited by all text nodes |
fontSize |
number | — | Inherited by all text nodes |
color |
string | black |
Inherited text color |
padding |
number | {top?,right?,bottom?,left?} |
— | Canvas padding |
gap |
number | — | Gap between flex children |
flexDirection |
'column' | 'row' |
'column' |
Flex direction |
justifyContent |
string | — | Flexbox justify-content |
alignItems |
string | — | Flexbox align-items |
children |
LayoutNode[] | — | Child nodes |
| Property | Type | Applies to | Description |
|---|---|---|---|
type |
'container' | 'text' |
all | Node type. container (default) is an invisible layout node |
margin |
number | {top?,right?,bottom?,left?} |
all | Margin |
padding |
number | {top?,right?,bottom?,left?} |
all | Padding |
width / height |
number | all | Fixed dimensions |
minWidth / minHeight / maxWidth / maxHeight |
number | all | Min/max constraints |
flexGrow / flexShrink |
number | all | Flex grow/shrink |
flexBasis |
number | 'auto' |
all | Flex basis |
flexDirection |
'column' | 'row' |
container | Flex direction |
justifyContent |
string | container | How children are distributed |
alignItems |
string | container | How children are aligned on cross axis |
flexWrap |
'nowrap' | 'wrap' |
container | Whether children wrap |
gap |
number | container | Gap between children |
fontFamily / fontSize / color |
string / number / string | all | Overrides inherited value for this node and its subtree |
content |
string | text | Text content |
textAnchor |
'start' | 'middle' | 'end' |
text | SVG text-anchor |
fontFamily, fontSize, and color flow from parent to child. Setting them on a node overrides the inherited value for that node and its subtree.
{
"fontFamily": "Inter, sans-serif",
"fontSize": 16,
"color": "#333",
"children": [
{ "type": "text", "content": "I inherit size 16" },
{ "type": "text", "content": "I override size", "fontSize": 24 }
]
}Use flexGrow: 1 on empty containers to create equal spacing between sections:
{
"children": [
{ "type": "text", "content": "Top", "height": 40 },
{ "type": "container", "flexGrow": 1 },
{ "type": "text", "content": "Bottom", "height": 40 }
]
}| File | Output |
|---|---|
examples/intro.json |
Brand intro card with header, description, and footer row |
examples/minimal.json |
Minimal centered card |
Apache-2.0 — Apache License, Version 2.0.