跳转到内容

Material Protocol v1 规范

这是一份协议参考,面向 Material 工具、Catalog、运行时适配和服务端实现。第一次制作效果请先读创建和安装 Material;需要查具体字段、端口、信任或版本规则时再回到本页。

项目内容
协议Aelion Material Protocol,简称 AMP
版本1.0.0 Draft
日期2026-07-10
状态RC 实现协议;尚未形成 1.0 稳定兼容承诺
适用范围视觉滤镜、视觉特效、视觉转场、视觉生成器

Material 是 SDK 的视觉扩展格式。应用可以制作、预览、打包和安装 Material,而不需要为每个新效果修改引擎内核。

协议分成四层:

  1. Material Package:可分发的 .aelionmat 包,包含清单、定义、图、资源和可选的受信任程序实现。
  2. Material Definition:一个滤镜、特效、转场或生成器的稳定定义,包括端口、参数、资源和执行契约。
  3. Material Graph:安全、声明式、可视化编辑的 DAG,由 Aelion 标准节点组成,可编译到 WebGPU/WebGL2。
  4. Material Instance:项目中对 Definition 的一次引用,保存参数关键帧、资源绑定和辅助输入绑定。
flowchart LR
Author["Material Studio / 代码作者"]
Source["Manifest + Graph + Resources"]
Package[".aelionmat Package"]
Registry["Aelion Material Registry"]
Instance["Project Material Instance"]
Compiler["Material Compiler"]
GPU["WebGPU / WebGL2"]
Author --> Source --> Package --> Registry
Registry --> Instance
Registry --> Compiler
Instance --> Compiler --> GPU

必须遵守的安全边界:

Project JSON 可以引用 Material,但不能携带或自动执行任意 JavaScript、WGSL、GLSL 或 WASM。声明式 Graph 可以按安全策略动态安装;包含程序代码的包只能由宿主显式信任和注册。

这套结构可以支持:

  • 上层搭建无代码 Material 编辑器;
  • 业务团队从 JSON Graph 制作大多数转场、滤镜和特效;
  • 高级团队用 Shader/WASM 实现复杂、多 Pass 或音频能力;
  • 同一个 Material 在 WebGPU、WebGL2、预览和导出间保持统一语义;
  • Material 商店、版本锁定、签名、灰度和回滚;
  • AelionSDK 内核无需为每个新效果新增特殊 Item/Segment 类型。

两者必须分开:

对象存放位置内容
Material Definition.aelionmat端口、参数 Schema、Graph、资源、实现和能力声明
Material InstanceAelion Project Document精确版本引用、参数值/动画、资源和辅助输入绑定

Definition 类似“效果类”,Instance 类似“项目里应用的一次效果”。同一个 Definition 可以产生任意多个 Instance,各自拥有独立参数。

  • Material 是面向创作者和项目的视觉能力单位。
  • Material Package 是其分发单位。
  • Plugin 是更高权限的宿主扩展,可注册自定义 Graph Node、Shader/WASM backend、Resolver 等。

纯 Graph Material 不需要编写 Plugin。只有标准 Graph 无法表达时,才需要受信任的程序实现或 Plugin。

  • Material 商店的账号、支付和推荐;
  • 素材版权自动判断;
  • 浏览器端代码或资源的绝对保密;
  • 任意第三方 Shader 的安全执行承诺;
  • UI 编辑器的具体框架和布局。

签名可以证明完整性和发布者身份,但浏览器下载到本地的 Shader、图和资源最终都可被用户检查。真正需要保密的算法必须留在服务端渲染链,不能依靠前端加密假装保密。


kind主输入系统输入输出用途
visual-filtersource 1 个时间、画幅、UVvisual-frameLUT、调色、颗粒、局部色彩处理
visual-effectsource 0 或 1 个,可有辅助输入时间、画幅、UVvisual-frame模糊、光效、故障、位移、抠像、叠加
visual-transitionfromto 各 1 个transitionProgressvisual-frame两个片段之间的转场
visual-generator无主输入,可有资源时间、画幅、UVvisual-frame纯色、渐变、粒子、程序纹理、背景

后续协议可以沿用相同 Package/Parameter 体系加入 audio-effectaudio-transition,但 AMP 1.0 的可移植声明式 Graph 先以视觉能力为正式基线。

visual-filter 必须满足:

  • 只有一个主视觉输入;
  • 输出尺寸与输入一致;
  • 不改变几何位置和有效边界;
  • 不依赖其他时间帧;
  • 不引用其他 Item/Track 输出;
  • 可以由编译器与相邻逐像素节点融合。

需要邻域采样、空间扩边、多输入、历史帧或几何位移时,应声明为 visual-effect。Kind 会参与端口校验和优化,不能只根据展示名称随意填写。

visual-transition 固定获得:

  • from:前一个 Item 在当前 Sequence 时间的已渲染视觉输出;
  • to:后一个 Item 在当前 Sequence 时间的已渲染视觉输出;
  • transitionProgress:规范化进度 [0, 1]
  • 当前输出尺寸、工作色彩空间和帧上下文。

Item 自身 Material 链先执行,Transition 再消费两个结果,随后进入 Track Material 链。Transition 不直接访问 Timeline、解码器或原始文件。

由于 Transition 区间使用半开区间,最后一个采样帧的 progress 可能小于 1;Transition 结束后的下一帧直接显示 to。Material 必须在 progress → 1 时连续趋近纯 to,在 progress = 0 时输出纯 from,除非 Definition 明确声明设计性 endpoint deviation,并因此不能作为通用转场。

