feat: add first-class text layers
This commit is contained in:
19
renderer/text-asset.ts
Normal file
19
renderer/text-asset.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import type { Asset } from "@core/asset";
|
||||
import type { TextLayer } from "@core/text-layer";
|
||||
import { measureTextLayer } from "@core/text-layer";
|
||||
|
||||
/** Produces a derived SVG texture; text content remains the only authoritative state. */
|
||||
export function textLayerRenderAsset(layer: TextLayer): Asset {
|
||||
const size = measureTextLayer(layer);
|
||||
const lines = layer.content.split("\n");
|
||||
const anchor = layer.style.alignment === "left" ? "start" : layer.style.alignment === "center" ? "middle" : "end";
|
||||
const x = layer.style.alignment === "left" ? 0 : layer.style.alignment === "center" ? size.w / 2 : size.w;
|
||||
const family = escapeXml(layer.style.fontFamily);
|
||||
const tspans = lines.map((line, index) => `<tspan x="${x}" y="${(index + 0.82) * layer.style.fontSize * layer.style.lineHeight}">${escapeXml(line || " ")}</tspan>`).join("");
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${size.w}" height="${size.h}" viewBox="0 0 ${size.w} ${size.h}"><text text-anchor="${anchor}" font-family="${family}" font-size="${layer.style.fontSize}" font-weight="${layer.style.fontWeight}" font-style="${layer.style.fontStyle}" fill="${layer.style.color}">${tspans}</text></svg>`;
|
||||
return { id: `text-render:${layer.id}`, name: layer.name, mimeType: "image/svg+xml", source: `data:image/svg+xml,${encodeURIComponent(svg)}`, intrinsicSize: size };
|
||||
}
|
||||
|
||||
function escapeXml(value: string) {
|
||||
return value.replace(/[&<>"']/g, (character) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[character]!);
|
||||
}
|
||||
Reference in New Issue
Block a user