handdrawn-3d 是做什麼的?
你將主題用幾個簡單的實體建立 3D 模型,然後繪圖工具包會用手繪風格繪製它。面會從左上角光源獲得三種平塗麥克筆色調。相鄰且色調相同的面會融合成一片。輪廓線使用粗重墨水,摺痕則用較細的線條,線條搖擺且漸細,畫在奶油色紙張上。場景會隨著 t 循環一圈逐幀繪製。輸出結果是循環動畫 SVG:幀之間透過 CSS 切換,無需腳本,因此可在瀏覽器和 <img> 標籤中播放。文字使用內建的手繪字體,完整支援越南文。
工具包:assets/kit.js · 渲染器:assets/render.mjs · 所有函數與選項:references/kit.md(在編寫場景前務必閱讀) · 工作範例:examples/(杯子、茶壺、烤麵包機、風車:閱讀最接近的範例)。
設定(一次性)
PNG/GIF 匯出需要 @resvg/resvg-js。如果 render.mjs 提示缺少該套件,請在此技能的資料夾中執行 npm install。SVG 本身不需要任何東西。
繪製前
- 是否可以繪製? 如果主題是抽象的(例如「希望」、「生產力」),不要描繪模糊的東西。建議一兩個能表現該主題的具體場景,然後繪製使用者選擇的那個。
- 圖表、圖表、UI、按鈕、互動事物: 不屬於此技能範圍。
- 什麼在動? 每張圖片都動畫化物體本身:攝影機從不移動。選擇一個或兩個屬於該主題的動作。水壺蓋會晃動並冒蒸氣。吐司會彈出。風車的扇葉會轉動。風扇會旋轉。貓的尾巴會甩動。檯燈會點頭。植物會搖擺。如果使用者指定了某個動作,就使用那個。如果沒有東西可以合理地移動,就使用蒸氣、輕微的上下搖動或擺動,以及線條本身的沸騰效果。
工作流程
- 零件。 列出主題的真實零件,以及每個零件如何由實體構成。在場景頂部的註解中以表格形式寫下:零件 · 呼叫方式 · 尺寸/位置 · 顏色。根據真實零件(邊緣、蓋子、旋鈕、把手、腳、插槽、鉸鏈)進行建模,而不是使用一個帶有名稱的整體。查找你不確定的比例。
- 建立模型 在
scene.js中(世界座標:x 向右,y 向後,z 向上,地面 z = 0;單位近似毫米;構圖自動):- 可以在車床上車製的圓形物體 →
k.lathe(容器使用wall:)、k.cylinder、k.sphere - 盒狀物體 →
k.box(round:用於柔化家電邊角)、不規則輪廓 →k.extrude - 把手、壺嘴、管子、腿、纜線、莖 →
k.tube,從主體內部開始(它會在表面被裁切) - 容器的內容物 →
{ in: container };平面上的平面標記 →k.panel/k.line搭配{ on: solid } - 當主題的「側面」應該面向觀看者時(例如茶壺的壺嘴在左側,把手在右側),使用
k.group({ rotate: { z: 45 } }, …)旋轉整個主題
- 可以在車床上車製的圓形物體 →
- 動畫 使用
t∈ [0, 1):移動的零件放在k.group({ about, rotate, at }, …)中,並由k.wave()、k.pulse()或360 * t驅動。每個動作都必須在t = 1時回到起始位置。 - 渲染並查看:
使用「讀取」工具開啟node <skill>/assets/render.mjs scene.js -o out/scene.svg --png out/scene.png --strip --thumbout/scene.png(靜止圖)以及out/scene-frames.png(循環中的 6 幀),然後仔細查看它們。加上--grid可讀取工作表座標。檢查out/scene-128.png:在 128 像素的尺寸下,它仍然必須能被識別為該主題。 - 修正並重新渲染。 檢查:
- 一眼看去是否能識別出主題?首先是輪廓。
- 沒有畫錯順序: 零件穿透主體、遠方零件蓋住近處零件、內容物被隱藏或穿出。使用
references/kit.md中「實體排序方式」的規則修正:分離實體、in:、on:、只建模從開口突出的部分,並將layer作為最後手段。 - 零件與其支撐物接觸。除非應該如此(例如跳動的蓋子),否則不應懸空。
- 動作在幀條中能讀懂,並且循環時沒有跳躍。
- 標籤位於邊緣,並且不能過度跨越圖畫。
重複步驟 4–5,直到正確為止(通常需要 2–4 輪)。最終渲染時不要加上
--grid。
在未查看靜止圖與幀條之前,絕對不能交付。 交付 SVG 路徑(動畫圖片)以及 PNG,並顯示 PNG。當使用者想要 GIF,或者 SVG 必須用於無法播放 SVG 動畫的地方(聊天應用程式、某些電子郵件用戶端)時,請加上 --gif out/scene.gif。
樣式規則
- 統一風格: 墨水 + 紙張上的平塗麥克筆色調。無漸層、發光、模糊、透明度技巧、SVG
<text>或原始 SVG。僅使用此工具包。 - 顏色: 調色盤名稱(參見
references/kit.md),每張圖片使用 3–5 種顏色加上墨水色。調色盤名稱效果最佳;任何十六進位顏色都會被柔化。每個填充會自動產生亮、中、暗色調。不要使用額外的實體來偽造陰影。 - 攝影機: 預設為等角投影。僅在有充分理由時才更改
sheet.camera。對於高大的物體(塔、瓶子、燈、人),較低的俯仰角(20–25)和 25–35 的偏航角可以營造更友善的「產品拍攝」效果。 - 簡單且厚實: 幾個乾淨的實體比許多細碎的實體更容易閱讀。小零件(旋鈕、腳、按鈕)是讓它看起來真實的關鍵:務必添加。
- 接地: 陰影是自動的。站立在板子、桌子或茶碟上的物體會在其上投射陰影。在小物體下方放置板子、托盤、土堆或桌子,有助於它在空間中定位。
- 文字: 可選的左上角
k.title(...),以及指向 3D 點的簡短小寫邊緣註釋(k.label)。使用使用者的語言書寫。圖畫上不要有方框或對話泡泡。 - 畫布: 預設為 1000×1000。對於寬場景,使用
export const sheet = { width: 1200, height: 900 }。--transparent會移除紙張背景。 - 動畫大小: 預設為 16 幀,12 fps(一個 1.3 秒的循環);典型的 SVG 大小為 0.5–1 MB。對於慢動作,使用
sheet.fps = 8。保持frames≤ 24。
場景範本
// 一個放在隔熱墊上的茶壺;蓋子在晃動。
// part call size / where colour
// 隔熱墊 cylinder r 120, h 10 wood
// 壺身 lathe { smooth } r 55→94→50, h 118, on the trivet teal
// 壺嘴 tube [14, 7] from inside the body, out to the left teal
// 把手 tube 8 both ends inside the body, right side teal
// 蓋子+鈕 lathe + sphere 在一個以其後緣為鉸鏈的群組中 teal, ochre
export const sheet = { seed: 3 };
export function draw(k, t = 0) {
k.cylinder([0, 0, 0], 120, 10, { fill: 'wood' });
k.group({ rotate: { z: 45 } }, () => { // 壺嘴在螢幕左側,把手在螢幕右側
k.lathe([0, 0, 10], [[55, 0], [78, 10], [94, 45], [90, 85], [68, 112], [50, 118]], { fill: 'teal', smooth: true });
k.tube([[-78, 0, 50], [-112, 0, 66], [-128, 0, 100], [-146, 0, 118]], [14, 7], { fill: 'teal' });
k.tube([[70, 0, 112], [112, 0, 108], [122, 0, 72], [84, 0, 40]], 8, { fill: 'teal' });
const hop = Math.max(0, k.wave(0, 2 * t)); // 0..1,每個循環跳兩次
k.group({ about: [44, 0, 128], rotate: { y: -18 * hop }, at: [0, 0, 16 * hop] }, () => {
k.lathe([0, 0, 127], [[52, 0], [50, 5], [30, 13], [8, 18], [0, 19]], { fill: 'teal', smooth: true });
k.sphere([0, 0, 152], 10, { fill: 'ochre' });
});
k.steam([-150, 0, 125], { h: 90, n: 2, spread: 18 });
});
k.label('rattling lid', { to: [0, 0, 140], side: 'right' });
}