visual-effect 可以声明:

  • 一个可选或必选 source
  • 其他 visual-frame、mask、depth、motion-vector 辅助端口;
  • 空间 padding;
  • 有界的过去/未来时间窗口;
  • 多 Pass;
  • bundled resource 或项目 Asset slot。

所有依赖必须显式声明。Material 不能在执行时自行遍历项目或请求任意 Timeline 节点。

Generator 没有隐含 source,通过 Material Content Item 放在时间线上。它使用 Item range 提供的 local time 和 duration,可输出透明画面或完整背景。


适合绝大多数上层和 Material Studio:

  • 只包含 JSON Graph、参数和静态资源;
  • 只能调用 Aelion 标准 Node Registry 中的节点;
  • 无循环、递归、任意文件访问、网络、DOM 或 JavaScript;
  • 编译器可以静态推导类型、Pass、时间窗口、空间 padding 和成本;
  • 可根据节点支持情况编译到 WebGPU 和 WebGL2;
  • 通过 Schema、语义校验和配额后,可以由应用动态加载。

适合标准 Graph 无法表达的算法:

  • WGSL Shader Pipeline;
  • GLSL ES 3.0 fallback;
  • CPU/WASM 实现;
  • 自定义 Graph Node Plugin。

此类包即使签名也不能自动获得信任。宿主必须通过 allowlist、内置清单或用户明确授权安装:

await sdk.materials.install(source, {
trust: 'trusted-code',
expectedPublisher: 'com.example.media',
expectedIntegrity: 'sha256:...',
});

只提供 Shader 会造成:

  • 上层难以搭建无代码编辑器;
  • WebGPU 与 WebGL2 要维护两份实现;
  • 参数、资源、时间、颜色和透明度没有统一语义;
  • 难以静态计算性能与依赖;
  • 难以安全加载第三方 Material;
  • 多 Pass、辅助输入和降级行为各自为政。

Graph 是大多数 Material 的标准源语言,Shader 是明确受信任的逃生舱。


开发阶段使用普通目录;发布时打成标准 ZIP,扩展名 .aelionmat

starter-pack.aelionmat/
├── manifest.json
├── materials/
│ ├── warm-film.material.json
│ ├── cross-zoom.material.json
│ └── light-leak.material.json
├── graphs/
│ ├── warm-film.graph.json
│ ├── cross-zoom.graph.json
│ └── light-leak.graph.json
├── resources/
│ ├── grain.webp
│ └── cinematic.cube
├── shaders/ # 仅 trusted-code 包可有
│ ├── effect.wgsl
│ └── effect.glsl
├── wasm/ # 仅 trusted-code 包可有
│ └── effect.wasm
├── previews/
│ ├── thumbnail.webp
│ └── preview.mp4
├── locales/
│ ├── zh-CN.json
│ └── en-US.json
├── LICENSES.json
└── signature.json # 可选
  • manifest.json 必须位于根目录。
  • 路径必须是规范 UTF-8 相对路径,不允许空 segment、./.. segment、尾随 /、NUL、绝对路径、反斜杠和符号链接。
  • ZIP 不允许嵌套加密、可执行入口或解压后逃逸目录。
  • 所有 payload 文件必须出现在 manifest 的 files 中,不允许未声明文件。
  • manifest.jsonsignature.json 不进入 files,避免自引用 hash。
  • 发布构建按路径字典序写入并固定时间戳,保证可重复打包。
  • 默认限制:包含 manifest.json 最多 256 个文件、canonical manifest 256 KiB、全部文件合计 64 MiB、单资源 32 MiB、确定性 ZIP 65 MiB;宿主可以收紧。限制必须在字节复制、hash、ZIP 重建或外部 archive 解压分配之前执行。
  • v1 不支持包依赖树。Material 只能依赖指定版本的 Aelion Core Node Set,避免供应链和菱形依赖问题。
{
"$schema": "https://schemas.aelion.dev/material/package/v1.json",
"protocolVersion": "1.0.0",
"package": {
"id": "dev.aelion.example.starter-pack",
"version": "1.0.0",
"displayName": "Aelion Starter Materials",
"publisher": {
"id": "dev.aelion.example",
"name": "Aelion Examples"
},
"license": "MIT",
"engines": {
"aelion": ">=1.0.0 <2.0.0",
"nodeSet": "aelion.visual.nodes/1.0.0"
},
"trust": "declarative"
},
"materials": [
{
"id": "warm-film",
"kind": "visual-filter",
"definition": "materials/warm-film.material.json"
}
],
"files": [
{
"path": "materials/warm-film.material.json",
"mediaType": "application/vnd.aelion.material+json",
"bytes": 1234,
"sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
}
]
}

同一 package 内 material.id 唯一。Material 的完整身份为:

package.id + package.version + material.id + package integrity

Project 必须锁定精确 package version 和 integrity,不能使用 latest 或 semver range。

  1. 每个 payload 在 manifest 中保存 SHA-256。
  2. manifest 使用 RFC 8785 JCS 规则 canonicalize。
  3. packageIntegrity = "sha256:" + lowercaseHex(SHA-256(JCS(manifest)))
  4. 可选 signature.json 使用发布者 Ed25519 key 对 SHA-256 的原始 32 bytes 签名。
{
"algorithm": "Ed25519",
"publisherId": "dev.aelion.example",
"keyId": "release-2026-01",
"packageIntegrity": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"signatureBase64": "..."
}

签名只解决身份与篡改,不自动授予 trusted-code 权限。Registry 可以要求签名,私有业务也可以只使用固定 integrity allowlist。


