API 文档
设计一个 Glance Widgets 能够渲染的接口,你需要知道的都在这里:小组件会发送什么请求、你的接口应当返回什么格式的响应,以及渲染器遵循的规则。本页每个实时示例,都由与 App 相同的规则渲染。
概览#
Glance Widgets 小组件由对你自己接口的一次 HTTPS GET 请求驱动。接口返回一个 JSON 对象,即一帧画面,用来描述要绘制的内容。App 会校验并规范化这一帧,再由 WidgetKit 渲染到主屏幕上。
一帧画面包含两个相互叠加的表达通道:
- 根点阵(
pixels):最多 4,096 个点位的矩形点阵,以整个小组件画布为布局区域。可以为每个点单独设置样式,也可以把大部分交给default与batch。 - 图层:带定位尺寸的内容元素,包括文字、曲线、图片、图标、线条、形状与局部点阵。
data 中的图片,让服务端渲染整张画面,见服务端整图渲染。快速开始#
最小的有效响应就是一个点阵。像素点样式数组中的元素为 null 继承 default,显式对象则覆盖它。
{
"protocol": 1,
"default": { "color": "#8EC8FB", "opacity": 0.12, "cornerRadius": 0.5 },
"pixels": [
[null, null, null, null, null],
[
null,
{ "color": "#7EDDB5", "opacity": 1 },
null,
{ "color": "#7EDDB5", "opacity": 1 },
null
],
[null, null, null, null, null],
[
{ "color": "#DFFF70", "opacity": 1 },
null,
null,
null,
{ "color": "#DFFF70", "opacity": 1 }
],
[
null,
{ "color": "#DFFF70", "opacity": 1 },
{ "color": "#DFFF70", "opacity": 1 },
{ "color": "#DFFF70", "opacity": 1 },
null
]
]
}- 把接口部署到任何支持 HTTPS 的地方。
- 在 App 中创建一个小组件,并将 URL 粘贴到 API 字段。
- 以真实主屏幕尺寸预览,然后将小组件添加到主屏幕。
小组件的内容结构#
卡片的材质与内容
小组件的表达由卡片本身的风格材质和卡片中的内容构成。风格材质只能在 App 或未来某些其他平台的自定义小组件编辑器中设置,无法通过 API 指定、动态更新。API 负责的是卡片中的内容及其样式。
卡片中的图层有两个来源。第一种是编辑器图层:在编辑器的可视化操作台中手动添加、摆放和设置,保存在小组件配置里。它可以完全静态;也可以填写一个数据路径,让 API 在每次响应中更新它的位置、内容与样式,此时编辑器中的设置就是首次取得数据前的初始状态,也是响应缺少某个字段时的兜底。
第二种是远程图层:编辑器中不做任何配置,由 API 在每次响应中声明。它可以是小组件配置里根本没有的内容,内容的原始定义完全来自 API。两种图层可以同时使用,具体写法见“响应体”和“图层”。
基础图层与点阵
在 Glance Widgets 里,可以通过添加文本、直线、曲线、图片、图标、形状等类型的图层,实现对基础内容的表达;它们的摆放可以重叠,通过专门的 zIndex 字段控制层级。
在此基础上,为了便捷地拓展表现力,同时保持描述、解析的简单易用,又提供了点阵类型。用户可以通过自己的服务端程序,实现各种想要的表达。像素屏这一实质,使得丰富的表达成为可能,而描述起来又仅仅是一个二维数组,非常简单。前面几种基本类型的内容,也同样可以通过像素点阵表达,实现像素风,完全取决于个人偏好与需要;实际精细度受点阵单元数预算限制。
点阵的表达同样分为两种。点阵图层(type: "matrix")和前面几种图层一样,在容器画布的指定位置、尺寸开辟一片区域,绘制局部点阵,其内容 content 就是一份点阵。另一种是根点阵(顶层 pixels):它不属于图层系统,而是在整个小组件内容画布上布局。根点阵的样式系统、渲染规则和 API 形式,与点阵图层没有本质区别。额外设立这一机制,主要是为了在只需要统一样式的纯像素风点阵表达一个简单主题、无需把多个局部点阵与其他图层组合时,让实现更简单直接。根点阵按 layout 等比适配并居中;是否视觉上铺满卡片,取决于点阵与画布的宽高比、间距及边缘设置。
点阵本身是由数个点单元构成的网格系统。用户除了可以定义每个点的样式,还可以让某个点不显示。确切地说,网格系统随着局部或整个根点阵的开辟始终存在,逻辑上的点位不会消失,但你可以决定某些点位什么都不显示、空出来,就像老式黑底红字的像素屏一样。以此空出特定区域,实现特定样式,或叠加其他内容图层,共同构成表达。{"empty": true} 的具体规则会在“像素与优先级”中展开。
最终的三层结构
- 最底层:卡片风格材质,作为背景板和容器,由编辑器配置。
- 中间层:根点阵,在整个内容画布上布局,可以局部留白,也可以完全留空。
- 最上层:各种内容图层,包括编辑器图层和 API 声明的远程图层,统一按
zIndex合成。局部点阵也属于这一层。
请求#
小组件发送 HTTPS GET 请求。你自己的查询参数会被保留,App 会追加保留的 gw_* 参数,用来描述它要绘制的空间。非 HTTPS 的 URL 会被拒绝。
| 参数 | 示例 | 说明 |
|---|---|---|
gw_protocol | 1 | 客户端使用的协议版本。 |
gw_platform | ios | 客户端平台。 |
gw_family | small · medium · large | 小组件尺寸类型。 |
gw_canvas_width_pt | 158.00 | 可用内容画布宽度,以 iOS 逻辑像素(pt)计,保留两位小数。 |
gw_canvas_height_pt | 158.00 | 可用内容画布高度,以 iOS 逻辑像素(pt)计,保留两位小数。 |
gw_aspect_ratio | 1.0000 | 宽 ÷ 高(保留四位小数)。 |
gw_context | app_preview | 渲染上下文。app_home:App 首页;app_preview:编辑预览;widget:主屏幕小组件。 |
gw_state_<key> | — | 为未来的交互状态扩展预留,当前请求流程尚未使用。所有 gw_ 开头的参数名均由客户端保留使用,请勿用作自定义查询参数。 |
gw_protocol- 示例
1 - 说明客户端使用的协议版本。
gw_platform- 示例
ios - 说明客户端平台。
gw_family- 示例
small·medium·large - 说明小组件尺寸类型。
gw_canvas_width_pt- 示例
158.00 - 说明可用内容画布宽度,以 iOS 逻辑像素(pt)计,保留两位小数。
gw_canvas_height_pt- 示例
158.00 - 说明可用内容画布高度,以 iOS 逻辑像素(pt)计,保留两位小数。
gw_aspect_ratio- 示例
1.0000 - 说明宽 ÷ 高(保留四位小数)。
gw_context- 示例
app_preview - 说明渲染上下文。
app_home:App 首页;app_preview:编辑预览;widget:主屏幕小组件。 gw_state_<key>- 示例—
- 说明为未来的交互状态扩展预留,当前请求流程尚未使用。所有
gw_开头的参数名均由客户端保留使用,请勿用作自定义查询参数。
pt 是 iOS 的逻辑尺寸单位,在 App 的 Flutter 端对应逻辑像素,不是屏幕物理像素,也不是点阵点位数。例如在 3 倍屏幕缩放倍率下,158 pt 对应 474 个物理像素的长度。这两个参数都已扣除卡片的内容内边距:宽度 = 小组件外框宽度 − 2 × contentInset,高度同理,最小值为 1 pt。
画布尺寸因设备而异。在宽度为 390–393 pt 的 iPhone 上,各尺寸大致为 158 × 158(小)、338 × 158(中)和 338 × 354(大)。
GET https://api.example.com/widget?team=core&gw_protocol=1&gw_platform=ios&gw_family=medium&gw_canvas_width_pt=338.00&gw_canvas_height_pt=158.00&gw_aspect_ratio=2.1392&gw_context=app_preview超时较短:App 中发送约 8 秒,接收约 12 秒。任何 2xx 状态码都视为成功。请返回 UTF-8 编码的 JSON,并尽量带上 Content-Type: application/json。
响应体#
响应体必须是一个 UTF-8 JSON 对象,最大 512 KB。protocol 可省略,建议显式返回 1;其他非空版本值不受支持。它描述本次请求的一帧内容,按三组理解:根点阵、数据根 data、远程图层声明 layers。未知的顶层字段会被忽略。
根点阵:pixels、default、layout、batch
pixels 确定网格的m*n大小并描述点的样式,layout 决定这些点如何组合成整体。复杂画面即便用服务端程序拼接二维数组,逐点绘制仍然繁琐;因此用 batch 表达一批相同样式的点,用 default 处理没有单独声明样式的点。
| 字段 | 类型 / 取值 | 用途与规则 |
|---|---|---|
pixels | (Pixel | null)[][] | 根点阵内容,必填。每个元素对应网格中一个点的样式,按 pixels[row][column] 访问;原点在左上角。矩形、至少 1 × 1,最多 4,096 个点位。 |
default | Pixel | 没有单独声明样式时采用的缺省值;也为显式像素对象和每个 batch 的省略字段提供回退值。 |
layout | MatrixLayout | 描述整个根点阵如何组合、布局:点之间的间距、单元宽高比、所占空间的边缘如何处理。它不描述单个点的颜色或形状。 |
batch | { pixel, coordinates }[] | 为一批具有相同样式的点声明 pixel,用从零开始的 [row, column] 坐标选中点位。适合由服务端程序生成规律图案,减少逐点重复声明。 |
pixels- 类型 / 取值
(Pixel | null)[][] - 用途与规则根点阵内容,必填。每个元素对应网格中一个点的样式,按
pixels[row][column]访问;原点在左上角。矩形、至少 1 × 1,最多 4,096 个点位。 default- 类型 / 取值
Pixel - 用途与规则没有单独声明样式时采用的缺省值;也为显式像素对象和每个 batch 的省略字段提供回退值。
layout- 类型 / 取值
MatrixLayout - 用途与规则描述整个根点阵如何组合、布局:点之间的间距、单元宽高比、所占空间的边缘如何处理。它不描述单个点的颜色或形状。
batch- 类型 / 取值
{ pixel, coordinates }[] - 用途与规则为一批具有相同样式的点声明
pixel,用从零开始的[row, column]坐标选中点位。适合由服务端程序生成规律图案,减少逐点重复声明。
覆盖顺序是 default → 按数组顺序应用 batch → pixels 中的显式对象。null 保留 default / batch 的结果;显式对象中省略的字段回退到 default,不会逐字段叠加 batch。这里“省略点的样式”是用 null 保留点位,不能删掉数组元素或缩短某一行。具体规则和示例见“像素与优先级”。
数据根:data
data 是一个可选对象,省略时为空对象,用来存放图层要读取的内容。字段名称与嵌套结构由你决定,可以按业务组织,例如把同一块面板的图层都放在 data.orders 下。图片材质的数据路径也从这里读取图片(见服务端整图渲染)。
data 本身只是一个可自由编排的对象,其值本身不会自动显示。编辑器内创建的动态内容,或你在 API 中构建返回的远程图层,会通过 dataPath 读取你指定的某个 data 内字段,并按照规则解析、绘制。如果这个字段是用来驱动编辑器图层或远程图层的,它必须是一个对象,并按图层类型遵循一定的协议规则。大体通用的结构是:在 dataPath 指向的这个字段里,包含该图层的位置、内容和样式,详见下面的 layers 和“图层”一章。
远程图层:layers
layers 是可选数组,省略时没有远程图层。数组中的每一项声明一个由 API 新增的图层,有且只有 id、type、dataPath 三个字段:id 以 remote: 开头且在本次响应中唯一,type 是七种图层类型之一,dataPath 指向 data 中描述这个图层的对象。
图层的位置、内容和样式不写在 layers 的条目里,而是写在 dataPath 指向的对象里:frame、zIndex、rotation、transform 决定尺寸和布局,content 是内容,style 是样式。远程图层完全由这个对象构造,所以必须带有 frame。
{
"protocol": 1,
"pixels": [[{ "empty": true }]],
"data": {
"orders": {
"badge": {
"frame": { "right": 0.07, "top": 0.14, "width": 0.24, "height": 0.2 },
"content": { "text": "LIVE" },
"style": { "color": "#0B1222", "backgroundColor": "#7EDDB5", "opacity": 1, "cornerRadiusRatio": 1 }
}
}
},
"layers": [
{ "id": "remote:badge", "type": "text", "dataPath": "data.orders.badge" }
]
}每次响应的 layers 描述当前这一帧的完整远程图层集合,下一次成功响应整体替换,不是增量修改指令。编辑器中添加的图层不在 layers 中声明,它们由编辑器里填写的数据路径绑定,规则见“图层”一章。
pixels 仍然必填。返回 [[{"empty": true}]] 可使根点阵完全留空,让图层显示在卡片材质之上。响应体完整类参考#
下面以树状嵌套对象和关联类型列出响应结构。? 表示字段可省略,[] 表示数组,| 表示可选类型;这是类型参考,不是可直接返回的 JSON。layers 中的 type 决定对应的 content / style 类型,不能把其他类型的字段混用。图层字段的具体用途、单位和生效条件见后文。
type WidgetResponse = {
protocol?: 1
pixels: (Pixel | null)[][]
default?: Pixel
layout?: MatrixLayout
batch?: Batch[]
// Objects that layers point to live anywhere in data; layers only declare remote layers.
data?: { [key: string]: JsonValue | LayerNode }
layers?: {
id: `remote:${string}`
type: 'text' | 'matrix' | 'curve' | 'image' | 'icon' | 'line' | 'shape'
dataPath: string // points to the object in data that describes this layer
}[]
}
// The object a dataPath points to. type selects content and style:
// text → TextContent / TextStyle, matrix → MatrixContent / (none),
// curve → CurveContent / CurveStyle, image → ImageContent / ImageStyle,
// icon → IconContent / IconStyle, line → LineContent / LineStyle,
// shape → (none) / ShapeStyle
type LayerNode = {
frame?: Frame // required for remote layers
zIndex?: number
rotation?: number
transform?: { translateX?: number; translateY?: number }
content?: object
style?: object
}
type Frame = {
width: number; height: number
left?: number; right?: number; top?: number; bottom?: number
}
type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue }
type Color = string // #RRGGBB / #AARRGGBB
type GapMode = 'zero' | 'near' | 'default' | 'far' | 'extraFar'
type Pixel = {
color?: Color; opacity?: number; cornerRadius?: number
rotation?: number; halo?: number; empty?: boolean
}
type Batch = { pixel: Pixel; coordinates: [row: number, column: number][] }
type MatrixLayout = {
gapMode?: GapMode; edgeInsetRatio?: number; cellAspectRatio?: number
columnGapRatio?: number; rowGapRatio?: number
}
type MatrixContent = {
pixels?: (Pixel | null)[][] // required for remote layers
default?: Pixel; batch?: Batch[]; layout?: MatrixLayout
}
type TextContent = { text?: string | number }
type TextStyle = ChromeStyle & {
color?: Color; textOpacity?: number; fontSizeRatio?: number
fontWeight?: '300' | '400' | '500' | '600' | '700'
fontFamily?: 'system' | 'systemMonospace' | 'monospace'
fontFamilyFallback?: string[]; letterSpacing?: number; baselineRatio?: number
horizontalAlignment?: 'left' | 'center' | 'right'
verticalAlignment?: 'top' | 'center' | 'bottom'
autoWrap?: boolean; paddingRatio?: number
}
type ChromeStyle = EffectsStyle & {
backgroundColor?: Color; opacity?: number
cornerRadiusRatio?: number
borderColor?: Color; borderOpacity?: number; borderWidth?: number
gradientEnabled?: boolean; gradientColors?: Color[]
gradientStops?: number[]; gradientAngle?: number
}
type EffectsStyle = {
maskColor?: Color; maskOpacity?: number
vignetteIntensity?: number
readabilityGradient?: 'none' | 'top' | 'bottom' | 'left' | 'right' | 'both'
| 'topLeftDiagonal' | 'topRightDiagonal'
}
type ShapeStyle = ChromeStyle & { color?: Color }
type ImageContent = { url?: string }
type ImageStyle = ChromeStyle & { color?: Color }
type IconContent =
| {
icon?: string; iconCodePoint?: number
iconFont?: 'phosphorBold' | 'devicon' | 'simpleIcons' | 'material'
}
| { url?: string }
type IconStyle = {
color?: Color; textOpacity?: number
iconGlowEnabled?: boolean; iconGlowColor?: Color
iconGlowOpacity?: number; iconGlowRadius?: number
}
type LineContent = { direction?: 'horizontal' | 'vertical' }
type LineStyle = {
color?: Color; opacity?: number; strokeWidth?: number
pattern?: 'solid' | 'dashed' | 'dotted'; cap?: 'round' | 'butt'
dashLength?: number; dashGap?: number
gradientEnabled?: boolean; gradientColors?: Color[]; gradientStops?: number[]
}
type CurveContent = {
mode?: 'samples' | 'function'
points?: [x: number, y: number][]
expression?: string; parameters?: { [name: string]: number }
domain?: [number, number]; yDomain?: [number, number]
interpolation?: 'linear' | 'stepAfter' | 'monotone'
markers?: {
at: { x?: number; sampleIndex?: number; offsetPt?: [number, number] }
symbol?: { shape?: 'circle'; radiusPt?: number; fill?: Color }
label?: string
labelStyle?: {
color?: Color; fontSizePt?: number
position?: 'top' | 'bottom' | 'left' | 'right'
}
}[]
}
type CurveStyle = {
color?: Color; opacity?: number; strokeWidth?: number
lineCap?: 'round' | 'butt' | 'square'; lineJoin?: 'round' | 'bevel' | 'miter'
dashLength?: number; dashGap?: number
fillColor?: Color; fillOpacity?: number; plotPadding?: number
}像素样式#
以下字段描述单个像素点的样式,写在根点阵的 default、batch[].pixel 或 pixels[row][column] 中,也适用于点阵图层 content 中的 default、batch[].pixel 和 pixels。
| 字段 | 范围 | 说明 |
|---|---|---|
color | #RRGGBB · #AARRGGBB | 十六进制颜色。8 位形式是透明度在前(ARGB),而不是 CSS 的 #RRGGBBAA。 |
opacity | 0 – 1 | 控制点的可见度,超出范围会被截断;与颜色的 alpha 相乘,0 完全透明,1 不额外降低不透明度。 |
cornerRadius | 0 – 0.5 | 圆角半径相对于像素点短边:0 为直角,0.5 为最大圆角;正方形像素点此时为圆形,矩形像素点为胶囊形。 |
rotation | 度 | 45 会把方形变成菱形。 |
halo | 0 – 1 | 点的发光强度,0 为关闭;用于强调亮点或营造像素屏的发亮质感。 |
empty | boolean | true 表示跳过该像素点的绘制。 |
color- 范围
#RRGGBB·#AARRGGBB - 说明十六进制颜色。8 位形式是透明度在前(ARGB),而不是 CSS 的
#RRGGBBAA。 opacity- 范围0 – 1
- 说明控制点的可见度,超出范围会被截断;与颜色的 alpha 相乘,
0完全透明,1不额外降低不透明度。 cornerRadius- 范围0 – 0.5
- 说明圆角半径相对于像素点短边:
0为直角,0.5为最大圆角;正方形像素点此时为圆形,矩形像素点为胶囊形。 rotation- 范围度
- 说明
45会把方形变成菱形。 halo- 范围0 – 1
- 说明点的发光强度,
0为关闭;用于强调亮点或营造像素屏的发亮质感。 empty- 范围boolean
- 说明
true表示跳过该像素点的绘制。
根点阵如果省略 default,像素点的初始值为 color #0A2D48、opacity 0.28、cornerRadius 0.18。需要鲜明、完全不透明的颜色时,请设置 opacity: 1。
像素与优先级#
每个单元按固定顺序解析,优先级从低到高:
default(若未提供,则使用内置初始值)- 每个
batch条目,按数组顺序,后面的样式对象替换前面的;每项省略的属性均从 default 补齐 pixels中显式的非 null 值
null 表示此处不覆盖,而不是透明。{"empty": true} 是显式留白:不绘制任何内容,但该单元仍占据点阵中的位置。显式的像素对象在省略颜色等字段时回退到 default,而不是下层的 batch 样式。empty 是显式留白标记:当 default 为 {"empty": true} 时,null 点位仍为空,但显式的普通像素对象会重新绘制该点。
{
"protocol": 1,
"layout": { "gapMode": "near" },
"default": { "color": "#18313A", "opacity": 0.34, "cornerRadius": 0.18 },
"pixels": [
[
{ "color": "#7CFFB2", "cornerRadius": 0.18 },
null,
{ "color": "#F4BC54", "rotation": 45 }
],
[
{ "empty": true },
{ "color": "#FFFFFF", "opacity": 0.7 },
null
]
],
"batch": [
{
"pixel": { "color": "#38A6FF", "cornerRadius": 0.5, "opacity": 1 },
"coordinates": [
[0, 1],
[1, 2]
]
}
]
}Batch 坐标是从零开始的 [row, column] 整数对,且必须位于点阵之内;超出范围的坐标会让 App 拒绝整个画面。
点阵布局#
以下字段描述整个点阵的布局,写在响应体的 layout 对象中,也适用于点阵图层的 content.layout。
点阵会等比适配到画布内(contain)并居中,保留像素点的宽高比。间距与边缘留白均以像素点的短边为基准;它们不是相对于整个卡片的百分比。edgeInsetRatio、columnGapRatio 和 rowGapRatio 的取值表示单个像素点短边长度的倍数,gapMode 用于选择预设的间距倍数;cellAspectRatio 则表示像素点的宽高比。
| 字段 | 取值 | 默认值 | 用途 |
|---|---|---|---|
gapMode | zero · near · default · far · extraFar | default | 相邻像素点之间的间距预设,依次为单个像素点短边长度的 0、0.08、0.16、0.28、0.42 倍,同时用于水平和垂直方向。 |
edgeInsetRatio | −0.45–0.45 | 0 | 点阵四周的边缘留白 = 单个像素点短边长度 × 此值。正值增加留白;负值让边缘像素点向绘制区域外延伸,超出部分会被裁剪。 |
cellAspectRatio | 0.1–10 | 1 | 单个像素点的宽度 ÷ 高度。1 为正方形,小于 1 为竖向长条,大于 1 为横向长条;不改变点阵的行数和列数。 |
columnGapRatio | 0–10 | — | 相邻两列像素点之间的水平间距 = 单个像素点短边长度 × 此值。设置后覆盖 gapMode 的水平间距,省略时使用 gapMode 预设。 |
rowGapRatio | 0–10 | — | 相邻两行像素点之间的垂直间距 = 单个像素点短边长度 × 此值。设置后覆盖 gapMode 的垂直间距,省略时使用 gapMode 预设。 |
gapMode- 取值
zero·near·default·far·extraFar - 默认值
default - 用途相邻像素点之间的间距预设,依次为单个像素点短边长度的
0、0.08、0.16、0.28、0.42倍,同时用于水平和垂直方向。 edgeInsetRatio- 取值−0.45–0.45
- 默认值
0 - 用途点阵四周的边缘留白 = 单个像素点短边长度 × 此值。正值增加留白;负值让边缘像素点向绘制区域外延伸,超出部分会被裁剪。
cellAspectRatio- 取值0.1–10
- 默认值
1 - 用途单个像素点的宽度 ÷ 高度。
1为正方形,小于1为竖向长条,大于1为横向长条;不改变点阵的行数和列数。 columnGapRatio- 取值0–10
- 默认值—
- 用途相邻两列像素点之间的水平间距 = 单个像素点短边长度 × 此值。设置后覆盖
gapMode的水平间距,省略时使用gapMode预设。 rowGapRatio- 取值0–10
- 默认值—
- 用途相邻两行像素点之间的垂直间距 = 单个像素点短边长度 × 此值。设置后覆盖
gapMode的垂直间距,省略时使用gapMode预设。
aspect = cellAspectRatio
short = min(aspect, 1)
gx = (columnGapRatio ?? gapModeRatio) * short
gy = (rowGapRatio ?? gapModeRatio) * short
inset = edgeInsetRatio * short
spanX = columns * aspect + (columns - 1) * gx + 2 * inset
spanY = rows + (rows - 1) * gy + 2 * inset
cellHeight = min(canvasWidth / spanX, canvasHeight / spanY)
cellWidth = cellHeight * aspect{
"protocol": 1,
"default": { "color": "#FFFFFF", "opacity": 0.1, "cornerRadius": 0.5 },
"layout": { "gapMode": "near", "cellAspectRatio": 0.32, "edgeInsetRatio": 0.45 },
"pixels": [
[
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#FFB86B", "opacity": 1 },
{ "color": "#FFB86B", "opacity": 1 },
{ "color": "#FFB86B", "opacity": 1 },
null,
null,
null,
null,
null,
null,
null
]
]
}图层#
图层是扁平的,没有嵌套,也没有子级。它们绘制在根点阵之上,远程图层与编辑器图层一起按 zIndex 合成,zIndex 相同时按 id 排序。
图层声明
layers 中的每一项声明一个远程图层:
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 以 remote: 开头,在本次响应中唯一。用于区分图层,并在 zIndex 相同时决定绘制顺序。 |
type | string | text · matrix · curve · image · icon · line · shape,决定 dataPath 指向的对象中 content、style 可用的字段。 |
dataPath | string | 描述这个图层的对象在 data 中的位置,语法见下文“数据路径”。 |
id- 类型string
- 说明以
remote:开头,在本次响应中唯一。用于区分图层,并在zIndex相同时决定绘制顺序。 type- 类型string
- 说明
text·matrix·curve·image·icon·line·shape,决定dataPath指向的对象中content、style可用的字段。 dataPath- 类型string
- 说明描述这个图层的对象在
data中的位置,语法见下文“数据路径”。
声明多出或缺少字段、id 前缀错误或重复、type 未知、dataPath 语法错误时,整个响应无效。
描述动态图层
不论是在编辑器内添加、作为自定义小组件配置保存的编辑器图层,还是纯 API 返回的远程图层,它们都通过一个路径指向 data 内的某个字段。前者在编辑器内对应的表单项中填写路径,后者则写在前面提到的 dataPath 字段中。dataPath 指向的对象结构都相同,由布局、内容和样式三部分组成:
| 字段 | 类型 | 说明 |
|---|---|---|
frame | object | 位置与尺寸,详见下文。远程图层必填;编辑器图层可选,给出时整体替换编辑器中的位置与尺寸。 |
zIndex | integer | 叠放顺序,较大值绘制在较小值之上。远程图层默认 0。 |
rotation | 度 | 围绕图层中心旋转整个图层。远程图层默认 0;点阵中单个点的旋转使用像素样式的 rotation。 |
transform | object | translateX、translateY:在 frame 定位之后再平移,单位是图层自身宽、高的比例。 |
content | object | 图层内容,字段由 type 决定,见“图层样式与内容”。 |
style | object | 图层样式,字段由 type 决定。matrix 没有样式字段,因为它的样式中,有关整体点阵呈现的基本属于 layout,有关某个具体像素点绘制的信息则放在了 pixels 的二维数组中,包括默认缺省样式、点批量应用样式,也都放在了 content 中。 |
frame- 类型object
- 说明位置与尺寸,详见下文。远程图层必填;编辑器图层可选,给出时整体替换编辑器中的位置与尺寸。
zIndex- 类型integer
- 说明叠放顺序,较大值绘制在较小值之上。远程图层默认
0。 rotation- 类型度
- 说明围绕图层中心旋转整个图层。远程图层默认
0;点阵中单个点的旋转使用像素样式的rotation。 transform- 类型object
- 说明
translateX、translateY:在frame定位之后再平移,单位是图层自身宽、高的比例。 content- 类型object
- 说明图层内容,字段由
type决定,见“图层样式与内容”。 style- 类型object
- 说明图层样式,字段由
type决定。matrix没有样式字段,因为它的样式中,有关整体点阵呈现的基本属于layout,有关某个具体像素点绘制的信息则放在了pixels的二维数组中,包括默认缺省样式、点批量应用样式,也都放在了content中。
该对象只接受上表中的字段,content、style 也只接受对应类型字段表中的字段。字段省略或为 null 都表示“不提供”。
小组件图层的合并规则
- 优先级为
dataPath指向的对象 > 编辑器设置 > 渲染器默认值。 content、style中的对象字段逐字段合并到编辑器保存的值上,例如点阵的content.default、content.layout;字符串、数字、布尔值和数组整体替换。frame总是整体替换:锚点只有放在一起才有意义,把响应的right合并到编辑器保存的left上,只会被left压过。因此给出frame时必须包含width和height。- 字段省略或为
null时沿用编辑器的值;0、false和空数组都是有效的覆盖值。 - 每次响应都从保存的配置重新计算。下一次响应不再返回某个字段时,该字段恢复为编辑器设置;请求失败时继续显示最近一次成功的响应。
点阵、文本、曲线、线条和形状图层在编辑器中有「当前预览」开关,它只决定编辑页显示什么:选择默认样式时,编辑页只显示编辑器中的值,方便调整兜底外观。App 首页、主屏幕和 StandBy 始终应用响应中的值。
[
{
"id": "local:title",
"type": "text",
"frame": { "left": 0.07, "top": 0.12, "width": 0.6, "height": 0.16 },
"zIndex": 10,
"content": { "text": "Orders today" },
"style": {
"color": "#A9C4E8",
"fontSizeRatio": 0.1,
"fontWeight": "500",
"horizontalAlignment": "left"
}
},
{
"id": "local:total",
"type": "text",
"frame": { "left": 0.07, "top": 0.32, "width": 0.6, "height": 0.4 },
"zIndex": 11,
"dataPath": "data.orders.total",
"content": { "text": "—" },
"style": {
"color": "#FFFFFF",
"fontSizeRatio": 0.26,
"fontWeight": "700",
"horizontalAlignment": "left"
}
}
]{
"protocol": 1,
"pixels": [
[
{ "empty": true }
]
],
"data": {
"orders": {
"total": {
"content": { "text": 128 },
"style": { "color": "#7EDDB5" }
},
"badge": {
"frame": {
"right": 0.07,
"top": 0.14,
"width": 0.24,
"height": 0.2
},
"zIndex": 12,
"content": { "text": "LIVE" },
"style": {
"color": "#0B1222",
"fontSizeRatio": 0.08,
"fontWeight": "700",
"horizontalAlignment": "center",
"verticalAlignment": "center",
"backgroundColor": "#7EDDB5",
"opacity": 1,
"cornerRadiusRatio": 1
}
}
}
},
"layers": [
{
"id": "remote:badge",
"type": "text",
"dataPath": "data.orders.badge"
}
]
}上例中,local:title 没有数据路径,始终显示编辑器中的文字;local:total 绑定 data.orders.total,该对象只给出文字和颜色,字号、字重和位置仍来自编辑器;remote:badge 由 layers 声明,位置、内容和样式全部来自 data.orders.badge。
位置与尺寸
frame 定义图层在内容画布中的位置和尺寸。所有值都用比例表示:水平方向以画布宽度为基准,垂直方向以画布高度为基准。例如 width: 0.5 表示图层宽度为画布宽度的一半,top: 0.1 表示图层上边缘距离画布顶部为画布高度的 10%。
- 宽高必填:
width、height设置图层宽高。给出frame时,两者都必须提供。 - 靠一侧定位:用
left/right、top/bottom设置与画布对应边缘的距离。例如right: 0.1表示图层右边缘距离画布右边缘为画布宽度的 10%。 - 同时指定两侧:
left和right同时设置时,图层填满两侧留白之间的宽度,width不参与计算。例如两者都为0.1,图层宽度就是画布宽度的 80%。top和bottom同理。 - 未指定位置:左右都不设置时,图层从画布最左侧开始;上下都不设置时,从最顶部开始。
width、height的取值限制在0.02–1.5。
{
"left": 0.1,
"top": 0.1,
"width": 0.4,
"height": 0.2
}若内容画布为 200 × 100 pt,上例会得到:距左侧 20 pt、距顶部 10 pt,图层宽 80 pt、高 20 pt。再加上 "transform": {"translateX": 0.5},图层会以自身宽度为单位右移一半,即再右移 40 pt。
| 字段 | 类型 / 范围 | 用途 |
|---|---|---|
width / height | 0.02–1.5 | 必填。宽度 / 高度占画布对应轴的比例;同轴两侧锚点同时存在时,该轴尺寸由两锚点决定。 |
left / right | number | 到左边 / 右边的距离占画布宽度的比例。两侧皆省略时从左侧 0 开始;仅 right 存在时右侧对齐。 |
top / bottom | number | 到顶边 / 底边的距离占画布高度的比例。两侧皆省略时从顶部 0 开始;仅 bottom 存在时底部对齐。 |
transform.translateX / translateY | number | 定位后的平移量,分别以图层自身的宽、高为单位;正值向右、向下。 |
width/height- 类型 / 范围0.02–1.5
- 用途必填。宽度 / 高度占画布对应轴的比例;同轴两侧锚点同时存在时,该轴尺寸由两锚点决定。
left/right- 类型 / 范围number
- 用途到左边 / 右边的距离占画布宽度的比例。两侧皆省略时从左侧 0 开始;仅 right 存在时右侧对齐。
top/bottom- 类型 / 范围number
- 用途到顶边 / 底边的距离占画布高度的比例。两侧皆省略时从顶部 0 开始;仅 bottom 存在时底部对齐。
transform.translateX/translateY- 类型 / 范围number
- 用途定位后的平移量,分别以图层自身的宽、高为单位;正值向右、向下。
数据路径
dataPath 从 data 开始,逐级访问字段与数字索引,例如 data.orders.total、data.cards[0]。不支持表达式、通配符或字符串键。它必须指向一个对象。
^data(?:\.[A-Za-z_][A-Za-z0-9_]*|\[[0-9]+\])*$`dataPath` 指向的对象出错时
这个对象的错误只影响对应的图层,不会使整个响应无效。路径不存在、指向的不是对象、出现对象本身或该类型不支持的字段、字段值的类型或取值不合法、frame 缺少 width 或 height、远程图层没有 frame、远程点阵没有 content.pixels 时:
- 编辑器图层回退到编辑器中保存的状态,App 在该图层的“数据路径”下方给出原因;
- 远程图层不绘制;
- 根点阵和其他图层照常显示。
数值超出字段表中列出的范围不算错误,渲染器会将其截断到可用范围。
{
"protocol": 1,
"default": { "color": "#8EC8FB", "opacity": 0.06, "cornerRadius": 0.5 },
"layout": { "gapMode": "far" },
"pixels": [
[null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]
],
"batch": [
{
"pixel": { "color": "#7EDDB5", "opacity": 1, "halo": 0.5 },
"coordinates": [
[7, 17]
]
}
],
"data": {
"orders": {
"title": {
"frame": {
"left": 0.07,
"top": 0.12,
"width": 0.6,
"height": 0.16
},
"zIndex": 10,
"content": { "text": "Orders today" },
"style": {
"color": "#A9C4E8",
"fontSizeRatio": 0.1,
"fontWeight": "500",
"horizontalAlignment": "left"
}
},
"total": {
"frame": {
"left": 0.07,
"top": 0.32,
"width": 0.6,
"height": 0.4
},
"zIndex": 11,
"content": { "text": 128 },
"style": {
"color": "#FFFFFF",
"fontSizeRatio": 0.26,
"fontWeight": "700",
"horizontalAlignment": "left"
}
},
"badge": {
"frame": {
"right": 0.07,
"top": 0.14,
"width": 0.24,
"height": 0.2
},
"zIndex": 5,
"style": {
"gradientEnabled": true,
"gradientColors": ["#2A63D4", "#56B9DD"],
"cornerRadiusRatio": 1,
"borderColor": "#D7F6FF",
"borderOpacity": 0.46,
"borderWidth": 1
}
},
"trend": {
"frame": {
"right": 0.07,
"top": 0.16,
"width": 0.24,
"height": 0.16
},
"zIndex": 6,
"content": {
"icon": "ph_trend_up",
"iconCodePoint": 58542,
"iconFont": "phosphorBold"
},
"style": { "color": "#FFFFFF" }
}
}
},
"layers": [
{
"id": "remote:orders-title",
"type": "text",
"dataPath": "data.orders.title"
},
{
"id": "remote:orders-total",
"type": "text",
"dataPath": "data.orders.total"
},
{
"id": "remote:badge",
"type": "shape",
"dataPath": "data.orders.badge"
},
{
"id": "remote:trend",
"type": "icon",
"dataPath": "data.orders.trend"
}
]
}图层样式与内容#
dataPath 指向的对象通过 content 描述内容,通过 style 控制外观。以下按类型列出字段,content. / style. 前缀表示字段在该对象中的位置;颜色使用 #RRGGBB 或透明度在前的 #AARRGGBB,pt 为 iOS 逻辑像素。表中的默认值是远程图层省略字段时的取值;编辑器图层省略字段时沿用编辑器中的设置,编辑器新建图层的预设可能与这些默认值不同。
各类型图层通用的样式字段
此表适用于 text、image、shape,各自的 opacity 含义见对应类型的字段表。其他图层使用各自类型表中列出的样式字段。
| 字段 | 类型 / 取值 | 用途与规则 |
|---|---|---|
style.backgroundColor | Color | 填充图层背景区域的颜色。文本默认不显示背景,需提高 style.opacity;形状未指定此字段时使用 style.color。 |
style.cornerRadiusRatio | 0–1 | 控制图层四角的弯曲程度,并沿此轮廓裁剪内容。半径 = 图层短边 × 此值 ÷ 2;0 是直角,1 是最大圆角;省略时为 0。正方形在 1 时成为圆,长方形成为胶囊。 |
style.borderColor | Color | 描在图层轮廓内侧的边框颜色,默认白色。只有 borderWidth > 0 且 borderOpacity > 0 时可见。 |
style.borderOpacity | 0–1 | 只控制边框可见度:0 隐藏,1 不额外降低颜色的透明度,默认 0。不会改变背景或内容的透明度。 |
style.borderWidth | number · pt | 边框向内占用的宽度,单位 pt,默认 0。文本的可用区域也会向内缩进同样宽度;建议使用 0–8 pt,文本会将超出此范围的值截断。 |
style.gradientEnabled | boolean | 是否用线性渐变替代纯色底色。API 省略时不启用;编辑器新建形状时通常会显式写入 true。 |
style.gradientColors | Color[] | 按渐变方向依次排列的颜色,使用 2–3 个;首色在起点,末色在终点,中间色的位置由 gradientStops 决定。需同时启用 gradientEnabled。 |
style.gradientStops | number[] · 0–1 | 每个渐变色沿渐变线的位置,数量须与颜色一一对应。0 是起点,1 是终点,如 [0, 0.2, 1] 把中间色放在全程的 20% 处。使用递增值;省略或数量不符时均匀分布。 |
style.gradientAngle | number · degrees | 只旋转背景渐变的方向,不旋转图层或内容,单位为度。0 从左向右,90 从上向下。API 省略时为 0;编辑器新建形状的预设为 135。 |
style.maskColor | Color | 均匀叠加在图层内容上方的颜色,默认黑色。实际覆盖强度由 maskOpacity 控制;可用深色压暗,也可用其他颜色叠加色调。 |
style.maskOpacity | 0–0.6 | 上述均匀遮罩的强度:0 不叠加,数值越大遮罩越明显,默认 0。它不直接降低原内容的透明度。 |
style.vignetteIntensity | 0–2 | 控制图层四周边缘和四角的暗化程度,0 关闭,数值越大边缘越暗,中心相对保持明亮;默认 0。 |
style.readabilityGradient | string | 从指定边缘向图层内部逐渐变透明的黑色渐变,用于衬托该处的叠加文字。none 关闭(默认);top、bottom、left、right 指定边缘,both 同时作用于上下两边,topLeftDiagonal、topRightDiagonal 从对应上角向对角方向渐隐。 |
style.backgroundColor- 类型 / 取值Color
- 用途与规则填充图层背景区域的颜色。文本默认不显示背景,需提高
style.opacity;形状未指定此字段时使用style.color。 style.cornerRadiusRatio- 类型 / 取值0–1
- 用途与规则控制图层四角的弯曲程度,并沿此轮廓裁剪内容。半径 = 图层短边 × 此值 ÷ 2;
0是直角,1是最大圆角;省略时为0。正方形在1时成为圆,长方形成为胶囊。 style.borderColor- 类型 / 取值Color
- 用途与规则描在图层轮廓内侧的边框颜色,默认白色。只有
borderWidth > 0且borderOpacity > 0时可见。 style.borderOpacity- 类型 / 取值0–1
- 用途与规则只控制边框可见度:
0隐藏,1不额外降低颜色的透明度,默认0。不会改变背景或内容的透明度。 style.borderWidth- 类型 / 取值number · pt
- 用途与规则边框向内占用的宽度,单位 pt,默认
0。文本的可用区域也会向内缩进同样宽度;建议使用 0–8 pt,文本会将超出此范围的值截断。 style.gradientEnabled- 类型 / 取值boolean
- 用途与规则是否用线性渐变替代纯色底色。API 省略时不启用;编辑器新建形状时通常会显式写入
true。 style.gradientColors- 类型 / 取值Color[]
- 用途与规则按渐变方向依次排列的颜色,使用 2–3 个;首色在起点,末色在终点,中间色的位置由
gradientStops决定。需同时启用gradientEnabled。 style.gradientStops- 类型 / 取值number[] · 0–1
- 用途与规则每个渐变色沿渐变线的位置,数量须与颜色一一对应。
0是起点,1是终点,如[0, 0.2, 1]把中间色放在全程的 20% 处。使用递增值;省略或数量不符时均匀分布。 style.gradientAngle- 类型 / 取值number · degrees
- 用途与规则只旋转背景渐变的方向,不旋转图层或内容,单位为度。
0从左向右,90从上向下。API 省略时为0;编辑器新建形状的预设为135。 style.maskColor- 类型 / 取值Color
- 用途与规则均匀叠加在图层内容上方的颜色,默认黑色。实际覆盖强度由
maskOpacity控制;可用深色压暗,也可用其他颜色叠加色调。 style.maskOpacity- 类型 / 取值0–0.6
- 用途与规则上述均匀遮罩的强度:
0不叠加,数值越大遮罩越明显,默认0。它不直接降低原内容的透明度。 style.vignetteIntensity- 类型 / 取值0–2
- 用途与规则控制图层四周边缘和四角的暗化程度,
0关闭,数值越大边缘越暗,中心相对保持明亮;默认0。 style.readabilityGradient- 类型 / 取值string
- 用途与规则从指定边缘向图层内部逐渐变透明的黑色渐变,用于衬托该处的叠加文字。
none关闭(默认);top、bottom、left、right指定边缘,both同时作用于上下两边,topLeftDiagonal、topRightDiagonal从对应上角向对角方向渐隐。
虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。
text · 文本
- 内容:
content.text是要显示的文字,可以是字符串,也可以是按原样显示的数字。编辑器图层未返回时,显示编辑器中填写的静态文本。 - 样式:
style控制字形、字号和排版。背景、圆角、边框等使用本章通用样式字段。
| 字段 | 类型 / 取值 | 用途与规则 |
|---|---|---|
content.text | string · number | 要显示的文字。数字按原样转为文字,例如 128 显示为“128”;远程图层省略时为空字符串。 |
style.color | Color | 文字颜色,默认白色;不会给背景着色。 |
style.textOpacity | 0–1 | 只控制文字笔画的可见度,默认 1。0 隐藏文字,1 保留文字颜色原有的透明度;文字背景由 style.opacity 控制。 |
style.opacity | 0–1 | 文字背景的透明度,默认 0;不是整个图层或文字本身的透明度。 |
style.fontSizeRatio | 0.02–0.28 | 字号 = 整个内容画布的短边长度 × 此值,默认 0.12。例如画布短边为 160 pt,设为 0.1 得到 16 pt 字号;不是文本图层高度的 10%。 |
style.fontWeight | string | 文字笔画的粗细,使用字符串 "300"、"400"、"500"、"600"、"700",依次更粗;默认 "400"。 |
style.fontFamily | string | 选择文字字形:system 为系统比例字体(默认);systemMonospace 为系统等宽字体,适合计数或时间;monospace 使用 Menlo 等宽字体。 |
style.fontFamilyFallback | string[] | 缺字时依次尝试的系统字体名称;不会从网络下载字体。 |
style.letterSpacing | number · pt | 在正常排版的字距上增加的距离,单位 pt,iOS 默认 0。正值让文字更疏,负值更紧;不改变字号。 |
style.baselineRatio | number | 可选的首行基线定位:基线距文字内容顶部的距离 = 字号 × 此值。用于把多个文本图层的文字基线对齐;省略时使用字体自然基线。 |
style.horizontalAlignment | left / center / right | 文字在扣除内边距和边框后的可用区域内靠左、居中或靠右,默认 right;不会移动图层框。 |
style.verticalAlignment | top / center / bottom | 文字在可用区域内靠上、居中或靠下,默认 top;不会修改 frame.top 或 frame.bottom。 |
style.autoWrap | boolean | 是否按文本框可用宽度自动换行,默认 false;显式换行仍然保留,溢出内容会裁剪。 |
style.paddingRatio | 0–0.3 | 每一侧的内边距 = 文本图层框短边长度 × 此值,默认 0;边框宽度再额外加到内边距上。数值越大,留给文字的区域越小。 |
content.text- 类型 / 取值string · number
- 用途与规则要显示的文字。数字按原样转为文字,例如
128显示为“128”;远程图层省略时为空字符串。 style.color- 类型 / 取值Color
- 用途与规则文字颜色,默认白色;不会给背景着色。
style.textOpacity- 类型 / 取值0–1
- 用途与规则只控制文字笔画的可见度,默认
1。0隐藏文字,1保留文字颜色原有的透明度;文字背景由style.opacity控制。 style.opacity- 类型 / 取值0–1
- 用途与规则文字背景的透明度,默认
0;不是整个图层或文字本身的透明度。 style.fontSizeRatio- 类型 / 取值0.02–0.28
- 用途与规则字号 = 整个内容画布的短边长度 × 此值,默认
0.12。例如画布短边为 160 pt,设为0.1得到 16 pt 字号;不是文本图层高度的 10%。 style.fontWeight- 类型 / 取值string
- 用途与规则文字笔画的粗细,使用字符串
"300"、"400"、"500"、"600"、"700",依次更粗;默认"400"。 style.fontFamily- 类型 / 取值string
- 用途与规则选择文字字形:
system为系统比例字体(默认);systemMonospace为系统等宽字体,适合计数或时间;monospace使用 Menlo 等宽字体。 style.fontFamilyFallback- 类型 / 取值string[]
- 用途与规则缺字时依次尝试的系统字体名称;不会从网络下载字体。
style.letterSpacing- 类型 / 取值number · pt
- 用途与规则在正常排版的字距上增加的距离,单位 pt,iOS 默认
0。正值让文字更疏,负值更紧;不改变字号。 style.baselineRatio- 类型 / 取值number
- 用途与规则可选的首行基线定位:基线距文字内容顶部的距离 = 字号 × 此值。用于把多个文本图层的文字基线对齐;省略时使用字体自然基线。
style.horizontalAlignment- 类型 / 取值
left/center/right - 用途与规则文字在扣除内边距和边框后的可用区域内靠左、居中或靠右,默认
right;不会移动图层框。 style.verticalAlignment- 类型 / 取值
top/center/bottom - 用途与规则文字在可用区域内靠上、居中或靠下,默认
top;不会修改frame.top或frame.bottom。 style.autoWrap- 类型 / 取值boolean
- 用途与规则是否按文本框可用宽度自动换行,默认
false;显式换行仍然保留,溢出内容会裁剪。 style.paddingRatio- 类型 / 取值0–0.3
- 用途与规则每一侧的内边距 = 文本图层框短边长度 × 此值,默认
0;边框宽度再额外加到内边距上。数值越大,留给文字的区域越小。
文字或样式变化后,运行时按新的文字、字号、换行、内边距和边框计算所需的最小文本区域,并限制在内容画布内,避免主屏幕沿用旧区域裁字;这一计算不会改写 frame。
虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。
{
"protocol": 1,
"pixels": [
[
{ "empty": true }
]
],
"data": {
"parcels": {
"frame": { "left": 0.08, "top": 0.22, "width": 0.84, "height": 0.56 },
"content": { "text": 128 },
"style": {
"color": "#D9F2F7",
"textOpacity": 1,
"fontSizeRatio": 0.26,
"fontWeight": "600",
"fontFamily": "systemMonospace",
"horizontalAlignment": "center",
"verticalAlignment": "center",
"autoWrap": false,
"paddingRatio": 0,
"backgroundColor": "#397DA0",
"opacity": 0.3,
"cornerRadiusRatio": 0,
"borderColor": "#90BBCD",
"borderOpacity": 0.6,
"borderWidth": 1
}
}
},
"layers": [
{ "id": "remote:count", "type": "text", "dataPath": "data.parcels" }
]
}matrix · 点阵
- 内容:
content与根点阵同构,由pixels、default、batch、layout组成,含义和规则与根点阵完全相同。真实网格的行列数由pixels决定。 - 样式:点阵没有
style字段。点的外观写在content.default、batch和pixels中,间距和留白写在content.layout中。
| 字段 | 类型 / 取值 | 用途与规则 |
|---|---|---|
content.pixels | (Pixel | null)[][] | 局部点阵内容,规则同根点阵的 pixels。远程点阵必填;编辑器点阵未返回时显示默认示例。 |
content.default | Pixel | 缺省点样式。编辑器点阵会把它逐字段合并到编辑器设置的默认点样式上;远程点阵的基础值为 color #5EA2FF、opacity 0.82、cornerRadius 0.16。 |
content.batch | { pixel, coordinates }[] | 批量样式,规则同根点阵的 batch,必须与 content.pixels 一起返回。 |
content.layout | MatrixLayout | 间距、单元宽高比与边缘留白,字段同“点阵布局”。编辑器点阵逐字段合并到编辑器设置上;未设置 gapMode 时为 near。 |
content.pixels- 类型 / 取值
(Pixel | null)[][] - 用途与规则局部点阵内容,规则同根点阵的
pixels。远程点阵必填;编辑器点阵未返回时显示默认示例。 content.default- 类型 / 取值
Pixel - 用途与规则缺省点样式。编辑器点阵会把它逐字段合并到编辑器设置的默认点样式上;远程点阵的基础值为
color #5EA2FF、opacity 0.82、cornerRadius 0.16。 content.batch- 类型 / 取值
{ pixel, coordinates }[] - 用途与规则批量样式,规则同根点阵的
batch,必须与content.pixels一起返回。 content.layout- 类型 / 取值
MatrixLayout - 用途与规则间距、单元宽高比与边缘留白,字段同“点阵布局”。编辑器点阵逐字段合并到编辑器设置上;未设置
gapMode时为near。
虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。
优先级从高到低依次为:pixels 中的显式值,batch,响应中的 default / layout,编辑器中的 default / layout。编辑器中设置的行数、列数只用于默认示例:没有 pixels 或点阵无效时,渲染器按合并后的缺省样式生成一组稳定分布的示例,避免图层在 API 就绪前消失;有效的 pixels 不会被缩放或重排。
{
"protocol": 1,
"pixels": [
[
{ "empty": true }
]
],
"data": {
"title": {
"frame": { "left": 0.06, "top": 0.08, "width": 0.88, "height": 0.14 },
"content": { "text": "Contributions · 20 weeks" },
"style": {
"color": "#A9C4E8",
"fontSizeRatio": 0.09,
"fontWeight": "500",
"horizontalAlignment": "left"
}
},
"heatmap": {
"frame": { "left": 0.06, "top": 0.28, "width": 0.88, "height": 0.64 },
"content": {
"default": { "color": "#FFFFFF", "opacity": 0.08, "cornerRadius": 0.25 },
"layout": { "gapMode": "near" },
"pixels": [
[
{ "color": "#7EDDB5", "opacity": 0.85 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 0.7448688173552516 },
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
{ "color": "#7EDDB5", "opacity": 0.7545944628656934 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 0.9830690317402184 },
null,
null
],
[
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 0.5229617408287728 },
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
{ "color": "#7EDDB5", "opacity": 0.9544462806264128 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 0.6555567507870917 },
null,
null,
null
],
[
{ "color": "#7EDDB5", "opacity": 0.7222294489865844 },
null,
null,
null,
{ "color": "#7EDDB5", "opacity": 0.6638935382087501 },
{ "color": "#7EDDB5", "opacity": 0.6413972526463148 },
null,
null,
null,
null,
null,
{ "color": "#7EDDB5", "opacity": 0.5311184461090914 },
{ "color": "#7EDDB5", "opacity": 0.8927628180779044 },
{ "color": "#7EDDB5", "opacity": 0.8698567704801822 },
{ "color": "#7EDDB5", "opacity": 0.5938312809225924 },
null,
null,
{ "color": "#7EDDB5", "opacity": 0.710199232267813 },
{ "color": "#7EDDB5", "opacity": 0.9951574673001937 },
{ "color": "#7EDDB5", "opacity": 0.974044818430527 }
],
[
null,
{ "color": "#7EDDB5", "opacity": 0.6708227479019796 },
{ "color": "#7EDDB5", "opacity": 0.9875732368676824 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 0.6668848538904473 },
null,
null,
null,
null,
null,
{ "color": "#7EDDB5", "opacity": 0.5228328839421528 },
{ "color": "#7EDDB5", "opacity": 0.5214774850893487 },
null,
null,
null,
{ "color": "#7EDDB5", "opacity": 0.7065983124568725 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 0.972886955341248 },
null
],
[
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
{ "color": "#7EDDB5", "opacity": 0.9993158218339733 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 0.7303804474628726 },
null,
null
],
[
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 0.8229182097281214 },
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
{ "color": "#7EDDB5", "opacity": 0.6114321719061702 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 0.8256594886799811 },
null,
null,
null,
{ "color": "#7EDDB5", "opacity": 0.7008502184288221 }
],
[
{ "color": "#7EDDB5", "opacity": 0.5000626562032289 },
null,
null,
{ "color": "#7EDDB5", "opacity": 0.6949160968071824 },
{ "color": "#7EDDB5", "opacity": 0.8072480735714076 },
{ "color": "#7EDDB5", "opacity": 0.5647999972978959 },
null,
null,
null,
null,
null,
{ "color": "#7EDDB5", "opacity": 0.6708958418347376 },
{ "color": "#7EDDB5", "opacity": 0.8120773109877517 },
{ "color": "#7EDDB5", "opacity": 0.6297695437501125 },
null,
null,
{ "color": "#7EDDB5", "opacity": 0.5926441641837852 },
{ "color": "#7EDDB5", "opacity": 0.9642279221859965 },
{ "color": "#7EDDB5", "opacity": 1 },
{ "color": "#7EDDB5", "opacity": 0.8892938715888167 }
]
]
}
}
},
"layers": [
{ "id": "remote:title", "type": "text", "dataPath": "data.title" },
{ "id": "remote:heatmap", "type": "matrix", "dataPath": "data.heatmap" }
]
}curve · 曲线
- 内容:
content声明采样点或函数,以及跟随曲线的标记。曲线的内容只来自 API:编辑器中的曲线图层只保存数据路径、初始位置与兜底样式。 - 样式:
style控制描边、填充与绘图区内边距。
曲线内容:写在 dataPath 指向的对象的 content 中。
| 字段 | 类型 / 取值 | 用途与规则 |
|---|---|---|
content.mode | samples / function | 决定曲线的数据来源:samples 连接 points 中的采样点;function 在 domain 范围内计算 expression。有表达式时默认 function,否则为 samples。 |
content.points | [x, y][] | 最多 1,024 个采样点,使用数值坐标对。 |
content.expression | string · ≤512 | 以 x 为自变量的受限数学表达式,支持 + - * / ^、括号、sin cos exp log abs sqrt min max、pi、e 和具名参数;不执行任意脚本。 |
content.parameters | object · ≤64 | 表达式中的具名数值参数,值限制在 ±1e9。 |
content.domain | [min, max] | 横轴数据范围 [最小值, 最大值],分别映射到绘图区左、右边缘。省略时从采样点推导,无点时为 [0, 1]。 |
content.yDomain | [min, max] | 纵轴显示范围 [最小值, 最大值],最小值对应绘图区底边,最大值对应顶边。例如 [0, 100] 的值 50 位于高度中点。省略时从采样点推导,无点时为 [0, 1]。 |
content.interpolation | linear / stepAfter / monotone | 决定采样点之间的线形:linear 直接用直线连接,stepAfter 先保持前一个值再跳到后一个值,monotone 平滑连接并尽量避免过冲(默认)。 |
content.markers | array · ≤32 | 曲线上圆点与文字标记的数组;使用下表中的标记字段。 |
content.mode- 类型 / 取值
samples/function - 用途与规则决定曲线的数据来源:
samples连接points中的采样点;function在domain范围内计算expression。有表达式时默认function,否则为samples。 content.points- 类型 / 取值
[x, y][] - 用途与规则最多 1,024 个采样点,使用数值坐标对。
content.expression- 类型 / 取值string · ≤512
- 用途与规则以
x为自变量的受限数学表达式,支持+ - * / ^、括号、sin cos exp log abs sqrt min max、pi、e和具名参数;不执行任意脚本。 content.parameters- 类型 / 取值object · ≤64
- 用途与规则表达式中的具名数值参数,值限制在 ±1e9。
content.domain- 类型 / 取值
[min, max] - 用途与规则横轴数据范围
[最小值, 最大值],分别映射到绘图区左、右边缘。省略时从采样点推导,无点时为[0, 1]。 content.yDomain- 类型 / 取值
[min, max] - 用途与规则纵轴显示范围
[最小值, 最大值],最小值对应绘图区底边,最大值对应顶边。例如[0, 100]的值50位于高度中点。省略时从采样点推导,无点时为[0, 1]。 content.interpolation- 类型 / 取值
linear/stepAfter/monotone - 用途与规则决定采样点之间的线形:
linear直接用直线连接,stepAfter先保持前一个值再跳到后一个值,monotone平滑连接并尽量避免过冲(默认)。 content.markers- 类型 / 取值array · ≤32
- 用途与规则曲线上圆点与文字标记的数组;使用下表中的标记字段。
标记字段:写在每个 content.markers[] 对象中。
| 字段 | 类型 / 取值 | 用途与规则 |
|---|---|---|
at.x | number | 标记所在的横轴数据值,渲染器从曲线上计算对应高度;与 sampleIndex 择一。 |
at.sampleIndex | integer | 标记跟随的采样点序号,从 0 开始,仅适合采样模式;优先使用按横轴递增排列的采样数组。 |
at.offsetPt | [dx, dy] · −64–64 | 标签文字相对曲线点的 [水平偏移, 垂直偏移],单位 pt,默认 [0, 0];正值分别向右、向下移动。只移动文字,不移动圆点或曲线。 |
symbol.shape | circle | 目前绘制圆点标记,不支持任意形状。 |
symbol.radiusPt | 1–16 | 圆点半径,单位 pt,默认 4。 |
symbol.fill | Color | 圆点填充颜色,默认 #E6EDC9。 |
label | string | 标记文字,可省略;它不是另一个可嵌套的文本图层。 |
labelStyle.color | Color | 标签文字颜色,默认 #E6EEEE。 |
labelStyle.fontSizePt | 6–32 | 标签字号,单位 pt,默认 10。 |
labelStyle.position | top / bottom / left / right | 标签相对标记点的位置,默认 top。 |
at.x- 类型 / 取值number
- 用途与规则标记所在的横轴数据值,渲染器从曲线上计算对应高度;与
sampleIndex择一。 at.sampleIndex- 类型 / 取值integer
- 用途与规则标记跟随的采样点序号,从
0开始,仅适合采样模式;优先使用按横轴递增排列的采样数组。 at.offsetPt- 类型 / 取值
[dx, dy]· −64–64 - 用途与规则标签文字相对曲线点的
[水平偏移, 垂直偏移],单位 pt,默认[0, 0];正值分别向右、向下移动。只移动文字,不移动圆点或曲线。 symbol.shape- 类型 / 取值
circle - 用途与规则目前绘制圆点标记,不支持任意形状。
symbol.radiusPt- 类型 / 取值1–16
- 用途与规则圆点半径,单位 pt,默认
4。 symbol.fill- 类型 / 取值Color
- 用途与规则圆点填充颜色,默认
#E6EDC9。 label- 类型 / 取值string
- 用途与规则标记文字,可省略;它不是另一个可嵌套的文本图层。
labelStyle.color- 类型 / 取值Color
- 用途与规则标签文字颜色,默认
#E6EEEE。 labelStyle.fontSizePt- 类型 / 取值6–32
- 用途与规则标签字号,单位 pt,默认
10。 labelStyle.position- 类型 / 取值
top/bottom/left/right - 用途与规则标签相对标记点的位置,默认
top。
曲线样式:写在 dataPath 指向的对象的 style 中。
| 字段 | 类型 / 取值 | 用途与规则 |
|---|---|---|
style.color | Color | 曲线描边的颜色;区域填充另用 fillColor。 |
style.opacity | 0–1 | 曲线整体透明度,默认 1;也会乘到区域填充及标记的透明度上。 |
style.strokeWidth | 0.25–12 · pt | 曲线描边宽度,默认 2。 |
style.lineCap | round / butt / square | 描边端点形状:round 在端点增加半圆(默认),butt 在坐标处平齐截断,square 以方头向外延伸半个线宽。 |
style.lineJoin | round / bevel / miter | 折点处两段线的连接形状:round 圆角(默认),bevel 削平尖角,miter 保留尖角。主要在折线或阶梯曲线上明显。 |
style.dashLength | 0.5–64 · pt | 虚线实段长度;省略为实线。 |
style.dashGap | 0–64 · pt | 虚线间隔,默认 4,只在使用虚线时生效。 |
style.fillColor | Color | 曲线到绘图区底边之间的区域填充颜色,省略时使用描边颜色。 |
style.fillOpacity | 0–1 | 区域填充自身的透明度,默认 0(不填充)。最终还会乘 style.opacity;不会改变描边粗细或透明度。 |
style.plotPadding | 0–48 · pt | 图层框四边到内部绘图区的距离,单位 pt,默认 0。数值越大,曲线可用宽高越小;数据坐标仍按 domain / yDomain 映射到缩小后的绘图区。 |
style.color- 类型 / 取值Color
- 用途与规则曲线描边的颜色;区域填充另用
fillColor。 style.opacity- 类型 / 取值0–1
- 用途与规则曲线整体透明度,默认
1;也会乘到区域填充及标记的透明度上。 style.strokeWidth- 类型 / 取值0.25–12 · pt
- 用途与规则曲线描边宽度,默认
2。 style.lineCap- 类型 / 取值
round/butt/square - 用途与规则描边端点形状:
round在端点增加半圆(默认),butt在坐标处平齐截断,square以方头向外延伸半个线宽。 style.lineJoin- 类型 / 取值
round/bevel/miter - 用途与规则折点处两段线的连接形状:
round圆角(默认),bevel削平尖角,miter保留尖角。主要在折线或阶梯曲线上明显。 style.dashLength- 类型 / 取值0.5–64 · pt
- 用途与规则虚线实段长度;省略为实线。
style.dashGap- 类型 / 取值0–64 · pt
- 用途与规则虚线间隔,默认
4,只在使用虚线时生效。 style.fillColor- 类型 / 取值Color
- 用途与规则曲线到绘图区底边之间的区域填充颜色,省略时使用描边颜色。
style.fillOpacity- 类型 / 取值0–1
- 用途与规则区域填充自身的透明度,默认
0(不填充)。最终还会乘style.opacity;不会改变描边粗细或透明度。 style.plotPadding- 类型 / 取值0–48 · pt
- 用途与规则图层框四边到内部绘图区的距离,单位 pt,默认
0。数值越大,曲线可用宽高越小;数据坐标仍按domain/yDomain映射到缩小后的绘图区。
虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。
这些标记只绘制圆点和文字,不会自动生成坐标轴。使用 [x, y] 采样点、label 和 labelStyle.position 可保持 App 与主屏幕兼容;图片或图标标记请用独立图层组合。
{
"protocol": 1,
"pixels": [
[
{ "empty": true }
]
],
"data": {
"activity": {
"frame": { "left": 0.05, "top": 0.08, "width": 0.9, "height": 0.84 },
"content": {
"mode": "samples",
"points": [
[0, 30],
[2, 18],
[4, 65],
[6, 45],
[8, 90],
[10, 70]
],
"domain": [0, 10],
"yDomain": [0, 100],
"interpolation": "linear",
"markers": [
{
"at": { "x": 8 },
"symbol": { "shape": "circle", "radiusPt": 4, "fill": "#E1EEE0" },
"label": "Now",
"labelStyle": {
"color": "#E1EEE0",
"fontSizePt": 9,
"position": "top"
}
}
]
},
"style": {
"color": "#A7DAD7",
"opacity": 1,
"strokeWidth": 2,
"lineCap": "round",
"lineJoin": "round",
"fillColor": "#77B6BB",
"fillOpacity": 0.22,
"plotPadding": 8
}
}
},
"layers": [
{
"id": "remote:activity",
"type": "curve",
"dataPath": "data.activity"
}
]
}image · 图片
- 内容:
content.url指定图片,可以是 HTTPS 地址、data:image/…;base64,或原始 Base64 字符串。 - 样式:URL 图片按 cover 等比填满图层框,超出部分裁掉。圆角、边框和遮罩使用本章通用字段;编辑器上传的本地图片按 contain 完整显示。
| 字段 | 类型 / 取值 | 用途与规则 |
|---|---|---|
content.url | string | 图片地址或 Base64 数据。编辑器图片图层的来源选择“API 数据”时,从 dataPath 指向的对象读取此字段;给出 url 时,图层显示这张图片。服务端不能引用设备上的文件路径。 |
style.opacity | 0.1–1 | 控制图片本身的可见度,默认 1。0.5 表示图片以一半不透明度绘制,透出下面的内容;当前最小为 0.1。它不改变上方遮罩或边框的透明度。 |
style.color | Color | 图片加载中的占位颜色;不是图片染色。 |
content.url- 类型 / 取值string
- 用途与规则图片地址或 Base64 数据。编辑器图片图层的来源选择“API 数据”时,从
dataPath指向的对象读取此字段;给出url时,图层显示这张图片。服务端不能引用设备上的文件路径。 style.opacity- 类型 / 取值0.1–1
- 用途与规则控制图片本身的可见度,默认
1。0.5表示图片以一半不透明度绘制,透出下面的内容;当前最小为0.1。它不改变上方遮罩或边框的透明度。 style.color- 类型 / 取值Color
- 用途与规则图片加载中的占位颜色;不是图片染色。
虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。
主屏幕远程图片需返回 image/*,最大 6 MB,并缩略到最长边 1,200 px。Base64 解码上限 4 MB,但内嵌数据仍受整个 JSON 响应 512 KB 的限制。
icon · 图标
- 内容:内置图标用
content.icon、content.iconCodePoint、content.iconFont配套声明同一个图标;图片图标用content.url。同一个对象只能给出其中一种。 - 样式:图标等比完整放入
frame,由textOpacity控制透明度;字形颜色及发光使用下表字段。
| 字段 | 类型 / 取值 | 用途与规则 |
|---|---|---|
content.icon | string | 图标库中的稳定名称,如 ph_activity,供 App 预览查找图标。它与下两个字段标识同一个图标,应配套填写;不是与编码二选一。编辑器图层收到 icon 后,不再沿用编辑器中保存的码点和字体。 |
content.iconCodePoint | integer | 图标在 iconFont 指定字体中的 Unicode 码点,主屏幕按此值绘制字形。例如 ph_activity 为 57344;不是列表序号。必须与 icon 一起返回;缺少时主屏幕仅能按部分旧版 Material 名称回退,不能覆盖当前图标库。 |
content.iconFont | phosphorBold / devicon / simpleIcons / material | 主屏幕使用的内置字体标识,必须与 icon、iconCodePoint 一起返回。例如 ph_activity 对应 phosphorBold;同一码点在不同字体中可表示不同图形。此字段不加载远程字体。 |
content.url | string | 图片图标的地址或 Base64 数据,按 contain 完整显示;不能与 content.icon 同时返回。编辑器图标图层的来源选择“API 数据”时,该对象可以返回内置图标,也可以返回 url。 |
style.color | Color | 内置字形的笔画或填充颜色,默认白色;不会给图片图标染色。 |
style.textOpacity | 0–1 | 图标整体透明度,默认 1。字形和图片图标都使用此值,0 隐藏图标。 |
style.iconGlowEnabled | boolean | 启用发光,默认 false;用于内置字形及编辑器上传的本地 SVG,不用于远程图片图标。 |
style.iconGlowColor | Color | 图标周围模糊光晕的颜色,不改变字形本身的颜色;省略时使用图标颜色。需启用 iconGlowEnabled。 |
style.iconGlowOpacity | 0–1 | 光晕自身的透明度,默认 0.65;数值越大光越明显。图标整体的 textOpacity 还会影响最终发光可见度。 |
style.iconGlowRadius | 0.01–0.16 | 发光模糊范围相对于图标短边的比例,默认 0.07。数值越大,光越分散、覆盖范围越大;不会放大图标字形。 |
content.icon- 类型 / 取值string
- 用途与规则图标库中的稳定名称,如
ph_activity,供 App 预览查找图标。它与下两个字段标识同一个图标,应配套填写;不是与编码二选一。编辑器图层收到icon后,不再沿用编辑器中保存的码点和字体。 content.iconCodePoint- 类型 / 取值integer
- 用途与规则图标在
iconFont指定字体中的 Unicode 码点,主屏幕按此值绘制字形。例如ph_activity为57344;不是列表序号。必须与icon一起返回;缺少时主屏幕仅能按部分旧版 Material 名称回退,不能覆盖当前图标库。 content.iconFont- 类型 / 取值
phosphorBold/devicon/simpleIcons/material - 用途与规则主屏幕使用的内置字体标识,必须与
icon、iconCodePoint一起返回。例如ph_activity对应phosphorBold;同一码点在不同字体中可表示不同图形。此字段不加载远程字体。 content.url- 类型 / 取值string
- 用途与规则图片图标的地址或 Base64 数据,按 contain 完整显示;不能与
content.icon同时返回。编辑器图标图层的来源选择“API 数据”时,该对象可以返回内置图标,也可以返回url。 style.color- 类型 / 取值Color
- 用途与规则内置字形的笔画或填充颜色,默认白色;不会给图片图标染色。
style.textOpacity- 类型 / 取值0–1
- 用途与规则图标整体透明度,默认
1。字形和图片图标都使用此值,0隐藏图标。 style.iconGlowEnabled- 类型 / 取值boolean
- 用途与规则启用发光,默认
false;用于内置字形及编辑器上传的本地 SVG,不用于远程图片图标。 style.iconGlowColor- 类型 / 取值Color
- 用途与规则图标周围模糊光晕的颜色,不改变字形本身的颜色;省略时使用图标颜色。需启用
iconGlowEnabled。 style.iconGlowOpacity- 类型 / 取值0–1
- 用途与规则光晕自身的透明度,默认
0.65;数值越大光越明显。图标整体的textOpacity还会影响最终发光可见度。 style.iconGlowRadius- 类型 / 取值0.01–0.16
- 用途与规则发光模糊范围相对于图标短边的比例,默认
0.07。数值越大,光越分散、覆盖范围越大;不会放大图标字形。
在独立工具页按 App 的分类和顺序浏览、搜索图标,查看对应的 icon、iconCodePoint 和 iconFont,实时调整样式并复制图层 JSON。 打开图标查看与预览
虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。
主屏幕远程图片图标最大 1 MB,缩略到最长边 512 px。编辑器上传的本地图标由编辑器管理。
{
"protocol": 1,
"pixels": [
[
{ "empty": true }
]
],
"data": {
"icons": [
{
"frame": {
"left": 0.1,
"top": 0.25,
"width": 0.2,
"height": 0.5
},
"content": {
"icon": "ph_activity",
"iconCodePoint": 57344,
"iconFont": "phosphorBold"
},
"style": { "color": "#A7DAD7", "textOpacity": 1 }
},
{
"frame": {
"left": 0.4,
"top": 0.25,
"width": 0.2,
"height": 0.5
},
"content": {
"icon": "ph_lightning",
"iconCodePoint": 58078,
"iconFont": "phosphorBold"
},
"style": { "color": "#F0C778", "textOpacity": 1 }
},
{
"frame": {
"left": 0.7,
"top": 0.25,
"width": 0.2,
"height": 0.5
},
"content": {
"icon": "ph_trend_up",
"iconCodePoint": 58542,
"iconFont": "phosphorBold"
},
"style": { "color": "#A7DAD7", "textOpacity": 0.45 }
}
]
},
"layers": [
{
"id": "remote:activity",
"type": "icon",
"dataPath": "data.icons[0]"
},
{
"id": "remote:lightning",
"type": "icon",
"dataPath": "data.icons[1]"
},
{
"id": "remote:trend",
"type": "icon",
"dataPath": "data.icons[2]"
}
]
}line · 直线
- 内容:
content.direction选择横线或竖线,线条穿过图层框中心;其他角度使用对象的rotation。 - 样式:
frame决定摆放位置和长度,strokeWidth决定粗细,pattern决定实线、虚线或点线。
| 字段 | 类型 / 取值 | 用途与规则 |
|---|---|---|
content.direction | horizontal / vertical | 直线方向,默认水平;横线位于图层框的垂直中心,竖线位于水平中心。 |
style.color | Color | 实线、虚线或点线的颜色,默认白色;启用渐变时改用 gradientColors。 |
style.opacity | 0–1 | 整条直线的透明度,默认 1;同时作用于渐变色和点线圆点。 |
style.strokeWidth | 0.5–8 · pt | 直线宽度,默认 2;图层框决定长度,而不是粗细。 |
style.pattern | solid / dashed / dotted | 线条绘制方式:solid 连续实线(默认);dashed 重复绘制实段与空隙;dotted 重复绘制圆点,圆点直径由 strokeWidth 决定。 |
style.cap | round / butt | 实线及虚线实段的端点形状:round 为半圆端点(默认),butt 在端点处平齐结束。点线固定使用圆点,不受此字段影响。 |
style.dashLength | 1–32 · pt | 虚线每一实段的长度,默认 6,仅 dashed 使用。 |
style.dashGap | 0–32 · pt | 相邻虚线实段或圆点之间的留白长度,单位 pt,默认 4。数值越大线越稀疏,solid 模式下不使用。 |
style.gradientEnabled | boolean | 用渐变颜色绘制直线,默认 false。 |
style.gradientColors | Color[] | 2–3 个依次分布的渐变色。需启用 gradientEnabled;原生主屏幕按图层框从左到右渐变,App 的竖线预览则按从上到下渐变。 |
style.gradientStops | number[] · 0–1 | 各颜色对应的位置,0 为起点,1 为终点;数量须与颜色相同并递增,省略时均匀分布。 |
content.direction- 类型 / 取值
horizontal/vertical - 用途与规则直线方向,默认水平;横线位于图层框的垂直中心,竖线位于水平中心。
style.color- 类型 / 取值Color
- 用途与规则实线、虚线或点线的颜色,默认白色;启用渐变时改用
gradientColors。 style.opacity- 类型 / 取值0–1
- 用途与规则整条直线的透明度,默认
1;同时作用于渐变色和点线圆点。 style.strokeWidth- 类型 / 取值0.5–8 · pt
- 用途与规则直线宽度,默认
2;图层框决定长度,而不是粗细。 style.pattern- 类型 / 取值
solid/dashed/dotted - 用途与规则线条绘制方式:
solid连续实线(默认);dashed重复绘制实段与空隙;dotted重复绘制圆点,圆点直径由strokeWidth决定。 style.cap- 类型 / 取值
round/butt - 用途与规则实线及虚线实段的端点形状:
round为半圆端点(默认),butt在端点处平齐结束。点线固定使用圆点,不受此字段影响。 style.dashLength- 类型 / 取值1–32 · pt
- 用途与规则虚线每一实段的长度,默认
6,仅dashed使用。 style.dashGap- 类型 / 取值0–32 · pt
- 用途与规则相邻虚线实段或圆点之间的留白长度,单位 pt,默认
4。数值越大线越稀疏,solid模式下不使用。 style.gradientEnabled- 类型 / 取值boolean
- 用途与规则用渐变颜色绘制直线,默认
false。 style.gradientColors- 类型 / 取值Color[]
- 用途与规则2–3 个依次分布的渐变色。需启用
gradientEnabled;原生主屏幕按图层框从左到右渐变,App 的竖线预览则按从上到下渐变。 style.gradientStops- 类型 / 取值number[] · 0–1
- 用途与规则各颜色对应的位置,
0为起点,1为终点;数量须与颜色相同并递增,省略时均匀分布。
虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。
{
"protocol": 1,
"pixels": [
[
{ "empty": true }
]
],
"data": {
"solid": {
"frame": { "left": 0.1, "top": 0.32, "width": 0.8, "height": 0.04 },
"content": { "direction": "horizontal" },
"style": {
"color": "#A4DAE3",
"opacity": 0.55,
"strokeWidth": 1,
"pattern": "solid",
"cap": "butt"
}
},
"dashed": {
"frame": { "left": 0.1, "top": 0.62, "width": 0.8, "height": 0.04 },
"content": { "direction": "horizontal" },
"style": {
"color": "#A4DAE3",
"opacity": 1,
"strokeWidth": 3,
"pattern": "dashed",
"cap": "butt",
"dashLength": 8,
"dashGap": 6
}
}
},
"layers": [
{ "id": "remote:solid", "type": "line", "dataPath": "data.solid" },
{ "id": "remote:dashed", "type": "line", "dataPath": "data.dashed" }
]
}shape · 形状
- 内容:图层本身就是圆角矩形,不需要
content;适合作为底板、徽章或进度条轨道。 - 样式:用
style指定填充和边框,圆角、渐变及遮罩使用本章通用字段。渐变和边框需显式启用或设置可见值。
| 字段 | 类型 / 取值 | 用途与规则 |
|---|---|---|
content | object | 无需声明内容值,图层本身即一个可填充、带边框的圆角矩形。 |
style.color | Color | 形状的纯色填充,默认 #2A63D4。存在 backgroundColor 时后者优先;启用渐变后由 gradientColors 决定填充颜色。 |
style.opacity | 0–1 | 只控制形状内部填充的透明度,默认 1。0 隐藏填充但仍可保留边框,边框透明度另由 borderOpacity 控制。 |
content- 类型 / 取值object
- 用途与规则无需声明内容值,图层本身即一个可填充、带边框的圆角矩形。
style.color- 类型 / 取值Color
- 用途与规则形状的纯色填充,默认
#2A63D4。存在backgroundColor时后者优先;启用渐变后由gradientColors决定填充颜色。 style.opacity- 类型 / 取值0–1
- 用途与规则只控制形状内部填充的透明度,默认
1。0隐藏填充但仍可保留边框,边框透明度另由borderOpacity控制。
虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。
{
"protocol": 1,
"pixels": [
[
{ "empty": true }
]
],
"data": {
"badge": {
"frame": { "left": 0.12, "top": 0.22, "width": 0.76, "height": 0.56 },
"style": {
"opacity": 1,
"cornerRadiusRatio": 1,
"gradientEnabled": true,
"gradientColors": ["#225B80", "#78B6BA"],
"gradientStops": [0, 1],
"gradientAngle": 0,
"borderColor": "#BCE3E4",
"borderOpacity": 0.9,
"borderWidth": 2
}
}
},
"layers": [
{ "id": "remote:badge", "type": "shape", "dataPath": "data.badge" }
]
}服务端整图渲染#
除了用点阵和图层描述内容,你也可以让服务端完全接管绘制:用熟悉的图表库、模板引擎或无头浏览器,把整张小组件画面渲染成一张图片,再通过 data 返回。小组件把它作为「图片」材质铺满整个画布,不需要配置任何图层,也不必学习本页的绘制语法。
适合这些场景:已有成熟的报表或图片渲染管线;需要复杂图表、特殊字体或自由排版;希望由服务端一处控制全部视觉,随时调整而无需改动 App 中的配置。
在 App 中设置
- 在编辑页把表面材质设为「图片」;
- 图片来源选择「API」;
- 数据路径填写图片所在的字段,例如
data.cover; - 可按需开启可读性渐变,方便在图片上叠加文字图层。
响应
{
"protocol": 1,
"pixels": [[{ "empty": true }]],
"data": {
"cover": "https://cdn.example.com/widgets/orders-medium@3x.png"
}
}| 数据路径的值 | 规则 |
|---|---|
| HTTPS 地址 | 返回 image/*,最大 6 MB;主屏幕会将其缩略到最长边 1,200 px。 |
data:image/…;base64, 或原始 Base64 | 直接内嵌在响应中,适合小图;整个 JSON 响应仍受 512 KB 限制。 |
- HTTPS 地址
- 返回
image/*,最大 6 MB;主屏幕会将其缩略到最长边 1,200 px。 data:image/…;base64,或原始 Base64- 直接内嵌在响应中,适合小图;整个 JSON 响应仍受 512 KB 限制。
这里的数据路径属于材质设置,直接指向图片字符串;它不是图层,不需要写成对象。
图片按 cover 等比铺满整个小组件,超出部分裁掉。请按请求参数 gw_canvas_width_pt × gw_canvas_height_pt 的宽高比出图,并以 2–3 倍像素绘制,以保证在主屏幕上清晰。
pixels 仍然必填,返回 [[{"empty": true}]] 即可只显示图片。图片之上依旧可以叠加点阵或图层,例如用原生文字显示需要随时更新的数值。请求签名#
可以在 App 中为小组件添加密钥,使每个请求都携带两个可供你服务器验证的请求头,用于证明请求的确是来自 Glance Widgets 小组件,而不是无关或恶意的第三方。密钥本身永远不会被发送。
| 请求头 | 值 |
|---|---|
X-GlanceWidgets-Timestamp | Unix 时间,单位为毫秒,以十进制字符串表示。 |
X-GlanceWidgets-Signature | Base64(HMAC-SHA256(key = secret, message = timestamp + "\n" + secret)),全程使用 UTF-8。 |
X-GlanceWidgets-Timestamp- Unix 时间,单位为毫秒,以十进制字符串表示。
X-GlanceWidgets-SignatureBase64(HMAC-SHA256(key = secret, message = timestamp + "\n" + secret)),全程使用 UTF-8。
GlanceWidgets。签名只覆盖时间戳与密钥,不包含 URL、查询参数或请求体。在服务器端:拒绝过期的时间戳(例如 ±5 分钟),重新计算签名,并以恒定时间进行比较。
import crypto from 'node:crypto'
const SECRET = process.env.GLANCE_SECRET // same value as in the app
const WINDOW_MS = 5 * 60 * 1000
export function verify(req) {
const ts = req.get('X-GlanceWidgets-Timestamp')
const sig = req.get('X-GlanceWidgets-Signature')
if (!ts || !sig || Math.abs(Date.now() - Number(ts)) > WINDOW_MS) return false
const expected = crypto
.createHmac('sha256', SECRET)
.update(`${ts}\n${SECRET}`)
.digest('base64')
const a = Buffer.from(sig)
const b = Buffer.from(expected)
return a.length === b.length && crypto.timingSafeEqual(a, b)
}import base64, hashlib, hmac, os, time
SECRET = os.environ["GLANCE_SECRET"]
WINDOW_MS = 5 * 60 * 1000
def verify(headers) -> bool:
ts = headers.get("X-GlanceWidgets-Timestamp")
sig = headers.get("X-GlanceWidgets-Signature")
if not ts or not sig or abs(time.time() * 1000 - int(ts)) > WINDOW_MS:
return False
message = f"{ts}\n{SECRET}".encode()
expected = base64.b64encode(
hmac.new(SECRET.encode(), message, hashlib.sha256).digest()
).decode()
return hmac.compare_digest(sig, expected)测试向量:密钥 this is secret,时间戳 1700000000000 → sSFWELbV2YwjdDQhWZwTcWlX5BWUx5J6TPpsZmuPii0=。
限制与错误#
| 限制项 | 值 |
|---|---|
| 响应体大小 | 512 KB (524,288 bytes) |
| 根点阵 | rows × columns ≤ 4,096;≥ 1 × 1;矩形 |
| 图层声明 | 每条只含 id、type、dataPath,id 以 remote: 为前缀 |
| 协议 | 1 或省略 |
| 曲线 | ≤ 1,024 个点 · ≤ 32 个标记 · 表达式 ≤ 512 个字符 |
| 图片 | ≤ 6 MB 远程 · ≤ 4 MB Base64 · cover 填充 |
- 响应体大小
- 512 KB (524,288 bytes)
- 根点阵
- rows × columns ≤ 4,096;≥ 1 × 1;矩形
- 图层声明
- 每条只含
id、type、dataPath,id 以remote:为前缀 - 协议
1或省略- 曲线
- ≤ 1,024 个点 · ≤ 32 个标记 · 表达式 ≤ 512 个字符
- 图片
- ≤ 6 MB 远程 · ≤ 4 MB Base64 · cover 填充
响应体超限、根点阵尺寸无效、batch 坐标越界、图层声明结构错误等,会使 App 拒绝整个响应。dataPath 指向的对象出错只影响对应的图层:编辑器图层回退到保存的状态,远程图层不绘制。曲线采样、标记、参数超出数量上限时只取预算内的部分;超长或无效表达式不会执行。
刷新#
主屏幕小组件按 WidgetKit 时间线请求新画面,大约每 15 分钟一次。具体时刻由 iOS 根据电量、使用情况与系统的刷新预算决定。请让画面在两次更新之间依然有意义;如有需要,可在 data 中加入「最后更新」时间。
在线调试#
编辑 JSON,实时查看渲染结果。校验器采用与 App 相同的限制和优先级。
画面有效 0 个单元 · 0 个图层 · 0 字节
检查清单#
- HTTPS 接口,在数秒内返回
2xx。 - 根为带有
"protocol": 1的对象,以及不超过 4,096 个单元的矩形pixels数组。 - 颜色为
#RRGGBB(或 ARGB 形式的#AARRGGBB)。 layers每条只含id、type、dataPath,id 以remote:开头。- 每个
dataPath都指向data中的一个对象;远程图层的对象带有含width、height的frame。 - 点阵根据
gw_aspect_ratio确定大小,而不是使用固定表格。 - 若启用了签名,请校验时间窗口,并以恒定时间验证签名。