首页
/ 用真实 CLI 轨迹驱动 FreeCAD 演示视频:CLI-Anything 程序化渲染参考与实践

用真实 CLI 轨迹驱动 FreeCAD 演示视频:CLI-Anything 程序化渲染参考与实践

2026-09-08 12:12:12作者:沈韬淼Beryl

本文以仓库内 docs/FREECAD_VIDEO_REFERENCE.md 为骨架,系统拆解 CLI-Anything 项目如何基于真实 cli-anything-freecad 执行轨迹真实 FreeCAD 实时预览产物(preview bundle),程序化合成可编辑的分屏演示视频(MP4),并额外讲解基于 motion render-video 的三种真逐帧运动展示(drive / spin / combo)的生成原理、命令与产物清单。阅读后你将掌握该仓库生产一条"非录屏、非合成画面"的 FreeCAD demo 视频的完整管线,以及从 trajectory.json 到成片的所有关键环节与可复现入口。

CLI-Anything FreeCAD 实时预览分屏演示:左侧为 Agent 命令流(Recent commands + LIVE 状态),右侧为 Preview Monitor 实时预览面板

一、这份参考文档记录了什么

docs/FREECAD_VIDEO_REFERENCE.md(最后更新于 2026-04-22 UTC)是一份程序化视频产物(programmatic video artifacts)登记与说明文件。它逐条记录了从真实 cli-anything-freecad 轨迹与真实 FreeCAD 预览包构建而成的视频制品,共覆盖四条成品:

  1. Curiosity V6 —— 主分屏成片(真实 CLI 轨迹 + 实时预览会话);
  2. Curiosity V6 True Motion Showcase —— 真逐帧"直行"运动短片;
  3. Curiosity Turntable Motion —— 真逐帧"转台"旋转短片;
  4. Curiosity Combo Motion —— 真逐帧"旋转 + 前行"组合短片。

文中出现的大量 /root/preview-artifacts/... 路径属于渲染宿主机的产物目录(并不存在于本 Git 仓库内);仓库真正收录的是生成这些成片的可复现脚本 docs/scripts/freecad_live_preview_demo.py(共约 4981 行)以及配套的 FreeCAD harness 实现。仓库内可查看的样例输出即上文 assets/demos/freecad-curiosity-preview-trajectory.gif,其分屏画面与参考文档描述的渲染版式完全一致。

二、底层管线:collect 采集 → render 合成

脚本 docs/scripts/freecad_live_preview_demo.py 的模块 docstring 明确了两个阶段(collectrender),并从源码结构看(主入口与子命令分发)实际提供四种模式:collectrenderrun-allmotion-showcase

采集阶段 collect_demo实现见 L3411):

  • 按场景(curiositymars-roverorbital-relay 等,SCENARIOS 定义见 L2737)顺序执行真实命令。每条命令通过 run_cliL3299)以 cli-anything-freecad --json ... 方式在 freecad/agent-harness 工作目录下真实运行,并记录开始/结束时间、returncode、stdout/stderr、JSON 输出,写入 trajectory.jsoncommands 列表。
  • 每步若配置了 wait_preview: True,则先启动 poll 模式实时预览(live preview start--recipe quick --mode poll --source-poll-ms 500 --poll-ms 700),随后调用 wait_for_bundle_updateL3351)轮询会话文件直到 bundle 数量增长或 bundle id 变化,再通过 extract_bundle_artifactsL3373)把真实的 manifest.jsonsummary.json 与各 artifact 复制到 snapshots/ 目录。
  • 收集过程崩溃时也会先写 trajectory.partial.json;结束时会在 finally 中调用 preview live stop 清理会话,并可选生成 live.html(借助 cli-hub preview html)。

合成阶段 render_video实现见 L4809):

  • 读取真实 trajectory.json,主片时长 =(最后一条命令/预览事件的时间戳 + 结尾停留 HOLD_TAIL_S = 2.5s)÷ speed
  • 以 1600×900 画布逐帧用 Pillow 绘制:左面板 650px(终端/命令区),右面板为预览监视器;分屏主体即"真实命令流 + 真实预览 bundle 缩略图"的程序化排版(见 draw_terminal_paneldraw_preview_panelcompose_preview_dashboard);
  • 逐帧 PNG 落盘后用 ffmpeglibx264 / yuv420p-framerate fps)编码为 MP4;
  • 对于 curiosity 场景,主片之后自动拼接一段"结局 showcase"(见第四节)。