interface MaterialDefinition {
protocolVersion: '1.0.0';
id: string;
kind: 'visual-filter' | 'visual-effect' | 'visual-transition' | 'visual-generator';
display: MaterialDisplay;
scopes: Array<'source' | 'item' | 'track' | 'sequence' | 'transition'>;
ports: MaterialPort[];
parameters: MaterialParameter[];
bundledResources: BundledResource[];
resourceSlots: ResourceSlot[];
execution: MaterialExecutionContract;
implementations: MaterialImplementation[];
splitPolicy: 'copy' | 'reset' | 'reject';
}

Definition 是纯数据。其 ID、端口 ID、参数 ID 和资源 ID 发布后不能在同一 major 中改变含义。

interface MaterialDisplay {
name: string;
description?: string;
category?: string;
tags?: string[];
icon?: string;
thumbnail?: string;
preview?: string;
localizationPrefix?: string;
}

Display 只影响素材面板和编辑器,不参与渲染和 cache key。路径必须指向包内已声明文件。

  • source:在源方向/颜色规范化后、裁剪和空间变换前执行。
  • item:在 Item 本地视觉空间执行。
  • track:对已合成 Track 结果执行。
  • sequence:对最终 Sequence 画面执行。
  • transition:只能被 Transition 实例引用。

Definition 声明允许范围,Instance 的实际宿主必须属于其中之一。一个只适合全屏的后处理不能被错误挂到 source domain。


interface MaterialPort {
id: string;
direction: 'input' | 'output';
type: 'visual-frame' | 'mask' | 'depth' | 'motion-vectors';
role: 'source' | 'from' | 'to' | 'auxiliary' | 'result';
binding: 'host' | 'instance';
required: boolean;
description?: string;
}
  • host 端口由 SDK 自动提供,例如 filter 的 source、transition 的 from/to。
  • instance 端口由项目 Material Instance 显式绑定,例如位移贴图或外部遮罩。
  • v1 每端口 cardinality 固定为 one;多个输入需要声明多个稳定端口。
  • 所有引用都会进入 Render IR 依赖图,循环引用在项目校验阶段拒绝。
kind必需输入必需输出
visual-filtersource: visual-frame、hostresult: visual-frame
visual-effect按 Definition,可有 sourceresult: visual-frame
visual-transitionfromto: visual-frame、hostresult: visual-frame
visual-generatorresult: visual-frame

端口约束不仅由 JSON Schema 校验,还由 Material semantic validator 按 kind 校验。

{
"inputBindings": {
"displacement": {
"type": "item-output",
"itemId": "item_displacement_map",
"time": "same-sequence-time",
"boundary": "transparent"
},
"matte": {
"type": "asset",
"assetId": "asset_mask"
}
}
}

可绑定来源:

  • 项目 Asset;
  • 另一个 Item 的视觉输出;
  • Track 输出;
  • Nested Sequence 输出;
  • 协议定义的常量 frame/mask。

绑定必须类型兼容。依赖图有环、引用自身处理后的输出或跨越非法 Sequence 边界时拒绝提交。


AMP v1 支持:

typecanonical JSON典型用途
booleanboolean开关
integernumber safe integer采样数、模式索引
floatfinite number强度、比例
enumstring模式选择
vec2 / vec3 / vec4{x,y,...}方向、中心、向量
color{space, rgba}颜色
anglenumber,单位 degree旋转方向
durationsafe integer microseconds周期、延迟
gradientordered color stops光效、渐变
curveordered control points响应曲线
stringstring只用于非 Shader 文本/标签类节点
{
"id": "intensity",
"type": "float",
"default": 0.65,
"range": {
"min": 0,
"max": 1,
"softMin": 0,
"softMax": 1,
"step": 0.01
},
"unit": "ratio",
"animatable": true,
"interpolation": "linear",
"affects": "uniform",
"ui": {
"control": "slider",
"group": "look",
"order": 10,
"label": "Intensity"
}
}
  • id 是渲染语义的一部分,发布后不能改名而不迁移。
  • 所有数值必须 finite,运行时拒绝 NaN/Infinity。
  • range.min/max 是硬约束;soft range 只影响 UI。
  • affects = uniform 可以逐帧动画,不需要重编 pipeline。
  • affects = specialization 可能选择 pipeline variant,不能逐帧动画。
  • affects = graph 会改变图结构,只能在事务提交时修改,不能 animatable。
  • 颜色参数明确插值空间;默认在线性工作空间插值。
  • angle 默认数值插值;需要最短路径时写 interpolation = shortest-angle
  • duration 使用整数微秒,不使用浮点秒。
  • enum 保存稳定 value,不保存本地化 label。
  • UI 元数据不参与渲染结果,Material Studio 可自动生成面板。

跨参数约束采用受限的声明式条件,不允许 JavaScript 表达式:

{
"constraints": [
{
"when": { "parameter": "mode", "equals": "radial" },
"require": { "parameter": "samples", "max": 32 }
}
]
}

AMP v1 只支持等值、范围、all/any/not 等有限操作。复杂派生值应在 Graph 中计算,不应隐藏在 UI 表达式里。


跟随包发布且不可由项目替换:

{
"id": "grain",
"kind": "texture2d",
"path": "resources/grain.webp",
"mediaType": "image/webp",
"colorSpace": "srgb",
"alpha": "straight",
"sampling": {
"filter": "linear",
"addressU": "repeat",
"addressV": "repeat",
"mipmaps": true
}
}

