Doodle
一個以代碼繪製的插圖系統。主題以幾何圖形撰寫,透過相機投影,並由一個帶有種子的「手」渲染,使其看起來像手繪。純 HTML + JS,無需建置,無依賴項:在瀏覽器中開啟一個頁面即可。
設定:你的工作區
引擎位於此技能目錄下的 engine/(與此檔案相鄰)。切勿在此處編輯它;技能更新時會被覆寫。
- 如果此檔案旁存在
LOCAL.md,請先閱讀它:它會指定此機器的 工作區和工具,並覆蓋下面的預設值。 - 否則,工作區是當前專案中的
./.doodle(隱藏)。如果它 不存在,請建立它:cp -R "<此技能資料夾>/engine" ./.doodle。 - 下面的每個路徑(
src/…,bin/…)都是相對於工作區的。渲染 需要 Chrome 或 Chromium(覆蓋用CHROME=/path)和 python3;其他不需要。
一個繪圖 = bin/new.sh <name>,這會建立 drawings/<name>.js(在 draw(S) 中繪製,完整工具包,自動加框)和渲染它的頁面。一張圖片中的多個東西是一個繪圖;多張獨立的圖片是幾個不同的名稱。
範例是代碼,不是頁面。 src/ 中的模組(things.js,
people.js,trials.js,scapes.js …)包含已處理好的主題:閱讀它們並複製它們的建構方式到你的繪圖中;切勿新增或編輯它們。下面的路由表指定了從哪個模組開始。
交付圖片,不是頁面。 當繪圖準備好時,執行 bin/render.sh <name>:它會將 doodles/<name>/<name>.png(彩色)和 <name>-line.png(僅線條)寫入專案中,並為使用者開啟該資料夾。告訴他們資料夾路徑。除非使用者要求,否則不要建置、開啟或指向 HTML 頁面、畫布或控制面板。
此檔案為完整合約,為了讓它能夠完整載入,所以刻意簡潔。 詳細資訊存在 references/ 中(直接移至該處,未遺漏任何內容)。下面的路由表說明了該任務需要閱讀哪個參考資料。閱讀它是任務的一部分,而非可選項:這些檔案中的每一條規則都是透過被拒絕的繪圖換來的經驗。
每次的步驟
- 命名形式(FORM)和類別(CLASS)(見下方表格)。形式決定頁面、 框架和細節預算;類別決定筆、筆尖、填充和色調。
- 路由。閱讀路由表為你的主題指定的參考檔案,並以其命名的模組作為起點。 如果已存在該主題的工具包,切勿從空白檔案開始。
- 繪製前先測量。從參考圖像:比例和
調色盤,需探測,而非回想。若無參考圖像:將主題的
比例寫成數字放在模組標題中(鞋子需要八個
數字;在沒有它們的情況下渲染三次都失敗)。
references/hand-and-craft.md第 § 測量章節。 - 先建構線條。 在彩色前先判斷
?outline=1。每個數值 都承載兩次:一次作為填充,一次在線條中。細節從焦點到中景再到紙面逐漸減少。references/line-first.md。 - 渲染並觀察,線條和彩色都要,以最終尺寸進行。 用小樣圖檢查構圖, 用大單幀檢查線條品質。每次迭代都做這兩件事。
- 當問題出在輔助工具時,修正工具包,而非主題。 持續迭代直到每個主題都正常為止。
bin/check.sh drawings/<name>.html(無引數 = 所有繪圖):它會進行渲染,無 NaN,無控制檯錯誤,無類別漂移。- 交付:
bin/render.sh <name>— PNG 檔案在doodles/<name>/中,資料夾會被打開。 - 在同一次執行中將學到的東西歸納到此技能中(§ 進化章節)。
路由:要讀什麼,從哪裡開始
| 主題 | 從哪裡開始 | 閱讀 |
|---|---|---|
| 任何塗鴉,同階段首次 | 無 | references/line-first.md,references/forms-and-classes.md |
| 日常物品(手機、鑰匙、瓶子、布料、眼鏡……) | src/things.js(最接近的 20 個;cam,S.prism,S.on,S.dash) | things.md |
| 產品、裝置、小工具、電器 | src/retro.js(Retro._kit) | products.md,geometry.md |
| 圓形物體(杯子、花瓶、水果、瓶子) | src/stilllife.js 舞台(lathe,ball)或 src/still.js | still-life.md,geometry.md(路徑建構) |
| 靜物 / 佈置 / 來自照片 | src/stilllife.js | still-life.md |
| 傢俱 | src/furniture3.js,src/kitchen.js | products.md |
| 日常物品(筆電、剪刀、眼鏡、牙刷、吹風機、T恤、肥皂、筆記本、掛鎖、泰迪熊、衣架、背包、瓶子……) | src/things.js def(...) | products.md,geometry.md |
| 人物,人們,場景中的任何人 | src/people.js People.figure;切勿使用 Trials._figure(已棄用) | people.md |
| 動物 | src/trials.js(cat) | figures-and-trials.md |
| 玻璃、液體、透明 | src/trials.js(glass) | figures-and-trials.md |
| 自行車、框架、任何細管狀物體 | src/trials.js(bicycle),S.limb | figures-and-trials.md |
| 鞋子、衣物、布料 | src/trials.js(sneaker,fruit 布料) | figures-and-trials.md |
| 植物、花朵、葉子 | src/plants3.js,src/flowers.js;有洞的葉子:trials.js monstera | plants.md,figures-and-trials.md |
| 建築物、房屋、立面 | src/houses.js,src/arch.js,src/arch2.js | architecture.md,geometry.md |
| 風景、戶外景色 | src/scapes.js(場景工具包) | landscapes.md |
| 夜晚、黑暗、天氣、雨 | src/trials.js(night,rain)在場景工具包上 | figures-and-trials.md,landscapes.md |
| 街道、立體模型、咖啡館 | src/cafe.js,src/scenes.js | landscapes.md,geometry.md |
| 房間 / 內部 | src/kitchen.js,src/deskscene.js | geometry.md,landscapes.md(逼真度) |
| 鋼筆和墨水,無彩色 | src/pen.js | line-first.md(色調),forms-and-classes.md(ink) |
| 故事板 / 序列 | src/board.js | storyboards.md |
| 字體、標誌 | src/letter.js | pages-and-files.md |
| 螢幕、UI、終端機(淺色文字在深色背景上) | src/letter.js + 色調著色的線條 | pages-and-files.md(letter.js 條目) |
| 讓它動起來(Rive) | Rive 匯出工具(未捆綁;請參閱該檔案) | animation.md |
| 觀看它繪製,底稿 | ?draw=<key>,?sketch=1 | hand-and-craft.md |
| 乾淨 / 向量 / 不像塗鴉 | 無 | clean-illustration 技能(如果已安裝) |
| 一個集合(SET),壓力測試 | 以現有集合頁面作為模板 | checking.md |
| 一個必須與渲染對齊的塗鴉(草稿 → 最終擦除) | 描繪剪影,撰寫內部 | registration.md |
| 哪個頁面 / 檔案做什麼 | 無 | references/pages-and-files.md |
所有 references/ 路徑都是相對於此技能資料夾。
形式
| 他們說 | 形式 | 作為起點的範例 | 細節預算 |
|---|---|---|---|
| "幫我畫一個馬克杯 / 一張椅子" | 主體 | src/things.js,src/retro.js | 一切,一個物體以最高逼真度呈現 |
| "幫我做 N 個" | 集合 | 每個項目一個 bin/new.sh 繪圖,每個共用輔助工具 | 一個工具包,細節存在於工具包中 |
| "一棟房子 / 一個店面" | 立面圖 | src/houses.js,src/arch.js | 三個開間,55% 純黑色填充 |
| "一條街道 / 一個景色 / 一個風景" | 場景 | src/scapes.js,指定的框架 + 剪裁 | 三層深度階梯 |
| "整個街區 / 一個小世界" | 立體模型 | src/cafe.js | 街區的邊緣必須保持在圖片內 |
| "一個房間" | 室內 | src/kitchen.js,src/deskscene.js | 前景完整,後牆有特徵 |
| "故事板這個" | 板 | src/board.js | 由鏡頭尺寸(SHOT SIZE)決定,而非主題 |
| "鋼筆和墨水 / 無彩色" | 註冊 ink | src/pen.js | 色調由線條承載,完全無填充 |
集合不是場景(同一頁上的多個物體除了紙張外沒有任何共用元素),板也不是集合(相同的逼真度會失去序列感)。判斷標準:這些物體是否必須共用相同的空間?如果是,那就是場景。
類別(src/spec.js;完整文字在 references/forms-and-classes.md)
| 類別 | 筆 | 筆尖 | 適合度 | 填充 | 色調 |
|---|---|---|---|---|---|
object | 0.30 | 硬 | .84/.84 | 平面,按面法線著色 | 陰影是較暗的填充,加上其線條雙胞胎 |
ink | 0.26 | 筆 | .90/.88 | 無,紙張即物體 | 僅線條;禁止使用點陣 |
product | 0.30 | 硬 | .84/.84 | 一種材質 = 一種顏色 | 僅在摺痕 > ~35° 時著色 |
elevation | 0.30 | 硬 | .86/.84 | 55% 純黑色窗格 | 屋頂用影線,陰影側 |
plant | 0.30 | 硬 | .84/.88 | 平面;淺色陰影 .96,其他 .84 | 僅對大面積葉片使用潦草筆觸 |
flower | 0.26 | 硬 | .92/.90 | 平面 | 無 |
scene | 0.30 | 硬 | .96/.94 | 平面;陰影為較暗的填充 | 僅當前方無任何東西時使用影線 |
diorama | 0.22 | 硬 | .94/.92 | 平面 | 無 |
panel | 0.26 | 硬 | .94/.94 | 平面,少於單獨的主題 | 一個值用於地面,一個用於天空 |
furniture,interior | 0.16 / 0.15 | 筆 | — | 舊有權重;新作品使用 object | — |
宣告類別,切勿重新輸入數字: Spec.wrap(cls, label, build)。
bin/check.sh 會審計每個頁面的漂移。一個類別擁有手;一個頁面擁有
紙張。僅在填充或色調策略確實不同時才新增類別。
硬性規則(每一條都代表一個被拒絕的繪圖)
線條優先和逼真度
- 僅線條(
?outline=1)必須是一個完成的繪圖。每個頁面都尊重?outline=1;檢查你複製的頁面(一個寫死的outline: false)。 - 每個數值都承載兩次:深色材質 = 影線;轉折 = 隨表面彎曲的肋條;投影 = 無輪廓線的影線;一個能命名物體的標記 = 有輪廓線的標記,絕不是
w: 0填充。審計每個w: 0。 - 焦點區域有完整細節,中景為輪廓加 2–3 條線,背景是紙張(其唯一的色調是主體投射的陰影)。瞇眼看:如果牆壁和主體一樣繁忙,則刪減牆壁。
- 影線是以線條排隊的(
S.hatch),絕不是k.T色調;後續的填充會將其裁切。gap是數值:2.4 淺色,1.5 中色,1.1 深色。僅對焦點區域中唯一最深的物體使用交叉影線。 - 陰影側是一個月牙形,由隨物體形狀彎曲的曲線界定,絕不是直線的半平面切割(那看起來像一個物體被切成兩半)。
幾何和路徑建構
- 不是你創作的直線是路徑錯誤:將兩個半部以錯誤方向串接而成的弦,或者一個開放的形狀被描邊為
closed。印出點座標。 - 不透明物體上的帶狀物僅是其近半部分;只有張開的嘴巴才是完整的橢圓。
- 孔洞是切割出來的(
keyhole),絕不是用背景色繪製的。孔洞在線條中顯示但在彩色中不顯示 = 其纏繞方向。 - 薄的物體(肢體、管子、莖)是穿過其關節的一條帶狀物;描繪側邊的輪廓線,讓末端插入到後來繪製的物體中。
- 容器:內部 → 遠邊緣 → 內容物 → 前壁。內容物應低於邊緣。
- 在繪製已知物體之前,將比例作為數字進行測量。 拉伸錯誤的形狀只會讓它一直保持錯誤(鞋子)。
- 根據使用傢俱的身體來決定傢俱的大小,反之則不對。
- 必須與圖像對齊的塗鴉:從圖像的 Alpha 通道描繪其剪影,創建內部,將框架固定到圖像,並在匯出時裁剪掉類別的適合度(
registration.md)。 - 人物:僅使用
People.figure。 先做姿勢再處理細節(重心在一條腿上,臀部和肩膀向相反方向傾斜);姿勢是角度,因此比例是固定的;傢俱和手中握持的物品是從返回的關節點推導出來的。後面的頭髮在身體之前繪製。 - 穿過柔軟形狀的長直虛線 = 月牙環繞錯誤(已在
S.soft中修復);波浪狀車床 = 節點少 + 每段緩動:使用密集的剖面加上steps: 1。 { dash: true }不起作用:請使用S.dash。將框架物件對齊到其內容的邊界框,而不是用肉眼判斷。- "雜亂" = 建構,而不是細節:以全尺寸判斷一個主題;輪廓線必須相接(關節處不能有開放的端點),色調要緊湊且有規律或不存在,筆觸粗細要符合形狀的寬度。
取景
- 框架是推導出來的,絕不是手動輸入的:在圖像平面工具包中,它是第一個區域的邊界,因此第一個呼叫是
S.panel(<the frame>);使用相機時,從投影推導。有東西看不見?在將它畫得更大之前,檢查它是否在框架內。clip = true會裁剪到指定的框架。 - 每個地面圖層都要延伸到框架底部(
FOOT),否則天空會出現在較近圖層下凹的地方。一個地面規則應到達紙張的兩邊緣,而不是超過它們。
場景、夜晚、天氣
- 深度是一個數字
d(0 近,1 遠),筆觸、影線間距、顏色和細節都讀取它。山脈和長凳有相同的權重是平坦景觀的失敗。 - 夜晚反轉數值:天空是最密集的影線,每個燈光都是一個挖鑿的間隙;發光體比天空更亮。逆光中的人物是影線剪影。
- 雨是最後繪製的,雨傘下沒有雨;倒影是主體上下翻轉、壓扁、斷斷續續的帶狀,沒有輪廓線。
頁面和調色盤
- 頁面必須宣告其主體使用的每個調色盤鍵;未知的鍵會默默地渲染為黑色。
- 並行執行無頭 Chrome 時,每個都需要單獨的
--user-data-dir,否則截圖會是空白的。
驗證
cd <workspace> # 參閱設定
bin/check.sh drawings/<name>.html # 渲染,無 NaN,無控制檯錯誤,無類別漂移
bin/shot.sh "drawings/<name>.html?outline=1" out.png [1120x700] # 工作檢查;移除 ?outline=1 以獲得彩色
bin/render.sh <name> # 交付:doodles/<name>/*.png,資料夾被打開
Chrome/Chromium 由 bin/chrome.sh 找到(用 CHROME=/path 覆蓋);每次截圖都會獲得自己的 --user-data-dir,因此並行執行是安全的。檢視每個 PNG(開啟它,或者如果你能看到圖像就讀取它)。通過 check.sh 證明它已渲染,而不是證明它運作正常。
進化此技能
當你修復了一個缺口時,將其寫在一個新的階段能夠找到的地方(如果此技能是唯讀安裝的,則將這些筆記保留在工作區中並說明):
- 主題的參考檔案(
references/<topic>.md):規則,附帶其症狀,以指示形式陳述。
…
[為翻譯已截斷]