命令行入口
CLI 是 Ranim 项目的 native 二进制入口,不是场景定义本身。场景仍可定义在 src/lib.rs 或独立的库 crate 中;二进制选择要暴露的场景,组装成一个 bevy App(ranim::App 就是 bevy_app::App 的再导出)。WASM 不运行这套 CLI,而由宿主导出 app() -> WasmApp,供 JavaScript 显式创建预览。两种入口与场景库的完整关系见项目入口。
native 的 main 装配 App 后用 app.build()(RanimAppExt,prelude 导出)定稿插件构建——断言插件就绪、执行一次bevy 的 finish() / cleanup()——得到 ranim::RanimApp,把它交给自由函数 run_cli(prelude 导出,native + cmd-render feature 门控;命名刻意避开bevy App 自带的 run() runner 入口):它安装 tracing、解析进程参数,随即分发为四个子命令:
use *;
use hello; // 场景定义来自本包的 src/lib.rs,也可以来自其他库。
<project> <command>
├── preview 启动交互预览 app(需要 cmd-preview feature)
├── output 渲染场景声明的所有 #[output(...)](成片输出)
├── render 用默认输出设置快速渲染一个场景一次(冒烟)
└── inspect 不渲染,纯 CPU 检查场景 / 动画树 / 单帧物件
在自己的项目中以 cargo run -- <command> 调用;在本仓库中运行示例:
默认包含 cmd-preview,开启全部四类子命令;关闭 default 并只开启 cmd-render时,CLI 只提供 output、render 和 inspect,帮助中不显示 preview。
带 required-features(如 typst、gltf)的示例需同时开启对应 feature。仓库为 dev profile 开了 opt-level = 1、依赖 opt-level = 3,inspect 是纯CPU 查询,渲染也足够快,调试迭代一般不需要 release。
项目装配
子命令只能看到 App 中显式注册的场景;在 main 或插件的 build 中通过add_scene / add_scenes 注册(场景方法由 AppExt 提供;插件 build 的app: &mut bevy_app::App 与 &mut App 是同一类型;完整示例见Getting Started):
渲染装配是可选的:启用 items 的项目不注册 RenderSetup 时,渲染与预览使用默认配置,即注册内置相机与矢量/网格物件渲染(ranim_items::RanimItemsPlugin)。关闭 items时默认配置为空,自定义渲染项目应注册自己的 RenderSetup。需要渲染默认配置未覆盖的完整输出(容器、变换 wrapper、自定义类型)时,才在插件中提供自己的 RenderSetup:
;
项目的 RenderSetup 在每次安装渲染 SubApp 时重放,安装提取与渲染插件。inspect 只查询 CPU 数据,不执行 setup 中的 GPU 装配。
命令报错时先看编译输出;运行成功但场景未出现时,检查 main 或插件的build 是否显式调用了 add_scene / add_scenes。
preview [SCENE]
启动交互预览 app。需要 cmd-preview feature(它启用 cmd-render,后者启用 render);不传场景名时预览第一个场景。适合编写场景时的实时调试。
output [SCENES...]
渲染每个选中场景声明的所有 #[output(...)];不指定场景时渲染全部场景。这是交付前的最终验证命令。
#[output(...)] 可用的属性(默认值:1920x1080、60 fps、mp4、dir = "./output"、save_frames = false):
一个场景可以声明多个 #[output(...)](例如同时输出 mp4 和 gif)。
产物位置(以 dir = "./output"、场景名 hello 为例):
output/hello_1920x1080_60.mp4 视频:<dir>/<模板展开的主名>.<ext>
output/hello_1920x1080_60-frames/NNNN.png 帧序列(save_frames = true 时)
output/hello_1920x1080_60/<filename> TimeMark::Capture 截图
场景中通过 r.insert_time_mark(sec, TimeMark::Capture("x.png".to_string()))声明的截图,在主视频渲染完成后统一处理。
--buffer-count <N>(默认 2)控制 GPU readback 缓冲数量:越大并行度越高,但占用更多显存。
需要 GPU 与 ffmpeg;PATH 中找不到 ffmpeg 时会尝试在当前目录查找或下载。
render <SCENE>
用固定默认设置(1920x1080、60 fps、mp4)把单个场景快速渲染一次,输出到./output/<scene>_1920x1080_60.mp4。
它不读取任何 #[output(...)] 声明,也不处理 TimeMark::Capture。适合迭代中只想快速看整体效果的情况;正式验收仍应使用 output。
inspect
纯 CPU 检查,不创建 GPU context,可以在无 GPU 的环境运行。所有子命令支持--format text|json(默认 text;JSON 输出顶层含 schema_version,适合脚本化)。
inspect scenes
列出 App 中注册的场景及其 #[output(...)] 摘要(尺寸、fps、格式、输出目录、name_template、save_frames),不调用场景构造函数。适合开工第一步:确认场景名拼写、场景是否注册成功、输出配置是否符合预期。
inspect tree [SCENE]
构建场景并输出层级动画树。每个节点包含:DFS path、kind(anim/children/audio)、anim_name、父局部坐标下的 range、content_duration_secs、rate_func、enabled 与 children;iterative 节点额外包含 sim_step(with_steps(N) 声明的进度步长 1/N,未声明时为默认值)。当项目里只有一个场景时 [SCENE] 可省略。
注意 range 是父局部坐标,不要直接当成全局时间。
inspect frame <SCENE> --at <sec>
在 <sec> 直接采样类型化帧;迭代动画使用各自声明的内容步长。JSON frame输出的 schema_version 为 2。每个输入包含 order(完整输出的全局插入顺序)、id / animation_id / part、input_type 与来源根动画 source。已支持的裸内置类型还提供 CPU 投影数据:矢量、网格、相机,或 SVG / 文字的图元分组;--verbose 追加完整几何数据。未提供检查适配的复合或自定义类型保留为 opaque 输入元数据,不需要 GPU 或该类型的渲染插件。
用于渲染前定位「某时刻物件不对 / 位置不对 / z-order 不对 / 颜色不对」等问题,避免直接上 GPU 盲调。已知局限(如实输出,不要误读):
source只能回溯到根动画的animation_id,不能定位树内叶子节点;part是根动画中完整求值输出的序号,跨活跃叶子与类型连续递增;容器成员不单独占用输入序号。一个SvgItem或TypstText是一条输入,其 CPU 投影数据可以包含多个图元;order是输入顺序。渲染器在提取后还会按SourceOrder { order, part }排序生成最终SceneOrder,不能把输入序号直接当作 render entity 数量或最终 rank。
推荐工作流
inspect scenes 确认场景与输出配置
│
inspect tree 确认动画组织、时间范围、rate_func / enabled
│
inspect frame 在关键时刻确认物件、几何、z-order 与颜色(不上 GPU)
│
render 快速冒烟,看整体效果
│
output 最终验证:成片、帧序列与 Capture 截图
原则:能用便宜的 inspect 查清的问题,不要留到昂贵的 GPU 渲染之后才发现。