fill, stroke, effect 모델
도형은 위치와 크기만으로 충분하지 않습니다. 색, stroke, shadow, blur 같은 visual style이 필요합니다.
하지만 이 값들도 renderer API가 아니라 문서 모델로 저장해야 합니다.
fill은 배열로 둘 수 있다
Figma처럼 fill을 여러 개 가질 수 있게 모델링할 수 있습니다.
fills: [
{ type: "solid", color: [1, 1, 1, 1] },
{ type: "linear-gradient", stops: [...] }
]
문서 타입으로 쓰면 renderer가 지원 범위를 판단하기 쉽습니다.
type Fill =
| { type: "solid"; color: Color }
| { type: "image"; assetId: string; opacity: number };
interface Stroke {
color: Color;
width: number;
align: "inside" | "center" | "outside";
}
interface Effect {
type: "shadow" | "blur";
radius: number;
color?: Color;
offset?: { x: number; y: number };
}
처음 renderer는 solid fill 하나만 지원해도 됩니다. 모델은 나중 확장을 막지 않게 둡니다.
function rendererSupportsStyle(capability, node) {
return node.fills.every((fill) => capability.fills.includes(fill.type));
}
stroke는 geometry와 style을 함께 건드린다
stroke는 단순히 색만이 아닙니다. stroke width, align, join, cap 같은 값이 geometry에 영향을 줍니다.
strokes: [{ color, width, align: "inside" }]
WebGL에서는 stroke를 별도 mesh로 만들거나 shader에서 처리할 수 있습니다. 이 선택은 renderer 정책입니다.
effect는 비용이 큰 기능이다
shadow, blur, backdrop blur는 GPU renderer에서 비용이 큽니다. 처음부터 완벽히 구현하려고 하면 강의가 흐려집니다.
그래서 모델과 지원 범위를 분리합니다.
model can describe effects
renderer may support subset
지원하지 않는 effect는 fallback이나 warning으로 처리할 수 있습니다.
오늘의 핵심
visual style은 문서 의미이고, 구현 방식은 renderer 정책입니다.
fill/stroke/effect model
-> renderer capability
-> draw strategy
이 분리가 있어야 WebGL과 WebGPU renderer가 같은 문서를 공유할 수 있습니다.