支持的资源 kind:

  • texture2d;
  • texture3d / LUT3D;
  • LUT1D;
  • cube texture;
  • mask;
  • binary uniform table;
  • 后续 audio impulse extension。

资源进入 GPU 前由 SDK 解码、校验尺寸并转换到声明的采样/颜色语义。Graph 不直接读取文件字节。

由 Material Instance 绑定项目 Asset:

{
"id": "customOverlay",
"kind": "texture2d",
"required": false,
"fallbackResourceId": "defaultOverlay",
"constraints": {
"maxWidth": 4096,
"maxHeight": 4096,
"alphaRequired": true
}
}

资源 slot 和辅助视觉输入的区别:资源通常是静态/独立采样纹理;辅助输入是 Timeline 在某个时间求值的视觉节点。需要随时间播放的视频应使用 input port,而不是假装成静态资源。

  • Graph 只能引用已声明 bundled resource 或 slot。
  • 包内资源不允许再引用外部 URL、CSS 或脚本。
  • 远程资源必须先作为 Project Asset 经过 AssetResolver,再绑定 slot。
  • 解码后像素数、3D LUT 尺寸和 GPU bytes 都受预算控制。
  • 不识别的文件类型直接拒绝,不根据扩展名猜测执行方式。

interface MaterialGraph {
graphVersion: '1.0.0';
nodeSet: 'aelion.visual.nodes/1.0.0';
nodes: MaterialGraphNode[];
outputs: Record<string, GraphPortReference>;
}
interface MaterialGraphNode {
id: string;
type: string;
typeVersion: string;
inputs: Record<string, GraphValue>;
config?: Record<string, JsonValue>;
}
type GraphValue =
| { value: JsonValue }
| { parameter: string }
| { resource: string }
| { inputPort: string }
| { node: string; output: string }
| { system: SystemValue };

Graph 使用按 ID 寻址的扁平 Node 列表。数组顺序没有执行语义,编译器根据连接做拓扑排序。

标准 system values:

名称类型语义
sequenceTimeUsduration当前 Sequence 时间
itemTimeUsduration当前宿主 Item local time;非 Item scope 为 0
itemDurationUsduration宿主时长;无宿主为 0
normalizedItemTimefloat安全归一化到 0..1
transitionProgressfloat仅 transition,0..1
frameIndexinteger当前输出帧号
frameDurationUsduration当前输出帧区间长度
outputSizePxvec2输出像素尺寸
pixelSizeUvvec21 / outputSizePx
workingColorSpaceenum当前线性工作空间
qualityScalefloat预览动态分辨率比例;不能改变时间语义
randomSeedintegerSDK 计算的确定性实例种子

Graph 不提供墙钟、Math.random()、设备名或网络状态。随机效果必须从 randomSeed、frameIndex、像素坐标派生,保证 Seek 和导出可重现。

核心值类型:

  • scalar:bool、int、float;
  • vector:vec2、vec3、vec4;
  • color:linear premultiplied RGBA;
  • UV:normalized vec2;
  • visual-frame;
  • mask;
  • sampler/texture resource;
  • gradient/curve;
  • duration/int time。

连接必须精确匹配或经过标准显式转换节点。编译器不做可能丢失语义的隐式转换,例如 color→float、straight→premultiplied alpha、sRGB→linear。

第一版建议冻结以下类别:

类别代表节点
输入input.visual-frameinput.maskinput.resource-texture
采样sample.uvsample.offset-pxsample.transformsample.lod
数学math.add/sub/mul/divmin/max/clamppow/exp/logsin/cossmoothstep
向量vector.compose/splitdot/length/normalize/rotate2d
时间time.looptime.ping-pongtime.remap
颜色color.matrixexposurecontrastsaturationhsltemperature
LUTlut.1dlut.3d
混合composite.mixblendpremultiply/unpremultiply
模糊blur.gaussianblur.directionalblur.radial
形态mask.thresholdmask.feathermask.expand
几何geometry.cropgeometry.kaleidoscopegeometry.polar
噪声noise.hashnoise.value2dnoise.simplex2d
检测edge.sobelluma.extractchroma.distance
输出output.visual-frame

每个 Node Definition 都是独立版本化契约,至少声明:输入/输出类型、参数范围、颜色/alpha 语义、空间 padding、时间窗口、是否逐像素可融合、后端支持、确定性和成本估计。

本文和示例中出现的 time.transition-curvesample.zoomcolor.temperaturecolor.lift-black 等节点名称目前是 Core Node Set 候选。AMP Package/Graph/Instance 的结构可以先评审,但 Node Set 1.0 必须逐节点补齐精确数学公式、边界、精度与 Golden 后才能冻结;不能仅凭本文列名视为已实现标准。

默认 declarative 包:

  • 最多 128 nodes;
  • DAG 深度最多 32;
  • 最多 8 个视觉采样输入;
  • 最多 8 passes;
  • 最多 64 个 uniform scalar slots;
  • 静态卷积半径最多 64px;动态半径必须声明硬上限;
  • 不允许 graph cycle、递归、动态创建节点或无界循环;
  • 分支通过 select/mix 或静态 specialization,不允许逐像素任意循环;
  • 资源和中间纹理总预算由 runtime capability 再收紧。

Package 可以声明更低的 recommended budget,不能自行扩大宿主 hard limit。

Graph 编译器按节点需求自动划分 Pass。作者不应为了某后端手工描述 framebuffer,但可以通过具有明确语义的 Node 表达 blur、pyramid、feedback 等高级操作。

