Communitygithub.com

model-by-coding

使用當需要將實體物件轉換為程式碼建立的3D模型,並產出拆解展示影片和循環GIF時使用——從照片測量物件,以Three.js程式碼建模,透過無頭截圖比對每個姿勢與照片的吻合度,再使用HyperFrames 0.9.36渲染影片。

model-by-coding 是什麼?

model-by-coding 是一個專為開發者設計的 AI 助理技能,能將實際的硬表面物體(如風扇、燈具、相機等)從照片轉換為由程式碼建立的 Three.js 3D 模型,並自動產生拆解展示影片與循環 GIF。本技能的核心優勢在於每一步皆透過照片驗證模型精確度,確保最終呈現的是真實物體而非近似猜測。支援的流程包含五個階段:從照片測量尺寸、以程式碼建立模型、比對六個視角的渲染結果與照片、使用 HyperFrames 渲染影片,以及剪輯循環 GIF。技能內建多個 Python 與 HTML 輔助工具(如照片比對腳本、檢查報告解析),並提供完整的 PowerShell 範例流程,開發者可在幾小時至兩天內完成單一物件的建模與影片產出。強烈建議不可跳過驗證步驟,否則將導致模型錯誤。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Mng12345/model-by-coding/tree/main

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

model-by-coding 是做什麼的?

透過程式碼從照片建立實體物件的3D模型,再將其轉化為拆解展示影片和GIF。此流程對一件事有明確的堅持:模型在每一步都與照片進行驗證,因此影片呈現的是被拍攝的實際物體,而非僅是合理的推測。

何時使用

  • 需要透過短影片解釋或展示一個硬表面產品的內部結構(如風扇、燈具、喇叭、相機、工具、廚房家電);
  • 物件實際存在,且能從多個角度拍攝照片;
  • 輸出需為可用於 README、貼文或展示影片的循環拆解片段;
  • 現有照片集需轉變為可編輯、可重新渲染的模型——而非掃描網格。

何時不使用

  • 需要照片級逼真的資產:請改用攝影測量或掃描器;
  • 物件為有機、柔軟或會變形的材質(布料、植物、臉部);
  • 沒有可用照片,或物件只能在影片中看到;
  • 單張靜態圖片就已足夠——則不需要 HyperFrames 的步驟;
  • 主題為文字/UI動畫:此流程專注於幾何形狀。

流程

步驟產出驗收標準
1. 測量一個尺規尺寸、比例表、一個 DIM 物件比例在 ≥2 張照片上交叉比對,每個假設標記為推測
2. 建模程式碼建立的 Three.js 場景、一個 IIFE 套件、檢視器頁面組合狀態無縫隙;p = 1 時每個零件分離
3. 驗證六張相同姿勢的照片/渲染比對圖所有六張圖的輪廓和特徵比例在容許範圍內
4. 影片製作HyperFrames 組合、check 報告、交付 MP4ok: true,無錯誤,時長等於 data-duration
5. 剪輯循環 GIF起始與結束於穩定姿勢,小於 ~1 MB

單一物件通常需要花費數小時到兩天,大部分時間在步驟 2–3。跳過步驟 3 就是讓一週的建模工作變成按時交付但錯誤的模型。

步驟 1 — 從照片測量

收集六個姿勢(正面、正側面、背面、後3/4側面、頂面、底面),選擇一個大尺寸作為尺規,用徑向掃描測量它,並將所有其他尺寸表示為其比例。根據角度週期數算離散特徵(肋條、葉片、輻條),而非憑肉眼估算。將所有數字保存在一個 DIM 物件中,並用註解標註其來源照片名稱及是測量值還是推測值;絕對的真實世界尺寸是決策,不是測量值。

詳細說明:references/01-modeling.md §0–2。

步驟 2 — 程式碼建模

一個場景模組,具有純狀態 API:create、setView、setExplode、setExplodeMap、setSpin、setHeadTilt、setLift、render、getAnchors、resize、dispose。世界慣例:物件面向 +Z,底部在 y = 0,單位為公尺。將外殼建為 lathe 輪廓,格柵建為扁平帶狀(非圓管),葉片建為參數化曲面,並透過一個函數註冊每個零件,該函數儲存其組合位置、爆炸偏移量和錨點偏移量。零件名稱只定義一次;影片、標籤、錨點和聲音都以此名稱作為索引。

詳細說明:references/01-modeling.md §3–6。

步驟 3 — 與照片驗證

