APIリファレンス
Glance Widgets が描画できるエンドポイントを設計するために必要なことをすべて。ウィジェットがどのようなリクエストを送るか、あなたの API がどのような形式のレスポンスを返すべきか、そしてレンダラーが従うルールを解説します。このページのライブ例はすべて、アプリと同じルールで描画されています。
概要#
Glance Widgets のウィジェットは、あなたが管理するエンドポイントへの1回のHTTPS GETリクエストで動作します。エンドポイントは、描画内容を記述する1つのJSONオブジェクト(フレーム)を返します。アプリがフレームを検証・正規化し、WidgetKitがホーム画面に描画します。
フレームには、重ね合わせて合成される2つの表現チャンネルがあります。
- ルートピクセルグリッド(
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を提供できる場所に、エンドポイントをデプロイします。
- アプリでウィジェットを作成し、APIフィールドにURLを貼り付けます。
- ホーム画面と同じサイズでプレビューしてから、ウィジェットをホーム画面に追加します。
ウィジェットのコンテンツ構造#
カードの素材とコンテンツ
ウィジェットの表現は、カード自体のスタイル・素材とカード内のコンテンツで構成されます。素材はアプリ内のカスタムウィジェットエディタ、または将来提供される他のプラットフォームのエディタで設定します。API から素材を指定・動的更新することはできません。API が扱うのはコンテンツとそのスタイルです。
カード上のレイヤーには2つの出どころがあります。1つ目はエディタのレイヤーです。エディタの視覚的な操作画面で追加・配置・設定し、ウィジェット設定に保存します。完全に静的なままでもよく、データパスを指定すれば、API がレスポンスごとに位置・内容・スタイルを更新できます。このときエディタの設定は、最初のレスポンス前の初期状態であり、レスポンスにないフィールドの代替値でもあります。
2つ目はリモートレイヤーです。エディタでは何も設定せず、API がレスポンスごとに宣言します。保存済みのウィジェット設定にまったく存在しない内容でもよく、定義はすべて API から来ます。2種類のレイヤーは併用できます。具体的な書き方は「レスポンスボディ」と「レイヤー」で説明します。
基本レイヤーとドットマトリクス
Glance Widgets では、テキスト・直線・曲線・画像・アイコン・図形などのレイヤーを追加して、基本的な内容を表現できます。レイヤーは重ねて配置でき、専用の zIndex フィールドで重なり順を制御します。
表現力を広げつつ、記述と解析を簡単に保つため、ドットマトリクスも提供しています。サーバーのプログラムで自由な表現を生成し、二次元配列として記述できます。基本レイヤーで表す内容も、好みや用途に応じてピクセルアートとして表現できます。細かさはセル数の上限に制約されます。
マトリクスには2つの形があります。マトリクスレイヤー(type: "matrix")は、他のレイヤーと同じく指定位置・サイズの領域に描画し、その content が1つのマトリクスです。ルートマトリクス(トップレベルの pixels)はレイヤーシステムに属さず、コンテンツキャンバス全体を配置領域とします。セルのスタイル、描画ルール、API 構造は共通です。ルートを別に設けた目的は、統一したスタイルのピクセル表現だけで1つのテーマを作る際に、レイヤーの宣言を省いて簡潔に実現することです。layout に従って縦横比を維持して中央に収めるため、実際にカード全体を埋めるかどうかは配列の縦横比、間隔、余白に依存します。
マトリクスはセルの格子です。各点のスタイルを指定するだけでなく、特定の点を非表示にもできます。非表示にしても論理的な位置はなくなりません。黒地に赤い文字の古い電光掲示板のように一部を空け、模様を作ったり、別のレイヤーを重ねたりできます。{"empty": true} の詳細は「ピクセルと優先順位」で説明します。
最終的な3層構造
- 最下層:カードのスタイルと素材。背景とコンテナとしてエディタで設定します。
- 中間層:ルートマトリクス。キャンバス全体を配置領域とし、一部またはすべてのセルを空白にできます。
- 最上層:コンテンツレイヤー。エディタのレイヤーと API が宣言したリモートレイヤーを
zIndex順で合成します。局所的なマトリクスもここに含まれます。
リクエスト#
ウィジェットはHTTPSの GET を送信します。あなた自身のクエリパラメータはそのまま保持され、アプリは描画先の領域を示す予約済みの gw_* パラメータを追加します。HTTPS以外のURLは拒否されます。
| パラメータ | 例 | 説明 |
|---|---|---|
gw_protocol | 1 | クライアントが話すプロトコルのバージョン。 |
gw_platform | ios | クライアントのプラットフォーム。 |
gw_family | small · medium · large | ウィジェットのサイズファミリー。 |
gw_canvas_width_pt | 158.00 | 使用可能なコンテンツキャンバスの幅。単位は iOS の論理ピクセル(pt)、小数点以下2桁。 |
gw_canvas_height_pt | 158.00 | 使用可能なコンテンツキャンバスの高さ。単位は iOS の論理ピクセル(pt)、小数点以下2桁。 |
gw_aspect_ratio | 1.0000 | 幅 ÷ 高さ(小数点以下4桁)。 |
gw_context | app_preview | レンダリングコンテキスト。app_home:アプリのホーム、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)、小数点以下2桁。
gw_canvas_height_pt- 例
158.00 - 説明使用可能なコンテンツキャンバスの高さ。単位は iOS の論理ピクセル(pt)、小数点以下2桁。
gw_aspect_ratio- 例
1.0000 - 説明幅 ÷ 高さ(小数点以下4桁)。
gw_context- 例
app_preview - 説明レンダリングコンテキスト。
app_home:アプリのホーム、app_preview:編集プレビュー、widget:ホーム画面のウィジェット。 gw_state_<key>- 例—
- 説明将来の操作状態の拡張用に予約されており、現在のリクエスト処理では未使用です。
gw_で始まるパラメータ名はクライアント専用のため、独自のクエリパラメータには使用しないでください。
pt は iOS の論理的なレイアウト単位で、アプリの 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タイムアウトは短めで、アプリでは送信に約 8秒、受信に 12秒 です。2xx のステータスはすべて成功とみなされます。UTF-8のJSONで、できれば Content-Type: application/json を付けて応答してください。
レスポンスボディ#
本リクエストで表示する1フレームを、最大 512 KB の UTF-8 JSON オブジェクトとして返します。protocol は省略可能ですが 1 を推奨し、それ以外の null でない値は未対応です。ルートマトリクス、データのルート data、リモートレイヤーの宣言 layers の3つに分けて理解すると構造が明確になります。未知のトップレベルフィールドは無視されます。
ルート:pixels・default・layout・batch
pixels は格子の m*n の大きさを決め、各点のスタイルを記述します。layout は全体の配置を決めます。複雑な配列をサーバー側で1点ずつ組み立てる負担を減らすため、batch で同じスタイルの点をまとめ、default で個別指定のない点を補います。
| フィールド | 型 / 値 | 用途とルール |
|---|---|---|
pixels | (Pixel | null)[][] | 必須のルートマトリクス。各要素は pixels[row][column] のセルのスタイルです。左上が原点。長方形、最小 1 × 1、最大4,096セル。 |
default | Pixel | セルの既定スタイル。明示セルや各 batch のスタイルで省略したプロパティの補完にも使います。 |
layout | MatrixLayout | マトリクス全体の間隔、セルの縦横比、端の余白を定義します。各点の色や形状とは別です。 |
batch | { pixel, coordinates }[] | 同じ pixel スタイルを、0始まりの [row, column] 座標で選んだ点に適用します。規則的な模様を繰り返し記述せずに生成できます。 |
pixels- 型 / 値
(Pixel | null)[][] - 用途とルール必須のルートマトリクス。各要素は
pixels[row][column]のセルのスタイルです。左上が原点。長方形、最小 1 × 1、最大4,096セル。 default- 型 / 値
Pixel - 用途とルールセルの既定スタイル。明示セルや各 batch のスタイルで省略したプロパティの補完にも使います。
layout- 型 / 値
MatrixLayout - 用途とルールマトリクス全体の間隔、セルの縦横比、端の余白を定義します。各点の色や形状とは別です。
batch- 型 / 値
{ pixel, coordinates }[] - 用途とルール同じ
pixelスタイルを、0始まりの[row, column]座標で選んだ点に適用します。規則的な模様を繰り返し記述せずに生成できます。
優先順位は default → 配列順の batch → pixels の明示オブジェクトです。null は default / batch の結果を保持します。明示オブジェクトで省略したプロパティは default に戻り、batch のプロパティとは合成しません。セルのスタイルを省略するときは null を置き、要素の削除や行の短縮はしないでください。例は「ピクセルと優先順位」にあります。
データのルート:data
任意の data オブジェクト(省略時は空)には、レイヤーが読み取る内容を置きます。フィールド名や入れ子の構造は自由で、たとえば1つのパネルのレイヤーを data.orders の下にまとめられます。画像マテリアルのデータパスも、ここから画像を読み取ります(サーバー側で描画した画像を参照)。
data 自体は自由に構成できるオブジェクトにすぎず、その値だけでは表示されません。エディタで作った動的なコンテンツや、API が返すリモートレイヤーは、dataPath で指定した data 内のフィールドを読み取り、ルールに従って解釈・描画します。エディタのレイヤーやリモートレイヤーを動かすフィールドは、必ずオブジェクトで、レイヤーの種類ごとのプロトコルに従う必要があります。基本的な構造は、dataPath が指すフィールドにそのレイヤーの位置・内容・スタイルを含めることです。詳しくは下の layers と「レイヤー」の章を参照してください。
リモートレイヤー:layers
任意の layers 配列で、API が追加するレイヤーを宣言します。省略時はなしです。各項目は id、type、dataPath の3つだけを持ちます。id は remote: で始まりレスポンス内で一意、type は7種類のレイヤーのいずれか、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 はそのフレームのリモートレイヤー全体で、次の成功レスポンスで丸ごと置き換わります。差分更新の命令ではありません。エディタで追加したレイヤーはここで宣言せず、エディタで指定したデータパスでバインドします(「レイヤー」の章を参照)。
pixels は必須です。[[{"empty": true}]] を返すとルートが空白になり、カードの素材の上にレイヤーだけを表示できます。レスポンスボディの完全型リファレンス#
次の入れ子構造と関連する型がレスポンス全体を示します。? は省略可能、[] は配列、| は選択可能な型です。これは型のリファレンスであり、そのまま返す JSON ではありません。レイヤーの 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
}ピクセルのスタイル#
以下のフィールドは1つのピクセルのスタイルを表し、ルートの default、batch[].pixel、pixels[row][column] に記述します。マトリクスレイヤーの content 内の default、batch[].pixel、pixels にも適用します。
| フィールド | 範囲 | 説明 |
|---|---|---|
color | #RRGGBB · #AARRGGBB | 16進カラー。8桁形式はアルファが先頭(ARGB)で、CSSの #RRGGBBAA とは異なります。 |
opacity | 0 – 1 | 範囲内に丸められます。カラーのアルファと組み合わされます。 |
cornerRadius | 0 – 0.5 | セル短辺に対する角丸半径。0 は直角、0.5 は最大の角丸。正方形なら円、長方形ならカプセル形です。 |
rotation | 度 | 45 で正方形がひし形になります。 |
halo | 0 – 1 | 点の発光強度。0 で無効。点の強調や電光表示の質感を作ります。 |
empty | boolean | true でそのセルの描画をスキップします。 |
color- 範囲
#RRGGBB·#AARRGGBB - 説明16進カラー。8桁形式はアルファが先頭(ARGB)で、CSSの
#RRGGBBAAとは異なります。 opacity- 範囲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エントリ。配列の順で、後のものが優先 pixels内の、明示的な null 以外の値
null は透明ではなく、ここでは上書きしないことを意味します。{"empty": true} は明示的な空白で、何も描画されませんが、セルはグリッド内の場所を保ちます。明示的なピクセルオブジェクトは、省略されたフィールドについて default にフォールバックし、下にあるバッチのスタイルにはフォールバックしません。
{
"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]
]
}
]
}バッチの座標は0始まりの [row, column] の整数ペアで、グリッド内に収まっている必要があります。範囲外の座標があると、アプリはフレームを拒否します。
グリッドのレイアウト#
以下のフィールドはマトリクス全体の配置を表します。レスポンスの layout、またはマトリクスレイヤーの content.layout に記述します。
グリッドはピクセルの縦横比を保って中央に収めます(contain)。間隔と端の余白はピクセルの短辺を基準とし、カード全体に対する割合ではありません。edgeInsetRatio、columnGapRatio、rowGapRatio の値は、1つのピクセルの短辺の長さに対する倍率です。gapMode は間隔のプリセット倍率を選び、cellAspectRatio はピクセルの幅と高さの比率を指定します。
| フィールド | 値 | 既定値 | 用途 |
|---|---|---|---|
gapMode | zero · near · default · far · extraFar | default | 隣り合うピクセル間の間隔プリセット。順に、1つのピクセルの短辺の長さの 0、0.08、0.16、0.28、0.42 倍で、水平・垂直両方向に適用します。 |
edgeInsetRatio | −0.45–0.45 | 0 | マトリクス周囲の余白 = 1つのピクセルの短辺の長さ × この値。正値は余白を増やし、負値は端のピクセルを描画領域の外へ広げ、はみ出す部分をクリップします。 |
cellAspectRatio | 0.1–10 | 1 | 1つのピクセルの幅 ÷ 高さ。1 は正方形、1 未満は縦長、1 超は横長です。マトリクスの行数・列数は変更しません。 |
columnGapRatio | 0–10 | — | 隣接するピクセル列の水平間隔 = 1つのピクセルの短辺の長さ × この値。gapMode の水平間隔を上書きし、省略時はプリセットを使用します。 |
rowGapRatio | 0–10 | — | 隣接するピクセル行の垂直間隔 = 1つのピクセルの短辺の長さ × この値。gapMode の垂直間隔を上書きし、省略時はプリセットを使用します。 |
gapMode- 値
zero·near·default·far·extraFar - 既定値
default - 用途隣り合うピクセル間の間隔プリセット。順に、1つのピクセルの短辺の長さの
0、0.08、0.16、0.28、0.42倍で、水平・垂直両方向に適用します。 edgeInsetRatio- 値−0.45–0.45
- 既定値
0 - 用途マトリクス周囲の余白 = 1つのピクセルの短辺の長さ × この値。正値は余白を増やし、負値は端のピクセルを描画領域の外へ広げ、はみ出す部分をクリップします。
cellAspectRatio- 値0.1–10
- 既定値
1 - 用途1つのピクセルの幅 ÷ 高さ。
1は正方形、1未満は縦長、1超は横長です。マトリクスの行数・列数は変更しません。 columnGapRatio- 値0–10
- 既定値—
- 用途隣接するピクセル列の水平間隔 = 1つのピクセルの短辺の長さ × この値。
gapModeの水平間隔を上書きし、省略時はプリセットを使用します。 rowGapRatio- 値0–10
- 既定値—
- 用途隣接するピクセル行の垂直間隔 = 1つのピクセルの短辺の長さ × この値。
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 の順で合成されます。同値なら id 順です。
レイヤーの宣言
layers の各項目が1つのリモートレイヤーを宣言します。
| フィールド | 型 | 説明 |
|---|---|---|
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、空配列は有効な上書き値です。 - レスポンスのたびに保存済みの設定から計算し直します。次のレスポンスがあるフィールドを返さなくなるとエディタの値に戻り、リクエストが失敗した場合は最後に成功したレスポンスを表示し続けます。
マトリクス・テキスト・曲線・直線・図形のレイヤーには、エディタに「現在のプレビュー」の切り替えがあります。影響するのは編集画面だけで、既定スタイルを選ぶとエディタの値だけを表示し、代替表示の見た目を調整できます。アプリのホーム、ホーム画面、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%の余白を設けます。
- 幅と高さは必須:
frameを指定する場合、widthとheightを両方指定します。 - 片側からの距離:
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 | 左・右端からの距離を画布幅の比で指定。両方省略なら x = 0、right のみなら右側に固定。 |
top / bottom | number | 上・下端からの距離を画布高さの比で指定。両方省略なら y = 0、bottom のみなら下側に固定。 |
transform.translateX / translateY | number | 配置後の移動量。レイヤー自身の幅・高さが単位で、正の値は右・下へ移動します。 |
width/height- 型 / 範囲0.02–1.5
- 用途必須。画布の対応軸に対する幅・高さの比。両側アンカーが揃うとその軸のサイズを決定します。
left/right- 型 / 範囲number
- 用途左・右端からの距離を画布幅の比で指定。両方省略なら x = 0、right のみなら右側に固定。
top/bottom- 型 / 範囲number
- 用途上・下端からの距離を画布高さの比で指定。両方省略なら y = 0、bottom のみなら下側に固定。
transform.translateX/translateY- 型 / 範囲number
- 用途配置後の移動量。レイヤー自身の幅・高さが単位で、正の値は右・下へ移動します。
データパス
dataPath は data から始まり、フィールドと数値インデックスをたどります。例:data.orders.total、data.cards[0]。式、ワイルドカード、文字列キーは使えません。必ずオブジェクトを指す必要があります。
^data(?:\.[A-Za-z_][A-Za-z0-9_]*|\[[0-9]+\])*$オブジェクトにエラーがある場合
このオブジェクトのエラーは対応するレイヤーだけに影響し、レスポンス全体は有効なままです。パスが存在しない、オブジェクトを指していない、オブジェクトやレイヤーの種類が対応しないフィールドがある、値の型や選択肢が不正、frame に width か height がない、リモートレイヤーに frame がない、リモートマトリクスに content.pixels がない場合:
- エディタのレイヤーは保存済みの状態に戻り、アプリはそのレイヤーの「データパス」の下に理由を表示します。
- リモートレイヤーは描画されません。
- ルートグリッドとほかのレイヤーは通常どおり表示されます。
フィールド表の範囲外の数値はエラーではなく、レンダラーが範囲内に丸めます。
{
"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 または alpha が先頭の #AARRGGBB、pt は iOS の論理ピクセル。表の既定値はリモートレイヤーで省略した場合の値です。エディタのレイヤーでは省略したフィールドにエディタの設定を使い、新規レイヤーのプリセットはこれらの既定値と異なる場合があります。
各レイヤー種類で共通のスタイルフィールド
この表は text、image、shape に適用します。opacity の意味は各表を参照。他の種類はそれぞれの表にあるフィールドを使用します。
| フィールド | 型 / 値 | 用途とルール |
|---|---|---|
style.backgroundColor | Color | レイヤー背景を塗る色。テキスト背景は style.opacity を上げると表示され、図形は省略時に style.color を使います。 |
style.cornerRadiusRatio | 0–1 | 四隅を丸くし、その輪郭で内容をクリップします。半径 = レイヤー短辺 × 値 ÷ 2。0(省略時の既定値)は直角、1 は正方形なら円、長方形ならカプセル形。 |
style.borderColor | Color | レイヤー輪郭の内側に描く枠線の色。既定は白。borderWidth と 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 | 各色の位置を1対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は正方形なら円、長方形ならカプセル形。 style.borderColor- 型 / 値Color
- 用途とルールレイヤー輪郭の内側に描く枠線の色。既定は白。
borderWidthと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
- 用途とルール各色の位置を1対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 で文字色の alpha を保持。背景には 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で文字色の alpha を保持。背景には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 を計算。式があれば関数、なければサンプルが既定。 |
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 | 数式の名前付き数値パラメータを最大64個。値は ±1e9 に制限。 |
content.domain | [min, max] | X データ範囲 [最小, 最大] を描画領域の左右端へ対応させます。省略時は点から推定し、点がなければ [0, 1]。 |
content.yDomain | [min, max] | Y 表示範囲 [最小, 最大]。最小が下端、最大が上端。[0, 100] の50は高さの中央です。省略時は点から推定し、点がなければ [0, 1]。 |
content.interpolation | linear / stepAfter / monotone | 点の間の形。linear は直線、stepAfter は前の値を保ってから次へ跳び、monotone は過度な振れを避けて滑らかに接続(既定)。 |
content.markers | array · ≤32 | 曲線上の円とラベルのマーカー。最大32個。フィールドは次表。 |
content.mode- 型 / 値
samples/function - 用途とルール曲線の入力方式。
samplesはpointsを接続、functionはdomain内でexpressionを計算。式があれば関数、なければサンプルが既定。 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
- 用途とルール数式の名前付き数値パラメータを最大64個。値は ±1e9 に制限。
content.domain- 型 / 値
[min, max] - 用途とルールX データ範囲
[最小, 最大]を描画領域の左右端へ対応させます。省略時は点から推定し、点がなければ[0, 1]。 content.yDomain- 型 / 値
[min, max] - 用途とルールY 表示範囲
[最小, 最大]。最小が下端、最大が上端。[0, 100]の50は高さの中央です。省略時は点から推定し、点がなければ[0, 1]。 content.interpolation- 型 / 値
linear/stepAfter/monotone - 用途とルール点の間の形。
linearは直線、stepAfterは前の値を保ってから次へ跳び、monotoneは過度な振れを避けて滑らかに接続(既定)。 content.markers- 型 / 値array · ≤32
- 用途とルール曲線上の円とラベルのマーカー。最大32個。フィールドは次表。
マーカー:各 content.markers[] オブジェクトのプロパティ。
| フィールド | 型 / 値 | 用途とルール |
|---|---|---|
at.x | number | マーカーの X データ値。高さは曲線から計算。sampleIndex と片方を使用。 |
at.sampleIndex | integer | サンプルモードで追従する点の0始まりの番号。X 昇順の配列を使用します。 |
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
- 用途とルールマーカーの X データ値。高さは曲線から計算。
sampleIndexと片方を使用。 at.sampleIndex- 型 / 値integer
- 用途とルールサンプルモードで追従する点の0始まりの番号。X 昇順の配列を使用します。
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 | 曲線の線幅(pt)。既定 2。 |
style.lineCap | round / butt / square | 線端形状。round は半円を追加(既定)、butt は座標で平坦に終わり、square は半線幅だけ四角く延長。 |
style.lineJoin | round / bevel / miter | 折れ点の接合。round は丸(既定)、bevel は角を削り、miter は尖らせます。折線や階段状の線で分かりやすい効果です。 |
style.dashLength | 0.5–64 · pt | 破線の線分長(pt)。省略で実線。 |
style.dashGap | 0–64 · pt | 破線の間隔(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
- 用途とルール曲線の線幅(pt)。既定
2。 style.lineCap- 型 / 値
round/butt/square - 用途とルール線端形状。
roundは半円を追加(既定)、buttは座標で平坦に終わり、squareは半線幅だけ四角く延長。 style.lineJoin- 型 / 値
round/bevel/miter - 用途とルール折れ点の接合。
roundは丸(既定)、bevelは角を削り、miterは尖らせます。折線や階段状の線で分かりやすい効果です。 style.dashLength- 型 / 値0.5–64 · pt
- 用途とルール破線の線分長(pt)。省略で実線。
style.dashGap- 型 / 値0–64 · pt
- 用途とルール破線の間隔(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。画像・アイコン注釈は別レイヤーで組み合わせます。
{
"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 URL、data:image/…;base64,、または Base64 文字列を指定します。 - スタイル:URL 画像は cover で枠を埋めて切り取り。角丸・枠線・マスクは共通フィールド。エディタのローカル画像は contain。
| フィールド | 型 / 値 | 用途とルール |
|---|---|---|
content.url | string | 画像 URL または Base64 データ。エディタの画像レイヤーでソースを「API データ」にすると、そのオブジェクトのこのフィールドを読み取ります。url を返すと、その画像を表示します。サーバーから端末上のファイルパスは参照できません。 |
style.opacity | 0.1–1 | 画像自体の不透明度。既定 1。0.5 なら半透明で下が透け、最小は 0.1。マスクや枠線の不透明度は変えません。 |
style.color | Color | 読み込み中のプレースホルダー色。画像の着色ではありません。 |
content.url- 型 / 値string
- 用途とルール画像 URL または Base64 データ。エディタの画像レイヤーでソースを「API データ」にすると、そのオブジェクトのこのフィールドを読み取ります。
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を使います。1つのオブジェクトはどちらか一方だけを返します。 - スタイル:アイコンは縦横比を保って
frame内に全体を収め、textOpacityで不透明度を制御します。字形の色と発光は下表のフィールドを使います。
| フィールド | 型 / 値 | 用途とルール |
|---|---|---|
content.icon | string | ph_activity などの安定した識別名。アプリのプレビューがアイコンを検索するために使用します。下の2フィールドと同じアイコンを指定し、セットで記述します。名前とコードの二者択一ではありません。 |
content.iconCodePoint | integer | iconFont のフォント内で字形を指定する Unicode コードポイント。ホーム画面の描画に使用し、ph_activity は 57344。一覧の通し番号ではありません。省略時は一部の旧 Material 名だけにフォールバックし、現在の全アイコンには対応しません。 |
content.iconFont | phosphorBold / devicon / simpleIcons / material | ホーム画面が使用する内蔵フォントの識別子。iconCodePoint と一致する組が必要です。例:ph_activity は phosphorBold。同じコードでもフォントが違うと字形が変わります。外部フォントは読み込みません。 |
content.url | string | 画像アイコンの URL または Base64 データ。contain で全体を表示します。content.icon と同時には返せません。エディタのアイコンレイヤーでソースを「API データ」にすると、そのオブジェクトは内蔵アイコンと url のどちらでも返せます。 |
style.color | Color | 静的字形の色。既定は白。URL/API の画像アイコンは着色しません。 |
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などの安定した識別名。アプリのプレビューがアイコンを検索するために使用します。下の2フィールドと同じアイコンを指定し、セットで記述します。名前とコードの二者択一ではありません。 content.iconCodePoint- 型 / 値integer
- 用途とルール
iconFontのフォント内で字形を指定する Unicode コードポイント。ホーム画面の描画に使用し、ph_activityは57344。一覧の通し番号ではありません。省略時は一部の旧 Material 名だけにフォールバックし、現在の全アイコンには対応しません。 content.iconFont- 型 / 値
phosphorBold/devicon/simpleIcons/material - 用途とルールホーム画面が使用する内蔵フォントの識別子。
iconCodePointと一致する組が必要です。例:ph_activityはphosphorBold。同じコードでもフォントが違うと字形が変わります。外部フォントは読み込みません。 content.url- 型 / 値string
- 用途とルール画像アイコンの URL または Base64 データ。contain で全体を表示します。
content.iconと同時には返せません。エディタのアイコンレイヤーでソースを「API データ」にすると、そのオブジェクトは内蔵アイコンとurlのどちらでも返せます。 style.color- 型 / 値Color
- 用途とルール静的字形の色。既定は白。URL/API の画像アイコンは着色しません。
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。大きいほど光が広がりますが、字形サイズは変わりません。
専用ページでアプリと同じ分類・順序のアイコンを閲覧・検索し、対応する 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 | 線幅(pt)。既定 2。枠は長さを決め、太さはこの値で指定。 |
style.pattern | solid / dashed / dotted | 描画方式。solid は実線(既定)、dashed は実線部分と空隙、dotted は strokeWidth を直径とする円を繰り返します。 |
style.cap | round / butt | 実線と破線線分の端。round は半円(既定)、butt は平坦。点線は常に円で、この指定は使いません。 |
style.dashLength | 1–32 · pt | 破線の各線分長(pt)。既定 6。dashed のみで使用。 |
style.dashGap | 0–32 · pt | 破線の線分や円点の間の空白長(pt)。既定 4。大きいほど疎になり、solid では使いません。 |
style.gradientEnabled | boolean | グラデーションで線を描画。既定 false。 |
style.gradientColors | Color[] | 順に並ぶ2〜3色。gradientEnabled が必要。ネイティブは枠の左から右へ、アプリの縦線プレビューは上から下へ変化。 |
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
- 用途とルール線幅(pt)。既定
2。枠は長さを決め、太さはこの値で指定。 style.pattern- 型 / 値
solid/dashed/dotted - 用途とルール描画方式。
solidは実線(既定)、dashedは実線部分と空隙、dottedはstrokeWidthを直径とする円を繰り返します。 style.cap- 型 / 値
round/butt - 用途とルール実線と破線線分の端。
roundは半円(既定)、buttは平坦。点線は常に円で、この指定は使いません。 style.dashLength- 型 / 値1–32 · pt
- 用途とルール破線の各線分長(pt)。既定
6。dashedのみで使用。 style.dashGap- 型 / 値0–32 · pt
- 用途とルール破線の線分や円点の間の空白長(pt)。既定
4。大きいほど疎になり、solidでは使いません。 style.gradientEnabled- 型 / 値boolean
- 用途とルールグラデーションで線を描画。既定
false。 style.gradientColors- 型 / 値Color[]
- 用途とルール順に並ぶ2〜3色。
gradientEnabledが必要。ネイティブは枠の左から右へ、アプリの縦線プレビューは上から下へ変化。 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" }
]
}サーバー側で描画した画像#
ドットやレイヤーで内容を記述するほかに、描画をすべてサーバーに任せることもできます。使い慣れたグラフライブラリ、テンプレートエンジン、ヘッドレスブラウザでウィジェット全体を 1 枚の画像にし、data で返します。ウィジェットはそれを「画像」マテリアルとしてキャンバス全体に表示するため、レイヤーの設定も、このページの描画構文の習得も不要です。
既存のレポートや画像生成の仕組みがある場合、複雑なグラフや独自フォント、自由なレイアウトが必要な場合、アプリ側の設定を変えずにサーバーだけで見た目を調整したい場合に向いています。
アプリでの設定
- エディタでマテリアルを「画像」にする
- 画像ソースを「API」にする
- データパスに画像のフィールドを入力する(例:
data.cover) - 画像の上に文字レイヤーを重ねる場合は、必要に応じて読みやすさのグラデーションをオンにする
レスポンス
{
"protocol": 1,
"pixels": [[{ "empty": true }]],
"data": {
"cover": "https://cdn.example.com/widgets/orders-medium@3x.png"
}
}| データパスの値 | ルール |
|---|---|
| HTTPS URL | image/* を返し、最大 6 MB。ホーム画面では長辺 1,200 px に縮小されます。 |
data:image/…;base64, または Base64 文字列 | レスポンスに埋め込むため小さな画像向け。JSON レスポンス全体は 512 KB までです。 |
- HTTPS URL
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}]] を返せば画像だけが表示されます。画像の上にドットやレイヤーを重ねることもでき、頻繁に変わる数値はネイティブの文字で表示できます。リクエスト署名#
アプリでウィジェットにシークレットを設定すると、各リクエストにサーバーで検証できる2つのヘッダーを付けられます。リクエストが無関係な第三者や悪意ある第三者ではなく、Glance Widgets のウィジェットから送られたことを証明するために使います。シークレット自体が送信されることはありません。
| ヘッダー | 値 |
|---|---|
X-GlanceWidgets-Timestamp | Unix時間(ミリ秒)を10進数の文字列で。 |
X-GlanceWidgets-Signature | Base64(HMAC-SHA256(key = secret, message = timestamp + "\n" + secret))、すべてUTF-8。 |
X-GlanceWidgets-Timestamp- Unix時間(ミリ秒)を10進数の文字列で。
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以内 · Base64は4 MB以内 · カバーフィット |
- ボディサイズ
- 512 KB (524,288 bytes)
- ルートグリッド
- rows × columns ≤ 4,096;≥ 1 × 1;長方形
- レイヤーの宣言
- 各項目は
id、type、dataPathのみで、id はremote:で始まる - プロトコル
1または省略- 曲線
- 1,024点以内 · マーカー32個以内 · 式は512文字以内
- 画像
- リモート6 MB以内 · Base64は4 MB以内 · カバーフィット
レスポンス容量超過、不正なルート配列、範囲外の batch 座標、レイヤー宣言の構造エラーは、レスポンス全体がアプリで拒否されます。レイヤーが指すオブジェクトのエラーはそのレイヤーだけに影響し、エディタのレイヤーは保存済みの状態に戻り、リモートレイヤーは描画されません。曲線の点・マーカー・パラメータは上限内だけ読み取り、不正・長すぎる式は実行しません。
更新#
ホーム画面のウィジェットは、WidgetKitのタイムラインに沿って、約 15分 ごとに新しいフレームをリクエストします。正確なタイミングは、バッテリー、使用状況、システムの更新予算に応じてiOSが決めます。更新の合間にも意味が伝わるフレームを設計し、必要なら data に「最終更新」の時刻を含めてください。
プレイグラウンド#
JSONを編集すると、その場で描画されます。バリデーターは、アプリと同じ制限と優先順位を適用します。
有効なフレーム 0 セル · 0 レイヤー · 0 バイト
チェックリスト#
- HTTPSエンドポイントが、数秒以内に
2xxを返す。 - ルートが
"protocol": 1を持つオブジェクトで、pixelsが4,096セル以内の長方形の配列である。 - 色は
#RRGGBB(またはARGBの#AARRGGBB)である。 layersの各項目はid、type、dataPathだけを持ち、id はremote:で始まる。- すべての
dataPathがdata内のオブジェクトを指し、リモートレイヤーではそのオブジェクトにwidth、heightを含むframeがある。 - グリッドは固定の表ではなく、
gw_aspect_ratioからサイズを決めている。 - 署名を有効にしている場合は、タイムスタンプの有効期間を確認し、署名を定数時間で検証する。