Rebuild the face against the design kit; make fields configurable

Vendor the watchface-kit into design/ and derive everything from it instead
of from hand-transcribed constants.

Geometry, from design/rebuild.py and the ink boxes of the traced SVG paths:
  - ring ticks are annular sectors (fillPolygon), not radial lines
  - top arc is 21 ticks at 6.5+4k, not 22 at 2+4k
  - exact radii, tick widths, anchor dots, band and colon rectangles
  - element positions taken from measured ink bounding boxes

Colour, generated by tools/gen_themes.py straight out of the comps:
  - per-tick colour tables (21+21) replace 9/7 interpolated stops
  - 11-stop vertical gradients on the time digits, drawn with clip banding
  - per-element accent / value colours and per-theme unlit tick colour

Data: the design's sunrise and hi/lo fields turn out to be available after
all -- Weather.getSunrise and getDailyForecast both exist in SDK 9.1.0 --
so both are restored, and heart rate is added alongside them.

Bugs found on the way:
  - Gregorian FORMAT_MEDIUM returns day_of_week/month as strings, so the
    date band crashed on every update (caught in the simulator)
  - Stats.battery is already 0-100, multiplying by 100 gave "4000%"
  - moveBarLevel is an integer level 0..5, not a 0..1 ratio, so the move
    bar arc was all-or-nothing

Also: all four field slots are configurable with labels that follow the
selection, temperature unit is a setting, on-face wording moved into
resources with a Simplified Chinese variant, and 24h/distance/temperature
now follow the watch. Fonts are chosen by measured cap height rather than
by ascent.

Verified in the Connect IQ simulator on fenix847mm and by compiling all
17 target devices.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-09 22:04:27 +08:00
parent 553c55026a
commit 398018b51e
22 changed files with 3334 additions and 1012 deletions

314
README.md
View File

