用真实 CLI 轨迹驱动 FreeCAD 演示视频:CLI-Anything 程序化渲染参考与实践
本文以仓库内 docs/FREECAD_VIDEO_REFERENCE.md 为骨架,系统拆解 CLI-Anything 项目如何基于真实 cli-anything-freecad 执行轨迹与真实 FreeCAD 实时预览产物(preview bundle),程序化合成可编辑的分屏演示视频(MP4),并额外讲解基于 motion render-video 的三种真逐帧运动展示(drive / spin / combo)的生成原理、命令与产物清单。阅读后你将掌握该仓库生产一条"非录屏、非合成画面"的 FreeCAD demo 视频的完整管线,以及从 trajectory.json 到成片的所有关键环节与可复现入口。
一、这份参考文档记录了什么
docs/FREECAD_VIDEO_REFERENCE.md(最后更新于 2026-04-22 UTC)是一份程序化视频产物(programmatic video artifacts)登记与说明文件。它逐条记录了从真实 cli-anything-freecad 轨迹与真实 FreeCAD 预览包构建而成的视频制品,共覆盖四条成品:
- Curiosity V6 —— 主分屏成片(真实 CLI 轨迹 + 实时预览会话);
- Curiosity V6 True Motion Showcase —— 真逐帧"直行"运动短片;
- Curiosity Turntable Motion —— 真逐帧"转台"旋转短片;
- 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 明确了两个阶段(collect 与 render),并从源码结构看(主入口与子命令分发)实际提供四种模式:collect、render、run-all、motion-showcase。
采集阶段 collect_demo(实现见 L3411):
- 按场景(
curiosity、mars-rover、orbital-relay等,SCENARIOS 定义见 L2737)顺序执行真实命令。每条命令通过run_cli(L3299)以cli-anything-freecad --json ...方式在 freecad/agent-harness 工作目录下真实运行,并记录开始/结束时间、returncode、stdout/stderr、JSON 输出,写入trajectory.json的commands列表。 - 每步若配置了
wait_preview: True,则先启动 poll 模式实时预览(live previewstart,--recipe quick --mode poll --source-poll-ms 500 --poll-ms 700),随后调用wait_for_bundle_update(L3351)轮询会话文件直到 bundle 数量增长或 bundle id 变化,再通过extract_bundle_artifacts(L3373)把真实的manifest.json、summary.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_panel、draw_preview_panel、compose_preview_dashboard); - 逐帧 PNG 落盘后用
ffmpeg(libx264/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_project(L3610)中,向深拷贝的项目追加ShowcaseGround(184×96×4)与ShowcaseMarkerA/B/C三块标志物,使整车平移在 hero 视角下有可读参照; - 生成 12 张真实 hero capture:
generate_curiosity_showcase_sequence(L3686)对 12 个姿态(对应脚本常量SHOWCASE_FRAME_COUNT = 12)逐次施加姿态变换(平移 + 起伏 bump + 机械臂/桅杆/天线盘摇摆,见_apply_curiosity_showcase_poseL3652),每次调用真实命令preview capture,取 bundle 中artifacts/hero.png; - 缓存与清单:结果落盘为
showcase/sequence.json(协议freecad-showcase-sequence/v1)、showcase/projects/pose_XX.json、showcase/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_showcase(L3927)的执行链可以归纳为四步,每一步在仓库中均有对应证据:
- 舞台化:复用最终
Curiosity v6项目 JSON,经_curiosity_showcase_project加入舞台地面与 marker(与第四节同一辅助函数); - 姿态采样:按
keyframe_count等分0 → 1进度,用对应_apply_curiosity_*_motion_pose(直行/自旋/组合,L3755、L3827、L3874)计算每个部件的 placement,再通过motion_mod.create_motion+add_keyframe写入项目motions集合; - 真实渲染:调用
cli-anything-freecad -p <project> motion render-video <index> <video_path>。该命令由 harness 的 core/motion.py 提供(create_motion定义于 motion.py L215,render-video支持.mp4/.webm/.gif输出,见 motion.py L650),每帧经真实 FreeCAD GUI capture 渲染; - 编码与登记:
ffmpeg编码 MP4,同时产出运动项目 JSON、motion_manifest.json(协议freecad-true-motion-showcase/v1,含notes:逐帧渲染、无合成插帧)、frames/sequence.json与stills/start|mid|final.png静帧。
从源码的 manifest 字段还可确认渲染参数:create_motion 统一使用 camera="hero"、width=1600、height=900、background="White"、fit_mode="initial"。
参考文档同时给出了诚实的能力边界说明,写作时不应夸大:
- 三种运动均为真实逐帧 FreeCAD 渲染,不使用任何基于融合/合成的中间运动(no blend-based or synthetic in-between motion);
- 运动目前由逐部件 placement 关键帧驱动(part-placement keyframes),而不是原生 Assembly 关节运动仿真(not native Assembly joint simulation)。
六、成片可复现性与源码对照
- 采集管线真实性保证:
collect_demo的trajectory.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 数据模型与命令分组(含document、part、preview、motion等命令组,目录 freecad/agent-harness/cli_anything/freecad 下按core/模块组织)。 - 仓库内的相邻文档:docs/PREVIEW_PROTOCOL.md、docs/PREVIEW_MECHANISM_PROGRESS.md、docs/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-video(L4898)。参考文档登记的各项时长/帧数均取决于当时真实会话的耗时与所选倍率,重跑结果会随真实执行时间而变。
七、小结:一条可验证的"非录屏" 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 建模任务上。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.2 K634
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown300
jforgamejforgame是一个一站式游戏服务器开发框架。包含游戏服务器开发所需要的各种组件,比如网关,socket服务端与客户端,自定义高效消息编解码,游戏热更新,游戏通用工具等等。包含游戏服,跨服,匹配服,后台管理系统等实现,同时提供大量业务案例以供学习。亦可用于其他socket应用,例如及时聊天等。Java101
fizz-gateway-nodeAn Aggregation API Gateway in Java . FizzGate 是一个基于 Java开发的微服务聚合网关,是拥有自主知识产权的应用网关国产化替代方案,能够实现热服务编排聚合、自动授权选择、线上服务脚本编码、在线测试、高性能路由、API审核管理、回调管理等目的,拥有强大的自定义插件系统可以自行扩展,并且提供友好的图形化配置界面,能够快速帮助企业进行API服务治理、减少中间层胶水代码以及降低编码投入、提高 API 服务的稳定性和安全性。Java60
certd开源SSL证书管理工具;全自动证书申请、更新、续期;通配符证书,泛域名证书申请;证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔;https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署JavaScript60
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python280