AMP 1.0 不允许任意帧间 feedback 环。需要历史状态的 Material 使用有限的 temporal node:

{
"id": "trail",
"type": "temporal.delay-frame",
"typeVersion": "1.0.0",
"inputs": {
"source": { "inputPort": "source" },
"delayFrames": { "value": 1 }
},
"config": {
"maxDelayFrames": 4,
"seekPolicy": "reconstruct"
}
}

Temporal node 必须声明有限历史、Seek 重建方式和内存上限。若从随机 Seek 无法确定性重建,则 Material 不能声明 offline support。

{
"graphVersion": "1.0.0",
"nodeSet": "aelion.visual.nodes/1.0.0",
"nodes": [
{
"id": "ease",
"type": "math.smoothstep",
"typeVersion": "1.0.0",
"inputs": {
"edge0": { "value": 0 },
"edge1": { "value": 1 },
"x": { "system": "transitionProgress" }
}
},
{
"id": "zoomFrom",
"type": "sample.zoom",
"typeVersion": "1.0.0",
"inputs": {
"source": { "inputPort": "from" },
"center": { "parameter": "center" },
"scale": { "node": "ease", "output": "value" }
},
"config": {
"scaleMap": { "from": 1, "to": 1.18 }
}
},
{
"id": "zoomTo",
"type": "sample.zoom",
"typeVersion": "1.0.0",
"inputs": {
"source": { "inputPort": "to" },
"center": { "parameter": "center" },
"scale": { "node": "ease", "output": "value" }
},
"config": {
"scaleMap": { "from": 0.88, "to": 1 }
}
},
{
"id": "mix",
"type": "composite.mix",
"typeVersion": "1.0.0",
"inputs": {
"a": { "node": "zoomFrom", "output": "frame" },
"b": { "node": "zoomTo", "output": "frame" },
"amount": { "node": "ease", "output": "value" }
}
}
],
"outputs": {
"result": { "node": "mix", "output": "frame" }
}
}

这是逻辑示例。正式 Node Schema 会避免把动态映射藏在任意 config 中:scaleMap 应由标准 remap/math node 表达,从而保证所有可动画语义都能被静态分析。


interface MaterialExecutionContract {
color: {
input: 'working-linear';
output: 'working-linear';
};
alpha: {
input: 'premultiplied';
output: 'premultiplied';
preservesTransparency: boolean;
};
resolution: {
policy: 'same-as-host' | 'scale';
scale?: number;
minimum?: { width: number; height: number };
};
spatialPadding: {
mode: 'none' | 'fixed' | 'parameter-bound';
pixels?: number;
parameter?: string;
maximumPixels?: number;
};
temporal: {
pastUs: number;
futureUs: number;
stateful: boolean;
seekPolicy: 'stateless' | 'reconstruct' | 'reset-with-warning';
};
determinism: 'strict' | 'backend-tolerant' | 'non-deterministic';
supports: {
realtime: boolean;
offline: boolean;
alpha: boolean;
hdr: boolean;
tiled: boolean;
};
}
  • Aelion 在 Sequence 的线性工作空间合成。
  • Material 输入和输出固定为线性、预乘 Alpha。
  • 普通图片资源若声明 sRGB,由 SDK 转到工作空间后采样。
  • LUT Definition 必须声明输入/输出 color encoding,不能默认猜测。
  • 需要 straight alpha 的数学步骤必须显式经过 unpremultiply/premultiply node,并处理 alpha=0。
  • Material 不能读取浏览器 Canvas 默认颜色行为来决定结果。
  • UV 原点为左上角,x 向右、y 向下,范围通常为 [0,1]
  • 像素中心 UV 为 (x + 0.5) / width(y + 0.5) / height
  • 像素距离使用逻辑输出像素,并通过 qualityScale 映射到预览内部纹理。
  • 每个采样节点显式声明边界:clamp、repeat、mirror 或 transparent。
  • 不允许依赖 WebGPU/WebGL 的隐式默认采样差异。

Graph 参数使用协议类型;编译器决定后端 uniform layout,不把 WGSL alignment 暴露给普通作者。动画参数在每个 frame/sample time 先由 Aelion 求值,再上传变化值。

Trusted Shader ABI 使用固定的 AelionFrameUniforms v1,包含整数拆分的时间、frameIndex、尺寸、qualityScale、transitionProgress、randomSeed 等。自定义参数根据 manifest 生成稳定的 buffer layout;作者使用 CLI 生成的 bindings 文件,不能自行假设字段偏移。

  • 两者使用相同 Definition、Graph 和参数求值。
  • Preview 可以按 previewPolicy 跳过 Material 或降低内部 resolution,但必须由 Definition 声明并报告。
  • Export 必须使用 offline-capable 实现,执行全部 required Material。
  • 如果 WebGPU Graph 与 WebGL fallback 有不同实现,必须通过 conformance tolerance。
  • 没有 export backend 时,Preflight 返回错误,不能导出一份偷偷忽略效果的文件。

Material 可以声明:

{
"performanceHints": {
"cost": "medium",
"preferredScale": 0.5,
"cache": "when-parameters-static",
"fusible": true
}
}

Hints 帮助调度,不改变结果。编译器通过静态分析得到的 hard requirements 优先于作者 hint。谎报 hint 只会导致认证失败,不能扩大权限或预算。