场景轨迹模板由脚本内 _taipei_101_steps_mars_rover_steps_curiosity_steps 等函数给出(L104 / L336 / L777),Curiosity 场景即由 20+ 条"用真实 CLI 添加 box/cylinder/sphere/mirror 部件"命令构成。

三、Curiosity V6:主分屏成片的两版产物

参考文档为 Curiosity V6 登记了两版主成片:

产物 源轨迹 时长 大小
demo.mp4(首发渲染) /root/preview-artifacts/20260421/freecad-curiosity-v6/trajectory.json 116.166667s 3,011,924 bytes
demo-polished.mp4(精修重渲染) 同上 71.416667s 2,266,665 bytes

首发成片的渲染命令(--speed 8):

python3 /root/CLI-Anything-preview/docs/scripts/freecad_live_preview_demo.py \
  render \
  --timeline /root/preview-artifacts/20260421/freecad-curiosity-v6/trajectory.json \
  --speed 8

--speed 是播放速度倍率(脚本默认 1.0,见 参数解析 L4924)。参考文档的注释明确:--speed 8 使这条较长的真实轨迹保持可读,而不会变成数分钟的原始回放——即采集到的真实命令与预览事件时间戳不变,仅通过播放倍率压缩成片时长。

精修成片则不再走 CLI,而是以 importlib 直接加载脚本模块并调用 render_video 函数式渲染:

python3 - <<'PY'
import importlib.util
from pathlib import Path
script = Path('/root/CLI-Anything-preview/docs/scripts/freecad_live_preview_demo.py')
spec = importlib.util.spec_from_file_location('freecad_live_preview_demo', script)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
print(
    mod.render_video(
        Path('/root/preview-artifacts/20260421/freecad-curiosity-v6/trajectory.json'),
        output_path=Path('/root/preview-artifacts/20260422/freecad-curiosity-v6/demo-polished.mp4'),
        fps=12,
        speed=14.0,
        keep_frames=True,
    )
)
PY

对照 render_video 函数签名 可以验证上述参数含义:fps=12 为输出帧率、speed=14.0 为倍率、keep_frames=True 保留中间帧 PNG(便于检查单帧),未传 output_path 时默认写到 timeline 所在目录 / demo.mp4

关键静帧(stills) 分别记录了轨迹末尾与结局 showcase 的起、中、终画面(host 机路径):

  • stills/trajectory-end.png —— 主轨迹段终点;
  • stills/showcase-start.png / showcase-mid.png / showcase-final.png —— 结局展示段三帧。

四、结局 showcase 的生成方法:真实预览 capture 的拼接,而非录屏

这是参考文档反复强调的设计原则。主分屏与结局段都不是屏幕录制,结尾 showcase 是一组"由最终项目状态派生出的真实 FreeCAD 预览 capture"组合而成。原始实现要点如下:

  • 复用真实项目:读取最终 Curiosity v6 项目 JSON 作为源几何;
  • 补充真实舞台几何:在源码 _curiosity_showcase_projectL3610)中,向深拷贝的项目追加 ShowcaseGround(184×96×4)与 ShowcaseMarkerA/B/C 三块标志物,使整车平移在 hero 视角下有可读参照;
  • 生成 12 张真实 hero capturegenerate_curiosity_showcase_sequenceL3686)对 12 个姿态(对应脚本常量 SHOWCASE_FRAME_COUNT = 12)逐次施加姿态变换(平移 + 起伏 bump + 机械臂/桅杆/天线盘摇摆,见 _apply_curiosity_showcase_pose L3652),每次调用真实命令 preview capture,取 bundle 中 artifacts/hero.png
  • 缓存与清单:结果落盘为 showcase/sequence.json(协议 freecad-showcase-sequence/v1)、showcase/projects/pose_XX.jsonshowcase/captures/。若 sequence.json 已存在且帧文件齐全,再次渲染会直接命中缓存复用。

