v0.1
Status: Backfilled(补写) — 覆盖 #3–#96;按 v0.1.5(2025-10-18)发布时点快照描述。 起源期 PR(#3–#28,2024-11 → 2025-03)先于首个 tag
v0.1.0-alpha.1落地;alpha.8/alpha.10/alpha.15/alpha.16从未发布,v0.1.1–v0.1.3只含未经 PR 的直接修复。
v0.1 的故事,是 ranim 找到自己的渲染范式的故事:以 compute shader 描边起家(#3),短暂借道 Vello(#15/#18),最终落到 wgpu 单管线 SDF(#22,受 JAnim 启发)——这条 SDF 路线一直延续至今。支撑它的骨架也在这个版本线里成形:Extract → Prepare → Render 三阶段(#5)、Timeline 编码(#28)、Preview App(#53)、dylib 热重载的 CLI(#77),以及 v0.1.5 收官时的 crate 拆分与流水线化渲染(#94/#96)。
新增
- SDF 渲染管线:单一
vitem.wgsl片元着色器渲染全部 VItem——精确点到二次贝塞尔距离(解三次方程)+ 绕行判定 + 反走样;这是今天 vitem 渲染的直系祖先 - 三阶段渲染架构:Extract(CPU)→ Prepare(CPU→GPU)→ Render,物件所有权移交
Scene换取Id - Preview App:winit + egui-wgpu 窗口内预览,时间轴 scrub;后成为 wasm 网页预览与热重载的底座
- ranim-cli:
linkmedistributed slice +libloading的 dylib 热重载,ranim preview/ranim render,#[scene]/#[output]宏 - CameraFrame 即物件:相机成为普通可动画 item,
perspective_blend正交↔透视连续混合,frame_height = 8.0分辨率无关坐标 - Item 体系:
Extract::Target、VisualItem、组合物件(元组 Renderable)、几何构造器(arrow/arc/circle/polygon/line/svg/typst)、TypstText(按字符 diff 对齐) - crate 拆分:ranim-core / ranim-items / ranim-anims / ranim-render / ranim-app / ranim-cli / ranim-macros,façade 再导出
- serde feature(
derive_more去样板)、wasm 构建进 CI、zola 站点(后被 mdbook 取代)
演进中的关键更名
v0.1 是 API 高速重构期,列几条主干系谱,便于读旧代码:
Mobject→Rabject(#3)→TimelineId(#64)RanimTimeline/RabjectTimeline→RanimScene/ItemTimeline(#64)Blueprint系统:#57 引入 → #64 移除(“items 只保留自描述数据”)- 场景定义:trait(
SceneConstructor/SceneMeta/Scene)→fn(&mut RanimScene)+#[scene]宏(#77) - 坐标系:像素相关 →
frame_height = 8.0恒定(#44) - 包路径:单体
ranim::→ranim::{core, items, anims, render}(#94)
起源:compute shader 时代
相关 PR:#3(stroke compute)、#5(三阶段架构)、#9/#10(curve fill)、#12(fading)
- #3(首个 PR):VMobject 描边从 CPU 搬进 compute shader——每个二次贝塞尔段一个 workgroup,16 采样求点与切线,沿法向挤出描边轮廓顶点,转角连接由
joint_anglesstorage buffer 解决;渲染 pass 直接读 compute 写出的顶点数组(无 vertex buffer)。同 PR 里Mobject更名Rabject; - #5:奠定至今的三阶段架构——物件无层级,插入
Scene即移交所有权换取RabjectId,按Extract → Prepare → Render渲染;Animation包着消费进度alpha的AnimationFunc(与消费dt的Updater相对)——“动画是 alpha 的函数“从这里开始; - #9/#10:真正的曲线填充——填充三角形带参考三角形
uv_coord与fill_all旗标,片元里求值二次曲线只保留曲线内部;WgpuContext/WgpuBuffer由此诞生; - #12:淡入淡出的语义确立为整个物件在零透明快照与当前状态之间插值,而非缩放透明度——
Opacitytrait 只负责各类型自己的透明度写入。
渲染范式三连跳
相关 PR:#15(Vello + Wgpu)、#18(Vello for 2d)、#22(SDF)
flowchart LR
subgraph E1["时代一 · #3–#12"]
A1["VMobject 描边<br/>compute 挤出 + joint_angles"] --> R1["wgpu"]
end
subgraph E2["时代二 · #15 / #18"]
W["wgpu 手写 2D<br/>(#18 删除)"] --> C["Canvas 纹理"]
V["vello 2D<br/>透明纹理叠加"] --> C
C --> R2["合成进 3D 场景"]
end
subgraph E3["时代三 · #22 至今"]
S["全部 VItem"] --> P["单一 vitem.wgsl<br/>SDF:点到二次贝塞尔距离"]
P --> R3["wgpu"]
end
E1 -- "#15 引入 vello" --> E2
E2 -- "#22 弃用 vello" --> E3
- #15:世界变成 3D,2D 内容住进
Canvas(“basically a 2d scene”)。手写 wgpu 2D 与 Vello 并存:vello 渲到透明纹理再叠加混合——“所有 vello 渲染的东西都叠在别人上面”;Entitytrait 取代过于僵硬的Rabject管线; - #18:删掉全部手写 wgpu 2D 路径(
rabject2d/vpath/*与三个 vpath shader,-2647 行),2D 完全交给 vello,3D 留在 wgpu; - #22:范式定音——完全弃用 vello(diff -7967 行),所有 VItem 经单一 SDF 片元管线渲染:storage buffer 存点(xy 坐标 +
is_closed)、填/描色与描边宽度,distance_bezier解三次方程求精确最近点,SubpathAttr做绕行/内部判定,ANTI_ALIAS_WIDTH = 0.015反走样。今天的vitem.wgsl仍是这条路线。
动画、相机与坐标系
- #25:动画二分为
Dynamic(每帧prepare_alpha重备实例)与Static(一次性准备,如 creation/freeze);clip box 从 CPU 边界框搬进 compute shader 用atomicMin/atomicMax维护——这个思路后来在 v0.2 的 GPU-driven 合批(#138/#142)里长成主角; - #28:timeline 与 eval 泛化到任意类型(
TimelineTrait/Evaluator/ChainedAnimation),CameraFrame成为普通可动画 item(相机动画自此可能),“stacked” 动画(同一 item 的多条 timeline 经sync()同步),宏拆入packages/ranim-macros; - #44:
CameraFrame { pos, up, facing, scale, fovy, near, far, perspective_blend }完全可插值——perspective_blend在正交与透视投影矩阵间按 连续混合(closes #43);坐标改为分辨率无关的恒定frame_height = 8.0(closes #37),示例全部重写。
Preview App
egui 0.31 + winit ApplicationHandler 手写集成(当时还不是 eframe),场景经专用 AppPipeline 渲到 wgpu surface 的视口矩形,egui 时间轴控件(TimelineState)对 sealed timeline 做任意时刻 scrub;GPU profiling(wgpu-profiler/puffin)藏在 profiling feature 后。
这个原型后来长出 wasm 网页版(#64)与热重载(#77),并在 v0.2 换用 eframe(#114)。
Item 体系成型
- #57:typed timeline handle(
TimelineItem<'t, Mark>+ marker 类型),insert(item)返回带类型的句柄;per-item Extract 成形(VItemPrimitiveData); - #60:组合物件——为元组/数组实现
Renderable,Arrow { tip, line }作为整体存进实例池。设计上明确拒绝父子层级:“如果 tip 淡出了只剩线,它还是箭头吗?”——拆分交给decompose;(这一立场直到 v0.3 的场景图hierarchy::Node才被系统性重审,见 v0.3 篇。) - #64(本时代最大 PR,+35k 行):item 与时间线大重构——
Extract提取到关联Target;Renderable改名RenderCommand、旧Primitive改名RenderResource、新的Primitivetrait 声明type RenderInstance;VisualItem串起Extract → Renderable → RenderInstance流水;Blueprint 系统移除。时间线侧RanimTimeline→RanimScene、RabjectTimeline→ItemTimeline、Rabject→TimelineId。同 PR 关闭 #67(预览上 wasm)与 #54:website 改造为 mdbook book + rustdoc + 每个示例内嵌 wasm 预览; - #69:
DynTimeline类型擦除——一个 item 的 timeline 集合可容纳多种动画类型,map<T, E>在 item 状态类型变化时转换 timeline(closes #68)。
工程化:dylib、拆分与流水线
- #73:wasm 示例进 CI 构建,仓库里提交的
pkg/产物删除(-24.5k 行); - #77(ranim-cli 诞生,v0.1.0):
#[scene]/#[output]宏经linkmedistributed slice 收集&'static Scene,CLI 把用户 crate 构建成 dylib、复制到临时路径后libloading加载——ranim preview监听重建热重载,ranim render构建并渲染。SceneConstructor从此就是fn(&mut RanimScene);输出路径规范为<dir>/<场景名>_<宽>x<高>_<fps>.mp4(closes #76); - #87:每个 example 变成独立 cdylib(
examples/<name>/lib.rs),一次构建同时服务 render 与 preview,与用户项目的 dylib 故事一致; - #94(crate 拆分):单体 crate 按职责拆为 ranim-core / ranim-items / ranim-anims / ranim-render / ranim-app(+ 既有 ranim-cli/ranim-macros),façade
ranim再导出core/items/anims/render——用户 dylib 只依赖轻量 crate(为 issue #84 的编译时间与二进制体积); - #96(v0.1.5 收官):三件套——
CoreItemStore作为场景求值的交换格式;RenderPool(slotmap + 按TypeId回收)复用 GPU 实例;专用渲染 worker 线程(async_channelbounded(1))让第 N 帧在 GPU 上渲染时主线程求值第 N+1 帧。CPU 求值与 GPU 渲染自此解耦。
sequenceDiagram
participant M as 主线程(求值)
participant W as worker 线程(渲染)
Note over M,W: async_channel bounded(1) 同步
M->>W: 提交第 N 帧(CoreItemStore)
W->>W: 复用 RenderPool 实例,渲染第 N 帧
M->>M: 与渲染并行:求值第 N+1 帧
W-->>M: 第 N 帧完成
M->>W: 提交第 N+1 帧
其余小特性与修复
- #23:第一个 zola 生成的网站(后由 #64 的 mdbook + wasm 方案取代);
- #62:wgpu 24 → 25(合并顺序与 PR 号无关,见文首注);
- #63:
serdefeature 与derive_more去样板——首个外部贡献(MilkBlock); - #71:修零长向量叉积归一化的 NaN(closes #70),测试重写为精确
PI断言; - #90:
#[scene(clear_color = "#...")]可配清屏色; - #91:修
Alignable对VPointComponentVec/VItem/Group<T>的对齐(双侧补齐到最大长度,resize_preserving_order); - #93:
TypstTextitem——Typst 源码经typst_svg转字形轮廓,Alignable按字符级 diff 实现,文本变换动画按匹配/插入/删除的字符 morph。
v0.1.1–v0.1.3(2025-08-10 → 2025-08-20)是未经 PR 的小修复版本;v0.1.4 带 #90/#91;v0.1.5(2025-10-18)以 #93/#94/#96 收官——单 crate 时代就此结束,接力棒交给 v0.2。