type MaterialImplementation =
| {
type: 'graph';
graph: string;
nodeSet: string;
}
| {
type: 'shader';
backend: 'webgpu';
module: string;
entryPoint: string;
abi: 'aelion-material-shader/1';
requirements: BackendRequirements;
}
| {
type: 'shader';
backend: 'webgl2';
vertexModule?: string;
fragmentModule: string;
entryPoint: string;
abi: 'aelion-material-webgl/1';
requirements: BackendRequirements;
}
| {
type: 'wasm';
module: string;
abi: 'aelion-material-wasm/1';
requirements: BackendRequirements;
};

选择顺序由 SDK 决定:

  1. 过滤不满足 capability/trust/mode 的实现。
  2. 优先使用宿主配置和 Definition 推荐后端。
  3. Graph 可由 SDK 编译到可用 GPU 后端。
  4. 如果没有合法实现,返回 MATERIAL_BACKEND_UNAVAILABLE
  • 只能读取 manifest 声明的输入、资源和 uniforms。
  • Pipeline、bind group 和 target format 由宿主管理。
  • 不允许 shader 自行决定输出尺寸或申请无限中间纹理。
  • Storage buffer/texture、atomics、timestamp query 等需要额外 capability 与信任级别。
  • 编译错误必须映射到包路径、行列和 Material ID。
  • WebGL fallback 必须使用 GLSL ES 3.00,并由 SDK 注入受控 preamble;不得依赖扩展而不声明。
  • WASM 不直接获得 DOM、网络和文件 API。
  • Import table 固定为 Aelion ABI,默认只提供内存、日志、参数和受控 tile/frame buffer。
  • 设置线性内存上限和每帧 watchdog。
  • CPU frame effect 可能非常昂贵,CapabilityReport 要展示 realtime/offline 支持。
  • WASM 不被当作安全沙箱;仍需 trusted-code。

Custom Node 必须注册精确 Node type/version、类型签名、静态分析函数和每个后端实现。Graph 引用 custom node 后,包 manifest 声明 required plugin:

{
"requiredPlugins": [
{
"id": "com.example.optical-flow-nodes",
"version": "2.1.0",
"integrity": "sha256:..."
}
]
}

缺失插件时 Material 可以安装为 unavailable,但不能编译或 strict export。


Aelion Project 使用统一的 MaterialInstance:

interface MaterialInstance {
id: EntityId;
definition: {
packageId: string;
packageVersion: string;
packageIntegrity: string;
materialId: string;
};
name?: string;
enabled: boolean;
previewPolicy?: 'required' | 'skippable-when-degraded';
parameters: Record<string, JsonValue | Animatable<JsonValue>>;
resourceBindings?: Record<string, MaterialResourceBinding>;
inputBindings?: Record<string, MaterialInputBinding>;
randomSeed?: number;
extensions?: ExtensionMap;
}

实例的结构 Schema 位于 schemas/material/v1/instance.schema.json;具体 parameters/resourceBindings/inputBindings 还必须结合其 Material Definition 做第二阶段语义校验,单独的通用 Schema 无法判断动态参数 ID 和端口类型。

从首个公开预发布版本起,Project 顶层 collection 名称固定为 materialInstances。所有 滤镜、特效、转场、生成器都使用该 collection,不接受历史 effects 别名。

  • Item、Track、Sequence 的 materialInstanceIds 引用 filter/effect MaterialInstance。
  • Transition 的 materialInstanceId 引用 transition MaterialInstance。
  • Material Content Item 的 materialInstanceId 引用 generator MaterialInstance。
  • 一个 Instance 只能有一个宿主,避免共享参数的隐式联动。
  • 想复用配置时用 Preset 创建新的 Instance。

为避免每新增一种程序内容就扩展 Item 枚举,增加通用类型:

interface MaterialContentItem extends BaseItem {
type: 'material-content';
materialInstanceId: EntityId;
visual: VisualProperties;
}

它只能引用允许 visual-generator kind 和 item scope 的 Material。粒子背景、动态渐变、计时器、频谱等都能通过新 Material 扩展,而无需新增 Timeline 类型。

Project 不内嵌 Material Package。保存时可以额外生成资源锁文件:

{
"materialLockVersion": "1.0.0",
"packages": [
{
"id": "dev.aelion.example.starter-pack",
"version": "1.0.0",
"integrity": "sha256:...",
"source": "https://materials.example.com/starter-pack-1.0.0.aelionmat"
}
]
}

source 是可选获取提示,不是信任依据。加载顺序:

  1. 在 registry 按 id/version/integrity 查找。
  2. 若缺失,交给应用 MaterialResolver
  3. 下载并验证完整性、签名、协议、配额和信任策略。
  4. 注册 Definition,校验 Instance 参数/绑定。
  5. 缺失时保留实例和参数,显示 placeholder;strict export 失败。

Project 永远锁定精确版本。用户或业务显式发起升级:

const report = await session.materials.planUpgrade({
instanceIds: ['mat_fx_1'],
target: {
packageVersion: '2.0.0',
packageIntegrity: 'sha256:...',
},
});
await session.materials.applyUpgrade(report, {
baseRevision: session.revision,
});

升级是一个 Project Transaction。包提供纯数据迁移步骤,允许 rename、set-default、scale-number、map-enum、remove 等有限操作;包含任意代码的迁移只能由 trusted plugin 执行。报告必须列出参数丢失和视觉语义变化。


import {
MaterialLabSession,
materialDefinition,
materialGraph,
packMaterialPackage,
} from '@aelionsdk/material-sdk';
const graph = materialGraph(builder => {
builder.output('result', builder.invert('invert', builder.inputFrame('source')));
});
const authored = materialDefinition({
id: 'invert',
kind: 'visual-filter',
display: { name: 'Invert' },
})
.graph('graphs/invert.graph.json', graph)
.build();
const report = new MaterialLabSession(authored).analyze();
const artifact = await packMaterialPackage({ metadata, materials: [authored] });