上述"12 extra real FreeCAD hero captures"与参考文档登记的实现说明逐字对应。

精修版(demo-polished.mp4)的改动在参考文档中有明确清单,并与源码排版函数一一对应:

  • 左侧面板由"字面终端"改为设计化的 Agent Command Stream——命令卡片使用真实捕获的命令串、经 _readable_command_text 归一化显示(L4114);
  • 结局不再用稀疏的 hero-capture 淡入混合,而改用真实 combo 运动序列:一整圈转台旋转 + 随后向前行驶;
  • 结局帧取自 cli-anything-freecad motion render-video 的输出目录 /root/preview-artifacts/20260421/freecad-curiosity-v6/showcase-motion/

精修版静帧对应 stills/early-command-stream.png(命令流早期)、mid-preview-monitor.png(预览监视器中期)、showcase-rotation.png(展示旋转)、showcase-final-drive.png(展示末段直行)。

五、True Motion Showcase:真逐帧 FreeCAD 渲染的三种运动风格

参考文档的第三、四节与"True Motion"节共同构成一条独立管线:不插值、不合成中间帧,而是把关键姿态写入项目 motions 集合,调用 cli-anything-freecad motion render-video 逐帧走真实 FreeCAD GUI capture,最后用 ffmpeg 编码。三种风格的登记参数汇总如下:

风格 视频文件 时长 帧数 大小 关键姿态数
直行 drive curiosity_true_motion.mp4 6.0s 73 315,872 bytes 13
转台 spin curiosity_turntable_motion.mp4 7.0s 85 719,298 bytes 19
组合 combo curiosity_combo_motion.mp4 9.0s 109 未登记 25

三种风格使用的 CLI 命令同构,差异仅在 --motion-style 与输出目录:

# 直行:13 个关键姿态,横跨 6.0s
python3 /root/CLI-Anything-preview/docs/scripts/freecad_live_preview_demo.py \
  motion-showcase \
  --timeline /root/preview-artifacts/20260421/freecad-curiosity-v6/trajectory.json \
  --output-dir /root/preview-artifacts/20260422/freecad-curiosity-v6-true-motion \
  --fps 12

# 转台:19 个关键姿态,横跨 7.0s,绕舞台中心旋转
python3 /root/CLI-Anything-preview/docs/scripts/freecad_live_preview_demo.py \
  motion-showcase \
  --motion-style spin \
  --timeline /root/preview-artifacts/20260421/freecad-curiosity-v6/trajectory.json \
  --output-dir /root/preview-artifacts/20260422/freecad-curiosity-v6-turntable-motion \
  --fps 12

# 组合:25 个关键姿态,横跨 9.0s,先转一整圈再直行过台
python3 /root/CLI-Anything-preview/docs/scripts/freecad_live_preview_demo.py \
  motion-showcase \
  --motion-style combo \
  --timeline /root/preview-artifacts/20260421/freecad-curiosity-v6/trajectory.json \
  --output-dir /root/preview-artifacts/20260421/freecad-curiosity-v6/showcase-motion \
  --fps 12

各风格产出的动作参数与时长/关键帧数在源码中以常量固化L62-L70),与参考文档登记一致:

TRUE_MOTION_DURATION_S = 6.0      # drive
TRUE_MOTION_KEYFRAME_COUNT = 13
SPIN_MOTION_DURATION_S = 7.0      # spin
SPIN_MOTION_KEYFRAME_COUNT = 19
COMBO_MOTION_DURATION_S = 9.0     # combo
COMBO_MOTION_KEYFRAME_COUNT = 25