使用 esbuild 建立套件,在無頭 Chrome 中為每個姿勢渲染一幀,並將每個渲染結果與其照片以物件 bounding box 裁切後並排比對。以物件自身 bounding box 的比例來讀取比例和零件位置;不要在複雜背景上對邊緣做圓形擬合——擬合會抓住背景弧線。六個姿勢,每個姿勢迭代數次。

詳細說明:references/03-verify.md。

步驟 4 — 渲染影片

按照 HyperFrames 合約建立組合:一個帶有 data-duration 的根組合元素、一個在 window.__timelines["main"] 註冊的暫停 GSAP 時間軸(僅由 hf-seek 重新繪製 Three.js,不透過 rAF/定時器)、帶有 class="clip"、data-start/data-duration 屬性的媒體、一個音訊混合作為音訊片段、28 px 或更大的文字,以及將大型套件放在 assets/vendor/*.min.js。在製作動畫前先編寫鏡位表;從一個導演腳本驅動相機、爆炸和標籤,以便音訊提示可共用其常數。執行 check,閱讀報告,然後執行 render --quality delivery。

詳細說明:references/02-render.md。

步驟 5 — 剪輯 GIF

挑選一個 3–4 秒的穩定片段(通常是爆炸分解後的停頓),用 gif-master(寬度 480,12 fps,循環)或 ffmpeg 雙通道調色板指令剪輯,然後在發佈前檢查大小、幀數和循環。詳細說明:references/04-gif.md、scripts/make_gif.md。

硬性限制

以下是違反時會破壞流程的規則,非風格偏好。

  1. 合約優先。 物件面向 +Z,底部在 y = 0,單位為公尺,相機 target + dist * (sin(yaw)cos(pitch), sin(pitch), cos(yaw)cos(pitch)),yaw/pitch 以度為單位。每個腳本和影片都共用此慣例。
  2. 純狀態。 場景 API 必須將相同狀態渲染為相同像素。沒有動畫循環、沒有即時時鐘、不依賴 Math.random() 的幀。
  3. 幀 = f(t)。 相機、爆炸、旋轉、標籤、卡片和聲音都是影片時間的函數;別無其他。
  4. 組合合約。 根元素上需有 data-composition-id、data-start、data-duration、data-width、data-height;暫停的時間軸註冊為 window.__timelines["<id>"];在 hf-seek 內部使用 e.detail.time 重新繪製。
  5. 片段。 帶有自身開始和持續時間的媒體(音訊、影片、插入片段)需加上 class="clip"、data-start、data-duration;音訊額外加上 data-track-index。由時間軸驅動的 DOM 動畫不需要片段屬性。
  6. 可讀性。 在 1080p 下,資訊性文字不得小於 28 px(檢查器的字型下限為 28 px,即短邊的 2.6%)。
  7. 外部依賴。 three.js 和 GSAP 作為 .min.js 放置於 assets/vendor/ 下;使用本地字型;渲染期間不得有網路連線。
  8. 腳本通用化。 scripts/ 中不得包含物件名稱、絕對路徑或個人目錄;每個腳本必須能從全新克隆中執行。
  9. 指令驗證。 寫入文件、腳本或影片中的每個指令和參數,必須在鎖定版本下至少執行過一次,才能信任。

參考路由

任務閱讀
測量、比例、lathe 輪廓、格柵/葉片參數、零件、爆炸、錨點references/01-modeling.md
組合合約、導演/分鏡、音訊同步、HyperFrames 指令與輸出references/02-render.md
螢幕截圖循環、比對圖、讀取角度、圓形擬合失敗references/03-verify.md
gif-master 操作卡、致謝、ffmpeg GIF 配方references/04-gif.md
儲存庫、GitHub Release、社群列表 PR、YouTube/Xreferences/05-publish.md
症狀 → 原因 → 解決方案目錄(光照、陰影、肋條、字型、套件、Chrome)references/06-gotchas.md

本技能內建工具:

檔案角色
scripts/view.html單幀檢視器;姿勢和套件來自查詢參數
scripts/verify_sheet.py照片與渲染並排比對圖(--photo --render --out --bbox)
scripts/hf_read_check.py彙總 HyperFrames 檢查報告;--fail-on-error 用於 CI
scripts/make_gif.md瀏覽器/ffmpeg GIF 製作操作卡

最小可執行範例

以下指令從儲存庫根目錄執行,針對 examples/fan/ 中的範例;對於新物件,請替換 src/scene.js、photos/ 和 video/。工作檔案會寫入 %TEMP%,以便保持工作目錄乾淨。保留這些參數——它們是已驗證的參數。在 PowerShell 中執行。

$work = Join-Path $env:TEMP "mbc-verify"; New-Item -ItemType Directory -Force $work | Out-Null

# 1. 打包場景(新物件的範本;需要安裝 `three`)。
#    範例已附上其套件於 examples/fan/video/assets/vendor/fan.bundle.min.js,
#    因此此步驟可跳過。
npx --yes [email protected] src/scene.js --bundle --format=iife --global-name=Scene `
  --minify --target=chrome120 --outfile=dist/scene.bundle.min.js

# 2. 對範例截取一個驗證姿勢(1920x1080,每次執行使用全新設定檔)
$chrome = "C:\Program Files\Google\Chrome\Application\chrome.exe"
$png = Join-Path $work "front.png"
$udd = Join-Path $env:TEMP ("view-" + [guid]::NewGuid().ToString("N"))
& $chrome --headless=new --use-angle=d3d11 --window-size=1920,1080 `
  --hide-scrollbars --virtual-time-budget=12000 `
  --screenshot=$png --user-data-dir=$udd `
  "file:///$(($PWD.Path).Replace('\','/'))/scripts/view.html?bundle=../examples/fan/video/assets/vendor/fan.bundle.min.js&yaw=-10&pitch=12&dist=0.85&ty=0.185&fov=30&noshadow=1"

# 3. 將該渲染結果與相同姿勢的正面照片進行比對
python scripts/verify_sheet.py --photo examples/fan/reference/fan.jpg --render $png `
  --out (Join-Path $work "front-sheet.png") --bbox "130,245,1195,1455"

# 4. 檢查影片是否符合 HyperFrames 合約,然後閱讀報告
Set-Location examples/fan/video
# 需要 assets/audio/mix.wav(Release 資產;請見 examples/fan/README.md)
npx --yes [email protected] check --at 21.15,27.6,35.18
$report = Get-ChildItem .hyperframes/artifacts/checks/*.json |
  Sort-Object LastWriteTime | Select-Object -Last 1
python ../../../scripts/hf_read_check.py $report.FullName --fail-on-error
npx --yes [email protected] snapshot --at 29.6

# 5. 渲染交付主檔
npx --yes [email protected] render --quality delivery
Set-Location ../../..

# 6. 使用 ffmpeg 剪輯 GIF(瀏覽器方法請見:scripts/make_gif.md)
$mp4 = (Get-ChildItem examples/fan/video/renders/*.mp4 | Sort-Object LastWriteTime | Select-Object -Last 1).FullName
ffmpeg -hide_banner -loglevel error -y `
  -ss 29.6 -t 3.8 -i "$mp4" `
  -vf "fps=12,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen=max_colors=128[p];[s1][p]paletteuse=dither=sierra2_4a" `
  -loop 0 (Join-Path $work "teardown.gif")

步驟 3 會印出兩個裁切框;驗證完成的執行會印出 saved ...\front-sheet.png 1112x702 | photo (130, 245, 1195, 1455) | render (652, 264, 1252, 1080)。

預期輸出:check 會寫入 video/.hyperframes/artifacts/checks/<uuid>.json;snapshot 會寫入 video/.hyperframes/artifacts/snapshots/<uuid>/frame-00-at-29.6s.png;render 會寫入 video/renders/video_<YYYY-MM-DD>_<HH-MM-SS>.mp4(對於 43.5 秒、1920×1080/30 fps 的影片約 36 MB,使用硬體 GPU 時約需 2.5 分鐘的捕捉時間)。

需求

  • Node.js(已測試 22.19.0)搭配 npx;esbuild 0.24.2 透過 npx 安裝。
  • Python 3.11(已測試 3.11.1)搭配 Pillow 處理比對圖;numpy 為選用。
  • ffmpeg 需在 PATH 環境變數中(已測試 2025-12-28 git 版本)。
  • 用於無頭螢幕截圖的 Chrome(已測試 157.0.8103.40);上述路徑為 Windows 預設。
  • HyperFrames 鎖定為 0.9.36,透過 npx --yes [email protected] 使用。
  • check 和 render 會自動以 --browser-gpu 驅動無頭 Chrome:有硬體 GPU 時使用硬體,否則使用軟體(SwiftShader);preview 在有 GPU 時更流暢。

完成標準

  • 六張比對圖閱讀可接受,並列出與說明偏差;
  • hf_read_check.py --fail-on-error 在最終檢查報告上退出碼為 0;
  • 交付 MP4 存在,且其時長等於組合的 data-duration;
  • GIF 循環乾淨且大小適合發佈;
  • 本技能中的每個指令曾在全新克隆中執行過一次。

相關技能