当前发布包:

作用
@aelionsdk/material-compilerCore Node Registry、Graph 校验以及 WebGL2/WebGPU 编译
@aelionsdk/material-sdkDefinition/Graph Builder、Schema、Lab、Golden、打包、签名和作者 CLI
@aelionsdk/renderer-worker已解析 Material 的浏览器渲染执行

Material Studio 是可以基于这些 API 构建的上层产品,不是当前发布的 npm 包。

上层既可以直接写 JSON,也可以用强类型 Builder:

const graph = materialGraph({ nodeSet: 'aelion.visual.nodes/1.0.0' }, g => {
const from = g.inputFrame('from');
const to = g.inputFrame('to');
const p = g.system('transitionProgress');
const eased = g.smoothstep(0, 1, p);
return g.output('result', g.mix(from, to, eased));
});

Builder 只是生成 canonical Graph,不形成第二种运行协议。Material Studio 也必须导出同一种 Graph JSON。

aelion-material init ./my-pack
aelion-material build ./my-pack
aelion-material validate ./my-pack
aelion-material inspect ./my-pack
aelion-material types ./my-pack [--out material.generated.d.ts]
aelion-material preview ./my-pack [--out material-preview.json]
aelion-material golden actual.rgba expected.rgba [--tolerance 2]
aelion-material prepublish ./my-pack
aelion-material pack ./my-pack --out dist/my-pack.aelionmat

CLI 由 @aelionsdk/material-sdkbin 提供。签名密钥不由通用 CLI 读取;需要签名的宿主应从自己的密钥系统取得 CryptoKey,再显式调用 signMaterialPackage()

build 重新计算 manifest 已声明 payload 的字节数与 SHA-256,然后生成参数类型和 Lab 预览报告。Validate 检查:

  • JSON Schema;
  • package path/hash;
  • ID 与版本;
  • 端口/参数/资源引用;
  • Graph DAG 和类型;
  • kind 强制契约;
  • padding/temporal 推导是否被 contract 覆盖;
  • 后端和 feature 可用性;
  • 配额、确定性和安全边界。

prepublish 在此基础上要求没有 error diagnostic、Graph 同时通过 WebGL2/WebGPU 编译,而且 Material 不得声明为 non-deterministic。许可证政策和发布者身份属于 Catalog/宿主策略,不能由离线 CLI 猜测。

协议应允许上层构建:

  • Node Graph 编辑;
  • 参数面板设计;
  • 资源导入和压缩;
  • from/to/source 多输入预览;
  • 时间和关键帧预览;
  • WebGPU/WebGL2 切换;
  • 过曝、透明边界、不同画幅/分辨率测试;
  • GPU timing、Pass、纹理内存和采样次数查看;
  • Golden 快照与版本差异;
  • 打包、签名和发布。

协议不保存编辑器节点位置等 UI 状态到 Graph canonical 语义中。可将其放在单独的 authoring extension,打包时可选择剥离。


const inspection = await sdk.materials.inspect(packageSource);
if (inspection.trust === 'declarative' && inspection.errors.length === 0) {
await sdk.materials.install(packageSource, {
trust: 'declarative',
expectedIntegrity,
});
}
const capability = sdk.materials.query({
packageId,
packageVersion,
materialId: 'cross-zoom',
mode: 'preview',
});

Capability 返回:

interface MaterialCapability {
available: boolean;
selectedImplementation?: string;
backends: Record<
string,
{
supported: boolean;
realtime: boolean;
offline: boolean;
reasons: string[];
}
>;
limits: {
maxWidth?: number;
maxHeight?: number;
maxPaddingPx?: number;
estimatedGpuBytes?: number;
};
diagnostics: Diagnostic[];
}
  • 按精确 identity 查 Definition;
  • 校验 package integrity/signature;
  • 管理同包多版本并存;
  • 解析 Material → Graph/resource/implementation;
  • 缓存编译结果;
  • 提供搜索元数据;
  • 引用计数和安全卸载;
  • 不负责在线商店账户和支付。
type MaterialTrustPolicy = 'builtin' | 'declarative' | 'signed-declarative' | 'trusted-code';
  • builtin:SDK 内置,随 SDK 签名发布。
  • declarative:无代码,满足 Core Node/配额即可。
  • signed-declarative:另外要求可信发布者签名。
  • trusted-code:允许 Shader/WASM/custom node,由宿主 allowlist。

应用可以禁用网络安装,只允许构建时预注册包。企业环境可以要求所有包签名和私有 registry。

Material 编译缓存至少包含:

packageIntegrity
+ materialId
+ implementation hash
+ nodeSet/compiler version
+ selected backend/device feature tier
+ output format/color/alpha
+ specialization parameters

普通 uniform 参数不应使 pipeline cache 失效;Graph/资源内容改变必须产生新 integrity。


每个发布 Material 至少测试:

  • 1×1、奇数尺寸、竖屏、横屏、4K 限制内分辨率;
  • 透明/不透明输入;
  • 黑、白、原色、超出 SDR 范围的线性值;
  • 参数默认值、min/max、动画中点;
  • 时间 0、中点、末端和随机 Seek;
  • WebGPU/WebGL2(若宣称支持);
  • preview/export;
  • source/from/to 缺失或 placeholder;
  • device/context lost 后重建;
  • 内存/Pass/采样数预算;
  • 长时间运行无资源增长。

