PAGX 格式规范
最后更新: 2026 年 3 月 13 日
当前版本: https://pag.io/pagx/1.0/zh/
1. 介绍(Introduction)
PAGX(Portable Animated Graphics XML)是一种基于 XML 的矢量动画标记语言。它提供了统一且强大的矢量图形与动画描述能力,旨在成为跨所有主要工具与运行时的矢量动画交换标准。
1.1 设计目标
开放可读:纯文本 XML 格式,易于阅读和编辑,天然支持版本控制与差异对比,便于调试及 AI 理解与生成。
特性完备:完整覆盖矢量图形、图片、富文本、滤镜效果、混合模式、遮罩等能力,满足复杂动效的描述需求。
精简高效:提供简洁且强大的统一结构,兼顾静态矢量与动画的优化描述,同时预留未来交互和脚本的扩展能力。
生态兼容:可作为 After Effects、Figma、腾讯设计等设计工具的通用交换格式,实现设计资产无缝流转。
高效部署:设计资产可一键导出并部署到研发环境,转换为二进制 PAG 格式后获得极高压缩比和运行时性能。
1.2 文件结构
PAGX 是纯 XML 文件(.pagx),可引用外部资源文件(图片、视频、音频、字体等),也支持通过数据 URI 内嵌资源。PAGX 与二进制 PAG 格式可双向互转:发布时转换为 PAG 以优化加载性能;开发、审查或编辑时可使用 PAGX 格式以便阅读和修改。
1.3 文档组织
本规范按以下顺序组织:
- 基础数据类型:定义文档中使用的基本数据格式
- 文档结构:描述 PAGX 文档的整体组织方式
- 图层系统:定义图层及其相关特性(样式、滤镜、遮罩)
- 矢量元素系统:定义图层内容的矢量元素及其处理模型
附录(方便速查):
- 附录 A:节点层级与包含关系
- 附录 B:枚举类型速查
- 附录 C:常见用法示例
2. 基础数据类型(Basic Data Types)
本节定义 PAGX 文档中使用的基础数据类型和命名规范。
2.1 命名规范
| 类别 | 规范 | 示例 |
|---|---|---|
| 元素名 | PascalCase,不缩写 | Group、Rectangle、Fill |
| 属性名 | camelCase,尽量简短 | antiAlias、blendMode、fontSize |
| 默认单位 | 像素(无需标注) | width="100" |
| 角度单位 | 度 | rotation="45" |
2.2 属性表格约定
本规范中的属性表格统一使用"默认值"列描述属性的必填性:
| 默认值格式 | 含义 |
|---|---|
(必填) |
属性必须指定,没有默认值 |
具体值(如 0、true、normal) |
属性可选,未指定时使用该默认值 |
- |
属性可选,未指定时不生效 |
2.3 通用属性
以下属性可用于任意元素,不在各节点的属性表中重复列出:
| 属性 | 类型 | 说明 |
|---|---|---|
id |
string | 唯一标识符,用于被其他元素引用(如遮罩、颜色源)。在文档中必须唯一,不能为空或包含空白字符 |
data-* |
string | 自定义数据属性,用于存储应用特定的私有数据。* 可替换为任意名称(如 data-name、data-layer-id),运行时忽略这些属性 |
自定义属性说明:
- 属性名必须以
data-开头,后跟至少一个字符 - 属性名只能包含小写字母、数字和连字符(
-),不能以连字符结尾 - 属性值为任意字符串,由创建该属性的应用自行解释
- 运行时不处理这些属性,仅用于工具间传递元数据或存储调试信息
示例:
<Layer data-name="背景图层" data-figma-id="12:34" data-exported-by="PAGExporter">
<Rectangle position="50,50" size="100,100"/>
<Fill color="#FF0000"/>
</Layer>
2.4 基本数值类型
| 类型 | 说明 | 示例 |
|---|---|---|
float |
浮点数 | 1.5、-0.5、100 |
int |
整数 | 400、0、-1 |
bool |
布尔值 | true、false |
string |
字符串 | "Arial"、"myLayer" |
enum |
枚举值 | normal、multiply |
idref |
ID 引用 | @gradientId、@maskLayer |
2.5 点(Point)
点使用逗号分隔的两个浮点数表示:
"x,y"
示例:"100,200"、"0.5,0.5"、"-50,100"
2.6 矩形(Rect)
矩形使用逗号分隔的四个浮点数表示:
"x,y,width,height"
示例:"0,0,100,100"、"10,20,200,150"
2.7 变换矩阵(Matrix)
2D 变换矩阵
2D 变换使用 6 个逗号分隔的浮点数表示,对应标准 2D 仿射变换矩阵:
"a,b,c,d,tx,ty"
矩阵形式:
| a c tx |
| b d ty |
| 0 0 1 |
单位矩阵:"1,0,0,1,0,0"
3D 变换矩阵
3D 变换使用 16 个逗号分隔的浮点数表示,列优先顺序:
"m00,m10,m20,m30,m01,m11,m21,m31,m02,m12,m22,m32,m03,m13,m23,m33"
2.8 颜色(Color)
PAGX 支持两种颜色表示方式:
HEX 格式(十六进制)
HEX 格式用于表示 sRGB 色域的颜色,使用 # 前缀的十六进制值:
| 格式 | 示例 | 说明 |
|---|---|---|
#RGB |
#F00 |
3 位简写,每位扩展为两位(等价于 #FF0000) |
#RRGGBB |
#FF0000 |
6 位标准格式,不透明 |
#RRGGBBAA |
#FF000080 |
8 位带 Alpha,Alpha 在末尾(与 CSS 一致) |
浮点数格式
浮点数格式使用 色域(r, g, b) 或 色域(r, g, b, a) 的形式表示颜色,支持 sRGB 和 Display P3 两种色域:
| 色域 | 格式 | 示例 | 说明 |
|---|---|---|---|
| sRGB | srgb(r, g, b) |
srgb(1.0, 0.5, 0.2) |
sRGB 色域,各分量 0.0~1.0 |
| sRGB | srgb(r, g, b, a) |
srgb(1.0, 0.5, 0.2, 0.8) |
带透明度 |
| Display P3 | p3(r, g, b) |
p3(1.0, 0.5, 0.2) |
Display P3 广色域 |
| Display P3 | p3(r, g, b, a) |
p3(1.0, 0.5, 0.2, 0.8) |
带透明度 |
注意:
- 色域标识符(
srgb或p3)和括号不能省略 - 广色域颜色(Display P3)的分量值可以超出 [0, 1] 范围,以表示超出 sRGB 色域的颜色
- sRGB 浮点格式与 HEX 格式表示相同的色域,可根据需要选择
颜色源引用
使用 @resourceId 引用 Resources 中定义的颜色源(渐变、图案等)。
2.9 混合模式(Blend Mode)
混合模式定义源颜色(S)如何与目标颜色(D)组合。
| 值 | 公式 | 说明 |
|---|---|---|
normal |
S | 正常(覆盖) |
multiply |
S × D | 正片叠底 |
screen |
1 - (1-S)(1-D) | 滤色 |
overlay |
multiply/screen 组合 | 叠加 |
darken |
min(S, D) | 变暗 |
lighten |
max(S, D) | 变亮 |
colorDodge |
D / (1-S) | 颜色减淡 |
colorBurn |
1 - (1-D)/S | 颜色加深 |
hardLight |
multiply/screen 反向组合 | 强光 |
softLight |
柔和版叠加 | 柔光 |
difference |
|S - D| | 差值 |
exclusion |
S + D - 2SD | 排除 |
hue |
D 的饱和度和亮度 + S 的色相 | 色相 |
saturation |
D 的色相和亮度 + S 的饱和度 | 饱和度 |
color |
D 的亮度 + S 的色相和饱和度 | 颜色 |
luminosity |
S 的亮度 + D 的色相和饱和度 | 亮度 |
plusLighter |
S + D | 相加(趋向白色) |
plusDarker |
S + D - 1 | 相加减一(趋向黑色) |
2.10 路径数据语法(Path Data Syntax)
路径数据使用 SVG 路径语法,由一系列命令和坐标组成。
路径命令:
| 命令 | 参数 | 说明 |
|---|---|---|
| M/m | x y | 移动到(绝对/相对) |
| L/l | x y | 直线到 |
| H/h | x | 水平线到 |
| V/v | y | 垂直线到 |
| C/c | x1 y1 x2 y2 x y | 三次贝塞尔曲线 |
| S/s | x2 y2 x y | 平滑三次贝塞尔 |
| Q/q | x1 y1 x y | 二次贝塞尔曲线 |
| T/t | x y | 平滑二次贝塞尔 |
| A/a | rx ry rotation large-arc sweep x y | 椭圆弧 |
| Z/z | - | 闭合路径 |
2.11 外部资源引用(External Resource Reference)
外部资源通过相对路径或数据 URI 引用,适用于图片、视频、音频、字体等文件。
<!-- 相对路径引用 -->
<Image source="photo.png"/>
<Image source="assets/icons/logo.png"/>
<!-- 数据 URI 内嵌 -->
<Image source="data:image/png;base64,iVBORw0KGgo..."/>
路径解析规则:
- 相对路径:相对于 PAGX 文件所在目录解析,支持
../引用父目录 - 数据 URI:以
data:开头,格式为data:<mediatype>;base64,<data>,仅支持 base64 编码 - 路径分隔符统一使用
/(正斜杠),不支持\(反斜杠)
3. 文档结构(Document Structure)
本节定义 PAGX 文档的整体结构。
3.1 坐标系统
PAGX 使用标准的 2D 笛卡尔坐标系:
- 原点:位于画布左上角
- X 轴:向右为正方向
- Y 轴:向下为正方向
- 角度:顺时针方向为正(0° 指向 X 轴正方向)
- 单位:所有长度值默认为像素,角度值默认为度
3.2 根元素(pagx)
<pagx> 是 PAGX 文档的根元素,定义画布尺寸并直接包含图层列表。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates basic PAGX document structure -->
<pagx version="1.0" width="400" height="400">
<!-- Main content card with modern gradient -->
<Layer name="content">
<Rectangle position="200,200" size="240,240" roundness="40"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="240,240">
<ColorStop offset="0" color="#6366F1"/>
<ColorStop offset="1" color="#8B5CF6"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="16" blurX="48" blurY="48" color="#6366F160"/>
</Layer>
</pagx>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
version |
string | (必填) | 格式版本 |
width |
float | (必填) | 画布宽度 |
height |
float | (必填) | 画布高度 |
画布裁剪:由 width 和 height 定义的画布作为渲染边界,超出画布区域的内容会被裁剪,不参与渲染。
图层渲染顺序:图层按文档顺序依次渲染,文档中靠前的图层先渲染(位于下方),靠后的图层后渲染(位于上方)。
3.3 资源区(Resources)
<Resources> 定义可复用的资源,包括图片、路径数据、颜色源和合成。资源通过 id 属性标识,在文档其他位置通过 @id 形式引用。
元素位置:Resources 元素可放置在根元素内的任意位置,对位置没有限制。解析器必须支持元素引用在文档后面定义的资源或图层(即前向引用)。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates resource definitions and references -->
<pagx version="1.0" width="400" height="400">
<Layer>
<Rectangle position="200,200" size="320,320" roundness="32"/>
<Fill color="@oceanGradient"/>
<DropShadowStyle offsetY="12" blurX="40" blurY="40" color="#06B6D450"/>
</Layer>
<!-- Shape using solid color resource reference -->
<Layer>
<Ellipse position="200,200" size="120,120"/>
<Fill color="@coral"/>
</Layer>
<Resources>
<SolidColor id="coral" color="#F43F5E"/>
<LinearGradient id="oceanGradient" startPoint="0,0" endPoint="320,320">
<ColorStop offset="0" color="#06B6D4"/>
<ColorStop offset="1" color="#3B82F6"/>
</LinearGradient>
</Resources>
</pagx>
3.3.1 图片(Image)
图片资源定义可在文档中引用的位图数据。
<Image source="photo.png"/>
<Image source="data:image/png;base64,..."/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
source |
string | (必填) | 文件路径或数据 URI |
支持格式:PNG、JPEG、WebP、GIF
3.3.2 路径数据(PathData)
PathData 定义可复用的路径数据,供 Path 元素和 TextPath 修改器引用。
<PathData id="curvePath" data="M 0 0 C 50 0 50 100 100 100"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
data |
string | (必填) | SVG 路径数据 |
3.3.3 颜色源(Color Source)
颜色源定义可用于填充和描边的颜色,支持两种使用方式:
- 共享定义:在
<Resources>中预定义,通过@id引用。适用于被多处引用的颜色源。 - 内联定义:直接嵌套在
<Fill>或<Stroke>元素内部。适用于仅使用一次的颜色源,更简洁。
纯色(SolidColor)
<SolidColor color="#FF0000"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
color |
Color | (必填) | 颜色值 |
线性渐变(LinearGradient)
线性渐变沿起点到终点的方向插值。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates linear gradient -->
<pagx version="1.0" width="400" height="400">
<Layer>
<Rectangle position="200,200" size="320,320" roundness="32"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="320,320">
<ColorStop offset="0" color="#6366F1"/>
<ColorStop offset="0.5" color="#8B5CF6"/>
<ColorStop offset="1" color="#EC4899"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="12" blurX="40" blurY="40" color="#8B5CF650"/>
</Layer>
</pagx>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
startPoint |
Point | (必填) | 起点 |
endPoint |
Point | (必填) | 终点 |
matrix |
Matrix | 单位矩阵 | 变换矩阵 |
计算:对于点 P,其颜色由 P 在起点-终点连线上的投影位置决定。
径向渐变(RadialGradient)
径向渐变从中心向外辐射。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates radial gradient -->
<pagx version="1.0" width="400" height="400">
<Layer>
<Ellipse position="200,200" size="320,320"/>
<Fill>
<RadialGradient center="140,140" radius="260">
<ColorStop offset="0" color="#FFF"/>
<ColorStop offset="0.3" color="#06B6D4"/>
<ColorStop offset="0.7" color="#3B82F6"/>
<ColorStop offset="1" color="#1E293B"/>
</RadialGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="32" blurY="32" color="#06B6D450"/>
</Layer>
</pagx>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
center |
Point | 0,0 | 中心点 |
radius |
float | (必填) | 渐变半径 |
matrix |
Matrix | 单位矩阵 | 变换矩阵 |
计算:对于点 P,其颜色由 distance(P, center) / radius 决定。
锥形渐变(ConicGradient)
锥形渐变(也称扫描渐变)沿圆周方向插值。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates conic (sweep) gradient -->
<pagx version="1.0" width="400" height="400">
<Layer>
<Ellipse position="200,200" size="320,320"/>
<Fill>
<ConicGradient center="200,200">
<ColorStop offset="0" color="#F43F5E"/>
<ColorStop offset="0.2" color="#F59E0B"/>
<ColorStop offset="0.4" color="#10B981"/>
<ColorStop offset="0.6" color="#06B6D4"/>
<ColorStop offset="0.8" color="#8B5CF6"/>
<ColorStop offset="1" color="#F43F5E"/>
</ConicGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="32" blurY="32" color="#8B5CF650"/>
</Layer>
</pagx>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
center |
Point | 0,0 | 中心点 |
startAngle |
float | 0 | 起始角度 |
endAngle |
float | 360 | 结束角度 |
matrix |
Matrix | 单位矩阵 | 变换矩阵 |
计算:对于点 P,其颜色由 atan2(P.y - center.y, P.x - center.x) 在 [startAngle, endAngle] 范围内的比例决定。
角度约定:遵循全局坐标系约定(见 §3.1):0° 指向右侧(X 轴正方向),角度沿顺时针递增。这与 CSS conic-gradient(0° 指向顶部)不同。常用参考角度:
| 角度 | 方向 |
|---|---|
| 0° | 右 (3 点钟) |
| 90° | 下 (6 点钟) |
| 180° | 左 (9 点钟) |
| 270° | 上 (12 点钟) |
菱形渐变(DiamondGradient)
菱形渐变从中心向四角辐射。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates diamond gradient -->
<pagx version="1.0" width="400" height="400">
<!-- Rectangle size=320x320, half=160. Diamond radius=160 so corners touch rect edges exactly -->
<Layer>
<Rectangle position="200,200" size="320,320" roundness="24"/>
<Fill>
<DiamondGradient center="200,200" radius="160">
<ColorStop offset="0" color="#FBBF24"/>
<ColorStop offset="0.4" color="#F59E0B"/>
<ColorStop offset="0.7" color="#D97706"/>
<ColorStop offset="1" color="#1E293B"/>
</DiamondGradient>
</Fill>
<DropShadowStyle offsetY="12" blurX="40" blurY="40" color="#F59E0B50"/>
</Layer>
</pagx>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
center |
Point | 0,0 | 中心点 |
radius |
float | (必填) | 渐变半径 |
matrix |
Matrix | 单位矩阵 | 变换矩阵 |
计算:对于点 P,其颜色由切比雪夫距离 max(|P.x - center.x|, |P.y - center.y|) / radius 决定。
渐变色标(ColorStop)
<ColorStop offset="0.5" color="#FF0000"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
offset |
float | (必填) | 位置 0.0~1.0 |
color |
Color | (必填) | 色标颜色 |
渐变通用规则:
- 色标插值:相邻色标之间使用线性插值
- 色标边界:
offset < 0的色标被视为offset = 0offset > 1的色标被视为offset = 1- 如果没有
offset = 0的色标,使用第一个色标的颜色填充 - 如果没有
offset = 1的色标,使用最后一个色标的颜色填充
图片填充(ImagePattern)
图片图案使用图片作为颜色源。
<ImagePattern image="@img1" tileModeX="repeat" tileModeY="repeat"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
image |
idref | (必填) | 图片引用 "@id" |
tileModeX |
TileMode | clamp | X 方向平铺模式 |
tileModeY |
TileMode | clamp | Y 方向平铺模式 |
filterMode |
FilterMode | linear | 纹理过滤模式 |
mipmapMode |
MipmapMode | linear | Mipmap 模式 |
matrix |
Matrix | 单位矩阵 | 变换矩阵 |
TileMode(平铺模式):clamp(钳制)、repeat(重复)、mirror(镜像)、decal(贴花)
FilterMode(纹理过滤模式):nearest(最近邻)、linear(双线性插值)
MipmapMode(Mipmap 模式):none(禁用)、nearest(最近级别)、linear(线性插值)
完整示例:演示不同平铺模式的图片填充
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates ImagePattern fill with different tile modes -->
<pagx version="1.0" width="400" height="400">
<!-- Clamp mode: original size, centered in 140x140 rect -->
<!-- Rectangle position=110,110 size=140,140: left-top=(40,40), right-bottom=(180,180) -->
<!-- Image 256x256, scale 0.5 = 128x128 -->
<!-- Center in rect: image left-top = 40 + (140-128)/2 = 46 -->
<Layer name="ClampFill">
<Rectangle position="110,110" size="140,140" roundness="24"/>
<Fill>
<ImagePattern image="@logo" tileModeX="clamp" tileModeY="clamp" matrix="0.5,0,0,0.5,46,46"/>
</Fill>
<Stroke color="#FFF" width="2"/>
</Layer>
<Layer name="RepeatFill">
<Rectangle position="290,110" size="140,140" roundness="24"/>
<Fill>
<ImagePattern image="@logo" tileModeX="repeat" tileModeY="repeat" matrix="0.24,0,0,0.24,0,0"/>
</Fill>
<Stroke color="#FFF" width="2"/>
</Layer>
<Layer name="MirrorFill">
<Rectangle position="110,290" size="140,140" roundness="24"/>
<Fill>
<ImagePattern image="@logo" tileModeX="mirror" tileModeY="mirror" matrix="0.24,0,0,0.24,0,0"/>
</Fill>
<Stroke color="#FFF" width="2"/>
</Layer>
<Layer name="RepeatScaled">
<Rectangle position="290,290" size="140,140" roundness="24"/>
<Fill>
<ImagePattern image="@logo" tileModeX="repeat" tileModeY="repeat" matrix="0.35,0,0,0.35,0,0"/>
</Fill>
<Stroke color="#FFF" width="2"/>
</Layer>
<Resources>
<Image id="logo" source="pag_logo.png"/>
</Resources>
</pagx>
颜色源坐标系统
除纯色外,所有颜色源(渐变、图片填充)都有坐标系的概念,其坐标系相对于几何元素的局部坐标系原点。可通过 matrix 属性对颜色源坐标系应用变换。
变换行为:
外部变换会同时作用于几何和颜色源:Group 的变换、Layer 的矩阵等外部变换会整体作用于几何元素及其颜色源,两者一起缩放、旋转、平移。
修改几何属性不影响颜色源:直接修改几何元素的属性(如 Rectangle 的 width/height、Path 的路径数据)只改变几何内容本身,不会影响颜色源的坐标系。
示例:在 300×300 的区域内绘制一个对角线方向的线性渐变:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates that color source coordinates are relative to geometry origin -->
<pagx version="1.0" width="400" height="400">
<Layer>
<Rectangle position="200,200" size="300,300" roundness="24"/>
<Fill color="@grad"/>
<DropShadowStyle offsetY="12" blurX="40" blurY="40" color="#EC489950"/>
</Layer>
<Resources>
<LinearGradient id="grad" startPoint="0,0" endPoint="300,300">
<ColorStop offset="0" color="#EC4899"/>
<ColorStop offset="0.5" color="#8B5CF6"/>
<ColorStop offset="1" color="#6366F1"/>
</LinearGradient>
</Resources>
</pagx>
- 对该图层应用
scale(2, 2)变换:矩形变为 600×600,渐变也随之放大,视觉效果保持一致 - 直接将 Rectangle 的 size 改为 600,600:矩形变为 600×600,但渐变坐标不变,只覆盖矩形的左上四分之一
3.3.4 合成(Composition)
合成用于内容复用(类似 After Effects 的 Pre-comp)。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates composition (reusable component) -->
<pagx version="1.0" width="400" height="400">
<Layer composition="@buttonComp" x="100" y="60"/>
<Layer composition="@buttonComp" x="100" y="170"/>
<Layer composition="@buttonComp" x="100" y="280"/>
<Resources>
<Composition id="buttonComp" width="200" height="60">
<Layer name="button">
<Rectangle position="100,30" size="200,60" roundness="30"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="200,0">
<ColorStop offset="0" color="#6366F1"/>
<ColorStop offset="1" color="#8B5CF6"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#6366F180"/>
</Layer>
<Layer name="label">
<Text text="Button" fontFamily="Arial" fontStyle="Bold" fontSize="22" position="100,36" textAnchor="center"/>
<Fill color="#FFF"/>
</Layer>
</Composition>
</Resources>
</pagx>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
width |
float | (必填) | 合成宽度 |
height |
float | (必填) | 合成高度 |
3.3.5 字体(Font)
Font 定义嵌入字体资源,包含子集化的字形数据(矢量轮廓或位图)。PAGX 文件通过嵌入字形数据实现完全自包含,确保跨平台渲染一致性。
<!-- 嵌入矢量字体 -->
<Font id="myFont" unitsPerEm="1000">
<Glyph advance="600" path="M 50 0 L 300 700 L 550 0 Z"/>
<Glyph advance="550" path="M 100 0 L 100 700 L 400 700 C 550 700 550 400 400 400 Z"/>
</Font>
<!-- 嵌入位图字体(Emoji) -->
<Font id="emojiFont" unitsPerEm="136">
<Glyph advance="136" image="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA..."/>
<Glyph advance="136" image="emoji/heart.png" offset="0,-5"/>
</Font>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
unitsPerEm |
int | 1000 | 字体设计空间单位。渲染时按 fontSize / unitsPerEm 缩放 |
一致性约束:同一 Font 内的所有 Glyph 必须使用相同类型(全部 path 或全部 image),不允许混用。
GlyphID 规则:
- GlyphID 从 1 开始:Glyph 列表的索引 + 1 = GlyphID
- GlyphID 0 保留:表示缺失字形,不渲染
字形(Glyph)
Glyph 定义单个字形的渲染数据。path 和 image 二选一必填,不能同时指定。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
advance |
float | (必填) | 水平步进宽度,设计空间坐标(unitsPerEm 单位) |
path |
string | - | SVG 路径数据(矢量轮廓) |
image |
string | - | 图片数据(base64 数据 URI)或外部文件路径 |
offset |
Point | 0,0 | 字形偏移量,设计空间坐标(通常用于位图字形) |
字形类型:
- 矢量字形:指定
path属性,使用 SVG 路径语法描述轮廓 - 位图字形:指定
image属性,用于 Emoji 等彩色字形,可通过offset调整位置
坐标系说明:字形路径、偏移和步进均使用设计空间坐标。渲染时根据 GlyphRun 的 fontSize 和 Font 的 unitsPerEm 计算缩放比例:scale = fontSize / unitsPerEm。
3.4 文档层级结构
PAGX 文档采用层级结构组织内容:
<pagx> ← 根元素(定义画布尺寸)
├── <Layer> ← 图层(可多个)
│ ├── 几何元素 ← Rectangle、Ellipse、Path、Text 等
│ ├── 修改器 ← TrimPath、RoundCorner、TextModifier 等
│ ├── 绘制器 ← Fill、Stroke
│ ├── <Group> ← 矢量元素容器(可嵌套)
│ ├── LayerStyle ← DropShadowStyle、InnerShadowStyle 等
│ ├── LayerFilter ← BlurFilter、ColorMatrixFilter 等
│ └── <Layer> ← 子图层(递归结构)
│ └── ...
│
└── <Resources> ← 资源区(可选,定义可复用资源)
├── <Image> ← 图片资源
├── <PathData> ← 路径数据资源
├── <SolidColor> ← 纯色定义
├── <LinearGradient> ← 渐变定义
├── <ImagePattern> ← 图片图案定义
├── <Font> ← 字体资源(嵌入字体)
│ └── <Glyph> ← 字形定义
└── <Composition> ← 合成定义
└── <Layer> ← 合成内的图层
4. 图层系统(Layer System)
图层(Layer)是 PAGX 内容组织的基本单元,提供了丰富的视觉效果控制能力。
4.1 核心概念
本节介绍图层系统的核心概念,这些概念是理解图层样式、滤镜和遮罩等功能的基础。
图层渲染流程
图层绑定的绘制器(Fill、Stroke 等)通过 placement 属性分为下层内容和上层内容,默认为下层内容。单个图层渲染时按以下顺序处理:
- 图层样式(下方):渲染位于内容下方的图层样式(如投影阴影)
- 下层内容:渲染
placement="background"的 Fill 和 Stroke - 子图层:按文档顺序递归渲染所有子图层
- 图层样式(上方):渲染位于内容上方的图层样式(如内阴影)
- 上层内容:渲染
placement="foreground"的 Fill 和 Stroke(绘制在子图层之上) - 图层滤镜:将前面步骤的整体输出作为滤镜链的输入,依次应用所有滤镜
图层内容(Layer Content)
图层内容是指图层的下层内容、子图层和上层内容的完整渲染结果(渲染流程中的步骤 2、3 和 5),不包含图层样式和图层滤镜。
图层样式基于图层内容计算效果。例如,当填充位于下层内容、描边位于上层内容时,描边会绘制在子图层之上,但投影阴影仍然基于包含填充、子图层和描边的完整图层内容计算。
图层轮廓(Layer Contour)
图层轮廓是基于图层内容生成的一个二值(不透明或完全透明)遮罩。与普通图层内容相比,图层轮廓有以下区别:
- 包含 alpha=0 的填充:填充透明度完全为 0 的几何形状也会加入轮廓计算
- 纯色填充和渐变填充:原始颜色替换为不透明白色
- 图片填充:完全透明的像素保留透明;其余像素均转为完全不透明
注意:没有绘制器的几何元素(独立的 Rectangle、Ellipse 等)不参与轮廓计算。
图层背景(Layer Background)
图层背景是指当前图层下方所有已渲染内容的合成结果,包括:
- 当前图层下方的所有兄弟图层及其子树的渲染结果
- 当前图层已绘制的下方图层样式(不包括 BackgroundBlurStyle 本身)
图层背景主要用于:
- 图层样式:部分图层样式需要背景作为其中一个输入源
- 混合模式:部分混合模式需要背景信息才能正确渲染
背景透传:通过 passThroughBackground 属性控制是否允许图层背景透传给子图层。当设置为 false 时,子图层的背景依赖样式将无法获取到正确的图层背景。以下情况会自动禁用背景透传:
- 图层使用了非
normal的混合模式 - 图层应用了滤镜
- 图层使用了 3D 变换或投影变换
4.2 图层(Layer)
<Layer> 是内容和子图层的基本容器。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates layer properties and nesting -->
<pagx version="1.0" width="400" height="400">
<!-- Parent layer with nested child -->
<Layer name="Parent" x="50" y="50">
<Rectangle position="150,150" size="260,260" roundness="32"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="260,260">
<ColorStop offset="0" color="#F43F5E"/>
<ColorStop offset="1" color="#EC4899"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="16" blurX="40" blurY="40" color="#F43F5E60"/>
<!-- Nested child layer -->
<Layer name="Child">
<Ellipse position="150,150" size="120,120"/>
<Fill color="#FFF"/>
<DropShadowStyle offsetY="4" blurX="16" blurY="16" color="#00000030"/>
</Layer>
</Layer>
</pagx>
子元素
Layer 的子元素按类型自动归类为四个集合:
| 子元素类型 | 归类 | 说明 |
|---|---|---|
| VectorElement | contents | 几何元素、修改器、绘制器(参与累积处理) |
| LayerStyle | styles | DropShadowStyle、InnerShadowStyle、BackgroundBlurStyle |
| LayerFilter | filters | BlurFilter、DropShadowFilter 等滤镜 |
| Layer | children | 嵌套子图层 |
建议顺序:虽然子元素顺序不影响解析结果,但建议按 VectorElement → LayerStyle → LayerFilter → 子Layer 的顺序书写,以提高可读性。
图层属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name |
string | "" | 显示名称 |
visible |
bool | true | 是否可见 |
alpha |
float | 1 | 透明度 0~1 |
blendMode |
BlendMode | normal | 混合模式 |
x |
float | 0 | X 位置 |
y |
float | 0 | Y 位置 |
matrix |
Matrix | 单位矩阵 | 2D 变换 "a,b,c,d,tx,ty" |
matrix3D |
Matrix | - | 3D 变换(16 个值,列优先) |
preserve3D |
bool | false | 保持 3D 变换 |
antiAlias |
bool | true | 边缘抗锯齿 |
groupOpacity |
bool | false | 组透明度 |
passThroughBackground |
bool | true | 是否允许背景透传给子图层 |
scrollRect |
Rect | - | 滚动裁剪区域 "x,y,w,h" |
mask |
idref | - | 遮罩图层引用 "@id" |
maskType |
MaskType | alpha | 遮罩类型 |
composition |
idref | - | 合成引用 "@id" |
groupOpacity:当值为 false(默认)时,图层的 alpha 独立应用到每个子元素,重叠的半透明子元素在交叉处可能显得更深。当值为 true 时,所有图层内容先合成到离屏缓冲区,再将 alpha 整体应用到缓冲区,使整个图层呈现均匀的透明效果。
preserve3D:当值为 false(默认)时,具有 3D 变换的子图层在合成前会被压平到父级的 2D 平面。当值为 true 时,子图层保留其 3D 位置,在共享的 3D 空间中渲染,实现基于深度的交叉和正确的兄弟层 Z 排序。类似于 CSS 的 transform-style: preserve-3d。
变换属性优先级:x/y、matrix、matrix3D 三者存在覆盖关系:
- 仅设置
x/y:使用x/y作为平移 - 设置
matrix:matrix覆盖x/y的值 - 设置
matrix3D:matrix3D覆盖matrix和x/y的值
MaskType(遮罩类型):
| 值 | 说明 |
|---|---|
alpha |
Alpha 遮罩:使用遮罩的 alpha 通道 |
luminance |
亮度遮罩:使用遮罩的亮度值 |
contour |
轮廓遮罩:使用遮罩的轮廓进行裁剪 |
BlendMode:见 2.9 节混合模式完整表格。
4.3 图层样式(Layer Styles)
图层样式在图层内容的上方或下方添加视觉效果,不会替换原有内容。
图层样式的输入源:
所有图层样式都基于图层内容计算效果。计算时,图层内容会被转换为对应的不透明版本:使用正常的填充方式渲染几何形状,然后将所有半透明像素转换为完全不透明(完全透明的像素保留)。这意味着半透明填充产生的阴影效果与完全不透明填充相同。
部分图层样式还会额外使用图层轮廓或图层背景作为输入(详见各样式说明)。图层轮廓和图层背景的定义参见 4.1 节。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates layer styles: DropShadow and InnerShadow -->
<pagx version="1.0" width="400" height="400">
<Layer x="70" y="70">
<Rectangle position="130,130" size="260,260" roundness="40"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="260,260">
<ColorStop offset="0" color="#06B6D4"/>
<ColorStop offset="1" color="#0891B2"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="16" blurX="48" blurY="48" color="#06B6D480"/>
<InnerShadowStyle offsetX="8" offsetY="8" blurX="24" blurY="24" color="#00000040"/>
</Layer>
</pagx>
所有 LayerStyle 共有属性:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
blendMode |
BlendMode | normal | 混合模式(见 2.9 节) |
excludeChildEffects |
bool | false | 是否排除子图层效果 |
excludeChildEffects:当值为 false(默认)时,图层样式基于完整的图层内容计算,包含子图层的渲染结果。当值为 true 时,子图层的图层样式和图层滤镜不参与该样式的计算,但子图层的基础渲染结果仍然包含在内。
4.3.1 投影阴影(DropShadowStyle)
在图层下方绘制投影阴影。基于不透明图层内容计算阴影形状。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
offsetX |
float | 0 | X 偏移 |
offsetY |
float | 0 | Y 偏移 |
blurX |
float | 0 | X 模糊半径 |
blurY |
float | 0 | Y 模糊半径 |
color |
Color | #000000 | 阴影颜色 |
showBehindLayer |
bool | true | 图层后面是否显示阴影 |
渲染步骤:
- 获取不透明图层内容并偏移
(offsetX, offsetY) - 对偏移后的内容应用高斯模糊
(blurX, blurY) - 使用
color的颜色填充阴影区域 - 如果
showBehindLayer="false",使用图层轮廓作为擦除遮罩挖空被遮挡部分
showBehindLayer:
true:阴影完整显示,包括被图层内容遮挡的部分false:阴影被图层内容遮挡的部分会被挖空(使用图层轮廓作为擦除遮罩)
4.3.2 背景模糊(BackgroundBlurStyle)
在图层下方对图层背景应用模糊效果。基于图层背景计算效果,使用不透明图层内容作为遮罩裁剪。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
blurX |
float | 0 | X 模糊半径 |
blurY |
float | 0 | Y 模糊半径 |
tileMode |
TileMode | mirror | 平铺模式 |
渲染步骤:
- 获取图层边界下方的图层背景
- 对图层背景应用高斯模糊
(blurX, blurY) - 使用不透明图层内容作为遮罩裁剪模糊结果
4.3.3 内阴影(InnerShadowStyle)
在图层上方绘制内阴影,效果呈现在图层内容之内。基于不透明图层内容计算阴影范围。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
offsetX |
float | 0 | X 偏移 |
offsetY |
float | 0 | Y 偏移 |
blurX |
float | 0 | X 模糊半径 |
blurY |
float | 0 | Y 模糊半径 |
color |
Color | #000000 | 阴影颜色 |
渲染步骤:
- 获取不透明图层内容并偏移
(offsetX, offsetY) - 对偏移后内容的反向(内容外部区域)应用高斯模糊
(blurX, blurY) - 使用
color的颜色填充阴影区域 - 与不透明图层内容求交集,仅保留内容内部的阴影
4.4 图层滤镜(Layer Filters)
图层滤镜是图层渲染的最后一个环节,所有之前按顺序渲染的结果(包含图层样式)累积起来作为滤镜的输入。滤镜按文档顺序链式应用,每个滤镜的输出作为下一个滤镜的输入。
与图层样式(4.3 节)的关键区别:图层样式在图层内容的上方或下方独立渲染视觉效果,而滤镜修改图层的整体渲染输出。图层样式先于滤镜应用。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates layer filters: Blur and DropShadow -->
<pagx version="1.0" width="400" height="400">
<Layer x="70" y="70">
<Rectangle position="130,130" size="260,260" roundness="40"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="260,260">
<ColorStop offset="0" color="#8B5CF6"/>
<ColorStop offset="1" color="#6366F1"/>
</LinearGradient>
</Fill>
<BlurFilter blurX="4" blurY="4"/>
<DropShadowFilter offsetX="0" offsetY="16" blurX="48" blurY="48" color="#8B5CF680"/>
</Layer>
</pagx>
4.4.1 模糊滤镜(BlurFilter)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
blurX |
float | 0 | X 模糊半径 |
blurY |
float | 0 | Y 模糊半径 |
tileMode |
TileMode | decal | 平铺模式 |
4.4.2 投影阴影滤镜(DropShadowFilter)
基于滤镜输入生成阴影效果。与 DropShadowStyle 的核心区别:滤镜基于原始渲染内容投影,支持半透明度;而样式基于不透明图层内容投影。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
offsetX |
float | 0 | X 偏移 |
offsetY |
float | 0 | Y 偏移 |
blurX |
float | 0 | X 模糊半径 |
blurY |
float | 0 | Y 模糊半径 |
color |
Color | #000000 | 阴影颜色 |
shadowOnly |
bool | false | 仅显示阴影 |
渲染步骤:
- 将滤镜输入偏移
(offsetX, offsetY) - 提取 alpha 通道并应用高斯模糊
(blurX, blurY) - 使用
color的颜色填充阴影区域 - 将阴影与滤镜输入合成(
shadowOnly=false)或仅输出阴影(shadowOnly=true)
4.4.3 内阴影滤镜(InnerShadowFilter)
在滤镜输入的内部绘制阴影。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
offsetX |
float | 0 | X 偏移 |
offsetY |
float | 0 | Y 偏移 |
blurX |
float | 0 | X 模糊半径 |
blurY |
float | 0 | Y 模糊半径 |
color |
Color | #000000 | 阴影颜色 |
shadowOnly |
bool | false | 仅显示阴影 |
渲染步骤:
- 创建滤镜输入 alpha 通道的反向遮罩
- 偏移并应用高斯模糊
- 与滤镜输入的 alpha 通道求交集
- 将结果与滤镜输入合成(
shadowOnly=false)或仅输出阴影(shadowOnly=true)
4.4.4 混合滤镜(BlendFilter)
将指定颜色以指定混合模式叠加到图层上。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
color |
Color | (必填) | 混合颜色 |
blendMode |
BlendMode | normal | 混合模式(见 2.9 节) |
4.4.5 颜色矩阵滤镜(ColorMatrixFilter)
使用 4×5 颜色矩阵变换颜色。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
matrix |
Matrix | 单位矩阵 | 4x5 颜色矩阵(20 个逗号分隔的浮点数) |
矩阵格式(20 个值,行优先):
| R' | | m[0] m[1] m[2] m[3] m[4] | | R |
| G' | | m[5] m[6] m[7] m[8] m[9] | | G |
| B' | = | m[10] m[11] m[12] m[13] m[14] | × | B |
| A' | | m[15] m[16] m[17] m[18] m[19] | | A |
| 1 |
4.5 裁剪与遮罩(Clipping and Masking)
4.5.1 scrollRect(滚动裁剪)
scrollRect 属性定义图层的可视区域,超出该区域的内容会被裁剪。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates scrollRect clipping -->
<pagx version="1.0" width="400" height="400">
<Layer x="100" y="100" scrollRect="100,100,200,200">
<Ellipse position="200,200" size="320,320"/>
<Fill>
<RadialGradient center="200,200" radius="160">
<ColorStop offset="0" color="#F43F5E"/>
<ColorStop offset="0.6" color="#EC4899"/>
<ColorStop offset="1" color="#8B5CF6"/>
</RadialGradient>
</Fill>
</Layer>
<!-- Visible clip region indicator (dashed border) -->
<Layer>
<Rectangle position="200,200" size="200,200" roundness="16"/>
<Stroke color="#94A3B840" width="2" dashes="4,4"/>
</Layer>
</pagx>
4.5.2 遮罩(Masking)
通过 mask 属性引用另一个图层作为遮罩。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates alpha masking -->
<pagx version="1.0" width="400" height="400">
<!-- Mask shape (invisible but used for masking) -->
<Layer id="maskShape" visible="false">
<Polystar position="200,200" type="star" pointCount="5" outerRadius="150" innerRadius="70" rotation="-90"/>
<Fill color="#FFF"/>
</Layer>
<Layer mask="@maskShape">
<Rectangle position="200,200" size="360,360"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="360,360">
<ColorStop offset="0" color="#6366F1"/>
<ColorStop offset="0.33" color="#8B5CF6"/>
<ColorStop offset="0.66" color="#EC4899"/>
<ColorStop offset="1" color="#F43F5E"/>
</LinearGradient>
</Fill>
</Layer>
</pagx>
遮罩规则:
- 遮罩图层自身不渲染(
visible属性被忽略) - 遮罩图层的变换不影响被遮罩图层
5. 矢量元素系统(VectorElement System)
矢量元素系统定义了 Layer 内的矢量内容如何被处理和渲染。
5.1 处理模型(Processing Model)
VectorElement 系统采用累积-渲染的处理模型:几何元素在渲染上下文中累积,修改器对累积的几何进行变换,绘制器触发最终渲染。
5.1.1 术语定义
| 术语 | 包含元素 | 说明 |
|---|---|---|
| 几何元素 | Rectangle、Ellipse、Polystar、Path、Text | 提供几何形状的元素,在上下文中累积为几何列表 |
| 修改器 | TrimPath、RoundCorner、MergePath、TextModifier、TextPath、TextBox、Repeater | 对累积的几何进行变换 |
| 绘制器 | Fill、Stroke | 对累积的几何进行填充或描边渲染 |
| 容器 | Group | 创建独立作用域并应用矩阵变换,处理完成后合并 |
5.1.2 几何元素的内部结构
几何元素在上下文中累积时,内部结构有所不同:
| 元素类型 | 内部结构 | 说明 |
|---|---|---|
| 形状元素(Rectangle、Ellipse、Polystar、Path) | 单个 Path | 每个形状元素产生一个路径 |
| 文本元素(Text) | 字形列表 | 一个 Text 经过塑形后产生多个字形 |
5.1.3 处理与渲染顺序
VectorElement 按文档顺序依次处理,文档中靠前的元素先处理。默认情况下,先处理的绘制器先渲染(位于下方)。
由于 Fill 和 Stroke 可通过 placement 属性指定渲染到图层的背景或前景,因此最终渲染顺序可能与文档顺序不完全一致。但在默认情况下(所有内容均为背景),渲染顺序与文档顺序一致。
5.1.4 统一处理流程
几何元素 修改器 绘制器
┌──────────┐ ┌──────────┐ ┌──────────┐
│Rectangle │ │ TrimPath │ │ Fill │
│ Ellipse │ │RoundCorn │ │ Stroke │
│ Polystar │ │MergePath │ └────┬─────┘
│ Path │ │TextModif │ │
│ Text │ │ TextPath │ │
└────┬─────┘ │TextBox │ │
│ │ Repeater │ │
│ └────┬─────┘ │
│ │ │
│ 累积几何 │ 变换几何 │ 渲染
▼ ▼ ▼
┌─────────────────────────────────────────────────────────┐
│ 几何列表 [Path1, Path2, 字形列表1, 字形列表2...] │
└─────────────────────────────────────────────────────────┘
渲染上下文累积的是一个几何列表,其中:
- 每个形状元素贡献一个 Path
- 每个 Text 贡献一个字形列表(包含多个字形)
5.1.5 修改器的作用范围
不同修改器对几何列表中的元素有不同的作用范围:
| 修改器类型 | 作用对象 | 说明 |
|---|---|---|
| 形状修改器(TrimPath、RoundCorner、MergePath) | 仅 Path | 对文本触发强制转换 |
| 文本修改器(TextModifier、TextPath、TextBox) | 仅字形列表 | 对 Path 无效 |
| 复制器(Repeater) | Path + 字形列表 | 同时作用于所有几何 |
5.2 几何元素(Geometry Elements)
几何元素提供可渲染的形状。
5.2.1 矩形(Rectangle)
矩形从中心点定义,支持统一圆角。
<Rectangle position="100,100" size="200,150" roundness="10" reversed="false"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
position |
Point | 0,0 | 中心点坐标 |
size |
Size | 100,100 | 尺寸 "width,height" |
roundness |
float | 0 | 圆角半径 |
reversed |
bool | false | 反转路径方向 |
计算规则:
rect.left = position.x - size.width / 2
rect.top = position.y - size.height / 2
rect.right = position.x + size.width / 2
rect.bottom = position.y + size.height / 2
圆角处理:
roundness值自动限制为min(roundness, size.width/2, size.height/2)- 当
roundness >= min(size.width, size.height) / 2时,短边方向呈半圆形
示例:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates Rectangle shape with various roundness values -->
<pagx version="1.0" width="400" height="400">
<!-- Sharp rectangle -->
<Layer>
<Rectangle position="110,110" size="140,140"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="140,140">
<ColorStop offset="0" color="#F43F5E"/>
<ColorStop offset="1" color="#E11D48"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#F43F5E50"/>
</Layer>
<!-- Medium rounded rectangle -->
<Layer>
<Rectangle position="290,110" size="140,140" roundness="24"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="140,140">
<ColorStop offset="0" color="#8B5CF6"/>
<ColorStop offset="1" color="#7C3AED"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#8B5CF650"/>
</Layer>
<!-- Fully rounded rectangle (pill shape) -->
<Layer>
<Rectangle position="110,290" size="140,140" roundness="70"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="140,140">
<ColorStop offset="0" color="#06B6D4"/>
<ColorStop offset="1" color="#0891B2"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#06B6D450"/>
</Layer>
<!-- Wide rectangle -->
<Layer>
<Rectangle position="290,290" size="140,100" roundness="16"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="140,100">
<ColorStop offset="0" color="#10B981"/>
<ColorStop offset="1" color="#059669"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#10B98150"/>
</Layer>
</pagx>
路径起点:矩形路径从右上角开始,顺时针方向绘制(reversed="false" 时)。
5.2.2 椭圆(Ellipse)
椭圆从中心点定义。
<Ellipse position="100,100" size="100,60" reversed="false"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
position |
Point | 0,0 | 中心点坐标 |
size |
Size | 100,100 | 尺寸 "width,height" |
reversed |
bool | false | 反转路径方向 |
计算规则:
boundingRect.left = position.x - size.width / 2
boundingRect.top = position.y - size.height / 2
boundingRect.right = position.x + size.width / 2
boundingRect.bottom = position.y + size.height / 2
示例:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates Ellipse shape -->
<pagx version="1.0" width="400" height="400">
<!-- Perfect circle -->
<Layer>
<Ellipse position="120,120" size="140,140"/>
<Fill>
<RadialGradient center="50,50" radius="100">
<ColorStop offset="0" color="#FBBF24"/>
<ColorStop offset="1" color="#F59E0B"/>
</RadialGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#F59E0B60"/>
</Layer>
<!-- Horizontal ellipse -->
<Layer>
<Ellipse position="290,110" size="160,100"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="160,100">
<ColorStop offset="0" color="#EC4899"/>
<ColorStop offset="1" color="#DB2777"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#EC489950"/>
</Layer>
<!-- Vertical ellipse -->
<Layer>
<Ellipse position="110,290" size="100,160"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="100,160">
<ColorStop offset="0" color="#06B6D4"/>
<ColorStop offset="1" color="#0891B2"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#06B6D450"/>
</Layer>
<!-- Large ellipse -->
<Layer>
<Ellipse position="290,280" size="150,150"/>
<Fill>
<RadialGradient center="55,55" radius="100">
<ColorStop offset="0" color="#A78BFA"/>
<ColorStop offset="1" color="#8B5CF6"/>
</RadialGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#8B5CF650"/>
</Layer>
</pagx>
路径起点:椭圆路径从右侧中点(3 点钟方向)开始。
5.2.3 多边形/星形(Polystar)
支持正多边形和星形两种模式。
<Polystar position="100,100" type="star" pointCount="5" outerRadius="100" innerRadius="50" rotation="0" outerRoundness="0" innerRoundness="0" reversed="false"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
position |
Point | 0,0 | 中心点坐标 |
type |
PolystarType | star | 类型(见下方) |
pointCount |
float | 5 | 顶点数(支持小数) |
outerRadius |
float | 100 | 外半径 |
innerRadius |
float | 50 | 内半径(仅星形) |
rotation |
float | 0 | 旋转角度 |
outerRoundness |
float | 0 | 外角圆度 0~1 |
innerRoundness |
float | 0 | 内角圆度 0~1 |
reversed |
bool | false | 反转路径方向 |
PolystarType(类型):
| 值 | 说明 |
|---|---|
polygon |
正多边形:只使用外半径 |
star |
星形:使用外半径和内半径交替 |
多边形模式 (type="polygon"):
- 只使用
outerRadius和outerRoundness innerRadius和innerRoundness被忽略
星形模式 (type="star"):
- 外顶点位于
outerRadius处 - 内顶点位于
innerRadius处 - 顶点交替连接形成星形
顶点计算(第 i 个外顶点):
angle = rotation + (i / pointCount) * 360°
x = position.x + outerRadius * cos(angle)
y = position.y + outerRadius * sin(angle)
小数点数:
pointCount支持小数值(如5.5)- 小数部分表示最后一个顶点的"完成度",产生不完整的最后一个角
pointCount <= 0时不生成任何路径
圆度处理:
outerRoundness和innerRoundness取值范围 0~1- 0 表示尖角,1 表示完全圆滑
- 圆度通过在顶点处添加贝塞尔控制点实现
示例:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates Polystar shape (star and polygon) -->
<pagx version="1.0" width="400" height="400">
<!-- 5-pointed star -->
<Layer>
<Polystar position="110,110" type="star" pointCount="5" outerRadius="60" innerRadius="28" rotation="-90"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="120,120">
<ColorStop offset="0" color="#FBBF24"/>
<ColorStop offset="1" color="#F59E0B"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#F59E0B60"/>
</Layer>
<!-- 6-pointed star -->
<Layer>
<Polystar position="290,110" type="star" pointCount="6" outerRadius="60" innerRadius="32" rotation="-90"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="120,120">
<ColorStop offset="0" color="#F43F5E"/>
<ColorStop offset="1" color="#E11D48"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#F43F5E50"/>
</Layer>
<!-- Hexagon (polygon) -->
<Layer>
<Polystar position="110,290" type="polygon" pointCount="6" outerRadius="64"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="128,128">
<ColorStop offset="0" color="#06B6D4"/>
<ColorStop offset="1" color="#0891B2"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#06B6D450"/>
</Layer>
<!-- Pentagon (polygon) -->
<Layer>
<Polystar position="290,290" type="polygon" pointCount="5" outerRadius="64" rotation="-90"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="128,128">
<ColorStop offset="0" color="#8B5CF6"/>
<ColorStop offset="1" color="#7C3AED"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#8B5CF650"/>
</Layer>
</pagx>
5.2.4 路径(Path)
使用 SVG 路径语法定义任意形状,支持内联数据或引用 Resources 中定义的 PathData。
<!-- 内联路径数据 -->
<Path data="M 0 0 L 100 0 L 100 100 Z" reversed="false"/>
<!-- 引用 PathData 资源 -->
<Path data="@curvePath" reversed="false"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
data |
string/idref | (必填) | SVG 路径数据或 PathData 资源引用 "@id" |
reversed |
bool | false | 反转路径方向 |
示例:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates Path shape with custom bezier curves -->
<pagx version="1.0" width="400" height="400">
<!-- Heart shape (top-left quadrant: 0-200 x 0-200, center at 100,100) -->
<Layer>
<Path data="M 100,80 C 100,60 120,50 140,50 C 160,50 170,60 170,80 C 170,100 140,140 100,170 C 60,140 30,100 30,80 C 30,60 40,50 60,50 C 80,50 100,60 100,80 Z"/>
<Fill>
<LinearGradient startPoint="30,50" endPoint="170,170">
<ColorStop offset="0" color="#F43F5E"/>
<ColorStop offset="1" color="#EC4899"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="4" blurX="16" blurY="16" color="#F43F5E60"/>
</Layer>
<!-- Lightning bolt (top-right quadrant: 200-400 x 0-200, center at 300,100) -->
<Layer>
<Path data="M 310,45 L 275,110 L 305,110 L 270,195 L 340,100 L 310,100 L 340,45 Z"/>
<Fill>
<LinearGradient startPoint="270,45" endPoint="340,195">
<ColorStop offset="0" color="#FBBF24"/>
<ColorStop offset="1" color="#F59E0B"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="4" blurX="12" blurY="12" color="#F59E0B60"/>
</Layer>
<!-- Arrow (bottom-left quadrant: 0-200 x 200-400, center at 100,300) -->
<Layer>
<Path data="M 30,290 L 130,290 L 130,260 L 180,300 L 130,340 L 130,310 L 30,310 Z"/>
<Fill color="#06B6D4"/>
<DropShadowStyle offsetY="4" blurX="12" blurY="12" color="#06B6D460"/>
</Layer>
<!-- Star (bottom-right quadrant: 200-400 x 200-400, center at 300,300) -->
<Layer>
<Path data="M 300,220 L 318,270 L 370,270 L 328,300 L 343,350 L 300,322 L 257,350 L 272,300 L 230,270 L 282,270 Z"/>
<Fill color="#8B5CF6"/>
<DropShadowStyle offsetY="4" blurX="12" blurY="12" color="#8B5CF660"/>
</Layer>
</pagx>
5.2.5 文本(Text)
文本元素提供文本内容的几何形状。与形状元素产生单一 Path 不同,Text 经过塑形后会产生字形列表(多个字形)并累积到渲染上下文的几何列表中,供后续修改器变换或绘制器渲染。
<Text text="Hello World" position="100,200" fontFamily="Arial" fontStyle="Regular" fauxBold="true" fauxItalic="false" fontSize="24" letterSpacing="0" textAnchor="start"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
text |
string | "" | 文本内容 |
position |
Point | 0,0 | 文本起点位置,y 为基线 |
fontFamily |
string | "" | 字体族(空字符串表示系统默认字体) |
fontStyle |
string | "" | 字体变体(Regular, Bold, Italic, Bold Italic 等)。空字符串表示该字体的默认变体 |
fontSize |
float | 12 | 字号 |
letterSpacing |
float | 0 | 字间距 |
fauxBold |
bool | false | 仿粗体效果 |
fauxItalic |
bool | false | 仿斜体效果 |
textAnchor |
TextAnchor | start | 文本锚点对齐——控制文本相对原点的位置(见下方)。有 TextBox 排版时忽略 |
子元素:CDATA 文本、GlyphRun*
文本内容:通常使用 text 属性指定文本内容。当文本包含 XML 特殊字符(<、>、& 等)或需要保留多行格式时,可使用 CDATA 子节点替代 text 属性。Text 不允许直接包含纯文本子节点,必须用 CDATA 包裹。
<!-- 简单文本:使用 text 属性 -->
<Text text="Hello World" fontFamily="Arial" fontSize="24"/>
<!-- 包含特殊字符:使用 CDATA -->
<Text fontFamily="Arial" fontSize="24"><![CDATA[A < B & C > D]]></Text>
<!-- 多行文本:使用 CDATA 保留格式 -->
<Text fontFamily="Arial" fontSize="24">
<![CDATA[Line 1
Line 2
Line 3]]>
</Text>
渲染模式:Text 支持预排版和运行时排版两种模式。预排版通过 GlyphRun 子节点提供预计算的字形和位置,使用嵌入字体渲染,确保跨平台完全一致。运行时排版在运行时进行塑形和排版,因各平台字体和排版特性差异,可能存在细微不一致。如需精确还原设计工具的排版效果,建议使用预排版。
TextAnchor(文本锚点对齐):
控制文本相对其原点的定位方式。
| 值 | 说明 |
|---|---|
start |
原点位于文本起始位置,不做偏移 |
center |
原点位于文本中心位置,文本偏移半个宽度使其居中于原点 |
end |
原点位于文本结束位置,文本偏移整个宽度使其终点对齐原点 |
运行时排版渲染流程:
- 根据
fontFamily和fontStyle查找系统字体,不可用时按运行时配置的回退列表选择替代字体 - 使用
text属性(或 CDATA 子节点)进行塑形,换行符触发换行(默认 1.2 倍字号行高,可通过 TextBox 自定义) - 应用
fontSize、letterSpacing等排版参数 - 构造字形列表累积到渲染上下文
运行时排版示例:
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="400" height="400">
<Layer>
<Text text="PAGX" fontFamily="Arial" fontStyle="Bold" fontSize="84" position="200,145" textAnchor="center"/>
<Fill>
<LinearGradient startPoint="-200,0" endPoint="80,0">
<ColorStop offset="0" color="#6366F1"/>
<ColorStop offset="0.5" color="#8B5CF6"/>
<ColorStop offset="1" color="#EC4899"/>
</LinearGradient>
</Fill>
</Layer>
<Layer>
<Text text="Text Shape" fontFamily="Arial" fontSize="36" position="200,230" textAnchor="center"/>
<Fill color="#334155"/>
</Layer>
<Layer>
<Text text="Beautiful Typography" fontFamily="Arial" fontSize="24" position="200,310" textAnchor="center"/>
<Fill color="#475569"/>
</Layer>
</pagx>
预排版数据(GlyphRun)
GlyphRun 定义一组字形的预排版数据,每个 GlyphRun 独立引用一个字体资源。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
font |
idref | (必填) | 引用 Font 资源 @id |
fontSize |
float | 12 | 渲染字号。实际缩放比例 = fontSize / font.unitsPerEm |
glyphs |
string | (必填) | GlyphID 序列,逗号分隔(0 表示缺失字形) |
x |
float | 0 | 总体 X 偏移 |
y |
float | 0 | 总体 Y 偏移 |
xOffsets |
string | - | 每字形 X 偏移,逗号分隔 |
positions |
string | - | 每字形 (x,y) 偏移,分号分隔 |
anchors |
string | - | 每字形锚点偏移 (x,y),分号分隔。锚点是缩放、旋转和斜切变换的中心点。默认锚点为 (advance×0.5, 0) |
scales |
string | - | 每字形缩放 (sx,sy),分号分隔。缩放围绕锚点进行。默认 1,1 |
rotations |
string | - | 每字形旋转角度(度),逗号分隔。旋转围绕锚点进行。默认 0 |
skews |
string | - | 每字形斜切角度(度),逗号分隔。斜切围绕锚点进行。默认 0 |
所有属性均为可选,可任意组合使用。当属性数组长度小于字形数量时,缺失的值使用默认值。
位置计算:
finalX[i] = x + xOffsets[i] + positions[i].x
finalY[i] = y + positions[i].y
- 未指定
xOffsets时,xOffsets[i]视为 0 - 未指定
positions时,positions[i]视为 (0, 0) - 不指定
xOffsets和positions时:首个字形位于 (x, y),后续字形依次累加 advance
变换应用顺序:
当字形有 scale、rotation 或 skew 变换时,按以下顺序应用(与 TextModifier 一致):
- 平移到锚点(
translate(-anchor)) - 缩放(
scale) - 斜切(
skew,沿垂直轴方向) - 旋转(
rotation) - 平移回锚点(
translate(anchor)) - 平移到位置(
translate(position))
锚点:
- 每个字形的默认锚点位于
(advance × 0.5, 0),即字形水平中心的基线位置 anchors属性记录的是相对于默认锚点的偏移,最终锚点 = 默认锚点 + anchors[i]
预排版示例:
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="400" height="400">
<Layer>
<Text text="GlyphRun" fontFamily="Arial" fontStyle="Bold" fontSize="72">
<GlyphRun font="@font1" fontSize="72" glyphs="14,15,16,17,18,19,20,21" x="34" y="145"/>
</Text>
<Fill>
<LinearGradient startPoint="0,0" endPoint="280,0">
<ColorStop offset="0" color="#6366F1"/>
<ColorStop offset="0.5" color="#8B5CF6"/>
<ColorStop offset="1" color="#EC4899"/>
</LinearGradient>
</Fill>
</Layer>
<Layer>
<Text text="Embedded Font" fontFamily="Arial" fontSize="36">
<GlyphRun font="@font1" fontSize="36" glyphs="6,7,8,9,10,10,9,10,22,11,12,21,13" y="230" xOffsets="66,87,120,142,162,184,206,226,248,256,276,298,320"/>
</Text>
<Fill color="#334155"/>
</Layer>
<Layer>
<Text text="Pre-shaped Glyphs" fontFamily="Arial" fontSize="24">
<GlyphRun font="@font1" fontSize="24" glyphs="1,2,9,3,4,18,5,17,9,10,22,14,15,16,17,18,4" y="310" xOffsets="94.5,109.5,118.5,131.5,139.5,150.5,165.5,179.5,194.5,207.5,222.5,227.5,244.5,251.5,264.5,279.5,294.5"/>
</Text>
<Fill color="#475569"/>
</Layer>
<Resources>
<Font id="font1">
<Glyph path="M100 0L193 0L193 -299L314 -299C475 -299 584 -372 584 -531C584 -693 474 -750 310 -750L100 -750L100 0ZM193 -375L193 -674L298 -674C426 -674 492 -639 492 -531C492 -423 431 -375 301 -375L193 -375Z" advance="625"/>
<Glyph path="M92 0L183 0L183 -337C219 -427 275 -458 320 -458C342 -458 355 -456 372 -450L390 -542C372 -538 355 -542 331 -542C271 -542 215 -497 178 -429L174 -429L167 -542L92 -542L92 0Z" advance="375"/>
<Glyph path="M46 -250L301 -250L301 -320L46 -320L46 -250Z" advance="333.333"/>
<Glyph path="M234 0C362 0 432 -72 432 -155C432 -251 344 -281 266 -309C204 -330 148 -348 148 -396C148 -436 181 -469 250 -469C298 -469 336 -451 372 -424L417 -480C375 -513 316 -542 249 -542C131 -542 61 -473 61 -393C61 -307 144 -272 219 -246C280 -225 344 -202 344 -150C344 -106 309 -71 237 -71C172 -71 122 -95 76 -130L31 -74C83 -32 157 0 234 0Z" advance="458.333"/>
<Glyph path="M217 0C284 0 344 -35 396 -77L400 -77L408 0L482 0L482 -323C482 -453 426 -542 295 -542C208 -542 131 -503 81 -470L117 -410C160 -438 217 -465 280 -465C368 -465 392 -400 392 -333C161 -307 58 -251 58 -136C58 -56 126 0 217 0ZM243 -73C189 -73 146 -96 146 -154C146 -219 209 -261 392 -282L392 -140C339 -96 296 -73 243 -73Z" advance="583.333"/>
<Glyph path="M100 0L534 0L534 -79L193 -79L193 -338L471 -338L471 -417L193 -417L193 -643L523 -643L523 -722L100 -722L100 0Z" advance="583.333"/>
<Glyph path="M92 0L183 0L183 -392C233 -448 279 -475 320 -475C389 -475 421 -432 421 -331L421 0L512 0L512 -392C563 -448 607 -475 649 -475C718 -475 750 -432 750 -331L750 0L841 0L841 -343C841 -481 788 -556 676 -556C610 -556 553 -512 497 -451C475 -515 430 -556 347 -556C282 -556 225 -514 178 -462L175 -462L167 -556L92 -556L92 0Z" advance="916.667"/>
<Glyph path="M331 0C456 0 567 -106 567 -286C567 -447 491 -556 350 -556C290 -556 229 -521 180 -478L183 -576L183 -794L92 -794L92 0L165 0L173 -69L177 -69C224 -26 281 0 331 0ZM316 -76C280 -76 231 -90 183 -131L183 -406C235 -453 283 -478 329 -478C432 -478 472 -400 472 -284C472 -154 406 -76 316 -76Z" advance="611.111"/>
<Glyph path="M311 0C385 0 443 -25 491 -56L458 -113C418 -88 375 -73 322 -73C219 -73 148 -142 142 -250L508 -250C510 -263 512 -282 512 -302C512 -456 434 -556 296 -556C170 -556 51 -446 51 -271C51 -102 167 0 311 0ZM141 -316C152 -421 220 -482 297 -482C382 -482 432 -424 432 -316L141 -316Z" advance="555.556"/>
<Glyph path="M277 0C342 0 399 -35 442 -77L445 -77L453 0L527 0L527 -794L437 -794L437 -586L441 -491C393 -531 352 -556 288 -556C164 -556 53 -445 53 -270C53 -102 141 0 277 0ZM297 -76C201 -76 147 -151 147 -278C147 -397 216 -478 304 -478C349 -478 390 -463 437 -423L437 -148C391 -100 347 -76 297 -76Z" advance="611.111"/>
<Glyph path="M100 0L193 0L193 -333L473 -333L473 -411L193 -411L193 -643L523 -643L523 -722L100 -722L100 0Z" advance="555.556"/>
<Glyph path="M303 0C436 0 555 -103 555 -276C555 -451 436 -556 303 -556C170 -556 51 -451 51 -276C51 -103 170 0 303 0ZM303 -76C209 -76 146 -156 146 -276C146 -397 209 -479 303 -479C397 -479 461 -397 461 -276C461 -156 397 -76 303 -76Z" advance="611.111"/>
<Glyph path="M263 0C296 0 332 -10 363 -20L345 -88C327 -81 302 -74 283 -74C220 -74 199 -112 199 -179L199 -481L346 -481L346 -556L199 -556L199 -708L123 -708L112 -556L27 -550L27 -481L108 -481L108 -181C108 -73 147 0 263 0Z" advance="388.889"/>
<Glyph path="M388 14C487 14 568 -22 615 -71L615 -382L375 -382L375 -306L530 -306L530 -111C501 -83 450 -67 398 -67C240 -67 153 -185 153 -372C153 -555 249 -669 396 -669C471 -669 518 -638 555 -599L605 -659C563 -704 496 -750 394 -750C200 -750 58 -606 58 -368C58 -128 196 14 388 14Z" advance="694.444"/>
<Glyph path="M188 14C213 14 228 11 241 6L228 -64C218 -62 214 -62 209 -62C195 -62 183 -73 183 -101L183 -795L92 -795L92 -107C92 -30 120 14 188 14Z" advance="291.667"/>
<Glyph path="M101 236C209 236 266 154 303 47L508 -542L419 -542L322 -239C307 -191 291 -136 276 -87L271 -87C254 -136 235 -192 219 -239L108 -542L13 -542L231 3L219 44C197 111 158 161 96 161C82 161 66 156 55 152L37 225C54 232 75 236 101 236Z" advance="527.778"/>
<Glyph path="M92 222L183 222L183 45L181 -49C230 -9 282 14 331 14C456 14 567 -93 567 -279C567 -446 491 -556 351 -556C288 -556 227 -520 178 -479L175 -479L167 -542L92 -542L92 222ZM316 -62C280 -62 232 -77 183 -119L183 -403C236 -452 283 -479 329 -479C432 -479 472 -398 472 -278C472 -143 406 -62 316 -62Z" advance="625"/>
<Glyph path="M92 0L183 0L183 -393C238 -447 276 -475 332 -475C404 -475 435 -433 435 -331L435 0L526 0L526 -343C526 -481 474 -556 360 -556C286 -556 230 -515 180 -464L183 -576L183 -794L92 -794L92 0Z" advance="611.111"/>
<Glyph path="M100 0L193 0L193 -314L325 -314L503 0L608 0L420 -324C520 -348 586 -416 586 -529C586 -682 479 -736 330 -736L100 -736L100 0ZM193 -389L193 -660L316 -660C431 -660 494 -626 494 -529C494 -435 431 -389 316 -389L193 -389Z" advance="638.889"/>
<Glyph path="M250 14C325 14 379 -25 430 -84L433 -84L440 0L516 0L516 -542L425 -542L425 -157C373 -92 334 -65 278 -65C206 -65 176 -108 176 -209L176 -542L85 -542L85 -198C85 -60 136 14 250 14Z" advance="611.111"/>
<Glyph path="M92 0L183 0L183 -393C238 -447 276 -475 332 -475C404 -475 435 -433 435 -331L435 0L526 0L526 -343C526 -481 474 -556 360 -556C286 -556 230 -515 178 -464L175 -464L167 -542L92 -542L92 0Z" advance="611.111"/>
<Glyph advance="208.333"/>
</Font>
</Resources>
</pagx>
5.3 绘制器(Painters)
绘制器(Fill、Stroke)对当前时刻累积的所有几何(Path 和字形列表)进行渲染。
5.3.1 填充(Fill)
填充使用指定的颜色源绘制几何的内部区域。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates different fill types -->
<pagx version="1.0" width="400" height="400">
<!-- Solid color fill -->
<Layer>
<Rectangle position="110,110" size="140,140" roundness="24"/>
<Fill color="#F43F5E"/>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#F43F5E50"/>
</Layer>
<!-- Linear gradient fill -->
<Layer>
<Rectangle position="290,110" size="140,140" roundness="24"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="140,140">
<ColorStop offset="0" color="#6366F1"/>
<ColorStop offset="1" color="#8B5CF6"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#8B5CF650"/>
</Layer>
<!-- Radial gradient fill -->
<Layer>
<Ellipse position="200,300" size="320,140"/>
<Fill>
<RadialGradient center="160,70" radius="170">
<ColorStop offset="0" color="#FFF"/>
<ColorStop offset="0.5" color="#06B6D4"/>
<ColorStop offset="1" color="#0891B2"/>
</RadialGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#06B6D450"/>
</Layer>
</pagx>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
color |
Color/idref | #000000 | 颜色值或颜色源引用,默认黑色 |
alpha |
float | 1 | 透明度 0~1 |
blendMode |
BlendMode | normal | 混合模式(见 2.9 节) |
fillRule |
FillRule | winding | 填充规则(见下方) |
placement |
LayerPlacement | background | 绘制位置(见 5.3.3 节) |
子元素:可内嵌一个颜色源(SolidColor、LinearGradient、RadialGradient、ConicGradient、DiamondGradient、ImagePattern)
FillRule(填充规则):
| 值 | 说明 |
|---|---|
winding |
非零环绕规则:根据路径方向计数,非零则填充 |
evenOdd |
奇偶规则:根据交叉次数,奇数则填充 |
文本填充:
- 文本以字形(glyph)为单位填充
- 支持通过 TextModifier 对单个字形应用颜色覆盖
- 颜色覆盖采用 alpha 混合:
finalColor = lerp(originalColor, overrideColor, overrideAlpha)
5.3.2 描边(Stroke)
描边沿几何边界绘制线条。
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="400" height="400">
<Layer>
<Rectangle position="110,110" size="130,130" roundness="20"/>
<Stroke color="#06B6D4" width="8" cap="round" join="round"/>
</Layer>
<Layer>
<Rectangle position="290,110" size="130,130" roundness="20"/>
<Stroke color="#8B5CF6" width="6" dashes="12,8" cap="round"/>
</Layer>
<Layer>
<Path data="M 50,300 Q 200,180 350,300"/>
<Stroke width="10" cap="round">
<LinearGradient startPoint="0,0" endPoint="300,0">
<ColorStop offset="0" color="#F43F5E"/>
<ColorStop offset="0.5" color="#EC4899"/>
<ColorStop offset="1" color="#8B5CF6"/>
</LinearGradient>
</Stroke>
</Layer>
</pagx>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
color |
Color/idref | #000000 | 颜色值或颜色源引用,默认黑色 |
width |
float | 1 | 描边宽度 |
alpha |
float | 1 | 透明度 0~1 |
blendMode |
BlendMode | normal | 混合模式(见 2.9 节) |
cap |
LineCap | butt | 线帽样式(见下方) |
join |
LineJoin | miter | 线连接样式(见下方) |
miterLimit |
float | 4 | 斜接限制 |
dashes |
string | - | 虚线模式 "d1,d2,..." |
dashOffset |
float | 0 | 虚线偏移 |
dashAdaptive |
bool | false | 等长虚线段缩放 |
align |
StrokeAlign | center | 描边对齐(见下方) |
placement |
LayerPlacement | background | 绘制位置(见 5.3.3 节) |
LineCap(线帽样式):
| 值 | 说明 |
|---|---|
butt |
平头:线条不超出端点 |
round |
圆头:以半圆形扩展端点 |
square |
方头:以方形扩展端点 |
LineJoin(线连接样式):
| 值 | 说明 |
|---|---|
miter |
斜接:延伸外边缘形成尖角 |
round |
圆角:以圆弧连接 |
bevel |
斜角:以三角形填充连接处 |
StrokeAlign(描边对齐):
| 值 | 说明 |
|---|---|
center |
描边居中于路径(默认) |
inside |
描边在闭合路径内侧 |
outside |
描边在闭合路径外侧 |
内侧/外侧描边通过以下方式实现:
- 以双倍宽度描边
- 与原始形状进行布尔运算(内侧用交集,外侧用差集)
虚线模式:
dashes:定义虚线段长度序列,如"5,3"表示 5px 实线 + 3px 空白dashOffset:虚线起始偏移量dashAdaptive:为 true 时,缩放虚线间隔使各虚线段保持等长
5.3.3 绘制位置(LayerPlacement)
Fill 和 Stroke 的 placement 属性控制相对于子图层的绘制顺序:
| 值 | 说明 |
|---|---|
background |
在子图层下方绘制(默认) |
foreground |
在子图层上方绘制 |
5.4 形状修改器(Shape Modifiers)
形状修改器对累积的 Path 进行原地变换,对字形列表则触发强制转换为 Path。
5.4.1 路径裁剪(TrimPath)
裁剪路径到指定的起止范围。
<TrimPath start="0" end="0.5" offset="0" type="separate"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
start |
float | 0 | 起始位置 0~1 |
end |
float | 1 | 结束位置 0~1 |
offset |
float | 0 | 偏移量(度),360 度表示完整路径长度的一个周期。例如,180 度将裁剪范围偏移半个路径长度 |
type |
TrimType | separate | 裁剪类型(见下方) |
TrimType(裁剪类型):
| 值 | 说明 |
|---|---|
separate |
独立模式:每个形状独立裁剪,使用相同的 start/end 参数 |
continuous |
连续模式:所有形状视为一条连续路径,按总长度比例裁剪 |
边界情况:
start > end:对 start 和 end 值取镜像(start = 1 - start,end = 1 - end)并反转所有路径方向,然后执行正常裁剪。视觉效果为路径的互补段且方向相反- 支持环绕:当裁剪范围超出 [0,1] 时,自动环绕到路径另一端
- 路径总长度为 0 时,不执行任何操作
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates TrimPath: separate vs continuous mode comparison -->
<pagx version="1.0" width="400" height="400">
<!-- === Top row: Separate mode === -->
<Layer>
<Ellipse position="120,95" size="100,100"/>
<Ellipse position="280,95" size="100,100"/>
<Stroke color="#E2E8F0" width="8"/>
</Layer>
<!-- Trimmed: each ellipse trimmed independently to 0.2~0.9 -->
<Layer>
<Ellipse position="120,95" size="100,100"/>
<Ellipse position="280,95" size="100,100"/>
<TrimPath start="0.2" end="0.9"/>
<Stroke width="10" cap="round">
<LinearGradient startPoint="70,40" endPoint="330,150">
<ColorStop offset="0" color="#06B6D4"/>
<ColorStop offset="1" color="#8B5CF6"/>
</LinearGradient>
</Stroke>
</Layer>
<Layer>
<Text text="Separate (0.2–0.9)" fontFamily="Arial" fontStyle="Bold" fontSize="18" position="200,187" textAnchor="center"/>
<Fill color="#475569"/>
</Layer>
<!-- === Bottom row: Continuous mode === -->
<Layer>
<Ellipse position="120,265" size="100,100"/>
<Ellipse position="280,265" size="100,100"/>
<Stroke color="#E2E8F0" width="8"/>
</Layer>
<!-- Trimmed: both ellipses treated as one path, 0.2~0.9 of total length -->
<Layer>
<Ellipse position="120,265" size="100,100"/>
<Ellipse position="280,265" size="100,100"/>
<TrimPath start="0.2" end="0.9" type="continuous"/>
<Stroke width="10" cap="round">
<LinearGradient startPoint="70,210" endPoint="330,320">
<ColorStop offset="0" color="#F59E0B"/>
<ColorStop offset="1" color="#F43F5E"/>
</LinearGradient>
</Stroke>
</Layer>
<Layer>
<Text text="Continuous (0.2–0.9)" fontFamily="Arial" fontStyle="Bold" fontSize="18" position="200,357" textAnchor="center"/>
<Fill color="#475569"/>
</Layer>
</pagx>
5.4.2 圆角(RoundCorner)
将路径的尖角转换为圆角。
<RoundCorner radius="10"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
radius |
float | 10 | 圆角半径 |
处理规则:
- 只影响尖角(非平滑连接的顶点)
- 圆角半径自动限制为不超过相邻边长度的一半
radius <= 0时不执行任何操作
示例:
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="400" height="400">
<!-- Original sharp rectangle (reference) -->
<Layer>
<Rectangle position="120,120" size="140,140"/>
<Stroke color="#94A3B840" width="2" dashes="4,4"/>
</Layer>
<Layer>
<Rectangle position="120,120" size="140,140"/>
<RoundCorner radius="30"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="140,140">
<ColorStop offset="0" color="#10B981"/>
<ColorStop offset="1" color="#059669"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#10B98160"/>
</Layer>
<!-- Original star (reference) -->
<Layer>
<Polystar position="290,120" type="star" pointCount="5" outerRadius="70" innerRadius="32" rotation="-90"/>
<Stroke color="#94A3B840" width="2" dashes="4,4"/>
</Layer>
<Layer>
<Polystar position="290,120" type="star" pointCount="5" outerRadius="70" innerRadius="32" rotation="-90"/>
<RoundCorner radius="12"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="140,140">
<ColorStop offset="0" color="#F59E0B"/>
<ColorStop offset="1" color="#D97706"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#F59E0B60"/>
</Layer>
<Layer>
<Polystar position="200,300" type="polygon" pointCount="6" outerRadius="80"/>
<RoundCorner radius="20"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="160,160">
<ColorStop offset="0" color="#8B5CF6"/>
<ColorStop offset="1" color="#7C3AED"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#8B5CF660"/>
</Layer>
</pagx>
5.4.3 路径合并(MergePath)
将所有形状合并为单个形状。
<MergePath mode="append"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
mode |
MergePathMode | append | 合并操作(见下方) |
MergePathMode(路径合并操作):
| 值 | 说明 |
|---|---|
append |
追加:简单合并所有路径,不进行布尔运算(默认) |
union |
并集:合并所有形状的覆盖区域 |
intersect |
交集:只保留所有形状的重叠区域 |
xor |
异或:保留非重叠区域 |
difference |
差集:从第一个形状中减去后续形状 |
重要行为:
- MergePath 会清空当前作用域中之前累积的所有 Fill 和 Stroke 效果,几何列表中仅保留合并后的路径
- 合并时应用各形状的当前变换矩阵
- 合并后的形状变换矩阵重置为单位矩阵
示例:
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="400" height="400">
<Layer>
<Rectangle position="150,150" size="180,180" roundness="24"/>
<Ellipse position="250,250" size="180,180"/>
<MergePath mode="union"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="280,280">
<ColorStop offset="0" color="#6366F1"/>
<ColorStop offset="0.5" color="#8B5CF6"/>
<ColorStop offset="1" color="#EC4899"/>
</LinearGradient>
</Fill>
<DropShadowStyle offsetY="12" blurX="40" blurY="40" color="#8B5CF660"/>
</Layer>
</pagx>
5.5 文本修改器(Text Modifiers)
文本修改器对文本中的独立字形进行变换。
5.5.1 文本修改器处理
遇到文本修改器时,上下文中累积的所有字形列表会汇总为一个统一的字形列表进行操作:
<Group>
<Text text="Hello " fontFamily="Arial" fontSize="24"/>
<Text text="World" fontFamily="Arial" fontSize="24"/>
<TextModifier position="0,-5"/>
<TextBox position="100,50" textAlign="center"/>
<Fill color="#333333"/>
</Group>
5.5.2 文本转形状
当文本遇到形状修改器时,会强制转换为形状路径:
文本元素 形状修改器 后续修改器
┌──────────┐ ┌──────────┐
│ Text │ │ TrimPath │
└────┬─────┘ │RoundCorn │
│ │MergePath │
│ 累积字形列表 └────┬─────┘
▼ │
┌──────────────┐ │ 触发转换
│ 字形列表 │───────────┼──────────────────────┐
│ [H,e,l,l,o] │ │ │
└──────────────┘ ▼ ▼
┌──────────────┐ ┌──────────────────┐
│ 合并为单个 │ │ Emoji 被丢弃 │
│ Path │ │ (无法转为路径) │
└──────────────┘ └──────────────────┘
│
│ 后续文本修改器不再生效
▼
┌──────────────┐
│ TextModifier │ → 跳过(已是 Path)
└──────────────┘
转换规则:
- 触发条件:文本遇到 TrimPath、RoundCorner、MergePath 时触发转换
- 合并为单个 Path:一个 Text 的所有字形合并为一个 Path,而非每个字形产生一个独立 Path
- Emoji 丢失:Emoji 无法转换为路径轮廓,转换时被丢弃
- 不可逆转换:转换后成为纯 Path,后续的文本修改器对其无效
示例:
<Group>
<Text fontFamily="Arial" fontSize="24"><![CDATA[Hello 😀]]></Text>
<TrimPath start="0" end="0.5"/>
<TextModifier position="0,-10"/>
<Fill color="#333333"/>
</Group>
5.5.3 文本变换器(TextModifier)
对选定范围内的字形应用变换和样式覆盖。TextModifier 可包含多个 RangeSelector 子元素,用于定义不同的选择范围和影响因子。
<TextModifier anchor="0,0" position="0,0" rotation="0" scale="1,1" skew="0" skewAxis="0" alpha="1" fillColor="#FF0000" strokeColor="#000000" strokeWidth="1">
<RangeSelector start="0" end="0.5" shape="rampUp"/>
<RangeSelector start="0.5" end="1" shape="rampDown"/>
</TextModifier>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
anchor |
Point | 0,0 | 锚点偏移,相对于字形默认锚点位置。每个字形的默认锚点位于 (advance × 0.5, 0),即字形水平中心的基线位置 |
position |
Point | 0,0 | 位置偏移 |
rotation |
float | 0 | 旋转 |
scale |
Point | 1,1 | 缩放 |
skew |
float | 0 | 倾斜角度(度),沿 skewAxis 方向应用 |
skewAxis |
float | 0 | 倾斜轴角度(度),定义倾斜的作用方向 |
alpha |
float | 1 | 透明度 |
fillColor |
Color | - | 填充颜色覆盖 |
strokeColor |
Color | - | 描边颜色覆盖 |
strokeWidth |
float | - | 描边宽度覆盖 |
选择器计算:
- 根据 RangeSelector 的
start、end、offset计算选择范围(支持任意小数值,超出 [0,1] 范围时自动环绕) - 根据
shape计算每个字形的原始影响值(0~1),然后乘以weight - 多个选择器按
mode组合,组合结果限制到 [-1, 1]
factor = clamp(combine(rawInfluence₁ × weight₁, rawInfluence₂ × weight₂, ...), -1, 1)
变换应用:
位置和旋转线性应用 factor。变换按以下顺序应用:
- 平移到锚点的负方向(
translate(-anchor × factor)) - 从单位矩阵插值缩放(
scale(1 + (scale - 1) × factor)) - 倾斜(
skew(skew × factor, skewAxis)) - 旋转(
rotate(rotation × factor)) - 平移回锚点(
translate(anchor × factor)) - 平移到位置(
translate(position × factor))
透明度使用 factor 的绝对值:
alphaFactor = 1 + (alpha - 1) × |factor|
finalAlpha = originalAlpha × max(0, alphaFactor)
颜色覆盖:
颜色覆盖使用 factor 的绝对值进行 alpha 混合:
blendFactor = overrideColor.alpha × |factor|
finalColor = blend(originalColor, overrideColor, blendFactor)
示例:
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="400" height="400">
<!-- Wave effect: triangle selector shifts characters vertically -->
<Layer>
<Text text="WAVE" fontFamily="Arial" fontStyle="Bold" fontSize="72" position="200,120" textAnchor="center"/>
<TextModifier position="0,-30">
<RangeSelector start="0" end="1" shape="triangle"/>
</TextModifier>
<Fill>
<LinearGradient startPoint="-200,0" endPoint="80,0">
<ColorStop offset="0" color="#06B6D4"/>
<ColorStop offset="1" color="#3B82F6"/>
</LinearGradient>
</Fill>
</Layer>
<!-- Rotation effect: each character rotated with rampUp selector -->
<Layer>
<Text text="ROTATE" fontFamily="Arial" fontStyle="Bold" fontSize="56" position="200,240" textAnchor="center"/>
<TextModifier rotation="30">
<RangeSelector start="0" end="1" shape="rampUp"/>
</TextModifier>
<Fill>
<LinearGradient startPoint="-200,0" endPoint="80,0">
<ColorStop offset="0" color="#F59E0B"/>
<ColorStop offset="1" color="#F43F5E"/>
</LinearGradient>
</Fill>
</Layer>
<!-- Color override effect: characters with gradient color override -->
<Layer>
<Text text="COLOR" fontFamily="Arial" fontStyle="Bold" fontSize="64" position="200,350" textAnchor="center"/>
<TextModifier fillColor="#EC4899">
<RangeSelector start="0" end="1" shape="triangle"/>
</TextModifier>
<Fill color="#8B5CF6"/>
</Layer>
</pagx>
5.5.4 范围选择器(RangeSelector)
范围选择器定义 TextModifier 影响的字形范围和影响程度。
<RangeSelector start="0" end="1" offset="0" unit="percentage" shape="square" easeIn="0" easeOut="0" mode="add" weight="1" randomOrder="false" randomSeed="0"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
start |
float | 0 | 选择起始 |
end |
float | 1 | 选择结束 |
offset |
float | 0 | 选择偏移 |
unit |
SelectorUnit | percentage | 单位(见下方) |
shape |
SelectorShape | square | 形状(见下方) |
easeIn |
float | 0 | 缓入量 |
easeOut |
float | 0 | 缓出量 |
mode |
SelectorMode | add | 组合模式(见下方) |
weight |
float | 1 | 选择器权重 |
randomOrder |
bool | false | 随机顺序 |
randomSeed |
int | 0 | 随机种子 |
SelectorUnit(单位):
| 值 | 说明 |
|---|---|
index |
索引:按字形索引计算范围 |
percentage |
百分比:按字形总数的百分比计算范围 |
SelectorShape(形状):
| 值 | 说明 |
|---|---|
square |
矩形:范围内为 1,范围外为 0 |
rampUp |
上升斜坡:从 0 线性增加到 1 |
rampDown |
下降斜坡:从 1 线性减少到 0 |
triangle |
三角形:中心为 1,两端为 0 |
round |
圆形:正弦曲线过渡 |
smooth |
平滑:更平滑的过渡曲线 |
SelectorMode(组合模式):
| 值 | 说明 |
|---|---|
add |
相加:result = a + b |
subtract |
相减:result = b ≥ 0 ? a × (1 − b) : a × (−1 − b) |
intersect |
交集:result = a × b |
min |
最小:result = min(a, b) |
max |
最大:result = max(a, b) |
difference |
差值:`result = |
5.5.5 路径文本(TextPath)
将文本沿指定路径排列。路径可以通过引用 Resources 中定义的 PathData,也可以内联路径数据。TextPath 使用 基线(由 baselineOrigin 和 baselineAngle 定义的直线)作为文本的参考线:字形从基线上的位置映射到路径曲线上 的对应位置,保持相对间距和偏移。当 forceAlignment 启用时,忽略原始字形位置,将字形均匀分布以填满可用路径长度。
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="400" height="400">
<Layer>
<Text text="PAGX" fontFamily="Arial" fontStyle="Bold" fontSize="56"/>
<TextPath path="M 60,230 Q 200,30 340,230" forceAlignment="true"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="300,0">
<ColorStop offset="0" color="#06B6D4"/>
<ColorStop offset="0.5" color="#8B5CF6"/>
<ColorStop offset="1" color="#EC4899"/>
</LinearGradient>
</Fill>
</Layer>
<!-- Guide path (dashed) to visualize the curve -->
<Layer>
<Path data="M 60,230 Q 200,30 340,230"/>
<Stroke color="#64748B" width="1" dashes="6,4"/>
</Layer>
<Layer>
<Text text="TextPath" fontFamily="Arial" fontStyle="Bold" fontSize="28"/>
<TextPath path="M 80,320 Q 200,250 320,320" forceAlignment="true"/>
<Fill color="#475569"/>
</Layer>
</pagx>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
path |
string/idref | (必填) | SVG 路径数据或 PathData 资源引用 "@id" |
baselineOrigin |
Point | 0,0 | 基线原点,文本参考线的起点坐标 |
baselineAngle |
float | 0 | 基线角度(度),0 为水平,90 为垂直 |
firstMargin |
float | 0 | 起始边距 |
lastMargin |
float | 0 | 结束边距 |
perpendicular |
bool | true | 垂直于路径 |
reversed |
bool | false | 反转方向 |
forceAlignment |
bool | false | 强制拉伸文本填满路径 |
基线:
baselineOrigin:基线的起点坐标,相对于 TextPath 的本地坐标空间baselineAngle:基线的角度(度数),0 表示水平基线(文本从左到右沿 X 轴),90 表示垂直基线(文本从上到下沿 Y 轴)- 字形沿基线的距离决定其在曲线上的位置,字形垂直于基线的偏移量保持为垂直于曲线的偏移量
边距:
firstMargin:起点边距(从路径起点向内偏移)lastMargin:终点边距(从路径终点向内偏移)
强制对齐:
- 当
forceAlignment="true"时,字形按其推进宽度依次排列,然后按比例调整间距以填满 firstMargin 和 lastMargin 之间的路径区域
字形定位:
- 计算字形中心在路径上的位置
- 获取该位置的路径切线方向
- 如果
perpendicular="true",旋转字形使其垂直于路径
闭合路径:对于闭合路径,超出范围的字形会环绕到路径另一端。
5.5.6 文本框(TextBox)
TextBox 是文本框排版器,对累积的 Text 元素应用排版。它根据自身的 position、size 和对齐设置重新排版所有字形位置,排版结果通过反向变换补偿写入每个 Text 元素的 GlyphRun 数据,因此 Text 自身的 position 和父级 Group 变换在渲染管线中仍然有效。首行使用行框模型定位:行框近端贴齐文本区域近端边缘,基线位于近端下方 halfLeading + ascent 处,其中 halfLeading = (lineHeight - metricsHeight) / 2,metricsHeight = ascent + descent + leading。遵循 CSS Writing Modes 的惯例,lineHeight 是逻辑属性,始终作用于行框的块轴方向尺寸。竖排模式下,它控制的是列宽而非行高。列间距为 lineHeight(中心到中心的距离)。当 lineHeight 为 0(自动)时,列宽根据字体 metrics 计算(ascent + descent + leading),与横排自动行高的算法一致。列从右往左排列。
TextBox 是仅参与预排版的节点:它在渲染前的排版阶段被处理,不会在渲染树中实例化。如果累积的所有 Text 元素都已包含嵌入的 GlyphRun 数据,则排版阶段会跳过 TextBox。但即使已填写嵌入的 GlyphRun 数据和字体,仍建议保留 TextBox 节点,因为设计工具导入时需要读取其排版属性(size、对齐方式、wordWrap 等)用于编辑展示。
与其他修改器不同(如 TrimPath 对累积结果进行链式操作),TextBox 只影响 Text 元素的初始排版。它在修改器链开始之前确定字形位置,后续的 TextPath、TextModifier 等修改器在 TextBox 的排版结果基础上工作。TextBox 在节点顺序中的位置不影响这一行为。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates TextBox: word wrap, text alignment, vertical writing, paragraph alignment -->
<pagx version="1.0" width="400" height="400">
<!-- Box 1 (top-left): horizontal justify + lineHeight -->
<Layer>
<Rectangle position="104,104" size="180,180" roundness="6"/>
<Stroke color="#CBD5E1" width="1" dashes="4,3"/>
</Layer>
<Layer>
<Group>
<Text text="Justify aligns words evenly 分布在 each full line." fontFamily="Arial" fontSize="18"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="180,0">
<ColorStop offset="0" color="#6366F1"/>
<ColorStop offset="1" color="#8B5CF6"/>
</LinearGradient>
</Fill>
</Group>
<TextBox position="14,14" size="180,180" lineHeight="28" textAlign="justify"/>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#6366F130"/>
</Layer>
<!-- Box 2 (top-right): horizontal textAlign center + paragraphAlign middle -->
<Layer>
<Rectangle position="296,104" size="180,180" roundness="6"/>
<Stroke color="#CBD5E1" width="1" dashes="4,3"/>
</Layer>
<Layer>
<Group>
<Text text="Centered Horizontally & Vertically" fontFamily="Arial" fontStyle="Bold" fontSize="18"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="180,100">
<ColorStop offset="0" color="#F43F5E"/>
<ColorStop offset="1" color="#EC4899"/>
</LinearGradient>
</Fill>
</Group>
<TextBox position="206,14" size="180,180" textAlign="center" paragraphAlign="middle"/>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#F43F5E30"/>
</Layer>
<!-- Box 3 (bottom-left): vertical writing -->
<Layer>
<Rectangle position="104,296" size="180,180" roundness="6"/>
<Stroke color="#CBD5E1" width="1" dashes="4,3"/>
</Layer>
<Layer>
<Group>
<Text text="春眠不觉 Dawn 处处闻啼鸟 Night 来风雨声花落知多少" fontFamily="Arial" fontStyle="Bold" fontSize="18"/>
<Fill>
<LinearGradient startPoint="180,0" endPoint="0,180">
<ColorStop offset="0" color="#F59E0B"/>
<ColorStop offset="1" color="#F43F5E"/>
</LinearGradient>
</Fill>
</Group>
<TextBox position="14,206" size="180,180" writingMode="vertical" textAlign="justify"/>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#F59E0B30"/>
</Layer>
<!-- Box 4 (bottom-right): vertical textAlign center + paragraphAlign middle -->
<Layer>
<Rectangle position="296,296" size="180,180" roundness="6"/>
<Stroke color="#CBD5E1" width="1" dashes="4,3"/>
</Layer>
<Layer>
<Group>
<Text text="竖排文本 居中对齐" fontFamily="Arial" fontStyle="Bold" fontSize="18"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="180,180">
<ColorStop offset="0" color="#06B6D4"/>
<ColorStop offset="1" color="#10B981"/>
</LinearGradient>
</Fill>
</Group>
<TextBox position="206,206" size="180,180" writingMode="vertical" textAlign="center" paragraphAlign="middle"/>
<DropShadowStyle offsetY="8" blurX="24" blurY="24" color="#06B6D430"/>
</Layer>
</pagx>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
position |
Point | 0,0 | 文本区域左上角坐标 |
size |
Size | 0,0 | 排版尺寸。当宽度或高度为 0 时,该维度上文本无边界,可能导致 wordWrap 或 overflow 无效果 |
textAlign |
TextAlign | start | 文本对齐——沿行内方向对齐文本(见下方) |
paragraphAlign |
ParagraphAlign | near | 段落对齐——沿块流方向对齐文本行/列(见下方) |
writingMode |
WritingMode | horizontal | 排版方向(见下方) |
lineHeight |
float | 0 | 行高(像素值)。0 表示自动(根据字体 metrics 计算:ascent + descent + leading)。遵循 CSS Writing Modes 的逻辑属性惯例,竖排模式下控制列宽 |
wordWrap |
bool | true | 是否启用自动换行,在盒子宽度边界(横排)或高度边界(竖排)处换行。当该维度的 size 为 0 时无效果 |
overflow |
Overflow | visible | 文本超出盒子高度(横排)或宽度(竖排)时的溢出行为。当该维度的 size 为 0 时无效果 |
TextAlign(文本对齐):
| 值 | 说明 |
|---|---|
start |
起始对齐 |
center |
居中对齐 |
end |
结束对齐 |
justify |
两端对齐(最后一行起始对齐) |
ParagraphAlign(段落对齐):
沿块流方向(block-flow direction)对齐文本行或列。使用方向中立的 Near/Far 而非 Top/Bottom,在横排和竖排模式下语义一致。横排模式下控制垂直定位,竖排模式下控制水平定位。
| 值 | 说明 |
|---|---|
near |
近端对齐(横排时为顶部,竖排时为右侧)。使用行框模型,首行行框近端贴齐文本区域近端边缘。基线位于近端下方 halfLeading + ascent 处,其中 halfLeading = (lineHeight - metricsHeight) / 2。 |
middle |
居中对齐。整体文本块尺寸(所有行高/列宽之和)在对应维度内居中。 |
far |
远端对齐(横排时为底部,竖排时为左侧)。末行行框远端对齐文本区域远端边缘。 |
WritingMode(排版方向):
| 值 | 说明 |
|---|---|
horizontal |
横排文本 |
vertical |
竖排文本(列从右到左排列,传统中日文竖排) |
Overflow(溢出行为):
| 值 | 说明 |
|---|---|
visible |
超出盒子边界的文本仍然渲染(默认) |
hidden |
超出盒子高度(横排)或宽度(竖排)的整行/整列被丢弃,不会显示被截断的半行/半列。当该维度的 size 为 0 时无效果 |
5.5.7 富文本
富文本通过 Group 内的多个 Text 元素组合,每个 Text 可以有独立的 Fill/Stroke 样式。使用 TextBox 进行统一排版。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates rich text with mixed styles -->
<pagx version="1.0" width="400" height="400">
<Layer>
<Text text="Rich Text" fontFamily="Arial" fontStyle="Bold" fontSize="42" position="200,105" textAnchor="center"/>
<Fill>
<LinearGradient startPoint="-200,0" endPoint="0,0">
<ColorStop offset="0" color="#8B5CF6"/>
<ColorStop offset="1" color="#EC4899"/>
</LinearGradient>
</Fill>
</Layer>
<!-- Rich text: multiple Groups with different styles in one TextBox -->
<Layer>
<Group>
<Text text="Supports " fontFamily="Arial" fontSize="20"/>
<Fill color="#475569"/>
</Group>
<Group>
<Text text="bold" fontFamily="Arial" fontStyle="Bold" fontSize="20"/>
<Fill color="#F43F5E"/>
</Group>
<Group>
<Text text=", " fontFamily="Arial" fontSize="20"/>
<Fill color="#475569"/>
</Group>
<Group>
<Text text="italic" fontFamily="Arial" fontStyle="Italic" fontSize="20"/>
<Fill color="#10B981"/>
</Group>
<Group>
<Text text=" and " fontFamily="Arial" fontSize="20"/>
<Fill color="#475569"/>
</Group>
<Group>
<Text text="colored" fontFamily="Arial" fontStyle="Bold" fontSize="20"/>
<Fill color="#06B6D4"/>
</Group>
<Group>
<Text text=" text. " fontFamily="Arial" fontSize="20"/>
<Fill color="#475569"/>
</Group>
<Group>
<Text text="Mix " fontFamily="Arial" fontSize="16"/>
<Fill color="#475569"/>
</Group>
<Group>
<Text text="different" fontFamily="Arial" fontStyle="Bold" fontSize="24"/>
<Fill color="#F59E0B"/>
</Group>
<Group>
<Text text=" sizes " fontFamily="Arial" fontSize="16"/>
<Fill color="#475569"/>
</Group>
<Group>
<Text text="freely" fontFamily="Arial" fontStyle="Bold Italic" fontSize="24"/>
<Fill color="#8B5CF6"/>
</Group>
<Group>
<Text text=" within one line. " fontFamily="Arial" fontSize="16"/>
<Fill color="#475569"/>
</Group>
<Group>
<Text text="Center " fontFamily="Arial" fontSize="20"/>
<Fill color="#475569"/>
</Group>
<Group>
<Text text="aligned" fontFamily="Arial" fontStyle="Bold" fontSize="20"/>
<Fill color="#EC4899"/>
</Group>
<Group>
<Text text=" rich text." fontFamily="Arial" fontSize="20"/>
<Fill color="#475569"/>
</Group>
<TextBox position="0,142" size="400,0" lineHeight="48" textAlign="center"/>
</Layer>
<Layer>
<Text text="Gradient Fill" fontFamily="Arial" fontStyle="Bold" fontSize="28" position="200,310" textAnchor="center"/>
<Fill>
<LinearGradient startPoint="-100,0" endPoint="100,0">
<ColorStop offset="0" color="#F43F5E"/>
<ColorStop offset="0.5" color="#F59E0B"/>
<ColorStop offset="1" color="#10B981"/>
</LinearGradient>
</Fill>
</Layer>
</pagx>
说明:每个 Group 内的 Text + Fill/Stroke 定义一段样式独立的文本片段,TextBox 将所有片段作为整体进行排版,实现自动换行和对齐。
5.6 复制器(Repeater)
复制累积的内容和已渲染的样式,对每个副本应用渐进变换。Repeater 对 Path 和字形列表同时生效,且不会触发文本转形状。
<Repeater copies="5" offset="1" order="belowOriginal" anchor="0,0" position="50,0" rotation="0" scale="1,1" startAlpha="1" endAlpha="0.2"/>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
copies |
float | 3 | 副本数 |
offset |
float | 0 | 起始偏移 |
order |
RepeaterOrder | belowOriginal | 堆叠顺序(见下方) |
anchor |
Point | 0,0 | 锚点 |
position |
Point | 100,100 | 每个副本的位置偏移 |
rotation |
float | 0 | 每个副本的旋转 |
scale |
Point | 1,1 | 每个副本的缩放 |
startAlpha |
float | 1 | 首个副本透明度 |
endAlpha |
float | 1 | 末个副本透明度 |
变换计算(第 i 个副本,i 从 0 开始):
progress = i + offset
变换按以下顺序应用:
- 平移到锚点的负方向(
translate(-anchor)) - 指数缩放(
scale(scale^progress)) - 线性旋转(
rotate(rotation × progress)) - 线性位移(
translate(position × progress)) - 平移回锚点(
translate(anchor))
透明度插值:
maxCount = ceil(copies)
t = progress / maxCount
alpha = lerp(startAlpha, endAlpha, t)
// 最后一个副本的 alpha 还需乘以 copies 的小数部分(见下文)
RepeaterOrder(堆叠顺序):
| 值 | 说明 |
|---|---|
belowOriginal |
副本在原件下方。索引 0 在最上 |
aboveOriginal |
副本在原件上方。索引 N-1 在最上 |
小数副本数:
当 copies 为小数时(如 3.5),采用叠加半透明的方式实现部分副本效果:
- 几何复制:形状和文本按
ceil(copies)个复制(即 4 个),几何本身不做缩放或裁剪 - 透明度调整:最后一个副本的透明度乘以小数部分(如 0.5),产生半透明效果
- 视觉效果:通过透明度渐变模拟"部分存在"的副本
示例:copies="2.3" 时
- 复制 3 个完整的几何副本
- 第 1、2 个副本正常渲染
- 第 3 个副本透明度 × 0.3,呈现半透明效果
边界情况:
copies < 0:不执行任何操作copies = 0:清空所有累积的内容和已渲染的样式
Repeater 特性:
- 同时作用:复制所有累积的 Path 和字形列表
- 保留文本属性:字形列表复制后仍保留字形信息,后续文本修改器仍可作用
- 复制已渲染样式:同时复制已渲染的填充和描边
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="400" height="400">
<Layer>
<Rectangle position="60,200" size="56,56" roundness="12"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="56,56">
<ColorStop offset="0" color="#6366F1"/>
<ColorStop offset="1" color="#8B5CF6"/>
</LinearGradient>
</Fill>
<Repeater copies="5" position="70,0" endAlpha="0.15"/>
</Layer>
</pagx>
5.7 容器(Group)
Group 是带变换属性的矢量元素容器。
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="400" height="400">
<Layer>
<Group anchor="110,110" position="200,200" rotation="12">
<Rectangle position="110,110" size="220,220" roundness="32"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="220,220">
<ColorStop offset="0" color="#F43F5E"/>
<ColorStop offset="0.5" color="#EC4899"/>
<ColorStop offset="1" color="#8B5CF6"/>
</LinearGradient>
</Fill>
</Group>
<DropShadowStyle offsetY="12" blurX="40" blurY="40" color="#EC489960"/>
</Layer>
</pagx>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
anchor |
Point | 0,0 | 锚点 "x,y" |
position |
Point | 0,0 | 位置 "x,y" |
rotation |
float | 0 | 旋转角度 |
scale |
Point | 1,1 | 缩放 "sx,sy" |
skew |
float | 0 | 倾斜量 |
skewAxis |
float | 0 | 倾斜轴角度 |
alpha |
float | 1 | 透明度 0~1 |
变换顺序
变换按以下顺序应用:
- 平移到锚点的负方向(
translate(-anchor)) - 缩放(
scale) - 倾斜(
skew沿skewAxis方向) - 旋转(
rotation) - 平移到位置(
translate(position))
倾斜变换:
倾斜变换按以下顺序应用:
- 旋转到倾斜轴方向(
rotate(skewAxis)) - 沿 X 轴剪切(
shearX(tan(skew))) - 旋转回原方向(
rotate(-skewAxis))
作用域隔离
Group 创建独立的作用域,用于隔离几何累积和渲染:
- 组内的几何元素只在组内累积
- 组内的绘制器只渲染组内累积的几何
- 组内的修改器只影响组内累积的几何
- 组的变换矩阵应用到组内所有内容
- 组的
alpha属性应用到组内所有渲染内容
几何累积规则:
- 绘制器不清空几何:Fill 和 Stroke 渲染后,几何列表保持不变,后续绘制器仍可渲染相同的几何
- 子 Group 几何向上累积:子 Group 处理完成后,其几何会累积到父作用域,父级末尾的绘制器可以渲染所有子 Group 的几何
- 同级 Group 互不影响:每个 Group 创建独立的累积起点,不会看到后续兄弟 Group 的几何
- 隔离渲染范围:Group 内的绘制器只能渲染到当前位置已累积的几何,包括本组和已完成的子 Group
- Layer 是累积终止点:几何向上累积直到遇到 Layer 边界,不会跨 Layer 传递
示例 1 - 基本隔离:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates Group isolation: alpha applied to group, not individual shapes -->
<pagx version="1.0" width="400" height="400">
<Layer>
<Group alpha="0.7">
<Rectangle position="140,200" size="200,200" roundness="24"/>
<Fill color="#F43F5E"/>
</Group>
<Ellipse position="260,200" size="200,200"/>
<Fill color="#06B6D4"/>
</Layer>
</pagx>
示例 2 - 子 Group 几何向上累积:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates style propagation: Fill outside Groups applies to all shapes -->
<pagx version="1.0" width="400" height="400">
<Layer>
<Group>
<Rectangle position="140,200" size="160,160" roundness="24"/>
<Fill color="#F43F5E"/>
</Group>
<Group>
<Ellipse position="260,200" size="160,160"/>
<Fill color="#06B6D4"/>
</Group>
<!-- Semi-transparent overlay applied to both shapes -->
<Fill color="#8B5CF630"/>
</Layer>
</pagx>
示例 3 - 多个绘制器复用几何:
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="400" height="400">
<Layer>
<Rectangle position="200,200" size="260,260" roundness="32"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="260,260">
<ColorStop offset="0" color="#F43F5E"/>
<ColorStop offset="1" color="#E11D48"/>
</LinearGradient>
</Fill>
<Stroke color="#BE123C" width="8"/>
<DropShadowStyle offsetY="12" blurX="40" blurY="40" color="#F43F5E60"/>
</Layer>
</pagx>
多重填充与描边
由于绘制器不清空几何列表,同一几何可连续应用多个 Fill 和 Stroke。
示例 4 - 多重填充:
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="400" height="400">
<Layer>
<Rectangle position="200,200" size="300,200" roundness="32"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="300,200">
<ColorStop offset="0" color="#F59E0B"/>
<ColorStop offset="1" color="#F43F5E"/>
</LinearGradient>
</Fill>
<Fill color="#8B5CF640"/>
<DropShadowStyle offsetY="12" blurX="40" blurY="40" color="#F43F5E50"/>
</Layer>
</pagx>
示例 5 - 多重描边:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Demonstrates multiple Stroke styles creating glow/outline effect -->
<pagx version="1.0" width="400" height="400">
<Layer>
<Path data="M 60,200 Q 200,60 340,200 Q 200,340 60,200"/>
<!-- Outer glow -->
<Stroke color="#8B5CF615" width="48" cap="round" join="round"/>
<!-- Middle glow -->
<Stroke color="#8B5CF640" width="28" cap="round" join="round"/>
<!-- Core stroke -->
<Stroke width="8" cap="round" join="round">
<LinearGradient startPoint="0,0" endPoint="280,0">
<ColorStop offset="0" color="#6366F1"/>
<ColorStop offset="0.5" color="#8B5CF6"/>
<ColorStop offset="1" color="#EC4899"/>
</LinearGradient>
</Stroke>
</Layer>
</pagx>
示例 6 - 混合叠加:
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="400" height="400">
<Layer>
<Ellipse position="200,200" size="280,280"/>
<Fill>
<!-- RadialGradient uses canvas coordinates. Ellipse center is at 200,200,
highlight offset should be relative to that. 140,140 creates top-left highlight -->
<RadialGradient center="140,140" radius="200">
<ColorStop offset="0" color="#FFF"/>
<ColorStop offset="0.4" color="#06B6D4"/>
<ColorStop offset="1" color="#0891B2"/>
</RadialGradient>
</Fill>
<Stroke color="#0E7490" width="8"/>
<DropShadowStyle offsetX="0" offsetY="8" blurX="32" blurY="32" color="#06B6D460"/>
</Layer>
</pagx>
渲染顺序:多个绘制器按文档顺序渲染,先出现的位于下方。
附录 A. 节点层级与包含关系(Node Hierarchy)
本附录描述节点的分类和嵌套规则。
A.1 节点分类
| 分类 | 节点 |
|---|---|
| 容器 | pagx, Resources, Layer, Group |
| 资源 | Image, PathData, Composition, Font, Glyph |
| 颜色源 | SolidColor, LinearGradient, RadialGradient, ConicGradient, DiamondGradient, ImagePattern, ColorStop |
| 图层样式 | DropShadowStyle, InnerShadowStyle, BackgroundBlurStyle |
| 图层滤镜 | BlurFilter, DropShadowFilter, InnerShadowFilter, BlendFilter, ColorMatrixFilter |
| 几何元素 | Rectangle, Ellipse, Polystar, Path, Text, GlyphRun |
| 修改器 | TrimPath, RoundCorner, MergePath, TextModifier, RangeSelector, TextPath, TextBox, Repeater |
| 绘制器 | Fill, Stroke |
A.2 文档包含关系
pagx
├── Resources
│ ├── Image
│ ├── PathData
│ ├── SolidColor
│ ├── LinearGradient → ColorStop*
│ ├── RadialGradient → ColorStop*
│ ├── ConicGradient → ColorStop*
│ ├── DiamondGradient → ColorStop*
│ ├── ImagePattern
│ ├── Font → Glyph*
│ └── Composition → Layer*
│
└── Layer*
├── VectorElement*(见 A.3)
├── DropShadowStyle*
├── InnerShadowStyle*
├── BackgroundBlurStyle*
├── BlurFilter*
├── DropShadowFilter*
├── InnerShadowFilter*
├── BlendFilter*
├── ColorMatrixFilter*
└── Layer*(子图层)
A.3 VectorElement 包含关系
Layer 和 Group 可包含以下 VectorElement:
Layer / Group
├── Rectangle
├── Ellipse
├── Polystar
├── Path
├── Text → GlyphRun*(预排版模式)
├── Fill(可内嵌颜色源)
│ └── SolidColor / LinearGradient / RadialGradient / ConicGradient / DiamondGradient / ImagePattern
├── Stroke(可内嵌颜色源)
│ └── SolidColor / LinearGradient / RadialGradient / ConicGradient / DiamondGradient / ImagePattern
├── TrimPath
├── RoundCorner
├── MergePath
├── TextModifier → RangeSelector*
├── TextPath
├── TextBox
├── Repeater
└── Group*(递归)
附录 B. 枚举类型(Enumeration Types)
图层相关
| 枚举 | 值 |
|---|---|
| BlendMode | normal, multiply, screen, overlay, darken, lighten, colorDodge, colorBurn, hardLight, softLight, difference, exclusion, hue, saturation, color, luminosity, plusLighter, plusDarker |
| MaskType | alpha, luminance, contour |
| TileMode | clamp, repeat, mirror, decal |
| FilterMode | nearest, linear |
| MipmapMode | none, nearest, linear |
绘制器相关
| 枚举 | 值 |
|---|---|
| FillRule | winding, evenOdd |
| LineCap | butt, round, square |
| LineJoin | miter, round, bevel |
| StrokeAlign | center, inside, outside |
| LayerPlacement | background, foreground |
几何元素相关
| 枚举 | 值 |
|---|---|
| PolystarType | polygon, star |
修改器相关
| 枚举 | 值 |
|---|---|
| TrimType | separate, continuous |
| MergePathMode | append, union, intersect, xor, difference |
| SelectorUnit | index, percentage |
| SelectorShape | square, rampUp, rampDown, triangle, round, smooth |
| SelectorMode | add, subtract, intersect, min, max, difference |
| TextAlign | start, center, end, justify |
| TextAnchor | start, center, end |
| ParagraphAlign | near, middle, far |
| WritingMode | horizontal, vertical |
| RepeaterOrder | belowOriginal, aboveOriginal |
| Overflow | visible, hidden |
附录 C. 常见用法示例(Examples)
C.1 完整示例
以下示例涵盖 PAGX 的所有主要节点类型,展示完整的文档结构。
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="800" height="520">
<Layer name="background">
<Rectangle position="400,260" size="800,520"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="800,520">
<ColorStop offset="0" color="#0F172A"/>
<ColorStop offset="1" color="#1E293B"/>
</LinearGradient>
</Fill>
</Layer>
<Layer name="GlowTopLeft" blendMode="screen">
<Ellipse position="80,60" size="320,320"/>
<Fill color="@glowPurple"/>
<BlurFilter blurX="30" blurY="30"/>
</Layer>
<Layer name="GlowBottomRight" blendMode="screen">
<Ellipse position="720,460" size="400,400"/>
<Fill color="@glowCyan"/>
<BlurFilter blurX="40" blurY="40"/>
</Layer>
<Layer name="Title">
<Text text="PAGX" position="400,55" fontFamily="Arial" fontStyle="Bold" fontSize="56" textAnchor="center"/>
<Fill color="@titleGradient"/>
</Layer>
<Layer name="Subtitle">
<Text text="Portable Animated Graphics XML" fontFamily="Arial" fontSize="14"/>
<TextPath path="M 220,135 Q 400,65 580,135" forceAlignment="true"/>
<Fill color="#64748B"/>
</Layer>
<Layer name="Card1" x="110" y="155">
<Layer composition="@cardBg"/>
<Layer x="50" y="40">
<Rectangle position="0,0" size="50,35" roundness="8"/>
<Fill color="@coral"/>
<DropShadowStyle offsetY="4" blurX="12" blurY="12" color="#F43F5E80"/>
</Layer>
</Layer>
<Layer name="Card2" x="230" y="155">
<Layer composition="@cardBg"/>
<Layer x="50" y="40">
<Ellipse position="0,0" size="50,35"/>
<Fill color="@purple"/>
<InnerShadowStyle offsetX="2" offsetY="2" blurX="6" blurY="6" color="#00000080"/>
</Layer>
</Layer>
<Layer name="Card3" x="350" y="155">
<Layer composition="@cardBg"/>
<Layer x="50" y="40">
<Polystar position="0,0" type="star" pointCount="5" outerRadius="24" innerRadius="11" rotation="-90"/>
<Fill color="@amber"/>
<DropShadowStyle offsetY="4" blurX="12" blurY="12" color="#F59E0B80"/>
</Layer>
</Layer>
<Layer name="Card4" x="470" y="155">
<Layer composition="@cardBg"/>
<Layer x="50" y="40">
<Polystar position="0,0" type="polygon" pointCount="6" outerRadius="26"/>
<Fill color="@diamond"/>
<DropShadowStyle offsetY="4" blurX="12" blurY="12" color="#14B8A680"/>
</Layer>
</Layer>
<Layer name="Card5" x="590" y="155">
<Layer composition="@cardBg"/>
<Layer x="50" y="40">
<Path data="M-20 -15L0 -25L20 -15L20 15L0 25L-20 15Z"/>
<Fill color="@orange"/>
<DropShadowStyle offsetY="4" blurX="12" blurY="12" color="#F9731680"/>
</Layer>
</Layer>
<Layer name="GetStartedButton" x="148" y="325">
<Layer>
<Rectangle position="0,0" size="120,36" roundness="18"/>
<Fill color="@buttonGradient"/>
<DropShadowStyle offsetY="4" blurX="12" blurY="12" color="#6366F180"/>
</Layer>
<Layer>
<Text text="Get Started" position="0,4" fontFamily="Arial" fontStyle="Bold" fontSize="13" textAnchor="center"/>
<Fill color="#FFF"/>
</Layer>
</Layer>
<Layer name="Modifiers" y="325">
<Group position="258,0">
<Path data="@wavePath"/>
<TrimPath end="0.75"/>
<Stroke color="@cyan" width="3" cap="round"/>
</Group>
<Group position="368,0">
<Rectangle position="0,0" size="60,40"/>
<RoundCorner radius="10"/>
<Fill color="@emerald"/>
</Group>
<Group position="478,0">
<Rectangle position="-10,0" size="35,35"/>
<Ellipse position="10,0" size="35,35"/>
<MergePath mode="xor"/>
<Fill color="@purple"/>
</Group>
<Group position="588,0">
<Ellipse position="22,0" size="12,12"/>
<Fill color="@cyan"/>
<Repeater copies="5" position="0,0" rotation="72"/>
</Group>
<Group position="688,0">
<Rectangle position="0,0" size="50,50"/>
<Fill color="@rainbow"/>
</Group>
</Layer>
<Layer id="circleMask" visible="false">
<Ellipse position="0,0" size="45,45"/>
<Fill color="#FFF"/>
</Layer>
<Layer name="MaskedLayer" x="688" y="325" mask="@circleMask">
<Rectangle position="0,0" size="50,50"/>
<Fill color="@rainbow"/>
</Layer>
<Layer x="130" y="430">
<Rectangle position="0,0" size="80,60" roundness="10"/>
<Fill color="@emerald"/>
<BlurFilter blurX="3" blurY="3"/>
</Layer>
<Layer x="260" y="430">
<Rectangle position="0,0" size="80,60" roundness="10"/>
<Fill color="@cyan"/>
<DropShadowFilter offsetX="4" offsetY="4" blurX="12" blurY="12" color="#00000080"/>
</Layer>
<Layer x="390" y="430">
<Ellipse position="0,0" size="55,55"/>
<Fill color="@purple"/>
<ColorMatrixFilter matrix="0.33,0.33,0.33,0,0,0.33,0.33,0.33,0,0,0.33,0.33,0.33,0,0,0,0,0,1,0"/>
</Layer>
<Layer x="520" y="430">
<Rectangle position="0,0" size="80,60" roundness="10"/>
<Fill color="@coral"/>
<BlendFilter color="#6366F160" blendMode="overlay"/>
</Layer>
<Layer x="670" y="430">
<Rectangle position="0,0" size="90,60" roundness="8"/>
<Fill>
<ImagePattern image="@photo" tileModeX="clamp" tileModeY="clamp" matrix="0.23,0,0,0.23,-30,-30"/>
</Fill>
<Stroke color="#FFFFFF20" width="1"/>
<DropShadowStyle offsetY="6" blurX="16" blurY="16" color="#00000060"/>
</Layer>
<Layer x="400" y="500">
<Text fontFamily="Arial" fontSize="18">
<GlyphRun font="@iconFont" glyphs="1,2,3" y="0" xOffsets="0,28,56"/>
</Text>
<Fill color="#64748B"/>
</Layer>
<Resources>
<Image id="photo" source="pag_logo.png"/>
<PathData id="wavePath" data="M 0 0 Q 30 -20 60 0 T 120 0 T 180 0"/>
<Font id="iconFont">
<Glyph path="M 0 -8 L 8 8 L -8 8 Z" advance="20"/>
<Glyph path="M -8 -8 L 8 -8 L 8 8 L -8 8 Z" advance="20"/>
<Glyph path="M 0 -10 A 10 10 0 1 1 0 10 A 10 10 0 1 1 0 -10" advance="24"/>
</Font>
<RadialGradient id="glowPurple" center="160,160" radius="160">
<ColorStop offset="0" color="#8B5CF660"/>
<ColorStop offset="1" color="#8B5CF600"/>
</RadialGradient>
<RadialGradient id="glowCyan" center="200,200" radius="200">
<ColorStop offset="0" color="#06B6D450"/>
<ColorStop offset="1" color="#06B6D400"/>
</RadialGradient>
<LinearGradient id="titleGradient" startPoint="-400,0" endPoint="-200,0">
<ColorStop offset="0" color="#FFF"/>
<ColorStop offset="0.5" color="#8B5CF6"/>
<ColorStop offset="1" color="#06B6D4"/>
</LinearGradient>
<LinearGradient id="buttonGradient" startPoint="0,0" endPoint="120,0">
<ColorStop offset="0" color="#6366F1"/>
<ColorStop offset="1" color="#8B5CF6"/>
</LinearGradient>
<ConicGradient id="rainbow" center="25,25">
<ColorStop offset="0" color="#F43F5E"/>
<ColorStop offset="0.25" color="#8B5CF6"/>
<ColorStop offset="0.5" color="#06B6D4"/>
<ColorStop offset="0.75" color="#10B981"/>
<ColorStop offset="1" color="#F43F5E"/>
</ConicGradient>
<SolidColor id="coral" color="#F43F5E"/>
<SolidColor id="purple" color="#8B5CF6"/>
<SolidColor id="amber" color="#F59E0B"/>
<SolidColor id="orange" color="#F97316"/>
<SolidColor id="cyan" color="#06B6D4"/>
<SolidColor id="emerald" color="#10B981"/>
<DiamondGradient id="diamond" center="26,26" radius="26">
<ColorStop offset="0" color="#14B8A6"/>
<ColorStop offset="1" color="#0F766E"/>
</DiamondGradient>
<Composition id="cardBg" width="100" height="80">
<Layer>
<Rectangle position="50,40" size="100,80" roundness="12"/>
<Fill color="#1E293B"/>
<Stroke color="#334155" width="1"/>
</Layer>
</Composition>
</Resources>
</pagx>
C.2 应用图标
毛玻璃风格的图标网格 — 12 个多色图标位于深色背景上,配合柔和色场和背景模糊卡片。展示了基于 Path 的矢量图标构建、Composition 复用、BackgroundBlurStyle 和 DropShadowStyle。
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="640" height="520">
<!-- Background: Gray 900 -->
<Layer name="Background" x="320" y="260">
<Rectangle size="640,520"/>
<Fill color="#111827"/>
</Layer>
<!-- Background: soft color fields -->
<Layer name="BgPattern">
<Layer x="60" y="60">
<Ellipse size="320,320"/>
<Fill color="#8B5CF6" alpha="0.2"/>
<BlurFilter blurX="50" blurY="50"/>
</Layer>
<Layer x="560" y="80">
<Ellipse size="280,280"/>
<Fill color="#06B6D4" alpha="0.18"/>
<BlurFilter blurX="50" blurY="50"/>
</Layer>
<Layer x="600" y="380">
<Ellipse size="260,260"/>
<Fill color="#3B82F6" alpha="0.16"/>
<BlurFilter blurX="50" blurY="50"/>
</Layer>
<Layer x="80" y="480">
<Ellipse size="300,300"/>
<Fill color="#EC4899" alpha="0.18"/>
<BlurFilter blurX="50" blurY="50"/>
</Layer>
<Layer x="320" y="260">
<Ellipse size="200,200"/>
<Fill color="#10B981" alpha="0.1"/>
<BlurFilter blurX="40" blurY="40"/>
</Layer>
</Layer>
<!-- ==================== App Icons ==================== -->
<!-- Row 1 -->
<Layer name="Home" x="44" y="38">
<Layer composition="@card"/>
<Layer x="36" y="36">
<Path data="M0 -18L-19 1L-14 1L-14 18L-5 18L-5 7L5 7L5 18L14 18L14 1L19 1Z"/>
<Fill color="#F97316"/>
</Layer>
<Layer x="36" y="94">
<Text text="Home" fontFamily="Arial" fontSize="11" textAnchor="center"/>
<Fill color="#6B7280"/>
</Layer>
</Layer>
<Layer name="Search" x="204" y="38">
<Layer composition="@card"/>
<Layer x="36" y="36">
<Group>
<Ellipse position="-4,-4" size="26,26"/>
<Stroke color="#3B82F6" width="3.5"/>
</Group>
<Group>
<Path data="M6 6L16 16"/>
<Stroke color="#3B82F6" width="4" cap="round"/>
</Group>
</Layer>
<Layer x="36" y="94">
<Text text="Search" fontFamily="Arial" fontSize="11" textAnchor="center"/>
<Fill color="#6B7280"/>
</Layer>
</Layer>
<Layer name="Bell" x="364" y="38">
<Layer composition="@card"/>
<Layer x="36" y="36">
<Group>
<Path data="M-14 10C-14 0 -10 -12 0 -14C10 -12 14 0 14 10L17 14L-17 14Z"/>
<Fill color="#FBBF24"/>
</Group>
<Group>
<Path data="M0 -18L0 -12"/>
<Stroke color="#FBBF24" width="2.5" cap="round"/>
</Group>
<Group>
<Ellipse position="0,16" size="8,5"/>
<Fill color="#FBBF24"/>
</Group>
</Layer>
<Layer x="36" y="94">
<Text text="Bell" fontFamily="Arial" fontSize="11" textAnchor="center"/>
<Fill color="#6B7280"/>
</Layer>
</Layer>
<Layer name="Heart" x="524" y="38">
<Layer composition="@card"/>
<Layer x="36" y="36">
<Path data="M0 -7C-3 -17 -19 -20 -19 -7C-19 4 -7 12 0 19C7 12 19 4 19 -7C19 -20 3 -17 0 -7Z"/>
<Fill color="#EF4444"/>
</Layer>
<Layer x="36" y="94">
<Text text="Heart" fontFamily="Arial" fontSize="11" textAnchor="center"/>
<Fill color="#6B7280"/>
</Layer>
</Layer>
<!-- Row 2 -->
<Layer name="Chat" x="44" y="208">
<Layer composition="@card"/>
<Layer x="36" y="36">
<Group>
<Path data="M-18 -10C-18 -15 -15 -17 -10 -17L10 -17C15 -17 18 -15 18 -10L18 5C18 10 15 12 10 12L2 12L-10 17L-4 12L-10 12C-15 12 -18 10 -18 5Z"/>
<Fill color="#10B981"/>
</Group>
<Group>
<Ellipse position="-7,-3" size="4,4"/>
<Ellipse position="0,-3" size="4,4"/>
<Ellipse position="7,-3" size="4,4"/>
<Fill color="#1E2433"/>
</Group>
</Layer>
<Layer x="36" y="94">
<Text text="Chat" fontFamily="Arial" fontSize="11" textAnchor="center"/>
<Fill color="#6B7280"/>
</Layer>
</Layer>
<Layer name="Camera" x="204" y="208">
<Layer composition="@card"/>
<Layer x="36" y="36">
<Group>
<Rectangle position="0,2" size="38,26" roundness="5"/>
<Path data="M-7 -9L-4 -16L4 -16L7 -9"/>
<Fill color="#6366F1"/>
</Group>
<Group>
<Ellipse position="0,2" size="17,17"/>
<Fill color="#1E2433"/>
</Group>
<Group>
<Ellipse position="0,2" size="10,10"/>
<Stroke color="#6366F1" width="2.5"/>
</Group>
</Layer>
<Layer x="36" y="94">
<Text text="Camera" fontFamily="Arial" fontSize="11" textAnchor="center"/>
<Fill color="#6B7280"/>
</Layer>
</Layer>
<Layer name="Settings" x="364" y="208">
<Layer composition="@card"/>
<Layer x="36" y="36">
<Group>
<Path data="M-2.8 -19.8L2.8 -19.8L3.5 -13.6L7.1 -12.1L12 -16L16 -12L12.1 -7.1L13.6 -3.5L19.8 -2.8L19.8 2.8L13.6 3.5L12.1 7.1L16 12L12 16L7.1 12.1L3.5 13.6L2.8 19.8L-2.8 19.8L-3.5 13.6L-7.1 12.1L-12 16L-16 12L-12.1 7.1L-13.6 3.5L-19.8 2.8L-19.8 -2.8L-13.6 -3.5L-12.1 -7.1L-16 -12L-12 -16L-7.1 -12.1L-3.5 -13.6Z"/>
<Fill color="#8B5CF6"/>
</Group>
<Group>
<Ellipse size="14,14"/>
<Fill color="#1E2433"/>
</Group>
<Group>
<Ellipse size="5,5"/>
<Fill color="#8B5CF6"/>
</Group>
</Layer>
<Layer x="36" y="94">
<Text text="Settings" fontFamily="Arial" fontSize="11" textAnchor="center"/>
<Fill color="#6B7280"/>
</Layer>
</Layer>
<Layer name="User" x="524" y="208">
<Layer composition="@card"/>
<Layer x="36" y="36">
<Group>
<Ellipse size="46,46"/>
<Fill color="#06B6D4"/>
</Group>
<Group>
<Ellipse position="0,-11" size="12,12"/>
<Fill color="#1E2433"/>
</Group>
<Group>
<Path data="M-11 16C-11 4 -7 -2 0 -2C7 -2 11 4 11 16"/>
<Fill color="#1E2433"/>
</Group>
</Layer>
<Layer x="36" y="94">
<Text text="User" fontFamily="Arial" fontSize="11" textAnchor="center"/>
<Fill color="#6B7280"/>
</Layer>
</Layer>
<!-- Row 3 -->
<Layer name="Calendar" x="44" y="376">
<Layer composition="@card"/>
<Layer x="36" y="36">
<Group>
<Rectangle position="0,2" size="38,38" roundness="6"/>
<Rectangle position="-9,-16" size="3,9" roundness="2"/>
<Rectangle position="9,-16" size="3,9" roundness="2"/>
<Fill color="#EF4444"/>
</Group>
<Group>
<Rectangle position="0,6" size="30,22" roundness="3"/>
<Fill color="#1E2433"/>
</Group>
<Group>
<Text text="17" position="0,12" fontFamily="Arial" fontStyle="Bold" fontSize="16" textAnchor="center"/>
<Fill color="#EF4444"/>
</Group>
</Layer>
<Layer x="36" y="94">
<Text text="Calendar" fontFamily="Arial" fontSize="11" textAnchor="center"/>
<Fill color="#6B7280"/>
</Layer>
</Layer>
<Layer name="Lock" x="204" y="376">
<Layer composition="@card"/>
<Layer x="36" y="36">
<Group>
<Path data="M-10 -4L-10 -11C-10 -20 10 -20 10 -11L10 -4"/>
<Stroke color="#F97316" width="4" cap="round"/>
</Group>
<Group>
<Rectangle position="0,8" size="30,22" roundness="6"/>
<Fill color="#F97316"/>
</Group>
<Group>
<Ellipse position="0,6" size="7,7"/>
<Rectangle position="0,12" size="3,6" roundness="1"/>
<Fill color="#1E2433"/>
</Group>
</Layer>
<Layer x="36" y="94">
<Text text="Lock" fontFamily="Arial" fontSize="11" textAnchor="center"/>
<Fill color="#6B7280"/>
</Layer>
</Layer>
<Layer name="Music" x="364" y="376">
<Layer composition="@card"/>
<Layer x="36" y="36">
<Group>
<Path data="M-11 10L-11 -13L9 -18L9 5M-11 -8L9 -13"/>
<Stroke color="#EC4899" width="3.5" cap="round" join="round"/>
</Group>
<Group>
<Ellipse position="-10,14" size="15,11"/>
<Ellipse position="10,9" size="15,11"/>
<Fill color="#EC4899"/>
</Group>
</Layer>
<Layer x="36" y="94">
<Text text="Music" fontFamily="Arial" fontSize="11" textAnchor="center"/>
<Fill color="#6B7280"/>
</Layer>
</Layer>
<Layer name="Download" x="524" y="376">
<Layer composition="@card"/>
<Layer x="36" y="36">
<Group>
<Ellipse position="-1,-7" size="24,22"/>
<Ellipse position="-12,-1" size="16,16"/>
<Ellipse position="10,-1" size="18,16"/>
<Ellipse position="-1,1" size="34,10"/>
<Fill color="#3B82F6"/>
</Group>
<Group>
<Path data="M-1 7L-1 14M-4 12L-1 16L2 12"/>
<Stroke color="#3B82F6" width="3" cap="round" join="round"/>
</Group>
</Layer>
<Layer x="36" y="94">
<Text text="Download" fontFamily="Arial" fontSize="11" textAnchor="center"/>
<Fill color="#6B7280"/>
</Layer>
</Layer>
<!-- ==================== Resources ==================== -->
<Resources>
<Composition id="card" width="72" height="72">
<Layer x="36" y="36">
<Rectangle size="72,72" roundness="12"/>
<Fill color="#FFFFFF" alpha="0.06"/>
<Stroke color="#FFFFFF" width="0.5" alpha="0.25"/>
<BackgroundBlurStyle blurX="20" blurY="20"/>
<DropShadowStyle offsetY="4" blurX="20" blurY="20" color="#00000040"/>
</Layer>
</Composition>
</Resources>
</pagx>
C.3 星云学员
全屏 UI 面板,包含顶部导航栏、头像、进度条、操作按钮、货币组件和底部 Tab 栏。展示了典型应用界面的布局方式和组件组合。
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="800" height="600">
<Layer name="Background">
<Rectangle position="400,300" size="800,600"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="0,600">
<ColorStop offset="0" color="#0B1026"/>
<ColorStop offset="0.6" color="#0F1C3D"/>
<ColorStop offset="1" color="#1B1140"/>
</LinearGradient>
</Fill>
</Layer>
<Layer name="NebulaLeft">
<Ellipse position="160,220" size="360,300"/>
<Fill>
<RadialGradient center="160,220" radius="220">
<ColorStop offset="0" color="#1D4ED880"/>
<ColorStop offset="1" color="#1D4ED800"/>
</RadialGradient>
</Fill>
</Layer>
<Layer name="NebulaRight">
<Ellipse position="640,180" size="360,280"/>
<Fill>
<RadialGradient center="640,180" radius="220">
<ColorStop offset="0" color="#C026D380"/>
<ColorStop offset="1" color="#C026D300"/>
</RadialGradient>
</Fill>
</Layer>
<Layer name="NebulaBottom" alpha="0.9">
<Ellipse position="400,505" size="600,220"/>
<Fill>
<RadialGradient center="400,505" radius="260">
<ColorStop offset="0" color="#22D3EE60"/>
<ColorStop offset="1" color="#22D3EE00"/>
</RadialGradient>
</Fill>
</Layer>
<Layer name="Stars" alpha="0.9">
<Group>
<Ellipse position="120,80" size="2,2"/>
<Ellipse position="180,110" size="3,3"/>
<Ellipse position="260,90" size="2,2"/>
<Ellipse position="340,70" size="2,2"/>
<Ellipse position="420,110" size="3,3"/>
<Ellipse position="520,80" size="2,2"/>
<Ellipse position="610,120" size="2,2"/>
<Ellipse position="700,90" size="2,2"/>
<Ellipse position="740,150" size="3,3"/>
<Ellipse position="90,160" size="2,2"/>
<Fill color="#FFFFFFCC"/>
</Group>
<Group>
<Ellipse position="150,200" size="2,2"/>
<Ellipse position="240,170" size="2,2"/>
<Ellipse position="360,190" size="2,2"/>
<Ellipse position="470,160" size="3,3"/>
<Ellipse position="560,210" size="2,2"/>
<Ellipse position="660,180" size="2,2"/>
<Ellipse position="740,230" size="2,2"/>
<Ellipse position="210,240" size="2,2"/>
<Ellipse position="540,240" size="2,2"/>
<Fill color="#7DD3FC88"/>
</Group>
</Layer>
<Layer name="StarBursts">
<Layer>
<Polystar position="220,130" type="star" pointCount="4" outerRadius="8" innerRadius="3" rotation="45"/>
<Fill color="#FFFFFFEE"/>
<DropShadowStyle blurX="6" blurY="6" color="#7DD3FC80"/>
</Layer>
<Layer>
<Polystar position="620,210" type="star" pointCount="4" outerRadius="7" innerRadius="3" rotation="45"/>
<Fill color="#FFFFFFDD"/>
<DropShadowStyle blurX="6" blurY="6" color="#C084FC80"/>
</Layer>
<Layer>
<Polystar position="700,420" type="star" pointCount="4" outerRadius="6" innerRadius="2" rotation="45"/>
<Fill color="#FFFFFFCC"/>
<DropShadowStyle blurX="5" blurY="5" color="#22D3EE80"/>
</Layer>
</Layer>
<Layer name="HudRings" alpha="0.7" x="400" y="310">
<Group>
<Ellipse size="480,480"/>
<Stroke color="#1E3A8A" width="2" dashes="10,12"/>
</Group>
<Group>
<Ellipse size="420,420"/>
<TrimPath start="0.1" end="0.4" offset="40"/>
<Stroke width="4" cap="round">
<ConicGradient>
<ColorStop offset="0" color="#38BDF8"/>
<ColorStop offset="0.5" color="#22D3EE"/>
<ColorStop offset="1" color="#7C3AED"/>
</ConicGradient>
</Stroke>
</Group>
<Group>
<Ellipse size="360,360"/>
<TrimPath start="0.55" end="0.85" offset="-30"/>
<Stroke color="#38BDF8" width="3" alpha="0.8" cap="round"/>
</Group>
</Layer>
<Layer name="MainPanel">
<Rectangle position="400,310" size="680,360" roundness="28"/>
<Fill>
<LinearGradient startPoint="60,310" endPoint="740,310">
<ColorStop offset="0" color="#0F1C3DCC"/>
<ColorStop offset="0.5" color="#12244ACC"/>
<ColorStop offset="1" color="#0C1B33CC"/>
</LinearGradient>
</Fill>
<Stroke width="1.5">
<LinearGradient startPoint="60,310" endPoint="740,310">
<ColorStop offset="0" color="#3B82F6AA"/>
<ColorStop offset="0.5" color="#22D3EE88"/>
<ColorStop offset="1" color="#A78BFAAA"/>
</LinearGradient>
</Stroke>
<BackgroundBlurStyle blurX="24" blurY="24" tileMode="mirror"/>
<DropShadowStyle offsetY="12" blurX="20" blurY="20" color="#00000066"/>
</Layer>
<Layer name="TopBar">
<Rectangle position="400,65" size="760,90" roundness="22"/>
<Fill>
<LinearGradient startPoint="20,65" endPoint="780,65">
<ColorStop offset="0" color="#0C1B33EE"/>
<ColorStop offset="1" color="#10284CEE"/>
</LinearGradient>
</Fill>
<Stroke width="1">
<LinearGradient startPoint="20,65" endPoint="780,65">
<ColorStop offset="0" color="#1D4ED8AA"/>
<ColorStop offset="1" color="#38BDF8AA"/>
</LinearGradient>
</Stroke>
<DropShadowStyle offsetY="8" blurX="16" blurY="16" color="#00000055"/>
</Layer>
<Layer name="Avatar">
<Group>
<Polystar position="70,65" type="polygon" pointCount="6" outerRadius="36" rotation="30"/>
<Stroke width="2">
<LinearGradient startPoint="34,29" endPoint="106,101">
<ColorStop offset="0" color="#38BDF8"/>
<ColorStop offset="1" color="#A78BFA"/>
</LinearGradient>
</Stroke>
</Group>
<Group>
<Ellipse position="70,65" size="56,56"/>
<Fill color="#0B1225"/>
</Group>
<Group>
<Ellipse position="70,65" size="48,48"/>
<Fill>
<RadialGradient center="70,65" radius="30">
<ColorStop offset="0" color="#38BDF8AA"/>
<ColorStop offset="1" color="#0B122500"/>
</RadialGradient>
</Fill>
</Group>
<DropShadowStyle blurX="10" blurY="10" color="#1D4ED880"/>
</Layer>
<Layer name="PlayerName">
<Text text="NEBULA CADET" position="120,45" fontFamily="Arial" fontStyle="Bold" fontSize="16"/>
<Fill color="#E2E8F0"/>
</Layer>
<Layer name="PlayerIdRow">
<Group>
<Text text="#A17X9" position="120,63" fontFamily="Arial" fontSize="11"/>
<Fill color="#7DD3FC"/>
</Group>
<Layer name="LevelBadge">
<Rectangle position="195,60" size="48,14" roundness="7"/>
<Fill>
<LinearGradient startPoint="171,60" endPoint="219,60">
<ColorStop offset="0" color="#0EA5E9"/>
<ColorStop offset="1" color="#22D3EE"/>
</LinearGradient>
</Fill>
<Stroke color="#7DD3FC" width="1"/>
<Group>
<Text text="LV 27" position="195,64" fontFamily="Arial" fontStyle="Bold" fontSize="9" textAnchor="center"/>
<Fill color="#E0F2FE"/>
</Group>
</Layer>
</Layer>
<Layer name="ExpBar">
<Group>
<Rectangle position="260,79" size="280,10" roundness="5"/>
<Fill color="#1E293B"/>
</Group>
<Group>
<Rectangle position="215,79" size="190,6" roundness="3"/>
<Fill>
<LinearGradient startPoint="120,79" endPoint="310,79">
<ColorStop offset="0" color="#22D3EE"/>
<ColorStop offset="1" color="#3B82F6"/>
</LinearGradient>
</Fill>
</Group>
</Layer>
<Layer name="EnergyBar">
<Group>
<Rectangle position="260,95" size="280,10" roundness="5"/>
<Fill color="#172437"/>
</Group>
<Group>
<Rectangle position="200,95" size="160,6" roundness="3"/>
<Fill>
<LinearGradient startPoint="120,95" endPoint="280,95">
<ColorStop offset="0" color="#34D399"/>
<ColorStop offset="1" color="#10B981"/>
</LinearGradient>
</Fill>
</Group>
</Layer>
<Layer name="CoinChip">
<Rectangle position="691,48" size="150,28" roundness="14"/>
<Fill>
<LinearGradient startPoint="616,48" endPoint="766,48">
<ColorStop offset="0" color="#0F1A33CC"/>
<ColorStop offset="1" color="#14244ACC"/>
</LinearGradient>
</Fill>
<Stroke color="#334155" width="1"/>
<Group>
<Ellipse position="636,48" size="16,16"/>
<Fill>
<LinearGradient startPoint="628,48" endPoint="644,48">
<ColorStop offset="0" color="#FFE29A"/>
<ColorStop offset="1" color="#F59E0B"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Ellipse position="636,48" size="8,8"/>
<Stroke color="#F8D477" width="1"/>
</Group>
<Group>
<Text text="12,450" position="656,52" fontFamily="Arial" fontStyle="Bold" fontSize="13"/>
<Fill color="#F8FAFC"/>
</Group>
</Layer>
<Layer name="DiamondChip">
<Rectangle position="691,82" size="150,28" roundness="14"/>
<Fill>
<LinearGradient startPoint="616,82" endPoint="766,82">
<ColorStop offset="0" color="#0F1A33CC"/>
<ColorStop offset="1" color="#14244ACC"/>
</LinearGradient>
</Fill>
<Stroke color="#334155" width="1"/>
<Group position="628,74">
<Path data="@IconDiamond"/>
<Fill>
<LinearGradient startPoint="0,8" endPoint="16,8">
<ColorStop offset="0" color="#7DD3FC"/>
<ColorStop offset="1" color="#A78BFA"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Text text="860" position="656,86" fontFamily="Arial" fontStyle="Bold" fontSize="13"/>
<Fill color="#F8FAFC"/>
</Group>
</Layer>
<Layer name="StartButton">
<Rectangle position="400,218" size="340,78" roundness="28"/>
<Fill>
<LinearGradient startPoint="230,218" endPoint="570,218">
<ColorStop offset="0" color="#00FFC6"/>
<ColorStop offset="0.5" color="#00C2FF"/>
<ColorStop offset="1" color="#00FFA6"/>
</LinearGradient>
</Fill>
<Stroke color="#5AFADF" width="2"/>
<Group>
<Rectangle position="400,208" size="310,34" roundness="18"/>
<Fill color="#FFFFFF22"/>
</Group>
<Group position="280,206">
<Path data="@IconPlay"/>
<Fill color="#ECFEFF"/>
</Group>
<Layer>
<Text text="START" position="400,227" fontFamily="Arial" fontStyle="Bold" fontSize="24" textAnchor="center"/>
<Fill color="#F0FFFD"/>
<DropShadowStyle offsetY="2" blurX="6" blurY="6" color="#0F172A80"/>
</Layer>
<DropShadowStyle offsetY="12" blurX="18" blurY="18" color="#00FFC066"/>
</Layer>
<Layer name="ShopButton">
<Rectangle position="400,310" size="340,78" roundness="28"/>
<Fill>
<LinearGradient startPoint="230,310" endPoint="570,310">
<ColorStop offset="0" color="#FFD166"/>
<ColorStop offset="1" color="#FF8C42"/>
</LinearGradient>
</Fill>
<Stroke color="#FFD166" width="1.5"/>
<Group position="280,298">
<Path data="@IconCart"/>
<Fill color="#FFF7ED"/>
</Group>
<Group>
<Text text="SHOP" position="400,319" fontFamily="Arial" fontStyle="Bold" fontSize="22" textAnchor="center"/>
<Fill color="#FFF7ED"/>
</Group>
<DropShadowStyle offsetY="10" blurX="16" blurY="16" color="#F59E0B66"/>
</Layer>
<Layer name="RankButton">
<Rectangle position="400,402" size="340,78" roundness="28"/>
<Fill>
<LinearGradient startPoint="230,402" endPoint="570,402">
<ColorStop offset="0" color="#7C3AED"/>
<ColorStop offset="1" color="#EC4899"/>
</LinearGradient>
</Fill>
<Stroke color="#C084FC" width="1.5"/>
<Group position="280,390">
<Path data="@IconCrown"/>
<Fill color="#FDF2F8"/>
</Group>
<Group>
<Text text="RANK" position="400,411" fontFamily="Arial" fontStyle="Bold" fontSize="22" textAnchor="center"/>
<Fill color="#FDF2F8"/>
</Group>
<DropShadowStyle offsetY="10" blurX="16" blurY="16" color="#C084FC66"/>
</Layer>
<Layer name="BottomBar">
<Rectangle position="400,545" size="760,70" roundness="20"/>
<Fill>
<LinearGradient startPoint="20,545" endPoint="780,545">
<ColorStop offset="0" color="#0B1A33CC"/>
<ColorStop offset="1" color="#10284ECC"/>
</LinearGradient>
</Fill>
<Stroke color="#1D4ED8AA" width="1"/>
</Layer>
<Layer name="BottomButtonSettings">
<Layer x="217" y="522" composition="@navButton"/>
<Layer x="228" y="533">
<Group>
<Polystar position="12,12" type="star" pointCount="8" outerRadius="10" innerRadius="6"/>
<Stroke color="#93C5FD" width="2"/>
</Group>
<Group>
<Ellipse position="12,12" size="6,6"/>
<Fill color="#93C5FD"/>
</Group>
</Layer>
</Layer>
<Layer name="BottomButtonHelp">
<Layer x="377" y="522" composition="@navButton"/>
<Layer x="388" y="533">
<Path data="@IconQuestion"/>
<Fill color="#93C5FD"/>
</Layer>
</Layer>
<Layer name="BottomButtonShare">
<Layer x="537" y="522" composition="@navButton"/>
<Layer x="548" y="533">
<Path data="@IconShare"/>
<Fill color="#93C5FD"/>
</Layer>
</Layer>
<Layer name="TechLines" alpha="0.6">
<Group>
<Path data="M 80 130 L 160 130 L 200 170"/>
<Stroke color="#38BDF8" width="1"/>
</Group>
<Group>
<Path data="M 720 130 L 640 130 L 600 170"/>
<Stroke color="#A78BFA" width="1"/>
</Group>
<Group>
<Path data="M 90 460 L 170 460 L 210 420"/>
<Stroke color="#22D3EE" width="1"/>
</Group>
<Group>
<Path data="M 710 460 L 630 460 L 590 420"/>
<Stroke color="#C084FC" width="1"/>
</Group>
</Layer>
<Layer name="HexDecor" alpha="0.6">
<Group>
<Polystar position="120,200" type="polygon" pointCount="6" outerRadius="14" rotation="30"/>
<Stroke color="#1D4ED8" width="1"/>
</Group>
<Group>
<Polystar position="680,240" type="polygon" pointCount="6" outerRadius="12" rotation="30"/>
<Stroke color="#38BDF8" width="1"/>
</Group>
<Group>
<Polystar position="180,420" type="polygon" pointCount="6" outerRadius="10" rotation="30"/>
<Stroke color="#22D3EE" width="1"/>
</Group>
<Group>
<Polystar position="640,420" type="polygon" pointCount="6" outerRadius="12" rotation="30"/>
<Stroke color="#A78BFA" width="1"/>
</Group>
</Layer>
<Resources>
<PathData id="IconPlay" data="M 0 0 L 24 12 L 0 24 Z"/>
<PathData id="IconCart" data="M 5 6 L 20 6 L 18 14 L 7 14 Z M 9 18 A 2 2 0 1 0 9 22 A 2 2 0 1 0 9 18 Z M 16 18 A 2 2 0 1 0 16 22 A 2 2 0 1 0 16 18 Z"/>
<PathData id="IconCrown" data="M 2 16 L 6 6 L 12 12 L 18 6 L 22 16 Z M 4 16 L 4 20 L 20 20 L 20 16 Z"/>
<PathData id="IconDiamond" data="M 8 0 L 16 4 L 16 12 L 8 16 L 0 12 L 0 4 Z"/>
<PathData id="IconQuestion" data="M 12 4 C 8 4 6 6 6 9 L 9 9 C 9 7.5 10 6.5 12 6.5 C 14 6.5 15 7.5 15 9 C 15 10.5 13.5 11 12 12 C 10.5 13 10 14 10 16 L 14 16 C 14 14.5 14.5 13.5 16 12.5 C 18 11.5 19 10 19 8 C 19 5 16 4 12 4 Z M 12 18 A 2 2 0 1 0 12 22 A 2 2 0 1 0 12 18 Z"/>
<PathData id="IconShare" data="M 14 4 L 22 12 L 14 20 L 14 15 L 4 15 L 4 9 L 14 9 Z"/>
<Composition id="navButton" width="46" height="46">
<Layer>
<Ellipse position="23,23" size="46,46"/>
<Fill>
<LinearGradient startPoint="0,23" endPoint="46,23">
<ColorStop offset="0" color="#0D2038CC"/>
<ColorStop offset="1" color="#162B4DCC"/>
</LinearGradient>
</Fill>
<Stroke color="#3B82F6" width="1"/>
</Layer>
</Composition>
</Resources>
</pagx>
C.4 游戏 HUD
科幻风格的游戏平视显示器,包含瞄准十字线、弧形生命值和能量仪表、雷达小地图、弹药计数器和任务目标栏。展示了 Repeater 驱动的刻度线、弧形 Stroke 上的 TrimPath、ConicGradient 扫描效果和多层 Mask 叠加。
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="800" height="600">
<Layer id="triangleMask" visible="false">
<Polystar type="polygon" pointCount="3" outerRadius="80" rotation="90"/>
<Fill color="#FFF"/>
</Layer>
<Layer name="Background">
<Layer>
<Rectangle position="400,300" size="800,600"/>
<Fill>
<RadialGradient center="400,300" radius="500">
<ColorStop offset="0" color="#001122"/>
<ColorStop offset="0.7" color="#000811"/>
<ColorStop offset="1" color="#000"/>
</RadialGradient>
</Fill>
</Layer>
<Layer alpha="0.15">
<Rectangle position="400,0" size="800,1"/>
<Repeater copies="35" position="0,17"/>
<Group position="400,300" rotation="60">
<Rectangle position="0,-510" size="1200,1"/>
<Repeater copies="60" position="0,17"/>
</Group>
<Group position="400,300" rotation="-60">
<Rectangle position="0,-510" size="1200,1"/>
<Repeater copies="60" position="0,17"/>
</Group>
<Fill color="#0066AA"/>
</Layer>
<Layer>
<Rectangle position="400,300" size="800,600"/>
<Fill>
<RadialGradient center="400,300" radius="600">
<ColorStop offset="0.6" color="#00000000"/>
<ColorStop offset="1" color="#00000080"/>
</RadialGradient>
</Fill>
</Layer>
</Layer>
<Layer name="ReticleComplex" x="400" y="300">
<Layer>
<Rectangle position="0,-220" size="2,15"/>
<Fill color="#00CCFF" alpha="0.6"/>
<Repeater copies="60" rotation="6"/>
</Layer>
<Layer>
<Rectangle position="0,-215" size="1,8"/>
<Fill color="#00CCFF" alpha="0.3"/>
<Repeater copies="60" offset="0.5" rotation="6"/>
</Layer>
<Layer rotation="15">
<Ellipse size="380,380"/>
<Stroke color="#0FF" width="1" alpha="0.4" dashes="60,40"/>
</Layer>
<Layer rotation="-20">
<Ellipse size="360,360"/>
<Stroke color="#0088FF" width="2" alpha="0.5" dashes="10,80"/>
</Layer>
<Layer>
<Ellipse size="300,300"/>
<Stroke color="#00CCFF" width="3"/>
<DropShadowStyle blurX="8" blurY="8" color="#00CCFF80"/>
</Layer>
<Layer>
<Polystar type="polygon" pointCount="3" outerRadius="80" rotation="90"/>
<Stroke color="#FFAA00" width="4"/>
<Fill>
<RadialGradient radius="80">
<ColorStop offset="0" color="#FFAA0040"/>
<ColorStop offset="1" color="#FFAA0010"/>
</RadialGradient>
</Fill>
<DropShadowStyle blurX="25" blurY="25" color="#FFAA00"/>
</Layer>
<Layer mask="@triangleMask">
<Rectangle position="0,0" size="100,100"/>
<Fill>
<LinearGradient startPoint="-50,0" endPoint="50,0">
<ColorStop offset="0" color="#FFAA0000"/>
<ColorStop offset="0.5" color="#FFAA0040"/>
<ColorStop offset="1" color="#FFAA0000"/>
</LinearGradient>
</Fill>
</Layer>
<Layer>
<Ellipse size="6,6"/>
<Fill color="#FFF"/>
<Path data="M -20 0 L 20 0 M 0 -20 L 0 20"/>
<Stroke color="#FFF" width="1" alpha="0.5"/>
</Layer>
</Layer>
<Layer name="LeftSide" x="400" y="300">
<Layer>
<Path data="@healthArc"/>
<Stroke color="#002233" width="24" cap="butt"/>
</Layer>
<Layer>
<Path data="@healthArc"/>
<Stroke width="20" cap="butt" dashes="4,2">
<LinearGradient startPoint="-180,100" endPoint="-180,-100">
<ColorStop offset="0" color="#F00"/>
<ColorStop offset="0.5" color="#FF0"/>
<ColorStop offset="1" color="#0F0"/>
</LinearGradient>
</Stroke>
<TrimPath end="0.85"/>
<DropShadowStyle blurX="5" blurY="5" color="#FF000040"/>
</Layer>
<Layer name="HealthText">
<Layer>
<Text text="100%" position="-240,10" fontFamily="Arial" fontStyle="Bold" fontSize="24" textAnchor="end"/>
<Fill color="#FFF"/>
</Layer>
<Layer>
<Text text="STRUCTURAL INTEGRITY" position="-240,25" fontFamily="Arial" fontSize="10" textAnchor="end"/>
<Fill color="#0088FF"/>
</Layer>
</Layer>
</Layer>
<Layer name="SystemStats" x="50" y="60">
<Group>
<Text text="PWR: 88%" fontFamily="Arial" fontSize="12"/>
<Fill color="#00CCFF" alpha="0.7"/>
</Group>
<Group position="0,18">
<Text text="RADAR: ACT" fontFamily="Arial" fontSize="12"/>
<Fill color="#00CCFF" alpha="0.7"/>
</Group>
<Group position="0,36">
<Text text="SHIELD: OK" fontFamily="Arial" fontSize="12"/>
<Fill color="#00CCFF" alpha="0.7"/>
</Group>
</Layer>
<Layer name="RightSide" x="400" y="300">
<Layer>
<Path data="@energyArc"/>
<Stroke color="#002233" width="24" cap="butt"/>
</Layer>
<Layer>
<Path data="@energyArc"/>
<Stroke width="20" cap="butt" dashes="10,2">
<LinearGradient startPoint="180,-100" endPoint="180,100">
<ColorStop offset="0" color="#0FF"/>
<ColorStop offset="1" color="#0044FF"/>
</LinearGradient>
</Stroke>
<TrimPath end="0.6"/>
<DropShadowStyle blurX="5" blurY="5" color="#00FFFF40"/>
</Layer>
<Layer name="EnergyText">
<Layer>
<Text text="60%" position="240,10" fontFamily="Arial" fontStyle="Bold" fontSize="24"/>
<Fill color="#FFF"/>
</Layer>
<Layer>
<Text text="PLASMA RESERVES" position="240,25" fontFamily="Arial" fontSize="10"/>
<Fill color="#0088FF"/>
</Layer>
</Layer>
</Layer>
<Layer name="Bottom" x="400" y="520">
<Layer>
<Path data="M -200 0 L -180 -40 L 180 -40 L 200 0 L 180 20 L -180 20 Z"/>
<Fill color="#001122" alpha="0.95"/>
<Stroke color="#0066AA" width="2"/>
<DropShadowStyle blurX="15" blurY="15" color="#000"/>
</Layer>
<Layer name="WeaponInfo">
<Layer>
<Text text="MK-IV RAILGUN" position="0,-15" fontFamily="Arial" fontStyle="Bold" fontSize="20" textAnchor="center"/>
<Fill color="#FFF"/>
</Layer>
<Layer>
<Text text="[ BURST MODE ]" position="0,5" fontFamily="Arial" fontSize="12" textAnchor="center"/>
<Fill color="#FFAA00"/>
</Layer>
</Layer>
<Layer y="30">
<Group>
<Rectangle position="0,0" size="40,4"/>
<Fill color="#004488"/>
</Group>
<Group>
<Rectangle position="-30,0" size="10,4"/>
<Rectangle position="30,0" size="10,4"/>
<Fill color="#002244"/>
</Group>
</Layer>
</Layer>
<Layer name="Radar" x="100" y="500">
<Group>
<Ellipse size="140,140"/>
<Fill color="#001122" alpha="0.9"/>
<Stroke color="#0066AA" width="2"/>
</Group>
<Group>
<Ellipse size="100,100"/>
<Ellipse size="50,50"/>
<Path data="M -70 0 L 70 0 M 0 -70 L 0 70"/>
<Stroke color="#004488" width="1"/>
</Group>
<Layer rotation="-45">
<Ellipse size="130,130"/>
<Fill>
<ConicGradient endAngle="90">
<ColorStop offset="0" color="#00FF0000"/>
<ColorStop offset="1" color="#00FF0080"/>
</ConicGradient>
</Fill>
</Layer>
<Layer>
<Ellipse position="30,-20" size="6,6"/>
<Ellipse position="-40,10" size="6,6"/>
<Fill color="#F00"/>
<DropShadowStyle blurX="4" blurY="4" color="#F00"/>
</Layer>
<Layer>
<Ellipse size="4,4"/>
<Fill color="#FFF"/>
</Layer>
</Layer>
<Layer name="Objectives" x="400" y="50">
<Text text="MISSION OBJECTIVES: [ ] INFILTRATE BASE [ ] HACK TERMINAL [x] SECURE PERIMETER" fontFamily="Arial" fontStyle="Bold" fontSize="12" textAnchor="center"/>
<Fill color="#FFF"/>
<DropShadowStyle blurX="2" blurY="2" color="#000"/>
</Layer>
<Layer name="StatusIcons" x="706" y="70">
<Rectangle size="8,8"/>
<Stroke color="#FFAA00" width="1"/>
<Repeater copies="3" position="15,0"/>
<DropShadowStyle blurX="5" blurY="5" color="#FFAA00"/>
</Layer>
<Layer name="AmmoDisplay" x="630" y="496">
<Layer>
<Path data="@bullet"/>
<Fill color="#FFAA00"/>
<Stroke color="#000" width="1"/>
<Repeater copies="10" position="10,0"/>
</Layer>
<Layer y="15">
<Layer>
<Path data="@bullet"/>
<Fill color="#FFAA00"/>
<Stroke color="#000" width="1"/>
<Repeater copies="5" position="10,0"/>
</Layer>
<Layer>
<Path data="@bullet"/>
<Fill color="#331100"/>
<Stroke color="#442200" width="1"/>
<Repeater copies="5" offset="5" position="10,0"/>
</Layer>
</Layer>
</Layer>
<Layer name="Corners">
<Path data="M 40 100 L 40 40 L 100 40 M 760 100 L 760 40 L 700 40 M 40 500 L 40 560 L 100 560 M 760 500 L 760 560 L 700 560"/>
<Stroke color="#00CCFF" width="4"/>
</Layer>
<Resources>
<PathData id="bullet" data="M 0 0 L 4 0 L 6 4 L 4 12 L 0 12 L -2 4 Z"/>
<PathData id="healthArc" data="M -180 100 A 200 200 0 0 0 -180 -100"/>
<PathData id="energyArc" data="M 180 -100 A 200 200 0 0 0 180 100"/>
</Resources>
</pagx>
C.5 PAGX 特性概览
信息图/演示幻灯片风格的 PAGX 能力介绍 — 中心标题搭配轨道环、五张特性卡片通过虚线连接、底部转换流程条。展示了 TextBox 多行排版、卡片式信息架构和装饰性连接线图形。
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="1600" height="1200">
<Layer name="Background">
<Rectangle position="800,600" size="1600,1200"/>
<Fill color="@bgGradient"/>
</Layer>
<Layer name="GlowB" alpha="0.22">
<Ellipse position="1560,300" size="700,550"/>
<Fill color="#38BDF8"/>
<BlurFilter blurX="220" blurY="200"/>
</Layer>
<Layer name="GlowC" alpha="0.18">
<Ellipse position="350,1050" size="500,350"/>
<Fill color="#10B981"/>
<BlurFilter blurX="180" blurY="130"/>
</Layer>
<Layer name="OrbitRing" alpha="0.18" x="800" y="530">
<Ellipse size="760,760"/>
<Stroke color="#334155" width="1"/>
</Layer>
<Layer name="Grid" alpha="0.05">
<Group position="60,60">
<Path data="M -4 0 L 4 0 M 0 -4 L 0 4"/>
<Stroke color="#475569" width="1" cap="round"/>
<Repeater copies="13" position="120,0"/>
</Group>
<Repeater copies="10" position="0,120"/>
</Layer>
<Layer name="Core" x="800" y="530">
<Layer alpha="0.2">
<Ellipse size="320,320"/>
<Fill color="#3B82F6"/>
<BlurFilter blurX="80" blurY="80"/>
</Layer>
<Layer>
<Ellipse size="260,260"/>
<Stroke color="#475569" width="2"/>
</Layer>
<Layer alpha="0.7">
<Ellipse size="310,310"/>
<TrimPath end="0.77"/>
<Stroke width="2.5" cap="round">
<ConicGradient>
<ColorStop offset="0" color="#06B6D400"/>
<ColorStop offset="0.77" color="#06B6D4"/>
<ColorStop offset="1" color="#06B6D400"/>
</ConicGradient>
</Stroke>
</Layer>
<Layer alpha="0.4">
<Path data="M 0 -155 L 0 -163 M 155 0 L 163 0 M 0 155 L 0 163 M -155 0 L -163 0"/>
<Stroke color="#94A3B8" width="1.5" cap="round"/>
</Layer>
<Layer x="0" y="-10">
<Text text="PAGX" position="0,10" fontFamily="Arial" fontStyle="Bold" fontSize="52" textAnchor="center"/>
<Fill color="#FFF"/>
<DropShadowStyle offsetY="4" blurX="20" blurY="20" color="#06B6D440"/>
</Layer>
<Group position="0,42">
<Text text="Portable Animated Graphics XML" fontFamily="Arial" fontSize="14" textAnchor="center"/>
<Fill color="#94A3B8"/>
</Group>
<Group>
<Text text="An XML-based markup language for describing animated vector graphics." fontFamily="Arial" fontSize="12"/>
<TextPath path="M -141 0 A 141 141 0 0 0 141 0" forceAlignment="true"/>
<Fill color="#64748B60"/>
</Group>
</Layer>
<Layer name="ConnectorDots" alpha="0.7">
<Ellipse position="800,375" size="6,6"/>
<Ellipse position="954,511" size="6,6"/>
<Ellipse position="903,646" size="6,6"/>
<Ellipse position="697,646" size="6,6"/>
<Ellipse position="646,511" size="6,6"/>
<Fill color="#06B6D4"/>
</Layer>
<Layer name="Connectors" alpha="0.35">
<Path data="M 800 375 L 800 240 M 954 511 L 1119 466 M 903 646 L 989 790 M 697 646 L 611 790 M 646 511 L 481 466"/>
<Stroke color="@accentLine" width="2" dashes="8,14"/>
</Layer>
<Layer name="CardReadable" x="800" y="160">
<Rectangle position="0,0" size="400,160" roundness="20"/>
<Fill color="#1E293B80"/>
<Stroke color="#33415580" width="1"/>
<DropShadowStyle offsetY="4" blurX="24" blurY="24" color="#00000060"/>
<Layer alpha="0.08">
<Path data="M -180 -80 L 180 -80"/>
<Stroke width="1">
<LinearGradient startPoint="-180,-80" endPoint="180,-80">
<ColorStop offset="0" color="#F43F5E00"/>
<ColorStop offset="0.5" color="#F43F5E"/>
<ColorStop offset="1" color="#F43F5E00"/>
</LinearGradient>
</Stroke>
</Layer>
<Layer x="-120" y="0">
<Group>
<Path data="M -22 -32 L 6 -32 L 22 -16 L 22 36 L -22 36 Z"/>
<Stroke color="#F43F5E" width="2" join="round"/>
<Fill color="#F43F5E10"/>
</Group>
<Group>
<Path data="M 6 -32 L 6 -16 L 22 -16"/>
<Stroke color="#F43F5E" width="1.5" join="round"/>
</Group>
<Group>
<Path data="M -10 -4 L -16 4 L -10 12 M 10 -4 L 16 4 L 10 12"/>
<Stroke color="#F43F5E" width="2" cap="round" join="round"/>
</Group>
<Group>
<Path data="M 3 -8 L -3 16"/>
<Stroke color="#F43F5E" width="1.5" cap="round"/>
</Group>
</Layer>
<Layer x="-50" y="-20">
<Text text="Readable" fontFamily="Arial" fontStyle="Bold" fontSize="24"/>
<Fill color="#F43F5E"/>
</Layer>
<Layer x="-50" y="-7">
<Group>
<Text text="Plain-text XML, easy to diff, debug, and AI-generate." fontFamily="Arial" fontSize="16"/>
<Fill color="#CBD5E1"/>
</Group>
<TextBox size="220,0" lineHeight="22"/>
</Layer>
</Layer>
<Layer name="CardComprehensive" x="1319" y="466">
<Rectangle position="0,0" size="400,160" roundness="20"/>
<Fill color="#1E293B80"/>
<Stroke color="#33415580" width="1"/>
<DropShadowStyle offsetY="4" blurX="24" blurY="24" color="#00000060"/>
<Layer alpha="0.08">
<Path data="M -180 -80 L 180 -80"/>
<Stroke width="1">
<LinearGradient startPoint="-180,-80" endPoint="180,-80">
<ColorStop offset="0" color="#38BDF800"/>
<ColorStop offset="0.5" color="#38BDF8"/>
<ColorStop offset="1" color="#38BDF800"/>
</LinearGradient>
</Stroke>
</Layer>
<Layer x="-120" y="-2">
<Group>
<Rectangle position="-5,-18" size="52,32" roundness="6"/>
<Stroke color="#38BDF8" width="2"/>
<Fill color="#38BDF820"/>
</Group>
<Group>
<Rectangle position="5,2" size="52,32" roundness="6"/>
<Stroke color="#38BDF8" width="2"/>
<Fill color="#38BDF815"/>
</Group>
<Group>
<Rectangle position="15,22" size="52,32" roundness="6"/>
<Stroke color="#38BDF8" width="2"/>
<Fill color="#38BDF810"/>
</Group>
</Layer>
<Layer x="-50" y="-20">
<Text text="Comprehensive" fontFamily="Arial" fontStyle="Bold" fontSize="24"/>
<Fill color="#38BDF8"/>
</Layer>
<Layer x="-50" y="-7">
<Group>
<Text text="Covers vectors, images, text, effects, and masks." fontFamily="Arial" fontSize="16"/>
<Fill color="#CBD5E1"/>
</Group>
<TextBox size="220,0" lineHeight="22"/>
</Layer>
</Layer>
<Layer name="CardExpressive" x="281" y="466">
<Rectangle position="0,0" size="400,160" roundness="20"/>
<Fill color="#1E293B80"/>
<Stroke color="#33415580" width="1"/>
<DropShadowStyle offsetY="4" blurX="24" blurY="24" color="#00000060"/>
<Layer alpha="0.08">
<Path data="M -180 -80 L 180 -80"/>
<Stroke width="1">
<LinearGradient startPoint="-180,-80" endPoint="180,-80">
<ColorStop offset="0" color="#A855F700"/>
<ColorStop offset="0.5" color="#A855F7"/>
<ColorStop offset="1" color="#A855F700"/>
</LinearGradient>
</Stroke>
</Layer>
<Layer x="-110" y="-2">
<Group>
<Rectangle position="-22,0" size="32,72" roundness="5"/>
<Stroke color="#A855F7" width="2"/>
<Fill color="#A855F720"/>
</Group>
<Group>
<Path data="M -34 -16 L -10 -16 M -34 0 L -16 0 M -34 16 L -10 16"/>
<Stroke color="#A855F7" width="1.5" cap="round"/>
</Group>
<Group>
<Path data="M 2 0 L 12 0 M 8 -5 L 12 0 L 8 5"/>
<Stroke color="#A855F7" width="2" cap="round" join="round"/>
</Group>
<Group>
<Ellipse position="22,-28" size="18,18"/>
<Stroke color="#A855F7" width="1.5"/>
</Group>
<Group>
<Path data="M 15 0 L 22 -7 L 29 0 L 22 7 Z"/>
<Fill color="#A855F7"/>
</Group>
<Group>
<Path data="M 22 18 L 15 36 L 29 36 Z"/>
<Stroke color="#A855F7" width="1.5" join="round"/>
<Fill color="#A855F715"/>
</Group>
</Layer>
<Layer x="-50" y="-20">
<Text text="Expressive" fontFamily="Arial" fontStyle="Bold" fontSize="24"/>
<Fill color="#A855F7"/>
</Layer>
<Layer x="-50" y="-7">
<Group>
<Text text="Compact structure for both static and animated content." fontFamily="Arial" fontSize="16"/>
<Fill color="#CBD5E1"/>
</Group>
<TextBox size="220,0" lineHeight="22"/>
</Layer>
</Layer>
<Layer name="CardInteroperable" x="499" y="870">
<Rectangle position="0,0" size="400,160" roundness="20"/>
<Fill color="#1E293B80"/>
<Stroke color="#33415580" width="1"/>
<DropShadowStyle offsetY="4" blurX="24" blurY="24" color="#00000060"/>
<Layer alpha="0.08">
<Path data="M -180 -80 L 180 -80"/>
<Stroke width="1">
<LinearGradient startPoint="-180,-80" endPoint="180,-80">
<ColorStop offset="0" color="#10B98100"/>
<ColorStop offset="0.5" color="#10B981"/>
<ColorStop offset="1" color="#10B98100"/>
</LinearGradient>
</Stroke>
</Layer>
<Layer x="-110" y="0">
<Group>
<Ellipse position="-18,0" size="40,40"/>
<Ellipse position="18,0" size="40,40"/>
<Stroke color="#10B981" width="2"/>
</Group>
<Group>
<Path data="M -2 0 L 2 0"/>
<Stroke color="#10B981" width="2" cap="round"/>
</Group>
<Group>
<Path data="M -35 -25 L -48 -38 M 35 25 L 48 38"/>
<Stroke color="#10B981" width="1" dashes="3,3"/>
</Group>
</Layer>
<Layer x="-50" y="-20">
<Text text="Interoperable" fontFamily="Arial" fontStyle="Bold" fontSize="24"/>
<Fill color="#10B981"/>
</Layer>
<Layer x="-50" y="-7">
<Group>
<Text text="Bridges AE, Figma, SVG, PDF, and more seamlessly." fontFamily="Arial" fontSize="16"/>
<Fill color="#CBD5E1"/>
</Group>
<TextBox size="220,0" lineHeight="22"/>
</Layer>
</Layer>
<Layer name="CardDeployable" x="1101" y="870">
<Rectangle position="0,0" size="400,160" roundness="20"/>
<Fill color="#1E293B80"/>
<Stroke color="#33415580" width="1"/>
<DropShadowStyle offsetY="4" blurX="24" blurY="24" color="#00000060"/>
<Layer alpha="0.08">
<Path data="M -180 -80 L 180 -80"/>
<Stroke width="1">
<LinearGradient startPoint="-180,-80" endPoint="180,-80">
<ColorStop offset="0" color="#FBBF2400"/>
<ColorStop offset="0.5" color="#FBBF24"/>
<ColorStop offset="1" color="#FBBF2400"/>
</LinearGradient>
</Stroke>
</Layer>
<Layer x="-120" y="-2">
<Group>
<Path data="M 0 -40 C 10 -35 18 -20 18 0 L 18 22 L -18 22 L -18 0 C -18 -20 -10 -35 0 -40 Z"/>
<Stroke color="#FBBF24" width="2" join="round"/>
<Fill color="#FBBF2420"/>
</Group>
<Group>
<Path data="M -18 12 L -30 30 L -18 25 Z M 18 12 L 30 30 L 18 25 Z"/>
<Stroke color="#FBBF24" width="2" join="round"/>
<Fill color="#FBBF2415"/>
</Group>
<Group>
<Ellipse position="0,-10" size="12,12"/>
<Stroke color="#FBBF24" width="2"/>
</Group>
<Group>
<Path data="M -10 22 L -5 38 L 0 30 L 5 38 L 10 22"/>
<Stroke color="#FB923C" width="2" cap="round" join="round"/>
</Group>
</Layer>
<Layer x="-50" y="-20">
<Text text="Deployable" fontFamily="Arial" fontStyle="Bold" fontSize="24"/>
<Fill color="#FBBF24"/>
</Layer>
<Layer x="-50" y="-7">
<Group>
<Text text="One-click export to binary PAG with high performance." fontFamily="Arial" fontSize="16"/>
<Fill color="#CBD5E1"/>
</Group>
<TextBox size="220,0" lineHeight="22"/>
</Layer>
</Layer>
<Layer name="Pipeline" x="800" y="1070">
<Group alpha="0.18">
<Path data="M -400 -40 L 400 -40"/>
<Stroke width="1">
<LinearGradient startPoint="-400,0" endPoint="400,0">
<ColorStop offset="0" color="#6366F100"/>
<ColorStop offset="0.2" color="#6366F1"/>
<ColorStop offset="0.5" color="#8B5CF6"/>
<ColorStop offset="0.8" color="#EC4899"/>
<ColorStop offset="1" color="#EC489900"/>
</LinearGradient>
</Stroke>
</Group>
<Group position="-180,0">
<Rectangle position="0,0" size="120,40" roundness="20"/>
<Fill color="#6366F120"/>
<Stroke color="#6366F160" width="1"/>
<Group position="0,5">
<Text text=".pagx" fontFamily="Arial" fontStyle="Bold" fontSize="16" textAnchor="center"/>
<Fill color="#A78BFA"/>
</Group>
</Group>
<Group position="-80,0">
<Path data="@arrowRight"/>
<Stroke color="#64748B" width="2" cap="round" join="round"/>
</Group>
<Group>
<Rectangle position="0,0" size="100,40" roundness="20"/>
<Fill color="#EC489920"/>
<Stroke color="#EC489960" width="1"/>
<Group position="0,5">
<Text text=".pag" fontFamily="Arial" fontStyle="Bold" fontSize="16" textAnchor="center"/>
<Fill color="#F472B6"/>
</Group>
</Group>
<Group position="90,0">
<Path data="@arrowRight"/>
<Stroke color="#64748B" width="2" cap="round" join="round"/>
</Group>
<Group position="190,0">
<Rectangle position="0,0" size="140,40" roundness="20"/>
<Fill color="#34D39920"/>
<Stroke color="#34D39960" width="1"/>
<Group position="0,5">
<Text text="Production" fontFamily="Arial" fontStyle="Bold" fontSize="16" textAnchor="center"/>
<Fill color="#34D399"/>
</Group>
</Group>
</Layer>
<Layer name="BottomTagline" x="800" y="1130">
<Text text="Design - Develop - Deploy" fontFamily="Arial" fontSize="16" textAnchor="center"/>
<Fill color="#64748B"/>
</Layer>
<Layer name="Corners" alpha="0.2">
<Group>
<Path data="M 50 110 L 50 50 L 110 50 M 1490 50 L 1550 50 L 1550 110 M 50 1090 L 50 1150 L 110 1150 M 1490 1150 L 1550 1150 L 1550 1090"/>
<Stroke color="#64748B" width="1" cap="round" join="round"/>
</Group>
<Group>
<Ellipse position="50,50" size="4,4"/>
<Ellipse position="1550,50" size="4,4"/>
<Ellipse position="50,1150" size="4,4"/>
<Ellipse position="1550,1150" size="4,4"/>
<Fill color="#64748B"/>
</Group>
</Layer>
<Resources>
<LinearGradient id="bgGradient" startPoint="0,0" endPoint="0,1200">
<ColorStop offset="0" color="#0F172A"/>
<ColorStop offset="0.4" color="#0B1228"/>
<ColorStop offset="1" color="#0F172A"/>
</LinearGradient>
<LinearGradient id="accentLine" startPoint="-120,0" endPoint="120,0">
<ColorStop offset="0" color="#06B6D4"/>
<ColorStop offset="1" color="#3B82F6"/>
</LinearGradient>
<PathData id="arrowRight" data="M -15 0 L 10 0 M 4 -6 L 12 0 L 4 6"/>
</Resources>
</pagx>
C.6 太空探索者
一幅外星球探险插画,包含宇航员、奇异植物、外星生物和大气效果。展示了复杂场景合成、分层背景、手绘风格 Path 图形、通过超长 Path 数据程序化生成的草地纹理以及丰富的渐变光效。
<?xml version="1.0" encoding="UTF-8"?>
<pagx version="1.0" width="1200" height="800">
<Layer id="sky" x="600" y="400">
<Rectangle size="1200,800"/>
<Fill>
<LinearGradient startPoint="0,-400" endPoint="0,400">
<ColorStop offset="0" color="#020810"/>
<ColorStop offset="0.15" color="#06122E"/>
<ColorStop offset="0.35" color="#0E1450"/>
<ColorStop offset="0.5" color="#1A1060"/>
<ColorStop offset="0.65" color="#2D1B69"/>
<ColorStop offset="0.8" color="#4A1942"/>
<ColorStop offset="0.92" color="#6B2040"/>
<ColorStop offset="1" color="#7A2545"/>
</LinearGradient>
</Fill>
</Layer>
<Layer alpha="0.22" blendMode="screen" x="600" y="250">
<Ellipse size="1200,200"/>
<Fill>
<RadialGradient radius="600">
<ColorStop offset="0" color="#C4B5FD55"/>
<ColorStop offset="0.3" color="#A78BFA30"/>
<ColorStop offset="0.6" color="#7C3AED18"/>
<ColorStop offset="1" color="#7C3AED00"/>
</RadialGradient>
</Fill>
<BlurFilter blurX="50" blurY="25"/>
</Layer>
<Layer alpha="0.5" blendMode="screen" x="150" y="200">
<Ellipse size="550,450"/>
<Fill>
<RadialGradient radius="275">
<ColorStop offset="0" color="#7C3AED90"/>
<ColorStop offset="0.4" color="#7C3AED45"/>
<ColorStop offset="0.7" color="#7C3AED18"/>
<ColorStop offset="1" color="#7C3AED00"/>
</RadialGradient>
</Fill>
<BlurFilter blurX="45" blurY="45"/>
</Layer>
<Layer alpha="0.45" blendMode="screen" x="1000" y="120">
<Ellipse size="480,360"/>
<Fill>
<RadialGradient radius="240">
<ColorStop offset="0" color="#06B6D470"/>
<ColorStop offset="0.4" color="#06B6D430"/>
<ColorStop offset="0.7" color="#06B6D415"/>
<ColorStop offset="1" color="#06B6D400"/>
</RadialGradient>
</Fill>
<BlurFilter blurX="40" blurY="40"/>
</Layer>
<Layer alpha="0.28" blendMode="screen" x="550" y="90">
<Ellipse size="400,220"/>
<Fill>
<RadialGradient radius="200">
<ColorStop offset="0" color="#EC489955"/>
<ColorStop offset="0.5" color="#EC489922"/>
<ColorStop offset="1" color="#EC489900"/>
</RadialGradient>
</Fill>
<BlurFilter blurX="30" blurY="30"/>
</Layer>
<Layer x="80" y="55" composition="@comp1"/>
<Layer x="150" y="125" composition="@comp4"/>
<Layer x="260" y="42" composition="@comp5"/>
<Layer x="340" y="175" composition="@comp1"/>
<Layer x="420" y="68" composition="@comp6"/>
<Layer x="530" y="22">
<Ellipse size="4,4"/>
<Fill color="#FFFFFF"/>
</Layer>
<Layer x="610" y="150" composition="@comp4"/>
<Layer x="700" y="48" composition="@comp1"/>
<Layer x="780" y="108" composition="@comp5"/>
<Layer x="850" y="32" composition="@comp1"/>
<Layer x="940" y="88" composition="@comp6"/>
<Layer x="1020" y="58" composition="@comp1"/>
<Layer x="1100" y="138" composition="@comp4"/>
<Layer x="180" y="275" composition="@comp5"/>
<Layer x="480" y="235" composition="@comp7"/>
<Layer x="750" y="255" composition="@comp2"/>
<Layer x="1050" y="218" composition="@comp7"/>
<Layer x="320" y="315" composition="@comp4"/>
<Layer x="60" y="345" composition="@comp1"/>
<Layer x="45" y="160" composition="@comp5"/>
<Layer x="200" y="380" composition="@comp6"/>
<Layer x="370" y="260" composition="@comp1"/>
<Layer x="560" y="310" composition="@comp4"/>
<Layer x="650" y="200" composition="@comp5"/>
<Layer x="900" y="195" composition="@comp6"/>
<Layer x="1150" y="80" composition="@comp7"/>
<Layer x="440" y="150" composition="@comp4"/>
<Layer x="1080" y="350" composition="@comp5"/>
<Layer x="30" y="450" composition="@comp7"/>
<Layer x="680" y="350" composition="@comp2"/>
<Layer alpha="0.9" x="300" y="95">
<Group>
<Ellipse size="6,6"/>
<Fill color="#FFFFFF"/>
</Group>
<Group>
<Ellipse size="22,22"/>
<Fill>
<RadialGradient radius="11">
<ColorStop offset="0" color="#FFFFFF60"/>
<ColorStop offset="1" color="#FFFFFF00"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Path data="M-14 0L14 0M0 -14L0 14"/>
<Stroke color="#FFFFFF50"/>
</Group>
</Layer>
<Layer alpha="0.85" x="820" y="65">
<Group>
<Ellipse size="5,5"/>
<Fill color="#FFFFFF"/>
</Group>
<Group>
<Ellipse size="18,18"/>
<Fill>
<RadialGradient radius="9">
<ColorStop offset="0" color="#FFFFFF50"/>
<ColorStop offset="1" color="#FFFFFF00"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Path data="M-10 0L10 0M0 -10L0 10"/>
<Stroke color="#FFFFFF40"/>
</Group>
</Layer>
<Layer alpha="0.8" x="1100" y="295">
<Group>
<Ellipse size="5,5"/>
<Fill color="#FFE4B5"/>
</Group>
<Group>
<Ellipse size="16,16"/>
<Fill>
<RadialGradient radius="8">
<ColorStop offset="0" color="#FFE4B540"/>
<ColorStop offset="1" color="#FFE4B500"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer alpha="0.75" x="550" y="180">
<Group>
<Ellipse size="4,4"/>
<Fill color="#E0E7FF"/>
</Group>
<Group>
<Ellipse size="14,14"/>
<Fill>
<RadialGradient radius="7">
<ColorStop offset="0" color="#E0E7FF40"/>
<ColorStop offset="1" color="#E0E7FF00"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Path data="M-8 0L8 0M0 -8L0 8"/>
<Stroke color="#E0E7FF30"/>
</Group>
</Layer>
<Layer x="1020" y="140">
<Group>
<Ellipse size="130,130"/>
<Fill>
<RadialGradient center="-20,-20" radius="80">
<ColorStop offset="0" color="#F97316"/>
<ColorStop offset="0.35" color="#EA580C"/>
<ColorStop offset="0.65" color="#C2410C"/>
<ColorStop offset="1" color="#7C2D12"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Path data="M-55 -8C-30 -12 30 -4 55 -8"/>
<Stroke color="#FBBF2420" width="4"/>
</Group>
<Group>
<Path data="M-50 14C-15 10 20 16 50 14"/>
<Stroke color="#F9731620" width="5"/>
</Group>
<Group>
<Path data="M-45 32C-10 28 15 34 45 32"/>
<Stroke color="#FBBF2415" width="3"/>
</Group>
<Group rotation="-20">
<Ellipse size="200,42"/>
<Stroke color="#F9731660" width="5"/>
</Group>
<Group rotation="-20">
<Ellipse size="170,30"/>
<Stroke color="#FB923C40" width="3"/>
</Group>
<Group>
<Ellipse size="150,150"/>
<Fill>
<RadialGradient radius="75">
<ColorStop offset="0.7" color="#F9731600"/>
<ColorStop offset="1" color="#F9731635"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer x="420" y="105">
<Group>
<Ellipse size="28,28"/>
<Fill>
<RadialGradient center="-4,-4" radius="16">
<ColorStop offset="0" color="#A78BFA"/>
<ColorStop offset="0.6" color="#7C3AED"/>
<ColorStop offset="1" color="#4C1D95"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse size="36,36"/>
<Fill>
<RadialGradient radius="18">
<ColorStop offset="0.7" color="#A78BFA00"/>
<ColorStop offset="1" color="#A78BFA25"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer id="planet" x="60" y="580">
<Group>
<Ellipse size="420,420"/>
<Fill>
<RadialGradient center="-40,-60" radius="230">
<ColorStop offset="0" color="#3B82F6"/>
<ColorStop offset="0.3" color="#2563EB"/>
<ColorStop offset="0.6" color="#1D4ED8"/>
<ColorStop offset="1" color="#1E3A5F"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Path data="M-180 -40C-130 -46 -50 -34 0 -40C50 -46 130 -34 180 -40"/>
<Stroke color="#60A5FA25" width="10"/>
</Group>
<Group>
<Path data="M-170 25C-100 18 -30 32 40 25C100 18 170 32 190 25"/>
<Stroke color="#93C5FD20" width="8"/>
</Group>
<Group>
<Path data="M-160 75C-90 68 -10 82 50 75C110 68 175 82 190 75"/>
<Stroke color="#60A5FA18" width="12"/>
</Group>
<Group>
<Path data="M-150 -80C-80 -86 10 -74 80 -80"/>
<Stroke color="#93C5FD15" width="6"/>
</Group>
<Group>
<Ellipse size="450,450"/>
<Fill>
<RadialGradient radius="225">
<ColorStop offset="0.8" color="#3B82F600"/>
<ColorStop offset="1" color="#3B82F635"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer id="mountains" alpha="0.55">
<Group>
<Path data="M0 560L50 515L100 535L180 475L230 498L300 452L360 485L420 442L480 465L540 422L580 450L650 412L700 438L760 408L820 432L880 402L940 428L1000 392L1050 418L1100 398L1150 422L1200 405L1200 560Z"/>
<Fill>
<LinearGradient startPoint="600,-85" endPoint="600,85">
<ColorStop offset="0" color="#1A0F3A"/>
<ColorStop offset="0.5" color="#150C30"/>
<ColorStop offset="1" color="#100825"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M0 560L50 515L100 535L180 475L230 498L300 452L360 485L420 442L480 465L540 422L580 450L650 412L700 438L760 408L820 432L880 402L940 428L1000 392L1050 418L1100 398L1150 422L1200 405"/>
<Stroke color="#8B5CF625" width="1.5"/>
</Group>
</Layer>
<Layer id="terrain">
<Group>
<Path data="M0 800L0 605C60 595 120 580 200 575C300 568 380 585 440 570C500 550 540 560 600 545C660 530 720 545 780 538C840 530 900 550 960 540C1020 530 1080 545 1140 538L1200 535L1200 800Z"/>
<Fill>
<LinearGradient startPoint="600,-135" endPoint="600,135">
<ColorStop offset="0" color="#2D1854"/>
<ColorStop offset="0.3" color="#1F1240"/>
<ColorStop offset="0.7" color="#150D30"/>
<ColorStop offset="1" color="#0A0618"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M0 605C60 595 120 580 200 575C300 568 380 585 440 570C500 550 540 560 600 545C660 530 720 545 780 538C840 530 900 550 960 540C1020 530 1080 545 1140 538L1200 535"/>
<Stroke color="#8B5CF640" width="2"/>
</Group>
<Group>
<Path data="M0 800L0 645C80 640 160 628 240 638C340 650 400 634 480 628C560 622 640 636 720 628C800 620 880 634 960 628C1040 622 1120 636 1200 628L1200 800Z"/>
<Fill color="#18103A"/>
</Group>
<Group>
<Path data="M200 615L225 632L255 624L275 642"/>
<Stroke color="#8B5CF615"/>
</Group>
<Group>
<Path data="M650 575L675 592L705 584"/>
<Stroke color="#8B5CF612"/>
</Group>
<Group>
<Path data="M900 568L935 582L955 574L985 590"/>
<Stroke color="#8B5CF610"/>
</Group>
</Layer>
<Layer id="crater1" x="400" y="570">
<Group>
<Ellipse size="80,20"/>
<Fill>
<RadialGradient radius="40">
<ColorStop offset="0" color="#0A0618"/>
<ColorStop offset="0.6" color="#120B28"/>
<ColorStop offset="1" color="#1F1240"/>
</RadialGradient>
</Fill>
<Stroke color="#8B5CF625" width="1.5"/>
</Group>
<Group>
<Ellipse position="0,2" size="56,12"/>
<Fill>
<RadialGradient center="0,2" radius="28">
<ColorStop offset="0" color="#050310"/>
<ColorStop offset="1" color="#05031000"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer id="crater2" x="760" y="539">
<Group>
<Ellipse size="50,14"/>
<Fill>
<RadialGradient radius="25">
<ColorStop offset="0" color="#0A0618"/>
<ColorStop offset="0.6" color="#120B28"/>
<ColorStop offset="1" color="#1F1240"/>
</RadialGradient>
</Fill>
<Stroke color="#8B5CF620"/>
</Group>
</Layer>
<Layer id="crystal1" x="140" y="563">
<Group>
<Path data="M-8 25L-15 0L-5 -50L5 -60L12 -10L8 25Z"/>
<Fill>
<LinearGradient startPoint="-10,0" endPoint="10,0">
<ColorStop offset="0" color="#4C1D95"/>
<ColorStop offset="0.5" color="#6D28D9"/>
<ColorStop offset="1" color="#4C1D95"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M-5 -45L0 -30L5 -55"/>
<Stroke color="#A78BFA40"/>
</Group>
<Group>
<Path data="M-2 -55L0 -65L2 -55"/>
<Stroke color="#A78BFA" width="2" cap="round"/>
</Group>
<Group>
<Ellipse position="0,-62" size="16,16"/>
<Fill>
<RadialGradient center="0,-62" radius="8">
<ColorStop offset="0" color="#A78BFA80"/>
<ColorStop offset="1" color="#A78BFA00"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer id="crystal2" x="1060" y="516">
<Group>
<Path data="M-12 22L-18 -10L-8 -55L0 -65L8 -50L15 -5L10 22Z"/>
<Fill>
<LinearGradient startPoint="-12,0" endPoint="12,0">
<ColorStop offset="0" color="#7E22CE"/>
<ColorStop offset="0.5" color="#A855F7"/>
<ColorStop offset="1" color="#7E22CE"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M18 22L22 -5L28 -35L32 -42L36 -22L34 22Z"/>
<Fill>
<LinearGradient startPoint="22,0" endPoint="36,0">
<ColorStop offset="0" color="#6D28D9"/>
<ColorStop offset="0.5" color="#8B5CF6"/>
<ColorStop offset="1" color="#6D28D9"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M-22 22L-28 5L-24 -18L-20 -24L-16 -12L-18 22Z"/>
<Fill>
<LinearGradient startPoint="-28,0" endPoint="-16,0">
<ColorStop offset="0" color="#5B21B6"/>
<ColorStop offset="0.5" color="#7C3AED"/>
<ColorStop offset="1" color="#5B21B6"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Ellipse position="0,-65" size="18,18"/>
<Fill>
<RadialGradient center="0,-65" radius="9">
<ColorStop offset="0" color="#C4B5FDA0"/>
<ColorStop offset="1" color="#C4B5FD00"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="32,-42" size="14,14"/>
<Fill>
<RadialGradient center="32,-42" radius="7">
<ColorStop offset="0" color="#C4B5FD80"/>
<ColorStop offset="1" color="#C4B5FD00"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer x="348.5" y="583.5">
<Path data="M-10.5 11.5L-13.5 -1.5L-4.5 -11.5L7.5 -8.5L13.5 1.5L11.5 11.5Z"/>
<Fill color="#2D1854"/>
</Layer>
<Layer x="499" y="570">
<Path data="M-7 8L-9 -2L-2 -8L6 -6L9 2L7 8Z"/>
<Fill color="#241548"/>
</Layer>
<Layer x="679" y="547">
<Path data="M-9 11L-11 -2L-3 -11L6 -9L11 1L9 11Z"/>
<Fill color="#3B1F6E"/>
</Layer>
<Layer x="829" y="543.5">
<Path data="M-5 6.5L-7 -1.5L-1 -6.5L5 -4.5L7 1.5L5 6.5Z"/>
<Fill color="#2D1854"/>
</Layer>
<Layer x="959" y="548">
<Path data="M-7 8L-9 -2L-2 -8L6 -6L9 1L7 8Z"/>
<Fill color="#251448"/>
</Layer>
<Layer x="260" y="568">
<Group>
<Path data="M0 10C-2 -5 2 -20 -3 -38C-5 -45 -2 -52 0 -58"/>
<Stroke color="#10B981" width="3" cap="round"/>
</Group>
<Group>
<Path data="M-3 -25C-22 -38 -28 -22 -14 -19"/>
<Fill color="#059669"/>
</Group>
<Group>
<Path data="M2 -38C20 -50 25 -34 12 -31"/>
<Fill color="#059669"/>
</Group>
<Group>
<Path data="M-2 -48C-14 -53 -16 -42 -8 -41"/>
<Fill color="#047857"/>
</Group>
<Group>
<Ellipse position="0,-61" size="10,12"/>
<Fill>
<RadialGradient center="0,-61" radius="6">
<ColorStop offset="0" color="#34D399"/>
<ColorStop offset="0.6" color="#10B981"/>
<ColorStop offset="1" color="#059669"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="0,-61" size="34,34"/>
<Fill>
<RadialGradient center="0,-61" radius="17">
<ColorStop offset="0" color="#34D39968"/>
<ColorStop offset="0.5" color="#34D39935"/>
<ColorStop offset="1" color="#34D39900"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer id="vine" x="910" y="542">
<Group>
<Path data="M0 10C3 -8 -1 -25 2 -42C4 -50 1 -58 0 -65"/>
<Stroke color="#14B8A6" width="2.5" cap="round"/>
</Group>
<Group>
<Path data="M-1 -20C-18 -30 -22 -16 -10 -14M2 -40C17 -50 20 -36 10 -34M-2 -52C-14 -58 -16 -48 -8 -46"/>
<Fill color="#0D9488"/>
</Group>
<Group>
<Ellipse position="0,-68" size="8,10"/>
<Fill>
<RadialGradient center="0,-68" radius="5">
<ColorStop offset="0" color="#2DD4BF"/>
<ColorStop offset="0.6" color="#14B8A6"/>
<ColorStop offset="1" color="#0D9488"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="0,-68" size="28,28"/>
<Fill>
<RadialGradient center="0,-68" radius="14">
<ColorStop offset="0" color="#2DD4BF58"/>
<ColorStop offset="0.5" color="#2DD4BF28"/>
<ColorStop offset="1" color="#2DD4BF00"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer id="plant2" x="1130" y="538">
<Group>
<Path data="M0 8C-1 -5 1 -20 -2 -32"/>
<Stroke color="#10B981" width="2" cap="round"/>
</Group>
<Group>
<Path data="M14 8C16 -3 13 -18 15 -26"/>
<Stroke color="#14B8A6" width="2" cap="round"/>
</Group>
<Group>
<Ellipse position="0,-35" size="7,8"/>
<Fill color="#34D399"/>
</Group>
<Group>
<Ellipse position="14,-29" size="6,7"/>
<Fill color="#2DD4BF"/>
</Group>
<Group>
<Ellipse position="6,-32" size="26,26"/>
<Fill>
<RadialGradient center="6,-32" radius="13">
<ColorStop offset="0" color="#34D39958"/>
<ColorStop offset="1" color="#34D39900"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer id="plant1" x="455" y="565">
<Group>
<Path data="M0 6C1 -4 -1 -14 0 -22"/>
<Stroke color="#10B981" width="2" cap="round"/>
</Group>
<Group>
<Path data="M-1 -12C-10 -18 -12 -10 -6 -9"/>
<Fill color="#059669"/>
</Group>
<Group>
<Ellipse position="0,-25" size="6,8"/>
<Fill color="#34D399"/>
</Group>
<Group>
<Ellipse position="0,-25" size="20,20"/>
<Fill>
<RadialGradient center="0,-25" radius="10">
<ColorStop offset="0" color="#34D39955"/>
<ColorStop offset="1" color="#34D39900"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer id="alien1" x="860" y="523">
<Group>
<Ellipse size="18,14"/>
<Fill>
<RadialGradient radius="9">
<ColorStop offset="0" color="#A78BFA"/>
<ColorStop offset="0.7" color="#7C3AED"/>
<ColorStop offset="1" color="#6D28D9"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="-4,-3" size="5,6"/>
<Ellipse position="4,-3" size="5,6"/>
<Fill color="#E0E7FF"/>
</Group>
<Group>
<Ellipse position="-4,-3" size="2,3"/>
<Ellipse position="4,-3" size="2,3"/>
<Fill color="#1E1B4B"/>
</Group>
<Group>
<Path data="M-3 -7C-6 -15 -8 -18 -10 -22M3 -7C6 -15 8 -18 10 -22"/>
<Stroke color="#A78BFA" width="1.5" cap="round"/>
</Group>
<Group>
<Ellipse position="-10,-22" size="5,5"/>
<Ellipse position="10,-22" size="5,5"/>
<Fill color="#C4B5FD"/>
</Group>
<Group>
<Path data="M-6 5L-8 12M6 5L8 12M-2 6L-3 13M2 6L3 13"/>
<Stroke color="#7C3AED" width="2" cap="round"/>
</Group>
</Layer>
<Layer id="alien2" x="330" y="573">
<Group>
<Ellipse size="14,10"/>
<Fill>
<RadialGradient radius="7">
<ColorStop offset="0" color="#67E8F9"/>
<ColorStop offset="0.7" color="#22D3EE"/>
<ColorStop offset="1" color="#0891B2"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="-3,-2" size="4,5"/>
<Ellipse position="3,-2" size="4,5"/>
<Fill color="#E0F2FE"/>
</Group>
<Group>
<Ellipse position="-3,-2" size="2,2"/>
<Ellipse position="3,-2" size="2,2"/>
<Fill color="#164E63"/>
</Group>
<Group>
<Path data="M-2 -5C-4 -12 -3 -15 -5 -18M2 -5C4 -12 3 -15 5 -18"/>
<Stroke color="#22D3EE" width="1.5" cap="round"/>
</Group>
<Group>
<Ellipse position="-5,-18" size="3,3"/>
<Ellipse position="5,-18" size="3,3"/>
<Fill color="#67E8F9"/>
</Group>
</Layer>
<Layer id="ship" x="280" y="310">
<Group>
<Path data="M-15 30C-28 58 -12 95 0 120C12 95 28 58 15 30"/>
<Fill>
<LinearGradient startPoint="0,30" endPoint="0,120">
<ColorStop offset="0" color="#38BDF890"/>
<ColorStop offset="0.3" color="#06B6D460"/>
<ColorStop offset="0.6" color="#0891B230"/>
<ColorStop offset="1" color="#0891B200"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M-38 10C-42 0 -32 -16 -22 -24C-12 -30 12 -30 22 -24C32 -16 42 0 38 10C28 20 -28 20 -38 10Z"/>
<Fill>
<LinearGradient startPoint="0,-28" endPoint="0,20">
<ColorStop offset="0" color="#94A3B8"/>
<ColorStop offset="0.3" color="#CBD5E1"/>
<ColorStop offset="0.6" color="#E2E8F0"/>
<ColorStop offset="1" color="#94A3B8"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M-30 5C-15 8 15 8 30 5"/>
<Stroke color="#64748B"/>
</Group>
<Group>
<Path data="M-14 -24C-14 -38 14 -38 14 -24"/>
<Fill>
<LinearGradient startPoint="-14,-38" endPoint="14,-24">
<ColorStop offset="0" color="#38BDF8"/>
<ColorStop offset="0.5" color="#7DD3FC"/>
<ColorStop offset="1" color="#38BDF8"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M-7 -33C-7 -36 2 -37 4 -35"/>
<Stroke color="#FFFFFF80" width="1.5" cap="round"/>
</Group>
<Group>
<Path data="M-32 10C-22 16 22 16 32 10"/>
<Stroke color="#64748B" width="2"/>
</Group>
<Group>
<Ellipse position="-20,14" size="4,3"/>
<Ellipse position="0,16" size="4,3"/>
<Ellipse position="20,14" size="4,3"/>
<Fill color="#FBBF24"/>
</Group>
<Group>
<Ellipse size="95,55"/>
<Fill>
<RadialGradient radius="48">
<ColorStop offset="0.6" color="#38BDF800"/>
<ColorStop offset="1" color="#38BDF820"/>
</RadialGradient>
</Fill>
</Group>
<DropShadowStyle offsetY="5" blurX="18" blurY="18" color="#38BDF850"/>
</Layer>
<Layer x="499" y="344">
<Path data="M-9 7L-11 -3L-4 -9L6 -7L11 1L8 9Z"/>
<Fill color="#3B2060"/>
<Stroke color="#8B5CF620"/>
</Layer>
<Layer x="559.5" y="379.5">
<Path data="M-5.5 4.5L-6.5 -2.5L-1.5 -5.5L4.5 -4.5L6.5 1.5L4.5 5.5Z"/>
<Fill color="#2D1854"/>
</Layer>
<Layer x="469.5" y="394.5">
<Path data="M-4.5 3.5L-5.5 -1.5L-1.5 -4.5L3.5 -3.5L5.5 1.5L3.5 4.5Z"/>
<Fill color="#351C5A"/>
</Layer>
<Layer x="640" y="314.5">
<Path data="M-7 5.5L-8 -2.5L-3 -6.5L4 -5.5L8 1.5L5 6.5Z"/>
<Fill color="#2D1854"/>
<Stroke color="#8B5CF615"/>
</Layer>
<Layer x="789.5" y="354.5">
<Path data="M-4.5 4.5L-5.5 -1.5L-1.5 -4.5L4.5 -3.5L5.5 2.5L3.5 4.5Z"/>
<Fill color="#301A58"/>
</Layer>
<Layer id="station" alpha="0.65" x="1130" y="395">
<Group>
<Rectangle size="12,8" roundness="2"/>
<Fill color="#94A3B8"/>
</Group>
<Group>
<Rectangle position="-14,0" size="12,4"/>
<Rectangle position="14,0" size="12,4"/>
<Fill color="#38BDF8"/>
</Group>
<Group>
<Path data="M-8 0L-20 0M8 0L20 0"/>
<Stroke color="#94A3B8"/>
</Group>
<Group>
<Ellipse position="0,-5" size="2,2"/>
<Fill color="#EF4444"/>
</Group>
</Layer>
<Layer id="shadow" x="600" y="545">
<Ellipse size="140,25"/>
<Fill>
<RadialGradient radius="70">
<ColorStop offset="0" color="#00000060"/>
<ColorStop offset="0.6" color="#00000030"/>
<ColorStop offset="1" color="#00000000"/>
</RadialGradient>
</Fill>
</Layer>
<Layer id="astronaut" x="600" y="433">
<Group>
<Rectangle position="25,8" size="30,54" roundness="6"/>
<Fill>
<LinearGradient startPoint="10,0" endPoint="40,0">
<ColorStop offset="0" color="#94A3B8"/>
<ColorStop offset="0.5" color="#CBD5E1"/>
<ColorStop offset="1" color="#94A3B8"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M14 -12L36 -12M14 5L36 5M14 20L36 20"/>
<Stroke color="#64748B"/>
</Group>
<Group>
<Ellipse position="20,30" size="6,4"/>
<Ellipse position="30,30" size="6,4"/>
<Fill color="#475569"/>
</Group>
<Group>
<Path data="M32 -16L34 -38L36 -42"/>
<Stroke color="#94A3B8" width="2" cap="round"/>
</Group>
<Group>
<Ellipse position="36,-42" size="5,5"/>
<Fill color="#EF4444"/>
</Group>
<Group>
<Ellipse position="36,-42" size="14,14"/>
<Fill>
<RadialGradient center="36,-42" radius="7">
<ColorStop offset="0" color="#EF444470"/>
<ColorStop offset="1" color="#EF444400"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Path data="M-22 -22C-27 -10 -27 16 -24 32C-22 42 -16 48 0 50C16 48 22 42 24 32C27 16 27 -10 22 -22C12 -27 -12 -27 -22 -22Z"/>
<Fill>
<LinearGradient startPoint="-27,0" endPoint="27,0">
<ColorStop offset="0" color="#94A3B8"/>
<ColorStop offset="0.15" color="#CBD5E1"/>
<ColorStop offset="0.5" color="#F1F5F9"/>
<ColorStop offset="0.85" color="#CBD5E1"/>
<ColorStop offset="1" color="#94A3B8"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M0 -22L0 48"/>
<Stroke color="#E2E8F0" width="3"/>
</Group>
<Group>
<Ellipse position="-18,-14" size="8,6"/>
<Fill color="#EF4444"/>
</Group>
<Group>
<Ellipse position="18,-14" size="8,6"/>
<Fill color="#3B82F6"/>
</Group>
<Group>
<Rectangle position="0,5" size="22,18" roundness="3"/>
<Fill color="#475569"/>
</Group>
<Group>
<Ellipse position="-4,2" size="4,4"/>
<Fill color="#22C55E"/>
</Group>
<Group>
<Ellipse position="4,2" size="4,4"/>
<Fill color="#EAB308"/>
</Group>
<Group>
<Ellipse position="-4,8" size="4,4"/>
<Fill color="#3B82F6"/>
</Group>
<Group>
<Ellipse position="4,8" size="4,4"/>
<Fill color="#EF4444"/>
</Group>
<Group>
<Rectangle position="0,14" size="14,4" roundness="1"/>
<Fill color="#0F172A"/>
</Group>
<Group>
<Rectangle position="-2,14" size="6,2" roundness="1"/>
<Fill color="#22D3EE60"/>
</Group>
<Group>
<Path data="M-24 32C-12 36 12 36 24 32"/>
<Stroke color="#64748B" width="4"/>
</Group>
<Group>
<Rectangle position="0,34" size="10,8" roundness="2"/>
<Fill color="#94A3B8"/>
</Group>
<Group>
<Rectangle position="-14,36" size="8,6" roundness="2"/>
<Rectangle position="14,36" size="8,6" roundness="2"/>
<Fill color="#64748B"/>
</Group>
<Group>
<Path data="M-22 -12C-30 -15 -38 -20 -44 -26C-46 -28 -46 -30 -46 -32"/>
<Stroke color="#CBD5E1" width="14" cap="round" join="round"/>
</Group>
<Group>
<Ellipse position="-46,-45" size="16,18"/>
<Fill>
<LinearGradient startPoint="-54,-45" endPoint="-38,-45">
<ColorStop offset="0" color="#94A3B8"/>
<ColorStop offset="0.5" color="#E2E8F0"/>
<ColorStop offset="1" color="#94A3B8"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M-50 -52L-50 -58M-46 -53L-46 -60M-42 -52L-42 -58"/>
<Stroke color="#CBD5E1" width="3" cap="round"/>
</Group>
<Group>
<Ellipse position="-46,-36" size="16,6"/>
<Fill color="#64748B"/>
</Group>
<Group>
<Path data="M22 -12C32 -5 40 12 44 28"/>
<Stroke color="#CBD5E1" width="14" cap="round" join="round"/>
</Group>
<Group>
<Ellipse position="44,30" size="16,18"/>
<Fill>
<LinearGradient startPoint="36,30" endPoint="52,30">
<ColorStop offset="0" color="#94A3B8"/>
<ColorStop offset="0.5" color="#E2E8F0"/>
<ColorStop offset="1" color="#94A3B8"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Ellipse position="44,20" size="16,6"/>
<Fill color="#64748B"/>
</Group>
<Group>
<Rectangle position="44,18" size="8,22" roundness="2"/>
<Fill color="#475569"/>
</Group>
<Group>
<Rectangle position="44,9" size="6,6" roundness="1"/>
<Fill color="#0F172A"/>
</Group>
<Group>
<Ellipse position="44,9" size="4,4"/>
<Fill color="#22D3EE"/>
</Group>
<Group>
<Ellipse position="44,9" size="16,16"/>
<Fill>
<RadialGradient center="44,9" radius="8">
<ColorStop offset="0" color="#22D3EE55"/>
<ColorStop offset="1" color="#22D3EE00"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Path data="M-12 48C-14 64 -16 78 -18 94M12 48C14 64 16 78 18 94"/>
<Stroke color="#CBD5E1" width="14" cap="round"/>
</Group>
<Group>
<Ellipse position="-15,70" size="10,8"/>
<Ellipse position="15,70" size="10,8"/>
<Fill color="#94A3B8"/>
</Group>
<Group>
<Path data="M-24 92C-26 99 -26 106 -22 109C-18 112 -8 112 -6 109C-4 104 -10 96 -14 92"/>
<Fill>
<LinearGradient startPoint="-26,92" endPoint="-6,109">
<ColorStop offset="0" color="#64748B"/>
<ColorStop offset="0.5" color="#94A3B8"/>
<ColorStop offset="1" color="#64748B"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M14 92C12 99 12 106 16 109C20 112 28 112 30 109C32 104 24 96 18 92"/>
<Fill>
<LinearGradient startPoint="12,92" endPoint="30,109">
<ColorStop offset="0" color="#64748B"/>
<ColorStop offset="0.5" color="#94A3B8"/>
<ColorStop offset="1" color="#64748B"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M-24 108C-18 112 -8 112 -6 108M14 108C20 112 28 112 30 108"/>
<Stroke color="#475569" width="3"/>
</Group>
<Group>
<Path data="M-21 110L-19 110M-16 110L-14 110M-11 110L-9 110M17 110L19 110M21 110L23 110M25 110L27 110"/>
<Stroke color="#475569" width="1.5" cap="round"/>
</Group>
<Group>
<Ellipse position="0,-44" size="54,54"/>
<Fill>
<LinearGradient startPoint="-27,-71" endPoint="27,-17">
<ColorStop offset="0" color="#E2E8F0"/>
<ColorStop offset="0.3" color="#F8FAFC"/>
<ColorStop offset="0.7" color="#E2E8F0"/>
<ColorStop offset="1" color="#CBD5E1"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Ellipse position="0,-44" size="42,38"/>
<Fill>
<LinearGradient startPoint="-21,-63" endPoint="21,-25">
<ColorStop offset="0" color="#1E293B"/>
<ColorStop offset="0.25" color="#334155"/>
<ColorStop offset="0.5" color="#1E3A5F"/>
<ColorStop offset="0.75" color="#1E293B"/>
<ColorStop offset="1" color="#0F172A"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M-15 -58C-8 -61 5 -60 12 -57"/>
<Stroke color="#FFFFFF50" width="2" cap="round"/>
</Group>
<Group>
<Path data="M-11 -55C-4 -57 6 -56 11 -54"/>
<Stroke color="#FFFFFF30" width="1.5" cap="round"/>
</Group>
<Group>
<Path data="M11 -48C15 -42 16 -37 14 -32"/>
<Stroke color="#F9731630" width="3" cap="round"/>
</Group>
<Group>
<Ellipse position="-8,-40" size="2,2"/>
<Fill color="#FFFFFF30"/>
</Group>
<Group>
<Ellipse position="5,-48" size="1,1"/>
<Fill color="#FFFFFF25"/>
</Group>
<Group>
<Ellipse position="0,-44" size="54,54"/>
<Stroke color="#94A3B8" width="2"/>
</Group>
<Group>
<Rectangle position="0,-70" size="8,5" roundness="2"/>
<Fill color="#475569"/>
</Group>
<Group>
<Ellipse position="0,-70" size="4,3"/>
<Fill color="#FBBF24"/>
</Group>
<Group>
<Ellipse position="0,-21" size="38,12"/>
<Fill color="#94A3B8"/>
<Stroke color="#64748B" width="1.5"/>
</Group>
<Group>
<Path data="M-19 -21C-24 -16 -26 0 -24 10M19 -21C24 -16 26 0 24 10"/>
<Stroke color="#94A3B8" width="3" cap="round"/>
</Group>
<Group>
<Path data="M38 -16L38 -44"/>
<Stroke color="#94A3B8" width="2" cap="round"/>
</Group>
<Group>
<Path data="M38 -44L54 -42L54 -32L38 -34Z"/>
<Fill>
<LinearGradient startPoint="38,-44" endPoint="54,-32">
<ColorStop offset="0" color="#1E293B"/>
<ColorStop offset="0.5" color="#0F172A"/>
<ColorStop offset="1" color="#1E293B"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M45 -41L46 -37L47 -41Z"/>
<Fill color="#E2E8F0"/>
</Group>
<Group>
<Ellipse position="46,-36" size="6,3"/>
<Stroke color="#E2E8F0" width="0.8"/>
</Group>
</Layer>
<Layer id="hologram" alpha="0.75" x="505" y="385">
<Group>
<Rectangle size="60,45" roundness="3"/>
<Stroke color="#22D3EE55" width="1.5"/>
</Group>
<Group>
<Path data="M-30 -10L30 -10M-30 5L30 5"/>
<Stroke color="#22D3EE25"/>
</Group>
<Group>
<Path data="M-10 -22L-10 22M10 -22L10 22"/>
<Stroke color="#22D3EE20"/>
</Group>
<Group>
<Rectangle position="-18,-16" size="8,4" roundness="1"/>
<Fill color="#22D3EE40"/>
</Group>
<Group>
<Rectangle position="-6,-16" size="12,4" roundness="1"/>
<Fill color="#34D39940"/>
</Group>
<Group>
<Rectangle position="8,-16" size="6,4" roundness="1"/>
<Fill color="#FBBF2440"/>
</Group>
<Group>
<Ellipse size="14,14"/>
<Stroke color="#22D3EE50"/>
</Group>
<Group>
<Ellipse size="14,6"/>
<Stroke color="#22D3EE30"/>
</Group>
<Group>
<Rectangle position="-8,14" size="16,2" roundness="1"/>
<Fill color="#22D3EE30"/>
</Group>
<Group>
<Rectangle position="8,14" size="10,2" roundness="1"/>
<Fill color="#22D3EE25"/>
</Group>
<Group>
<Rectangle position="-4,18" size="20,2" roundness="1"/>
<Fill color="#22D3EE20"/>
</Group>
<Group>
<Ellipse size="75,58"/>
<Fill>
<RadialGradient radius="38">
<ColorStop offset="0.5" color="#22D3EE00"/>
<ColorStop offset="1" color="#22D3EE12"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer id="scanner" alpha="0.45" x="644" y="442">
<Group>
<Path data="M0 0L40 100L-15 108Z"/>
<Fill>
<LinearGradient startPoint="0,0" endPoint="12,108">
<ColorStop offset="0" color="#22D3EE70"/>
<ColorStop offset="0.3" color="#22D3EE40"/>
<ColorStop offset="0.6" color="#22D3EE18"/>
<ColorStop offset="1" color="#22D3EE00"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M6 28L22 28"/>
<Stroke color="#22D3EE25"/>
</Group>
<Group>
<Path data="M3 55L28 55"/>
<Stroke color="#22D3EE18"/>
</Group>
<Group>
<Path data="M0 82L32 82"/>
<Stroke color="#22D3EE12"/>
</Group>
</Layer>
<Layer id="beacon" x="780" y="510">
<Group>
<Rectangle position="0,10" size="4,30" roundness="1"/>
<Fill color="#64748B"/>
</Group>
<Group>
<Ellipse position="0,25" size="14,5"/>
<Fill color="#475569"/>
</Group>
<Group>
<Ellipse position="0,-5" size="8,8"/>
<Fill color="#22C55E"/>
</Group>
<Group>
<Ellipse position="0,-5" size="22,22"/>
<Fill>
<RadialGradient center="0,-5" radius="11">
<ColorStop offset="0" color="#22C55E55"/>
<ColorStop offset="0.5" color="#22C55E28"/>
<ColorStop offset="1" color="#22C55E00"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="0,-5" size="30,30"/>
<Stroke color="#22C55E18"/>
</Group>
<Group>
<Ellipse position="0,-5" size="42,42"/>
<Stroke color="#22C55E10"/>
</Group>
</Layer>
<Layer alpha="0.5" x="500" y="470">
<Ellipse size="3,3"/>
<Fill color="#A78BFA"/>
</Layer>
<Layer alpha="0.4" x="520" y="490">
<Ellipse size="2,2"/>
<Fill color="#C4B5FD"/>
</Layer>
<Layer alpha="0.5" x="700" y="500">
<Ellipse size="3,3"/>
<Fill color="#22D3EE"/>
</Layer>
<Layer alpha="0.35" x="740" y="480">
<Ellipse size="2,2"/>
<Fill color="#67E8F9"/>
</Layer>
<Layer alpha="0.45" x="560" y="520">
<Ellipse size="2,2"/>
<Fill color="#34D399"/>
</Layer>
<Layer alpha="0.4" x="660" y="530" composition="@comp3"/>
<Layer alpha="0.3" x="450" y="510">
<Ellipse size="2,2"/>
<Fill color="#C4B5FD"/>
</Layer>
<Layer alpha="0.5" x="770" y="520">
<Ellipse size="2,2"/>
<Fill color="#22D3EE"/>
</Layer>
<Layer alpha="0.35" x="580" y="430">
<Ellipse size="2,2"/>
<Fill color="#FBBF24"/>
</Layer>
<Layer alpha="0.3" x="630" y="410">
<Ellipse size="2,2"/>
<Fill color="#F97316"/>
</Layer>
<Layer alpha="0.4" x="540" y="455" composition="@comp3"/>
<Layer alpha="0.3" x="670" y="445">
<Ellipse size="2,2"/>
<Fill color="#34D399"/>
</Layer>
<Layer alpha="0.35" x="480" y="435">
<Ellipse size="2,2"/>
<Fill color="#C4B5FD"/>
</Layer>
<Layer alpha="0.3" x="465" y="548">
<Ellipse size="12,16"/>
<Fill color="#1A1040"/>
</Layer>
<Layer alpha="0.25" x="510" y="550">
<Ellipse size="12,16"/>
<Fill color="#1A1040"/>
</Layer>
<Layer alpha="0.2" x="548" y="546">
<Ellipse size="12,16"/>
<Fill color="#1A1040"/>
</Layer>
<Layer>
<Group>
<Path data="M0 800L0 710C50 700 120 690 200 695C300 702 400 685 500 690C600 695 700 682 800 688C900 694 1000 680 1100 685L1200 682L1200 800Z"/>
<Fill>
<LinearGradient startPoint="600,-58" endPoint="600,58">
<ColorStop offset="0" color="#120B28"/>
<ColorStop offset="0.5" color="#0D0820"/>
<ColorStop offset="1" color="#080515"/>
</LinearGradient>
</Fill>
</Group>
<Group>
<Path data="M25 755L10 715L38 690L72 705L80 745L55 760Z"/>
<Fill color="#1A1040"/>
</Group>
<Group>
<Path data="M85 760L72 735L92 720L110 730L105 755Z"/>
<Fill color="#150D30"/>
</Group>
<Group>
<Path data="M1110 740L1095 708L1125 688L1155 700L1162 735L1135 748Z"/>
<Fill color="#18103A"/>
</Group>
<Group>
<Path data="M1168 745L1160 715L1175 700L1188 720L1184 748Z"/>
<Fill>
<LinearGradient startPoint="1160,722" endPoint="1188,722">
<ColorStop offset="0" color="#5B21B6"/>
<ColorStop offset="0.5" color="#7C3AED"/>
<ColorStop offset="1" color="#5B21B6"/>
</LinearGradient>
</Fill>
</Group>
</Layer>
<Layer x="40" y="710">
<Group>
<Path data="M0 0C-1 -30 2 -65 -2 -95"/>
<Stroke color="#7C3AED" width="6" cap="round"/>
</Group>
<Group>
<Ellipse position="-2,-98" size="40,30"/>
<Fill>
<RadialGradient center="-2,-98" radius="20">
<ColorStop offset="0" color="#DDD6FE"/>
<ColorStop offset="0.3" color="#C4B5FD"/>
<ColorStop offset="0.7" color="#A78BFA"/>
<ColorStop offset="1" color="#7C3AED"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="-2,-98" size="16,12"/>
<Fill color="#EDE9FE90"/>
</Group>
<Group>
<Ellipse position="-2,-98" size="56,42"/>
<Fill>
<RadialGradient center="-2,-98" radius="28">
<ColorStop offset="0" color="#C4B5FD55"/>
<ColorStop offset="1" color="#C4B5FD00"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Path data="M-2 -83C-14 -74 -22 -58 -18 -42"/>
<Stroke color="#A78BFA55" width="3" cap="round"/>
</Group>
<Group>
<Path data="M-2 -83C10 -74 18 -58 14 -42"/>
<Stroke color="#A78BFA40" width="3" cap="round"/>
</Group>
<Group>
<Ellipse position="-18,-38" size="10,10"/>
<Fill color="#C4B5FD60"/>
</Group>
<Group>
<Ellipse position="14,-38" size="8,8"/>
<Fill color="#A78BFA50"/>
</Group>
</Layer>
<Layer x="80" y="720">
<Group>
<Path data="M0 0C1 -18 -1 -38 0 -52"/>
<Stroke color="#6D28D9" width="4" cap="round"/>
</Group>
<Group>
<Ellipse position="0,-55" size="28,22"/>
<Fill>
<RadialGradient center="0,-55" radius="14">
<ColorStop offset="0" color="#C4B5FD"/>
<ColorStop offset="0.5" color="#A78BFA"/>
<ColorStop offset="1" color="#7C3AED"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="0,-55" size="10,8"/>
<Fill color="#EDE9FE80"/>
</Group>
<Group>
<Ellipse position="0,-55" size="40,32"/>
<Fill>
<RadialGradient center="0,-55" radius="20">
<ColorStop offset="0" color="#C4B5FD40"/>
<ColorStop offset="1" color="#C4B5FD00"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer x="180" y="725">
<Group>
<Path data="M0 0C-3 -20 2 -45 -2 -70"/>
<Stroke color="#059669" width="5" cap="round"/>
</Group>
<Group>
<Path data="M-2 -35C-16 -44 -24 -36 -18 -26"/>
<Fill color="#10B981"/>
</Group>
<Group>
<Path data="M-2 -50C14 -58 22 -50 16 -40"/>
<Fill color="#059669"/>
</Group>
<Group>
<Path data="M-2 -60C-12 -66 -16 -58 -10 -52"/>
<Fill color="#14B8A6"/>
</Group>
<Group>
<Ellipse position="-2,-74" size="14,14"/>
<Fill color="#34D399"/>
</Group>
<Group>
<Ellipse position="-2,-72" size="36,36"/>
<Fill>
<RadialGradient center="-2,-72" radius="18">
<ColorStop offset="0" color="#34D39960"/>
<ColorStop offset="1" color="#34D39900"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer alpha="0.9" x="1080" y="695">
<Group>
<Path data="M0 0C-2 -25 1 -55 -1 -80"/>
<Stroke color="#6D28D9" width="7" cap="round"/>
</Group>
<Group>
<Ellipse position="-1,-84" size="44,34"/>
<Fill>
<RadialGradient center="-1,-84" radius="22">
<ColorStop offset="0" color="#F0ABFC"/>
<ColorStop offset="0.3" color="#D946EF"/>
<ColorStop offset="0.7" color="#A855F7"/>
<ColorStop offset="1" color="#7C3AED"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="-1,-84" size="18,14"/>
<Fill color="#FDF4FF90"/>
</Group>
<Group>
<Ellipse position="-1,-84" size="62,48"/>
<Fill>
<RadialGradient center="-1,-84" radius="31">
<ColorStop offset="0" color="#F0ABFC50"/>
<ColorStop offset="1" color="#F0ABFC00"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Path data="M-1 -67C-12 -55 -18 -40 -14 -28"/>
<Stroke color="#D946EF40" width="2.5" cap="round"/>
</Group>
<Group>
<Path data="M-1 -67C10 -55 16 -40 12 -28"/>
<Stroke color="#D946EF30" width="2.5" cap="round"/>
</Group>
<Group>
<Ellipse position="-14,-24" size="8,8"/>
<Fill color="#F0ABFC50"/>
</Group>
<Group>
<Ellipse position="12,-24" size="7,7"/>
<Fill color="#D946EF40"/>
</Group>
</Layer>
<Layer alpha="0.9" x="1160" y="708">
<Group>
<Path data="M0 0C-2 -18 1 -40 -1 -58"/>
<Stroke color="#0891B2" width="5" cap="round"/>
</Group>
<Group>
<Path data="M16 0C18 -14 15 -32 17 -46"/>
<Stroke color="#06B6D4" width="4" cap="round"/>
</Group>
<Group>
<Path data="M-12 0C-14 -12 -11 -28 -13 -40"/>
<Stroke color="#14B8A6" width="4" cap="round"/>
</Group>
<Group>
<Ellipse position="-1,-62" size="16,16"/>
<Fill color="#22D3EE"/>
</Group>
<Group>
<Ellipse position="17,-50" size="14,14"/>
<Fill color="#2DD4BF"/>
</Group>
<Group>
<Ellipse position="-13,-44" size="12,12"/>
<Fill color="#5EEAD4"/>
</Group>
<Group>
<Ellipse position="2,-52" size="55,55"/>
<Fill>
<RadialGradient center="2,-52" radius="28">
<ColorStop offset="0" color="#22D3EE50"/>
<ColorStop offset="1" color="#22D3EE00"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer alpha="0.85" x="320" y="715">
<Group>
<Path data="M0 0C-2 -16 1 -35 -1 -50"/>
<Stroke color="#7C3AED" width="5" cap="round"/>
</Group>
<Group>
<Path data="M-1 -50C-12 -60 -8 -70 0 -65"/>
<Fill color="#D946EF"/>
</Group>
<Group>
<Path data="M-1 -50C10 -60 8 -70 0 -65"/>
<Fill color="#A855F7"/>
</Group>
<Group>
<Path data="M-1 -50C-6 -65 0 -75 2 -68"/>
<Fill color="#C084FC"/>
</Group>
<Group>
<Ellipse position="-1,-52" size="8,8"/>
<Fill color="#FBBF24"/>
</Group>
<Group>
<Ellipse position="-1,-52" size="24,24"/>
<Fill>
<RadialGradient center="-1,-52" radius="12">
<ColorStop offset="0" color="#FBBF2440"/>
<ColorStop offset="1" color="#FBBF2400"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer alpha="0.8" x="500" y="710">
<Group>
<Path data="M0 0C-6 -15 -18 -35 -28 -48C-34 -54 -30 -42 -24 -30"/>
<Stroke color="#8B5CF6" width="4" cap="round"/>
</Group>
<Group>
<Path data="M0 0C6 -18 16 -40 26 -55C32 -62 28 -48 22 -34"/>
<Stroke color="#7C3AED" width="4" cap="round"/>
</Group>
<Group>
<Path data="M0 0C-1 -22 0 -48 -2 -68"/>
<Stroke color="#6D28D9" width="6" cap="round"/>
</Group>
<Group>
<Ellipse position="-28,-52" size="10,12"/>
<Fill color="#C4B5FD"/>
</Group>
<Group>
<Ellipse position="26,-58" size="10,12"/>
<Fill color="#A78BFA"/>
</Group>
<Group>
<Ellipse position="-2,-72" size="14,16"/>
<Fill color="#DDD6FE"/>
</Group>
<Group>
<Ellipse position="-2,-66" size="50,50"/>
<Fill>
<RadialGradient center="-2,-66" radius="25">
<ColorStop offset="0" color="#C4B5FD45"/>
<ColorStop offset="1" color="#C4B5FD00"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer alpha="0.8" x="640" y="718">
<Group>
<Path data="M0 0C-2 -12 1 -28 -1 -40"/>
<Stroke color="#7C3AED" width="4" cap="round"/>
</Group>
<Group>
<Ellipse position="-1,-44" size="22,18"/>
<Fill>
<RadialGradient center="-1,-44" radius="11">
<ColorStop offset="0" color="#F0ABFC"/>
<ColorStop offset="0.5" color="#D946EF"/>
<ColorStop offset="1" color="#A21CAF"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="-1,-44" size="10,8"/>
<Fill color="#FDF4FF90"/>
</Group>
<Group>
<Ellipse position="-1,-44" size="36,30"/>
<Fill>
<RadialGradient center="-1,-44" radius="18">
<ColorStop offset="0" color="#F0ABFC50"/>
<ColorStop offset="1" color="#F0ABFC00"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer alpha="0.85" x="770" y="705">
<Group>
<Path data="M0 0C2 -24 -1 -52 1 -72"/>
<Stroke color="#059669" width="5" cap="round"/>
</Group>
<Group>
<Path data="M1 -30C-14 -38 -24 -30 -18 -20"/>
<Fill color="#10B981"/>
</Group>
<Group>
<Path data="M1 -46C16 -54 24 -46 18 -36"/>
<Fill color="#059669"/>
</Group>
<Group>
<Path data="M1 -58C-10 -66 -16 -58 -10 -50"/>
<Fill color="#14B8A6"/>
</Group>
<Group>
<Path data="M1 -66C8 -72 12 -66 8 -60"/>
<Fill color="#2DD4BF"/>
</Group>
<Group>
<Ellipse position="1,-76" size="12,12"/>
<Fill color="#34D399"/>
</Group>
<Group>
<Ellipse position="1,-74" size="38,38"/>
<Fill>
<RadialGradient center="1,-74" radius="19">
<ColorStop offset="0" color="#34D39960"/>
<ColorStop offset="1" color="#34D39900"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer alpha="0.75" x="930" y="715">
<Group>
<Path data="M0 0C-8 -12 -22 -22 -32 -28C-36 -30 -32 -20 -26 -10"/>
<Stroke color="#0891B2" width="3.5" cap="round"/>
</Group>
<Group>
<Path data="M0 0C8 -14 20 -28 30 -35C34 -37 30 -26 24 -16"/>
<Stroke color="#06B6D4" width="3.5" cap="round"/>
</Group>
<Group>
<Path data="M0 0C0 -16 -1 -38 0 -52"/>
<Stroke color="#0E7490" width="5" cap="round"/>
</Group>
<Group>
<Ellipse position="0,-56" size="12,14"/>
<Fill color="#22D3EE"/>
</Group>
<Group>
<Ellipse position="-32,-30" size="8,10"/>
<Fill color="#67E8F9"/>
</Group>
<Group>
<Ellipse position="30,-38" size="8,10"/>
<Fill color="#5EEAD4"/>
</Group>
<Group>
<Ellipse position="0,-46" size="44,44"/>
<Fill>
<RadialGradient center="0,-46" radius="22">
<ColorStop offset="0" color="#22D3EE45"/>
<ColorStop offset="1" color="#22D3EE00"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer alpha="0.6" x="400" y="732">
<Group>
<Path data="M-10 5L-16 -5L-8 -14L4 -12L12 -3L8 5Z"/>
<Fill color="#1A1040"/>
</Group>
<Group>
<Path data="M14 5L10 -4L18 -10L26 -6L24 5Z"/>
<Fill color="#150D30"/>
</Group>
<Group>
<Path data="M-20 5L-24 -2L-18 -8L-12 -4L-14 5Z"/>
<Fill color="#120B28"/>
</Group>
</Layer>
<Layer alpha="0.6" x="850" y="728">
<Group>
<Path data="M-8 4L-12 -4L-4 -12L6 -8L10 0L6 4Z"/>
<Fill color="#18103A"/>
</Group>
<Group>
<Path data="M12 4L8 -3L14 -8L20 -4L18 4Z"/>
<Fill color="#1A1040"/>
</Group>
</Layer>
<Layer alpha="0.7" x="220" y="738">
<Group>
<Path data="M0 0C-1 -10 0 -22 -1 -30"/>
<Stroke color="#10B981" width="3" cap="round"/>
</Group>
<Group>
<Path data="M8 0C9 -8 7 -18 8 -24"/>
<Stroke color="#059669" width="2.5" cap="round"/>
</Group>
<Group>
<Ellipse position="0,-34" size="8,8"/>
<Fill color="#34D399"/>
</Group>
<Group>
<Ellipse position="8,-28" size="7,7"/>
<Fill color="#2DD4BF"/>
</Group>
<Group>
<Ellipse position="4,-30" size="28,28"/>
<Fill>
<RadialGradient center="4,-30" radius="14">
<ColorStop offset="0" color="#34D39950"/>
<ColorStop offset="1" color="#34D39900"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer alpha="0.5" x="550" y="735">
<Group>
<Ellipse size="30,12"/>
<Fill>
<RadialGradient radius="15">
<ColorStop offset="0" color="#22D3EE40"/>
<ColorStop offset="0.6" color="#22D3EE20"/>
<ColorStop offset="1" color="#22D3EE00"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="22,3" size="24,10"/>
<Fill>
<RadialGradient center="22,3" radius="12">
<ColorStop offset="0" color="#A78BFA35"/>
<ColorStop offset="0.6" color="#A78BFA18"/>
<ColorStop offset="1" color="#A78BFA00"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="-18,4" size="20,8"/>
<Fill>
<RadialGradient center="-18,4" radius="10">
<ColorStop offset="0" color="#34D39930"/>
<ColorStop offset="1" color="#34D39900"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer alpha="0.4" x="130" y="748">
<Ellipse size="26,10"/>
<Fill>
<RadialGradient radius="13">
<ColorStop offset="0" color="#A78BFA35"/>
<ColorStop offset="1" color="#A78BFA00"/>
</RadialGradient>
</Fill>
</Layer>
<Layer alpha="0.4" x="700" y="740">
<Ellipse size="22,8"/>
<Fill>
<RadialGradient radius="11">
<ColorStop offset="0" color="#22D3EE30"/>
<ColorStop offset="1" color="#22D3EE00"/>
</RadialGradient>
</Fill>
</Layer>
<Layer alpha="0.9">
<Group>
<Path data="M-71 840C-69 788 -47 611 -48 580C-42 611 -52 788 -53 840ZM-38 840C-38 796 -33 644 -29 618C-29 644 -25 796 -24 840ZM-9 840C-10 787 -8 606 -3 574C-3 606 6 787 7 840ZM21 840C22 790 54 620 52 590C58 620 37 790 35 840ZM35 840C34 795 49 644 52 617C53 644 46 795 47 840ZM62 840C63 796 89 646 90 619C92 646 74 796 74 840ZM75 840C73 788 54 611 60 580C58 611 86 788 87 840ZM109 840C111 796 152 644 149 618C155 644 121 796 119 840ZM130 840C129 799 105 658 110 634C110 658 144 799 145 840ZM146 840C145 798 125 654 129 629C129 654 157 798 158 840ZM169 840C169 799 185 662 188 637C189 662 183 799 183 840ZM201 840C201 800 228 664 229 640C233 664 219 800 218 840ZM225 840C224 800 217 664 220 640C221 664 238 800 238 840ZM259 840C258 789 209 616 215 586C213 616 269 789 271 840ZM276 840C277 787 320 608 319 576C324 608 291 787 290 840ZM299 840C299 791 309 625 310 595C313 625 313 791 313 840ZM331 840C332 782 357 583 356 548C361 583 345 782 344 840ZM352 840C352 786 367 601 369 568C372 601 370 786 370 840ZM376 840C378 800 421 664 420 640C426 664 395 800 394 840ZM400 840C400 785 378 599 382 566C383 599 417 785 417 840ZM418 840C419 781 443 581 441 546C448 581 436 781 434 840ZM439 840C440 799 448 658 448 633C452 658 452 799 452 840ZM451 840C451 799 454 659 456 634C459 659 468 799 468 840ZM486 840C487 785 501 599 502 567C505 599 500 785 499 840ZM499 840C498 790 513 622 518 592C519 622 516 790 517 840ZM543 840C543 798 544 655 544 629C547 655 554 798 553 840ZM556 840C557 792 593 631 593 602C597 631 572 792 571 840ZM571 840C571 791 582 623 585 593C585 623 582 791 583 840ZM605 840C606 799 610 660 610 635C614 660 620 799 619 840ZM623 840C624 785 637 599 637 566C642 599 642 785 641 840ZM654 840C656 786 702 604 698 572C705 604 667 786 665 840ZM686 840C685 799 657 658 660 633C660 658 695 799 696 840ZM699 840C698 782 658 586 663 552C662 586 713 782 714 840ZM714 840C715 793 743 634 742 606C746 634 727 793 726 840ZM750 840C749 794 750 637 754 609C753 637 759 794 760 840ZM770 840C772 798 815 656 814 631C820 656 789 798 787 840ZM801 840C803 796 821 646 821 619C825 646 816 796 815 840ZM826 840C827 791 868 626 867 597C873 626 844 791 842 840ZM836 840C836 797 872 650 873 624C876 650 852 797 852 840ZM859 840C858 788 842 611 847 580C847 611 874 788 875 840ZM886 840C886 781 900 581 901 546C905 581 904 781 904 840ZM903 840C901 787 892 606 898 575C896 606 915 787 917 840ZM926 840C927 794 958 638 956 610C961 638 937 794 936 840ZM959 840C958 782 937 587 940 552C941 587 971 782 971 840ZM980 840C980 795 964 640 966 613C967 640 992 795 992 840ZM1003 840C1003 798 1034 654 1034 629C1037 654 1015 798 1014 840ZM1021 840C1021 784 1037 594 1041 561C1041 594 1034 784 1035 840ZM1063 840C1063 782 1050 583 1051 548C1053 583 1074 782 1074 840ZM1086 840C1087 784 1132 593 1130 559C1137 593 1102 784 1100 840ZM1099 840C1097 782 1054 585 1062 550C1059 585 1115 782 1117 840ZM1113 840C1115 798 1141 655 1141 630C1146 655 1131 798 1129 840ZM1144 840C1144 785 1170 597 1172 564C1175 597 1161 785 1160 840ZM1178 840C1178 780 1196 577 1198 541C1199 577 1189 780 1189 840ZM1203 840C1204 785 1213 599 1213 566C1218 599 1222 785 1221 840ZM1222 840C1221 796 1226 648 1231 622C1232 648 1239 796 1239 840Z"/>
<Fill color="#14332A"/>
</Group>
</Layer>
<Layer alpha="0.8">
<Group>
<Path data="M-69 835C-68 797 -58 669 -58 647C-54 669 -54 797 -55 835ZM-33 835C-32 793 -12 650 -12 625C-8 650 -18 793 -19 835ZM-22 835C-22 795 -2 661 1 637C2 661 -9 795 -9 835ZM13 835C14 783 52 607 51 575C54 607 23 783 22 835ZM35 835C36 793 75 649 75 623C79 649 48 793 47 835ZM64 835C63 794 51 652 56 628C55 652 74 794 75 835ZM64 835C63 797 48 669 52 646C52 669 75 797 76 835ZM106 835C108 793 122 650 120 625C125 650 116 793 115 835ZM127 835C126 799 132 675 134 654C135 675 136 799 137 835ZM130 835C130 797 146 668 149 645C150 668 142 797 142 835ZM154 835C156 800 188 681 187 660C190 681 164 800 163 835ZM192 835C191 801 181 685 185 664C186 685 206 801 207 835ZM211 835C211 801 201 685 202 665C205 685 226 801 225 835ZM230 835C229 799 205 679 209 657C208 679 240 799 241 835ZM238 835C238 796 249 663 251 640C253 663 253 796 253 835ZM261 835C260 785 253 614 258 584C256 614 268 785 270 835ZM296 835C296 786 315 620 317 590C320 620 311 786 311 835ZM317 835C315 793 276 650 282 625C281 650 330 793 332 835ZM339 835C340 801 357 685 357 665C362 685 356 801 354 835ZM362 835C363 792 378 647 377 622C382 647 377 792 376 835ZM372 835C373 785 382 616 381 586C385 616 385 785 384 835ZM408 835C408 799 410 675 413 653C414 675 421 799 421 835ZM410 835C408 799 400 676 405 654C404 676 422 799 424 835ZM452 835C451 793 458 648 462 623C462 648 464 793 465 835ZM455 835C456 784 498 609 499 579C503 609 471 784 471 835ZM489 835C488 797 476 669 479 646C478 669 497 797 498 835ZM518 835C518 787 518 625 521 597C521 625 528 787 528 835ZM519 835C520 784 557 611 556 580C560 611 531 784 530 835ZM537 835C537 799 530 677 533 656C535 677 552 799 552 835ZM576 835C576 792 572 647 576 621C577 647 592 792 592 835ZM583 835C585 794 640 657 637 632C643 657 596 794 594 835ZM622 835C623 799 620 675 621 653C622 675 631 799 630 835ZM627 835C627 787 615 625 617 596C617 625 636 787 636 835ZM652 835C652 789 638 631 640 604C641 631 663 789 662 835ZM674 835C673 790 687 637 688 610C689 637 682 790 682 835ZM691 835C693 798 709 671 708 649C714 671 708 798 706 835ZM725 835C725 794 744 653 746 628C749 653 740 794 740 835ZM752 835C754 785 763 617 762 587C767 617 766 785 765 835ZM770 835C769 795 773 660 777 636C777 660 781 795 782 835ZM792 835C792 797 774 669 776 647C777 669 804 797 804 835ZM820 835C819 785 817 615 822 585C821 615 834 785 835 835ZM824 835C823 795 828 661 833 637C833 661 838 795 840 835ZM845 835C845 790 886 638 885 611C888 638 854 790 853 835ZM884 835C885 787 906 625 905 597C910 625 899 787 897 835ZM902 835C904 791 929 642 927 616C932 642 915 791 914 835ZM921 835C921 797 918 668 921 645C921 668 931 797 931 835ZM932 835C934 790 981 639 981 612C986 639 949 790 948 835ZM967 835C965 786 916 618 922 589C918 618 974 786 976 835ZM990 835C992 790 996 636 995 609C999 636 1000 790 999 835ZM1015 835C1013 787 1001 622 1007 593C1006 622 1029 787 1031 835ZM1019 835C1019 797 1052 670 1053 647C1056 670 1031 797 1030 835ZM1054 835C1053 792 1035 645 1041 619C1039 645 1065 792 1067 835ZM1069 835C1071 783 1123 608 1119 577C1126 608 1080 783 1078 835ZM1097 835C1096 792 1087 648 1090 622C1091 648 1112 792 1113 835ZM1110 835C1110 795 1126 657 1128 633C1130 657 1124 795 1124 835ZM1124 835C1122 793 1099 649 1105 623C1103 649 1136 793 1138 835ZM1148 835C1148 792 1143 645 1143 619C1146 645 1158 792 1158 835ZM1191 835C1190 796 1176 662 1178 639C1179 662 1202 796 1202 835ZM1212 835C1211 801 1221 684 1224 664C1224 684 1220 801 1221 835ZM1224 835C1225 788 1259 629 1257 601C1263 629 1238 788 1236 835Z"/>
<Fill color="#1A4038"/>
</Group>
</Layer>
<Layer alpha="0.7">
<Group>
<Path data="M-68 830C-68 789 -59 650 -59 626C-56 650 -55 789 -56 830ZM-24 830C-26 791 -64 660 -59 637C-61 660 -18 791 -16 830ZM-10 830C-9 787 24 639 24 613C28 639 1 787 0 830ZM1 830C2 794 -2 672 -1 651C2 672 13 794 13 830ZM12 830C11 791 4 658 8 634C7 658 23 791 25 830ZM44 830C45 792 65 663 65 640C68 663 56 792 55 830ZM55 830C55 789 33 650 36 625C37 650 67 789 68 830ZM82 830C83 791 119 660 117 637C121 660 90 791 89 830ZM98 830C98 799 132 693 133 675C136 693 111 799 111 830ZM117 830C117 797 119 683 120 663C123 683 130 797 129 830ZM138 830C137 801 132 701 135 683C135 701 148 801 149 830ZM163 830C164 802 172 706 172 689C176 706 177 802 175 830ZM180 830C181 802 207 706 206 690C209 706 190 802 188 830ZM204 830C203 792 191 663 195 640C195 663 214 792 215 830ZM231 830C230 787 212 642 215 616C215 642 239 787 240 830ZM248 830C249 796 262 682 262 662C265 682 260 796 259 830ZM270 830C269 790 239 654 242 630C242 654 277 790 278 830ZM287 830C287 799 314 695 315 677C318 695 300 799 300 830ZM307 830C309 802 348 706 347 690C352 706 322 802 320 830ZM329 830C328 798 309 691 313 672C313 691 340 798 341 830ZM355 830C356 789 354 649 355 625C357 649 366 789 365 830ZM360 830C358 799 361 693 366 674C365 693 372 799 374 830ZM376 830C376 799 369 694 370 675C372 694 388 799 387 830ZM401 830C402 799 422 693 422 674C426 693 416 799 415 830ZM418 830C420 795 476 676 475 655C480 676 434 795 432 830ZM443 830C444 797 480 684 479 664C483 684 453 797 451 830ZM460 830C458 800 440 697 445 679C444 697 472 800 473 830ZM475 830C474 795 460 678 464 657C463 678 485 795 486 830ZM505 830C504 800 489 696 493 678C492 696 514 800 515 830ZM514 830C512 798 505 691 510 672C509 691 526 798 528 830ZM545 830C547 801 564 704 563 686C567 704 558 801 556 830ZM568 830C569 799 587 693 586 674C589 693 576 799 575 830ZM585 830C585 792 596 661 597 638C600 661 597 792 597 830ZM599 830C598 802 598 705 601 688C602 705 609 802 609 830ZM631 830C632 787 656 642 656 616C658 642 639 787 638 830ZM648 830C649 798 686 688 685 669C690 688 662 798 660 830ZM663 830C663 792 682 663 684 641C684 663 671 792 672 830ZM690 830C690 797 711 685 711 666C714 685 699 797 699 830ZM716 830C718 794 756 673 754 651C759 673 726 794 725 830ZM736 830C737 789 760 650 759 626C762 650 746 789 745 830ZM742 830C743 789 761 648 762 623C765 648 756 789 755 830ZM761 830C760 787 767 639 771 613C770 639 770 787 771 830ZM776 830C776 788 779 644 780 618C781 644 783 788 783 830ZM798 830C798 792 781 662 785 639C785 662 811 792 812 830ZM813 830C812 789 805 649 808 624C808 649 824 789 825 830ZM853 830C851 797 821 683 825 663C824 683 861 797 863 830ZM861 830C860 796 865 680 869 660C868 680 869 796 871 830ZM885 830C885 790 884 652 885 628C886 652 893 790 893 830ZM905 830C906 795 926 677 926 656C929 677 917 795 917 830ZM922 830C920 791 889 657 894 634C894 657 934 791 935 830ZM939 830C939 797 933 686 934 667C935 686 947 797 947 830ZM956 830C956 798 968 688 968 668C971 688 966 798 965 830ZM975 830C975 787 973 639 974 613C976 639 984 787 984 830ZM1007 830C1005 799 988 692 993 673C993 692 1019 799 1021 830ZM1014 830C1015 793 1039 669 1038 647C1042 669 1027 793 1025 830ZM1046 830C1044 791 1039 658 1044 634C1042 658 1056 791 1058 830ZM1067 830C1069 790 1087 653 1085 629C1090 653 1079 790 1077 830ZM1097 830C1098 795 1124 676 1125 655C1127 676 1106 795 1105 830ZM1112 830C1114 794 1162 670 1160 648C1165 670 1126 794 1124 830ZM1132 830C1132 801 1137 702 1139 685C1140 702 1144 801 1144 830ZM1152 830C1153 790 1203 655 1201 632C1207 655 1167 790 1165 830ZM1159 830C1158 793 1120 665 1123 643C1122 665 1165 793 1167 830ZM1194 830C1194 799 1209 693 1211 674C1213 693 1207 799 1207 830ZM1195 830C1196 792 1220 662 1219 639C1223 662 1207 792 1206 830ZM1233 830C1232 795 1190 677 1194 656C1192 677 1240 795 1242 830Z"/>
<Fill color="#1F4D42"/>
</Group>
</Layer>
<Layer alpha="0.6">
<Group>
<Path data="M-67 825C-67 797 -62 703 -60 687C-59 703 -57 797 -57 825ZM-36 825C-36 791 -61 674 -59 653C-58 674 -26 791 -26 825ZM-8 825C-6 794 31 690 30 672C34 690 3 794 1 825ZM17 825C16 789 23 667 24 646C25 667 24 789 24 825ZM47 825C47 790 60 671 61 650C62 671 54 790 54 825ZM85 825C85 791 71 677 74 657C75 677 96 791 96 825ZM95 825C95 797 114 703 115 686C116 703 102 797 102 825ZM135 825C136 791 144 673 143 653C146 673 142 791 141 825ZM158 825C159 799 167 713 166 697C170 713 169 799 167 825ZM175 825C176 797 206 701 205 684C208 701 183 797 182 825ZM203 825C203 801 209 721 209 707C210 721 209 801 209 825ZM241 825C241 803 266 727 267 714C269 727 252 803 252 825ZM261 825C260 803 233 728 236 714C236 728 270 803 271 825ZM278 825C277 801 284 718 287 703C288 718 289 801 290 825ZM304 825C302 795 268 694 273 676C272 694 313 795 315 825ZM330 825C329 792 339 679 342 659C341 679 335 792 337 825ZM362 825C360 794 340 687 345 669C343 687 371 794 373 825ZM387 825C385 791 366 674 371 653C370 674 396 791 398 825ZM413 825C414 803 429 728 429 715C433 728 426 803 425 825ZM442 825C442 790 451 669 451 648C454 669 452 790 452 825ZM468 825C468 792 460 682 461 662C462 682 475 792 475 825ZM500 825C500 799 502 712 502 696C505 712 508 799 508 825ZM510 825C509 800 498 713 500 698C500 713 518 800 519 825ZM553 825C552 790 573 670 574 649C575 670 561 790 561 825ZM565 825C565 790 580 672 583 651C584 672 577 790 578 825ZM588 825C588 797 615 702 616 685C618 702 596 797 596 825ZM629 825C630 796 636 697 636 679C639 697 640 796 639 825ZM638 825C638 791 639 674 641 653C642 674 649 791 649 825ZM660 825C662 800 688 716 687 701C691 716 674 800 672 825ZM698 825C699 789 741 669 741 647C745 669 711 789 710 825ZM713 825C715 793 755 683 754 664C759 683 726 793 724 825ZM750 825C749 799 740 712 742 697C742 712 755 799 757 825ZM767 825C769 795 793 695 793 677C796 695 776 795 775 825ZM799 825C797 798 766 706 770 689C769 706 808 798 810 825ZM825 825C827 800 849 714 848 699C851 714 833 800 831 825ZM848 825C849 798 859 706 858 690C862 706 861 798 859 825ZM873 825C872 792 849 678 853 658C852 678 883 792 884 825ZM910 825C911 793 903 683 904 663C905 683 917 793 917 825ZM925 825C926 794 939 689 940 670C942 689 939 794 938 825ZM954 825C956 797 962 703 961 686C964 703 963 797 961 825ZM994 825C993 792 1008 680 1011 660C1011 680 1005 792 1005 825ZM1009 825C1008 794 1024 690 1026 672C1028 690 1021 794 1021 825ZM1028 825C1028 800 1047 716 1048 701C1049 716 1034 800 1035 825ZM1070 825C1071 796 1082 696 1082 679C1085 696 1079 796 1078 825ZM1085 825C1086 802 1111 722 1112 708C1115 722 1099 802 1098 825ZM1105 825C1106 797 1149 701 1148 684C1152 701 1117 797 1115 825ZM1139 825C1139 801 1165 718 1167 703C1169 718 1151 801 1151 825ZM1163 825C1161 793 1139 685 1143 666C1142 685 1168 793 1170 825ZM1192 825C1192 800 1180 714 1181 698C1182 714 1199 800 1199 825ZM1228 825C1226 794 1223 691 1227 672C1227 691 1239 794 1240 825Z"/>
<Fill color="#255A4E"/>
</Group>
</Layer>
<Layer alpha="0.45">
<Group>
<Path data="M-67 832C-68 806 -61 717 -59 702C-58 717 -57 806 -56 832ZM-24 832C-23 804 4 710 4 693C6 710 -16 804 -17 832ZM12 832C11 802 6 698 9 680C8 698 19 802 20 832ZM42 832C41 798 13 683 17 663C17 683 54 798 55 832ZM66 832C67 803 95 706 94 689C97 706 77 803 75 832ZM87 832C88 805 95 715 95 699C99 715 101 805 100 832ZM112 832C113 806 124 716 125 700C127 716 122 806 122 832ZM141 832C142 804 171 710 171 693C173 710 149 804 148 832ZM168 832C166 801 151 695 155 677C154 695 174 801 176 832ZM201 832C199 797 160 678 165 657C163 678 209 797 211 832ZM231 832C233 804 253 708 252 691C257 708 244 804 242 832ZM260 832C259 806 255 716 258 701C259 716 270 806 271 832ZM283 832C283 806 292 717 293 701C294 717 291 806 290 832ZM314 832C313 795 327 668 329 645C329 668 320 795 321 832ZM360 832C361 803 354 704 353 686C356 704 369 803 368 832ZM384 832C385 802 402 700 402 682C406 700 397 802 395 832ZM407 832C408 797 447 677 446 656C449 677 416 797 415 832ZM433 832C433 796 427 675 428 654C431 675 445 796 445 832ZM462 832C463 806 460 717 461 701C464 717 476 806 475 832ZM494 832C492 795 469 668 474 646C472 668 503 795 505 832ZM514 832C513 795 503 669 506 646C507 669 527 795 528 832ZM545 832C545 801 548 694 551 675C552 694 556 801 557 832ZM574 832C575 801 608 696 607 678C611 696 585 801 584 832ZM605 832C603 795 575 670 580 648C579 670 615 795 616 832ZM637 832C637 800 671 690 672 670C675 690 651 800 650 832ZM678 832C677 797 647 680 651 659C650 680 687 797 688 832ZM692 832C692 792 672 655 674 631C674 655 700 792 700 832ZM716 832C717 800 732 693 732 673C736 693 731 800 729 832ZM755 832C755 802 778 700 778 682C780 700 764 802 763 832ZM790 832C790 795 778 668 780 645C782 668 803 795 803 832ZM811 832C813 799 827 689 826 669C830 689 826 799 824 832ZM836 832C836 801 845 695 847 676C847 695 843 801 843 832ZM869 832C868 799 860 688 865 668C864 688 880 799 882 832ZM895 832C896 795 932 668 932 646C936 668 909 795 908 832ZM936 832C935 797 914 680 918 659C916 680 942 797 943 832ZM962 832C964 799 1004 686 1003 666C1008 686 975 799 973 832ZM998 832C1000 806 1030 716 1029 700C1033 716 1007 806 1005 832ZM1012 832C1011 803 1027 705 1029 688C1031 705 1024 803 1024 832ZM1043 832C1042 793 1027 661 1031 638C1031 661 1054 793 1055 832ZM1071 832C1070 806 1070 717 1074 701C1074 717 1083 806 1084 832ZM1097 832C1098 794 1124 667 1123 644C1127 667 1110 794 1109 832ZM1131 832C1131 802 1149 699 1150 680C1152 699 1141 802 1141 832ZM1150 832C1149 798 1132 683 1135 662C1134 683 1156 798 1157 832ZM1179 832C1177 800 1166 689 1170 670C1169 689 1189 800 1190 832ZM1223 832C1221 800 1227 692 1230 673C1229 692 1230 800 1231 832Z"/>
<Fill color="#2D6B5A"/>
</Group>
</Layer>
<Layer alpha="0.2">
<Group>
<Ellipse position="300,590" size="450,50"/>
<Fill>
<RadialGradient center="300,590" radius="225">
<ColorStop offset="0" color="#8B5CF6"/>
<ColorStop offset="1" color="#8B5CF600"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="600,578" size="380,40"/>
<Fill>
<RadialGradient center="600,578" radius="190">
<ColorStop offset="0" color="#A78BFA"/>
<ColorStop offset="1" color="#A78BFA00"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="880,570" size="400,42"/>
<Fill>
<RadialGradient center="880,570" radius="200">
<ColorStop offset="0" color="#06B6D4"/>
<ColorStop offset="1" color="#06B6D400"/>
</RadialGradient>
</Fill>
</Group>
<Group>
<Ellipse position="130,600" size="280,35"/>
<Fill>
<RadialGradient center="130,600" radius="140">
<ColorStop offset="0" color="#7C3AED"/>
<ColorStop offset="1" color="#7C3AED00"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Layer alpha="0.7" x="700" y="110">
<Group>
<Path data="M0 0L85 0"/>
<Stroke>
<LinearGradient startPoint="0,0" endPoint="85,0">
<ColorStop offset="0" color="#FFFFFF00"/>
<ColorStop offset="0.3" color="#FFFFFF40"/>
<ColorStop offset="0.7" color="#FFFFFFCC"/>
<ColorStop offset="1" color="#FFFFFF"/>
</LinearGradient>
</Stroke>
</Group>
<Group>
<Ellipse position="85,0" size="4,4"/>
<Fill color="#FFFFFF"/>
</Group>
</Layer>
<Layer alpha="0.45" x="400" y="205">
<Group>
<Path data="M0 0L50 0"/>
<Stroke>
<LinearGradient startPoint="0,0" endPoint="50,0">
<ColorStop offset="0" color="#FFFFFF00"/>
<ColorStop offset="0.4" color="#FFFFFF30"/>
<ColorStop offset="1" color="#FFFFFFAA"/>
</LinearGradient>
</Stroke>
</Group>
<Group>
<Ellipse position="50,0" size="3,3"/>
<Fill color="#FFFFFFAA"/>
</Group>
</Layer>
<Layer alpha="0.5" x="1150" y="48">
<Group>
<Path data="M0 0L45 0"/>
<Stroke>
<LinearGradient startPoint="0,0" endPoint="45,0">
<ColorStop offset="0" color="#67E8F900"/>
<ColorStop offset="0.5" color="#67E8F940"/>
<ColorStop offset="1" color="#67E8F9"/>
</LinearGradient>
</Stroke>
</Group>
<Group>
<Ellipse position="45,0" size="6,6"/>
<Fill color="#67E8F9"/>
</Group>
<Group>
<Ellipse position="45,0" size="14,14"/>
<Fill>
<RadialGradient center="45,0" radius="7">
<ColorStop offset="0" color="#67E8F945"/>
<ColorStop offset="1" color="#67E8F900"/>
</RadialGradient>
</Fill>
</Group>
</Layer>
<Resources>
<Composition id="comp1" width="3" height="3">
<Layer id="compLayer1">
<Ellipse size="3,3"/>
<Fill color="#FFFFFF"/>
</Layer>
</Composition>
<Composition id="comp2" width="3" height="3">
<Layer id="compLayer2">
<Ellipse size="3,3"/>
<Fill color="#FFFFFFBB"/>
</Layer>
</Composition>
<Composition id="comp3" width="3" height="3">
<Layer id="compLayer3">
<Ellipse size="3,3"/>
<Fill color="#A78BFA"/>
</Layer>
</Composition>
<Composition id="comp4" width="2" height="2">
<Layer id="compLayer4">
<Ellipse size="2,2"/>
<Fill color="#FFFFFFCC"/>
</Layer>
</Composition>
<Composition id="comp5" width="2" height="2">
<Layer id="compLayer5">
<Ellipse size="2,2"/>
<Fill color="#FFFFFFAA"/>
</Layer>
</Composition>
<Composition id="comp6" width="2" height="2">
<Layer id="compLayer6">
<Ellipse size="2,2"/>
<Fill color="#FFFFFFBB"/>
</Layer>
</Composition>
<Composition id="comp7" width="2" height="2">
<Layer id="compLayer7">
<Ellipse size="2,2"/>
<Fill color="#FFFFFF"/>
</Layer>
</Composition>
</Resources>
</pagx>