资源系统(offipy.assets)
offipy v0.14 引入统一的资源系统(Asset System v1):把图标、纹理、原生图元等
「视觉素材」抽象成 asset:// 资源,经过 provider 解析 → 确定性测量 → 占位符
注入 → 渲染落位 一条管线,最终变成 PowerPoint 里可编辑的原生对象(freeform
矢量 / SVG picture / 原生形状与文本框),而不是贴死的位图。
- 确定性:同一份 HTML + 同一主题,每次渲染结构一致;资源声明有稳定 ID。
- 可编辑:图标是 native freeform,图元是原生形状 + 文本框(双击可改文字)。
- 可溯源:每次渲染产出
assets.json用法清单,记录每个资源的 provider / 许可证 / 来源,满足合规审计。 - 无网络:图标 / 纹理 / 图元全部 vendored 进 wheel,渲染过程不联网。
快速开始
<div data-asset="asset://ph/icon/check"
style="position:absolute;left:80px;top:140px;width:120px;height:120px;color:var(--accent)"></div>
<div data-asset="asset://procedural/pattern/topography?seed=42" data-asset-placement="background"
style="position:absolute;left:0;top:0;width:100%;height:100%"></div>
<div data-asset="asset://primitives/primitive/metric-badge"
data-asset-param-value="24%" data-asset-param-label="YoY" data-asset-param-delta="+3.2%"
style="position:absolute;left:100px;top:200px;width:420px;height:220px"></div>
offipy deck make --html deck.html --theme mckinsey --layouts --out deck.pptx
v0.14 内置 provider
| provider | kind | 内容 | 许可证 | first_party |
|---|---|---|---|---|
ph |
icon |
1512 个 Phosphor 图标(vendored) | MIT | 否 |
lu |
icon |
1756 个 Lucide 图标(vendored) | ISC | 否 |
procedural |
pattern |
8 个确定性生成纹理(wave / blob / dot-grid / square-grid / rings / topography / circuit / gradient-orb) | MIT | 是 |
primitives |
primitive |
8 个可编辑原生图元(quote-mark / section-number / label-pill / metric-badge / timeline-node / process-arrow / device-frame / browser-mockup) | MIT | 是 |
AssetKind 预留 illustration / map / flag 等 kind 供未来外部 provider
(v0.15 里程碑),v0.14 不实现。
URI 语法
asset://<provider>/<kind>/<name>[?k=v&k2=v2...]
<provider>/<kind>/<name>均小写、短横线分隔。- 查询参数
k=v:键做_→-、小写、排序的规范化,键必须唯一;值做 percent-decode。十六进制颜色以%23RRGGBB往返(#→%23)。 - 拒绝
#片段与 CSSvar(引用(参数值不得引用 CSS 变量)。 - 示例:
asset://ph/icon/check
asset://lu/icon/settings
asset://procedural/pattern/topography?seed=42
asset://procedural/pattern/rings?count=4
asset://primitives/primitive/metric-badge
渲染模式
| 模式 | 含义 |
|---|---|
freeform_svg |
源 SVG 解析为 PowerPoint native freeform(p:sp + a:custGeom),双击显示可编辑路径(图标) |
svg |
SVG 以 OOXML SVG picture 写入:主 a:blip 挂 PNG 栅格回退,asvg:svgBlip 指矢量(procedural 纹理;无 Playwright 时降级纯 SVG) |
svg_template |
模板 SVG 经颜色插槽(如 __ACCENT__)实体化后写为 SVG picture |
raster |
位图 payload(add_picture) |
native_shape |
原生形状 + 文本框 + freeform 组合(图元) |
落位(placement)
| 值 | 语义 |
|---|---|
replace(默认) |
渲染产物插入原声明所在 DOM 槽位,替换占位符 |
decorative |
同 replace 槽位语义,标记为装饰元素 |
background |
移到 grpSpPr 之后、所有内容形状之前(沉底) |
v0.14 限制:
background只对 procedural 纹理等矢量资源可用;原生图元 (primitive)声明data-asset-placement="background"会显式报错。
HTML 用法
声明资源
<div data-asset="asset://<uri>"
data-asset-param-<key>="<value>"
data-asset-placement="replace|decorative|background"
style="..."></div>
data-asset-param-*:按 URI 里 provider 的 schema 传参;十六进制颜色用%23转义(如data-asset-param-accent="%232251ff"),或直接给主题语义 token (accent/surface/ink/muted/bg)。- 资源尺寸取自元素的测量矩形(浏览器渲染的真实 BCR),渲染产物会缩放进该矩形。
旧 data-icon 兼容
v0.12+ 的图标容器写法保持不变,内部迁移到 ph / lu provider:
<svg data-icon="ph:check-circle" viewBox="0 0 256 256" width="72" height="72"></svg>
data-icon="<集>:<名字>" 等价于 asset://ph/icon/<名字>(或 lu),v0.14 无行为
变化,无需迁移。
data-primitive 语法糖
原生图元提供简写:
<div data-primitive="metric-badge" data-asset-param-value="24%"></div>
预处理后会展开成规范的 data-asset="asset://primitives/primitive/metric-badge" +
内部 ID,与规范写法完全等价。
声明注入的前置检查
资源注入依赖 visual audit 产出的 measurements.json。因此:
no_visual_audit=True(CLI--no-visual-audit)与data-asset/data-primitive/data-icon声明不兼容,会在启动 chromium / convert 前 fail-fast。- visual-audit 渲染结束后,输出目录(如
out_audit/)内出现assets.json;no_visual_audit不产出资产清单。
Python API
from offipy.assets import get_default_registry
r = get_default_registry()
# 搜索
metas = r.search("grid", kind="pattern") # 按 kind 过滤
print([m.ref for m in metas])
# 解析
asset = r.resolve("asset://procedural/pattern/topography?seed=42")
print(asset.meta.ref, asset.provider_meta.license)
# 带必填参数的图元:用 AssetRequest 传参(示例用只含可选参数的图元)
from offipy.assets import AssetRef, AssetRequest
resolved = r.resolve(AssetRequest(AssetRef("primitives", "primitive", "browser-mockup")))
assert resolved.payload.primitive == "browser-mockup"
import offipy.assets 是纯标准库表面(model / uri / registry / license / color /
materialize),不加载 python-pptx / Pillow / playwright。
assets.json 用法清单
visual-audit 渲染后,输出目录的 _audit/assets.json 记录本次渲染用到的每个资源:
{
"schema": 1,
"assets": [
{
"declaration_id": "asset-s01-001",
"slide_index": 1,
"request": "asset://primitives/primitive/metric-badge",
"provider": {"id": "primitives", "license": "MIT", "source_url": "...", "first_party": true},
"placement": "replace"
}
]
}
declaration_id:稳定、确定性递增(asset-s<slide>-<seq>)。- 图表(
data-chart)不是 Asset System v1 资源,不会出现在清单里。
原生图元 schema(v0.14)
所有图元共有的可选参数:accent(默认主题 accent)、fill(图元专属默认)。
参数在 provider 层校验,非法参数显式报错。
| 图元 | 参数 | 默认填充 | 结构 |
|---|---|---|---|
quote-mark |
text(必填,≤240) |
transparent | 引号字形 + 文本框 |
section-number |
number(必填 int 0..9999)、label(可选 ≤120) |
surface | 数字 + 可选标签 + accent 装饰 |
label-pill |
text(必填,≤120) |
accent | 圆角矩形 + 居中文案 |
metric-badge |
value(必填 ≤80)、label(可选 ≤120)、delta(可选 ≤40) |
surface | 卡片 + value/label/delta |
timeline-node |
label(可选 ≤120)、phase(可选 past/current/future,默认 current) |
— | 节点圆点 + 标签;phase 决定样式 |
process-arrow |
steps(必填,逗号分隔 2..8 项,每项 ≤80)、direction(可选 horizontal/vertical,默认 horizontal) |
surface | 箭头分 N 段,每段文本可编辑 |
device-frame |
device(必填 phone/tablet/desktop) |
surface | 原生设备外框 + 空屏 |
browser-mockup |
title(可选 ≤120)、url(可选 ≤240) |
surface | 窗口卡片 + 顶部 chrome + 三圆点 |
已知限制(v0.14 明示,不视为 bug):
process-arrow的steps不支持转义逗号;标签含逗号请换别的图元。device-frame/browser-mockup不接受截图/嵌套资源:没有screenshot/src/image参数,屏幕是空的可编辑区域。- 图元文字用默认安全 sans 字体(Arial 系);主题字体 token 是 v0.15 方向,v0.14 不引入新的公开字体 token 模型。
非目标 / 未来 provider
- v0.15 里程碑:外部插画 / 地图 / 照片类 provider(
illustration/map/flag),需要网络或大体积素材,v0.14 不做。 - 嵌套资源(如「设备帧里放截图」)是显式非目标,遇到即报错而不是静默降级。