Filter:

  • 输出尺寸不变;
  • alpha 和几何不被意外改变;
  • 可融合声明正确。

Transition:

  • progress=0 输出 from;
  • progress→1 连续趋近 to;
  • from/to 尺寸、alpha 和颜色不同;
  • 非帧对齐 duration;
  • 反向播放与 Seek。

Effect:

  • padding 上界;
  • auxiliary input 类型和边界;
  • temporal pre-roll/post-roll;
  • tiled 与 full-frame 一致性(若声明)。

Generator:

  • 任意 Item range/local time;
  • 确定性随机;
  • 透明输出和不同画幅。
  • Graph reference/CPU 小尺寸结果作为标准节点基准。
  • 同 backend 的 deterministic Material 做精确或严格 epsilon 比较。
  • 跨 GPU/backend 使用按节点定义的 channel tolerance、SSIM 或 DeltaE。
  • Transition 至少保存 0、0.25、0.5、0.75、接近 1 的 Golden。
  • HDR/P3 单独建立 float/color-managed corpus。
  • Golden 更新需要 Material version 变更和人工审查。

Material 认证不能只写 low/medium/high,而要针对基准设备记录:

  • GPU time p50/p95;
  • Pass 数;
  • texture read/sample 数;
  • 峰值临时纹理 bytes;
  • pipeline compile/warm time;
  • 1080p30、1080p60、4K30 是否达到 deadline。

Registry 可根据测量给出 realtime-tier-a/boffline-only 标签,作者填写的 hint 不能替代测量。

一个 Material 只有同时具备以下项才算正式支持:

manifest/schema ✓
graph/type validation ✓
resource integrity ✓
default parameter render ✓
parameter boundary tests ✓
preview backend ✓
offline/export backend ✓
capability reporting ✓
diagnostics ✓
golden/conformance ✓
performance/memory budget ✓
license/signature policy ✓

建议稳定错误码:

code含义
MATERIAL_PACKAGE_INVALIDManifest、路径、ZIP 或 hash 不合法
MATERIAL_INTEGRITY_MISMATCH实际内容与锁定 integrity 不一致
MATERIAL_SIGNATURE_INVALID签名无效或发布者不可信
MATERIAL_TRUST_REQUIRED包含程序实现但没有 trusted-code 授权
MATERIAL_PROTOCOL_UNSUPPORTEDAMP major 或 Node Set 不支持
MATERIAL_DEFINITION_INVALIDkind/port/parameter/contract 不合法
MATERIAL_GRAPH_INVALIDDAG、Node、连接或类型错误
MATERIAL_RESOURCE_INVALID资源类型、尺寸或引用错误
MATERIAL_INSTANCE_INVALID项目参数/绑定不符合 Definition
MATERIAL_DEPENDENCY_CYCLEItem/Track/Material 输入形成环
MATERIAL_BACKEND_UNAVAILABLE当前设备没有可执行实现
MATERIAL_BUDGET_EXCEEDED内存、Node、Pass、采样或时间预算超限
MATERIAL_COMPILE_FAILEDGraph/Shader/Pipeline 编译失败
MATERIAL_EXECUTION_FAILED运行期 GPU/WASM 故障
MATERIAL_MISSINGProject 锁定的包未安装
MATERIAL_MIGRATION_REQUIRED精确版本缺失且不能自动兼容

Diagnostic 必须包含 package/material/instance ID、包路径、Graph node、参数或资源路径,以及 preview/export/backend 上下文。Shader 错误不得只返回浏览器原始长文本。


即便 Graph 无代码,仍可能通过超大资源、超多 Pass、极端 blur 或历史帧耗尽内存/GPU。因此安装时静态配额,执行时动态预算和 watchdog 缺一不可。

防护目标:

  • ZIP path traversal/bomb;
  • hash/signature 替换;
  • 恶意图片/LUT/字体 parser;
  • Graph cycle 和指数型展开;
  • Shader 编译/执行 DoS;
  • WASM 内存/CPU DoS;
  • 跨项目/跨 origin 资源读取;
  • 日志泄露 URL、参数或素材;
  • 包升级供应链攻击。
能力declarativetrusted-code
Core Node Graph
包内静态资源
项目显式绑定 Asset
任意网络请求
DOM/Window
自定义 WGSL/GLSL
WASM
自定义 Node Plugin需另注册
未声明 GPU resource

trusted-code 是“宿主允许注册的代码”,不是“获得浏览器和项目全部权限”。


AMP v1 当前由 @aelionsdk/material-compiler@aelionsdk/material-sdk、Project v1 Material Instance 和 renderer runtime 共同实现。声明式 Graph 是默认、可移植路径;trusted Shader/WASM 仍由宿主执行策略控制。

协议演进遵守以下规则:

  • Package、Definition、Graph 和 Instance 分别版本化,Project 锁定精确版本与 integrity;
  • Patch 不改变既有参数、端口、Core Node 或颜色/alpha 语义;
  • 新增可选字段必须有稳定缺省行为,未知必需能力必须 fail closed;
  • 迁移是确定性纯数据变换,不执行网络或任意代码;
  • Graph backend 可以增加,但不能让 Preview 与 Export 产生两套语义;
  • Core Node 的精确公式和 Golden 容差由 Core Node Math 1.0 定义;
  • 当前实现范围、宿主注册和发布检查见 Material 创作与接入

AMP v1 的稳定兼容承诺只会随正式版本和 release notes 生效;公开 RC 实现不自动 构成 1.0 稳定性承诺。