@@ -1,168 +1,246 @@
# Fenix 8 V3 — Garmin 数据表盘
一款基于 Connect IQ 设计稿(`watchface-kit`1:1 还原的多指标数据表盘。设计画布 **500×500** 正方形,渲染时按屏幕宽度等比缩放,支持圆形 AMOLEDFenix 8 / Enduro 3 / Epix 2)与圆屏 MIPFenix 7 / FR965 等)设备。
`watchface-kit` 设计稿 1:1 还原的多指标数据表盘。设计画布 **500×500**,渲染时按屏等比缩放 `s = screenWidth / 500`,支持圆形 AMOLEDFenix 8 / Epix 2 / Venu 3 等)与圆屏 MIPFenix 7 / Enduro 3 / FR255 等)共 17 款设备。
- **SDK**Connect IQ SDK 9.1.0`monkeyc` 9.1.0API level `minSdkVersion="4.2.0"`
- **语言**Monkey C
- **SDK**Connect IQ SDK 9.1.0`monkeyc` 9.1.0`minSdkVersion="4.2.0"`
- **语言**Monkey C;界面文案含英文与简体中文
- **类型**`watchface`
- **应用 ID**`f8a3c1b2c3d44e5f8a9b0c1d2e3f4a5b`
---
## 1. 布局还原(与设计稿基准)
所有坐标以 500×500 设计画布为基准,渲染时统一乘以缩放系数 `s = screenWidth / 500.0`Enduro 3 屏宽 416px → `s≈0.832`)。下表中 `y` 为设计稿原始像素值。
| 区域 | 设计坐标500 基准) | 内容 | 说明 |
|------|----------------------|------|------|
| 进度环 | 外半径 `rOut=249.5`,内半径 `rIn=231.5` | 四段进度弧 + 4 个锚点圆点 | 见 §2 |
| 电量 | `y=53.5`,电池框居中偏左 | 电池图标 + 百分比 | `System.getSystemStats().battery` |
| 上方双复杂功能 | 图标 `y=90`,数值 `y=130.5`;左侧 `x=156`,右侧 `x=343` | 天气温度 / 卡路里 / 步数 / 距离 / 楼层 / 电量 | 见 §4 |
| 中央时间 | `y=220`;小时 `x=211`(右对齐),分钟 `x=272`(左对齐) | `HH : MM`12 小时制) | 冒号用两块矩形块,位于 `x=238` |
| 日期带 | 矩形 `y=286.5`,高 `44` | 蓝牙图标 + 星期 + 月日 + AM/PM | 蓝牙图标 `x=36.5`,星期 `x=177.5`,月日 `x=297.5` |
| 底部指标 | 数值 `y=366`,标签 `y=410.5` | 左侧距离(`DST`),右侧步数(`STEP` | 距离单位 km |
进度环几何(取自设计稿 `rebuild.py`
- **顶弧**22 根刻度,角度 `TOP = [2,6,…,86]`(步距 4线宽 `13`,渐变停止点 9 个(`8→86`)。
- **底弧**21 根刻度,角度 `BOT = [6,9,…,66]`(步距 3线宽 `9`,渐变停止点 7 个(`7→47`)。
- **锚点圆点**:位于角度 `[0.0, 93.3, 180.0, 266.7]`,圆心半径 `240.5`,圆点半径 `9.5`
- 刻度“点亮”数量按对应指标进度换算:`litTR/TL = progress × 22``litBR/BL = progress × 21`
时间字体为 `FONT_NUMBER_HOT`(大号数字),其余为 `FONT_MEDIUM` / `FONT_SMALL`
设计稿本体7 张 SVG + tokens + 逆向脚本)在 `design/`,是本仓库所有坐标与配色的唯一来源。
---
## 2. 七套主题Themes
## 1. 目录结构
颜色数据由 `watchface-tokens.json``gen_themes.py` 生成到 `source/Themes.mc`**请勿手改**,改 tokens 后重新生成)。每套主题包含:顶/底弧渐变停止点、未点亮刻度色 `tickOff`、锚点色 `anchorDot`、日期带填充 `bandFill` / 文字 `bandText`、强调色 `accent`、主文字 `textPrimary`、冒号色 `colon`、小时 `hours`、分钟 `minutes`
```
fenix8v3-watchface/
├── manifest.xml # 应用清单ID / 支持设备 / 语言)
├── monkey.jungle # 构建配置
├── design/ # ⭐ 设计稿原件(唯一事实来源)
│ ├── watchface-0N-*.svg # 7 套主题的矢量还原稿
│ ├── watchface-tokens.json # 配色 token
│ └── rebuild.py # 原作者从位图逆向出 SVG 的脚本(仅存档,不参与构建)
├── tools/
│ ├── gen_themes.py # design/*.svg -> source/Themes.mc
│ └── gen_preview_svg.py # source/Themes.mc -> preview-themes.svg + preview.html
├── source/
│ ├── Fenix8V3App.mc # 应用入口
│ ├── Fenix8V3View.mc # 全部渲染逻辑
│ └── Themes.mc # ⚠️ 自动生成,勿手改
├── resources/ # 英文文案 + 设置项定义
├── resources-chn/ # 简体中文文案
└── bin/ # 编译产物(已 gitignore
```
| # | 主题 | 主色调 | 分钟数字 | 日期带 |
|---|------|--------|----------|--------|
| 1 | Ember | 橙红渐变(黄→红) | `0xFCA901` | 橙底黑字 |
| 2 | Aurora | 青绿渐变(黄绿→青) | `0xAAF701` | 深灰底白字 |
| 3 | Brass | 金铜渐变 | `0xECCC93` | 深棕底白字 |
| 4 | Voltage | 蓝→黄渐变 | `0x52A8FD` | 蓝底黑字 |
| 5 | Reef | 橙→青渐变 | `0xFC7801` | 青底黑字 |
| 6 | Acid | 黄绿(近单色) | `0xC4F900` | 深灰底黑字 |
| 7 | Kelp | 橙→绿渐变 | `0xF4880A` | 深灰底黑字 |
三份实现(表盘 / SVG 预览 / HTML 预览)只有 **一份颜色数据**`Themes.mc`。预览脚本直接解析它,不会与固件漂移。
---
## 3. 可配置设置Garmin Connect / 表盘设置
## 2. 布局500 基准,取自设计稿 SVG 路径的墨迹包围盒
通过 `resources/settings/` 暴露,键名与默认值见 `properties.xml`
| 元素 | 位置 | 说明 |
|------|------|------|
| 进度环 | 内半径 `231.09`,外半径 `249.10` | 见 §3 |
| 电量图标 | `x=192.70``cy=53.20``26.20×17.81` | 圆角外框 + 按电量填充 + 右侧触点 |
| 电量数值 | 左对齐 `x=232.00` | `NN%` |
| 上方双数据 | 图标 `cy=90`,数值 `cy=131.06`;左 `x=157.00`,右 `x=343.70` | 居中对齐 |
| 时间 | `cy=221.10`;小时右对齐 `x=211.40`,分钟左对齐 `x=276.02` | 竖向渐变,见 §4 |
| 冒号 | `x=237.88``24.24×21.30``y=183.68 / 234.57` | 两块矩形 |
| 日期带 | `y=286.30`,高 `44.19`,文字 `cy=308.10` | 蓝牙 `cx=36.88`、星期 `cx=178.05`、月日 `cx=298.28`、AM/PM 右对齐 `465.89` |
| 底部数值 | `cy=366.76`;距离右对齐 `234.30`,步数左对齐 `267.40` | |
| 底部标签 | `cy=410.88`,同上对齐 | 跟随所选数据(`DST` / `STEP` / `距离` …) |
字号按设计稿的**字面高度cap height**选取:日期带与电量 `25.34`、上方数据与底部行 `31.50`、时间 `98.70`
---
## 3. 进度环
刻度是**等角宽的环形扇区**`fillPolygon` 四点),不是径向线段。
- **顶弧**21 根,角度 `6.5 + 4.0k`k=0..20),角宽 `3.108°`
- **底弧**21 根,角度 `6.005 + 3.0k`,角宽 `2.086°`
- **四象限**:右上 `+a`、左上 `-a`、左下 `180+a`、右下 `180-a`(角度为自 12 点起顺时针)
- **锚点圆点**:半径 `9.00`,位于圆心距 `240.10`、角度 `0 / 93.15 / 180 / 266.85`
**点亮方向**(与设计稿一致):两条顶弧从 9 点 / 3 点一侧朝 12 点填充;两条底弧从 6 点朝两侧填充。
每根刻度的颜色是设计稿里**逐根取样**的实测值(`Themes.RINGTOP[21]` / `RINGBOTTOM[21]`),不是插值近似。
> **已知近似**:设计稿中底弧最多只点亮 14/21 根,因此 `RINGBOTTOM` 的第 1521 项无法实测,由 `gen_themes.py` 对最后 8 根做最小二乘线性外推得到。只有当指标超过约 67% 时才会显示这几根。
### 指标进度换算
| idx | 指标 | 分母 |
|-----|------|------|
| 0 | 步数 | `stepGoal` |
| 1 | 卡路里 | 固定 2000 kcal |
| 2 | 距离 | 10 km |
| 3 | 楼层 | `floorsClimbedGoal`(缺省 10 |
| 4 | 动动条 | `MOVE_BAR_LEVEL_MAX`=5 |
---
## 4. 时间数字的竖向渐变
设计稿的小时 / 分钟数字带竖向多段渐变(如 Ember 分钟由 `#FEAA00` 渐变到 `#FF2600`。Monkey C 无法给文字直接填渐变,实现方式是**同一串数字画 11 遍,每遍用 `dc.setClip` 限制在一条横向色带内**,色带颜色取自 `Themes.HOURS` / `Themes.MINUTES`(各 11 个停止点,实测自设计稿的 `linearGradient`)。首尾两条色带向外延伸,保证字形不会有未绘制的缝隙。
---
## 5. 字号选择
Connect IQ 只暴露 `getFontAscent` / `getFontDescent` / `getFontHeight`**没有字面高度接口**,而 ascent 里含有数字和大写字母用不到的变音符空间。因此代码用两个实测比例把 ascent 折算成 cap height
```
文本字体Roboto 系) cap ≈ 0.76 × ascent
数字字体Bionic 系) cap ≈ 0.71 × ascent
```
比例是在模拟器里渲染后、从截图上量出墨迹得到的fenix847mm`FONT_XTINY` ascent 29 → 大写高 22px`FONT_NUMBER_MILD` ascent 82 → 数字高 58px`pickFont` 取折算后**最接近**目标 cap height 的字体,而不是"最大且不超过"——后者会在设计尺寸落在两档字体之间时白白小一号。
各机型内置字体不完全相同Roboto-Regular / RobotoCondensed-Bold / Yantramanav / 各机型位图字体),比例会有几个百分点误差。设计稿使用的是更粗更方的第三方字体,不随包分发,字形差异无法消除。
---
## 6. 七套主题
`tools/gen_themes.py``design/watchface-0N-*.svg` 生成。每套包含:顶/底弧各 21 根刻度色、未点亮刻度色、锚点色、日期带底/字色、冒号色、小时/分钟各 11 段渐变、强调色(图标与 DST/STEP 标签)、主文字色(各项数值)。
| # | 主题 | 主色调 | 强调色 | 日期带 |
|---|------|--------|--------|--------|
| 1 | Ember | 黄 → 红 | `#FEAA05` | 橙底黑字 |
| 2 | Aurora | 黄绿 → 青 | `#ADABAE` | 深灰底白字 |
| 3 | Brass | 金铜 | `#B57E4B` | 深棕底白字 |
| 4 | Voltage | 蓝 → 黄 | `#ADABAE` | 蓝底黑字 |
| 5 | Reef | 橙 → 青 | `#FEAA05` | 青底黑字 |
| 6 | Acid | 黄绿(近单色) | `#C6FA03` | 深灰底黑字 |
| 7 | Kelp | 橙 → 绿 | `#34C294` | 深灰底黑字 |
改配色:编辑 / 替换 `design/` 里的 SVG然后
```bash
python3 tools/gen_themes.py && python3 tools/gen_preview_svg.py
```
新增主题需同步在 `settings.xml``Theme` 列表与 `strings.xml`(含 `resources-chn/`)中登记。
---
## 7. 可配置设置
共 13 项,通过 Garmin Connect 手机 App 的「表盘设置」修改(定义在 `resources/settings/settings.xml`,默认值在 `properties.xml`)。
| 设置 | 键 | 可选值 | 默认 |
|------|----|--------|------|
| 主题 | `Theme` | 17Ember…Kelp | 1 |
| 顶右弧指标 | `RingTR` | 0 步数 / 1 卡路里 / 2 距离 / 3 楼层 / 4 动动条 | 0 |
| 顶左弧指标 | `RingTL` | 同上 | 1 |
| 底右弧指标 | `RingBR` | 同上 | 4 |
| 底左弧指标 | `RingBL` | 同上 | 3 |
| 左上复杂功能 | `LeftTop` | 0 天气 / 1 卡路里 / 2 步数 / 3 距离 / 4 楼层 / 5 电量 | 1 |
| 右上复杂功能 | `RightTop` | 同上 | 0 |
| 显示顶行 | `ShowTop` | 布尔 | true |
| 显示日期带 | `ShowBand` | 布尔 | true |
| 显示底行 | `ShowBottom` | 布尔 | true |
| 主题 | `Theme` | 17 | 1 |
| 顶右 / 顶左 / 底右 / 底左弧指标 | `RingTR/TL/BR/BL` | 0 步数 / 1 卡路里 / 2 距离 / 3 楼层 / 4 动动条 | 0 / 1 / 4 / 3 |
| 左上数据 | `LeftTop` | 见下 | 6日出 |
| 右上数据 | `RightTop` | 见下 | 8最高/最低气温) |
| 左下数据 | `BottomLeft` | 见下 | 3(距离) |
| 右下数据 | `BottomRight` | 见下 | 2步数 |
| 温度单位 | `TempUnit` | 0 跟随手表 / 1 °C / 2 °F | 0 |
| 显示顶行 / 日期带 / 底行 | `ShowTop` / `ShowBand` / `ShowBottom` | 布尔 | true |
> 指标默认值对应设计稿:**顶右=步数、顶左=卡路里、底右=动动条、底左=楼层**;左上=卡路里、右上=天气
**数据项**(四个数据位共用同一张表):`0` 当前气温 · `1` 卡路里 · `2` 步数 · `3` 距离 · `4` 楼层 · `5` 电量 · `6` 日出 · `7` 日落 · `8` 最高/最低气温 · `9` 心率
### 指标进度换算规则(`metricProgress`
默认值即设计稿的配置:左上=日出时间、右上=`63°/52°`、左下=距离、右下=步数。
| idx | 指标 | 进度分母 |
|-----|------|----------|
| 0 | 步数 Steps | `stepGoal`(目标步数) |
| 1 | 卡路里 Calories | 固定 2000 kcal |
| 2 | 距离 Distance | 10 km1,000,000 cm |
| 3 | 楼层 Floors | `floorsClimbedGoal`(默认 10 |
| 4 | 动动条 Move Bar | `moveBarLevel`(归一化 01 |
进度超出 1 会被钳制,弧长即“点亮”刻度数。
底部两格的小标签跟随所选数据自动变化(`距离` / `步数` / `心率` …),不需要单独配置。
---
## 4. 数据源与已知偏差
## 8. 数据
| 元素 | 数据来源 | 备注 |
|------|----------|------|
| 步数 / 卡路里 / 距离 / 楼层 / 动动条 | `ActivityMonitor.getInfo()` | SDK 9.1.0 字段:`steps/stepGoal/calories/distance/floorsClimbed/floorsClimbedGoal/moveBarLevel` |
| 天气温度 | `Weather.getCurrentConditions().temperature` | 需手表已配对天气 |
| 电量 | `System.getSystemStats().battery` | 01 浮点×100 显示 |
| 日期 / 时间 | `Time.Gregorian` | 12 小时制,带 AM/PM |
| 蓝牙图标 | `System.getDeviceSettings().phoneConnected`(仅取状态) | 见下方偏差 |
| 元素 | API |
|------|-----|
| 步数 / 卡路里 / 距离 / 楼层 / 动动条 | `ActivityMonitor.getInfo()` |
| 日出 / 日落 | `Weather.getSunrise/getSunset(location, Time.now())`,位置取 `CurrentConditions.observationLocationPosition`,回退 `Activity.getActivityInfo().currentLocation` |
| 最高 / 最低气温 | `Weather.getDailyForecast()[0].highTemperature / lowTemperature` |
| 当前气温 | `Weather.getCurrentConditions().temperature` |
| 电量 | `System.getSystemStats().battery`0100 的百分比) |
| 时间 / 日期 | `Time.Gregorian``FORMAT_SHORT`(只有短格式的 `day_of_week` / `month` 是数字) |
| 蓝牙 | `DeviceSettings.phoneConnected`,未连接时图标压暗 |
### ⚠️ 与设计稿的关键偏差
1. **“日出sunrise”元素 → 实时天气温度。** 设计稿顶部复杂功能中有一个日出图标及时间,但 `Weather.CurrentConditions` 在 SDK 9.1.0 **不暴露 sunrise 字段**。因此该位置改为显示**实时天气温度**`NN°`),图标保留太阳造型。
2. **进度环为实时数据**,非设计稿中的静态填充演示值;四段弧指标可在设置中自由分配。
3. **蓝牙图标**目前按日期带文字色常显(未根据 `phoneConnected` 切换亮/暗),如需“未连接变暗”可后续在 `drawDateBand` 中据 `ds.phoneConnected` 调色。
单位与制式跟随手表设置:`is24Hour`24 小时制下不显示 AM/PM`distanceUnits`km / mi`temperatureUnits`°C / °F。天气与日出需手表已配对并同步过数据否则显示 `--`
---
## 5. 编译 / 构建
## 8.5 多语言
需安装 Connect IQ SDK本文基于 9.1.0)并把 `monkeyc` 加入 PATH且准备开发者密钥 `developer_key.der`(已在仓库内)
`manifest.xml` 声明了 `eng``chn`,两套文案分别在 `resources/strings/``resources-chn/strings/`,由 `monkey.jungle``base.resourcePath = resources;resources-chn` 同时纳入编译(目录名的 `-chn` 后缀就是语言标记)。手表会按系统语言自动选择
**表盘上的文字也走资源**,不是硬编码:
| 资源 | 英文 | 中文 |
|------|------|------|
| `DowNames` | `SUN,MON,…,SAT` | `周日,周一,…,周六` |
| `MonNames` | `JAN,FEB,…,DEC` | `1月,2月,…,12月` |
| `DateFormat` | `$1$ $2$``SEP 9` | `$1$$2$日``9月9日` |
| `Meridiem` | `AM,PM` | `上午,下午` |
| `FieldLabels` | `TEMP,KCAL,STEP,DST,…` | `气温,卡路里,步数,距离,…` |
逗号分隔的列表在 `loadStrings()` 里一次性读入并拆分(`loadResource` 每次调用开销不低,不宜放进 `onUpdate`)。
> 中文字形依赖手表固件里的 APAC 字体包(`fontSet: apac_twcn` / `apac_chn`)。国行机型自带;国际版若未安装中文字体包,会退回英文或显示方块。模拟器可用 `Settings → Language → Chinese (Simplified)` 验证。
---
## 9. 构建
需安装 Connect IQ SDK 9.1.0`monkeyc` 在 PATH 中,并备好 `developer_key.der`**不在仓库内**,需自行生成或提供)。
```bash
# 单设备Enduro 3 主产物)
monkeyc -o bin/Fenix8V3.prg -f monkey.jungle -y developer_key.der -d enduro3
monkeyc -o bin/Fenix8V3.prg -f monkey.jungle -y developer_key.der -d fenix847mm
```
# 导出调试资源(含 -settings.json便于模拟器载入设置
monkeyc -o bin/Fenix8V3.prg -f monkey.jungle -y developer_key.der -d enduro3 -x
全部 17 款设备批量编译(已验证通过):
# 多设备批量(已验证可编译)
for d in enduro3 fenix843mm fenix847mm fenix8pro47mm fenix8solar47mm \
fenix8solar51mm epix2 epix2pro47mm epix2pro51mm fenix7 fenix7x \
fenix7s fr965 fr265 fr255 venu3 vivoactive5; do
```bash
for d in enduro3 fenix843mm fenix847mm fenix8pro47mm fenix8solar47mm fenix8solar51mm \
epix2 epix2pro47mm epix2pro51mm fenix7 fenix7x fenix7s fr965 fr265 fr255 \
venu3 vivoactive5; do
monkeyc -o "bin/Fenix8V3_${d}.prg" -f monkey.jungle -y developer_key.der -d "$d" \
&& echo "[$d] OK" || echo "[$d] FAIL"
done
```
已验证编译通过的设备:`enduro3, fenix843mm, fenix847mm, fenix8pro47mm, fenix8solar47mm, fenix8solar51mm, epix2, epix2pro47mm, epix2pro51mm, fenix7, fenix7x, fenix7s, fr965, fr265, fr255, venu3, vivoactive5`。产物位于 `bin/`,每个设备对应一个 `.prg``.prg.debug.xml`(调试版含资源镜像)
屏幕分辨率跨度较大fenix7s 240×240 至 fenix847mm / venu3 454×454全部按 `s = width/500` 缩放
---
## 6. 模拟器与侧载
## 10. 模拟器与侧载
1. **Connect IQ Simulator**Garmin 自带):`File → Open App Project` 选本目录,选设备后 `Run`。在 `bin/*.prg.debug.xml` 旁会生成 `-settings.json`,可在模拟器菜单 `View → Settings` 载入并实时切换主题/指标验证。
2. **真机侧载Garmin Connect / Garmin Express**
- 用 Garmin Express 或 Connect 手机 App 的“侧载sideload”功能导入对应设备的 `bin/Fenix8V3_<device>.prg`
- 或把 `.prg` 拷入手表的 `/GARMIN/Apps/` 目录(需开发者模式 / WiFi 文件传输)。
3. 安装后在手表“表盘”列表选择 **Fenix 8 V3**,长按进入设置即可调主题与指标。
---
## 7. 目录结构
```
fenix8v3-watchface/
├── manifest.xml # 应用清单ID / 支持设备 / 语言)
├── monkey.jungle # 构建配置manifest + 源码/资源路径)
├── developer_key.der # Connect IQ 开发者签名密钥
├── source/
│ ├── Fenix8V3App.mc # 应用入口getInitialView / onSettingsChanged
│ ├── Fenix8V3View.mc # 表盘渲染主逻辑onUpdate + 各 draw*
│ └── Themes.mc # ⚠️ 自动生成7 套主题颜色(勿手改)
├── resources/
│ ├── strings/strings.xml # AppName / 设置项 / 主题 / 指标 / 字段文案
│ └── settings/
│ ├── properties.xml # 设置默认值
│ └── settings.xml # 设置 UI 定义(列表/布尔)
└── bin/ # 编译产物(.prg + 调试 xml + settings.json
```bash
connectiq & # 启动模拟器
monkeydo bin/Fenix8V3_fenix847mm.prg fenix847mm # 载入表盘
```
---
非 release 编译会同时产出 `bin/*-settings.json`,可在模拟器 `View → Settings` 载入以实时切换主题与指标。注意模拟器会**持久化**已保存的设置,改 `properties.xml` 的默认值对已运行过的实例不生效,需先重置应用数据。
## 8. 二次开发与扩展
- **改主题配色**:编辑 `watchface-tokens.json`(设计稿目录下),运行 `gen_themes.py` 重新生成 `source/Themes.mc`。新增主题时同步在 `Themes.mc``ORDER` 数组、`settings.xml``Theme` 列表、`strings.xml``ThemeXX` 文案中登记。
- **加指标**:在 `metricProgress`(进度换算)与 `complicationValue`(复杂功能文本)两个方法里按 `idx` 分支扩展,并在 `settings.xml` / `properties.xml` 的列表项补充。
- **调布局**:所有坐标集中在 `Fenix8V3View.mc``draw*` 方法里,均为 “设计像素 × `s`” 形式,改一处即可全局缩放生效。
真机侧载:用 Garmin Express 或 Connect 手机 App 导入对应机型的 `bin/Fenix8V3_<device>.prg`,或把 `.prg` 拷入手表 `/GARMIN/Apps/`
---
## 9. 设计稿来源
## 11. 预览
还原基准为 `watchface-kit.zip` 内的 8 张 SVG 变体 + `watchface-tokens.json`(配色)+ `watchface-spec.html`(像素测量规范)+ `rebuild.py`(几何常量)。本仓库为按该规范落地的 Monkey C 实现,设计版权归原作者所有。
```bash
python3 tools/gen_preview_svg.py
```
产出 `preview-themes.svg`(七套主题一览)与 `preview.html`(可切换主题的单页)。两者用网页字体渲染文字,**几何与配色可信,字形不可信** —— 真机字形以模拟器截图为准。
---
## 12. 与设计稿的差异
1. **字体**。设计稿用的是一款更粗、更方的第三方字体Garmin 只提供内置 Roboto / Bionic 系列,且各机型不同。字号按 cap height 对齐,字形无法一致。
2. **图标**。设计稿里的图标是位图描出的密集矢量路径(数百个点),不适合逐帧绘制;代码用圆、多边形、线段按实测的子形状位置重建了电量、日出/日落、多云三个图标。其余数据项(卡路里 / 步数 / 距离 / 楼层)设计稿未提供图标,为自绘。
3. **底弧高段颜色**为外推值,见 §3。
4. **进度环是实时数据**,设计稿中的是固定演示状态(右上 21/21、左上 10/21、右下 9/21、左下 14/21
---
## 13. 设计稿版权
`design/` 内的 SVG、tokens 与 `rebuild.py` 来自 `watchface-kit`,版权归原作者所有。本仓库是按该设计稿实现的 Monkey C 表盘。