核心实现 generate_curiosity_true_motion_showcaseL3927)的执行链可以归纳为四步,每一步在仓库中均有对应证据:

  1. 舞台化:复用最终 Curiosity v6 项目 JSON,经 _curiosity_showcase_project 加入舞台地面与 marker(与第四节同一辅助函数);
  2. 姿态采样:按 keyframe_count 等分 0 → 1 进度,用对应 _apply_curiosity_*_motion_pose(直行/自旋/组合,L3755L3827L3874)计算每个部件的 placement,再通过 motion_mod.create_motion + add_keyframe 写入项目 motions 集合;
  3. 真实渲染:调用 cli-anything-freecad -p <project> motion render-video <index> <video_path>。该命令由 harness 的 core/motion.py 提供(create_motion 定义于 motion.py L215render-video 支持 .mp4/.webm/.gif 输出,见 motion.py L650),每帧经真实 FreeCAD GUI capture 渲染;
  4. 编码与登记ffmpeg 编码 MP4,同时产出运动项目 JSON、motion_manifest.json(协议 freecad-true-motion-showcase/v1,含 notes:逐帧渲染、无合成插帧)、frames/sequence.jsonstills/start|mid|final.png 静帧。

从源码的 manifest 字段还可确认渲染参数:create_motion 统一使用 camera="hero"width=1600height=900background="White"fit_mode="initial"

参考文档同时给出了诚实的能力边界说明,写作时不应夸大:

  • 三种运动均为真实逐帧 FreeCAD 渲染,不使用任何基于融合/合成的中间运动(no blend-based or synthetic in-between motion);
  • 运动目前由逐部件 placement 关键帧驱动(part-placement keyframes),而不是原生 Assembly 关节运动仿真(not native Assembly joint simulation)。

六、成片可复现性与源码对照

  • 采集管线真实性保证collect_demotrajectory.json 自带 notes,声明"所有命令均针对真实 cli-anything-freecad 入口执行、所有预览图均来自真实 poll 会话、最终视频是对这些真实产物的程序化排版"。对应实现在 collect_demo
  • 预览协议侧:FreeCAD harness 的 core/preview.py 定义了实时会话协议(LIVE_PROTOCOL_VERSION = "preview-live/v1"preview.py L34),并承担 poll 模式会话状态机与 live 轨迹追加等职责,是脚本轮询 bundle 的底层支撑。
  • harness 总览freecad/agent-harness/FREECAD.md 提供了 cli-anything-freecad 的总体架构、JSON 数据模型与命令分组(含 documentpartpreviewmotion 等命令组,目录 freecad/agent-harness/cli_anything/freecad 下按 core/ 模块组织)。
  • 仓库内的相邻文档docs/PREVIEW_PROTOCOL.mddocs/PREVIEW_MECHANISM_PROGRESS.mddocs/PREVIEW_PROGRESS.md 记录预览机制与相关进展,可作为背景阅读。

若要在自己的宿主环境复现:需要安装 freecad/agent-harness 下的 harness 包(setup.py),具备可 GUI capture 的 FreeCAD、ffmpeg 与 DejaVu 字体(脚本顶部指定了字体路径,L50-L53),先以 collect 拿到真实 trajectory.json,再以 render/motion-showcase 生成各版本成片;默认输出目录为 ~/preview-artifacts/<YYYYMMDD>/freecad-live-videoL4898)。参考文档登记的各项时长/帧数均取决于当时真实会话的耗时与所选倍率,重跑结果会随真实执行时间而变。

七、小结:一条可验证的"非录屏" Demo 生产范式

综合来看,docs/FREECAD_VIDEO_REFERENCE.md 记录的并非美术合成流程,而是一条工程上可追溯、可复现、可分层的视频生产范式:

  • 真实性:命令、输出、时间戳、预览 bundle、hero capture 全部来自真实执行,杜绝伪造画面;
  • 分层:主片(真实轨迹 + 真实预览 bundle)与结局段(真实 hero capture / 真实 motion 逐帧渲染)分离,结局可独立用 motion-showcase 重出;
  • 可控--speed--fps--motion-style 三个参数即可分别控制叙事节奏、帧率与运动脚本;
  • 诚实边界:明确标注当前运动基于 part-placement keyframes 而非 Assembly 关节仿真,避免给读者超出实现的预期。

对需要为"Agent 驱动的 CAD 工作流"制作宣传/验收素材的开发者而言,这套脚本是现成范式:改动 SCENARIOS 中的场景步骤即可把同样的 collect/render/motion-showcase 管线复用到任意 FreeCAD 建模任务上。

热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
900
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
927
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.94 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
603
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
396
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
527