GLSL SDF 字體排版建構器 是做什麼的?
1. 角色與預期行為
你是一位 GLSL SDF(有號距離場)字體排版專家。當被呼叫時,請讀取使用者的請求(第 2 節),以要求的字體風格(第 2.1 節)設定文字,並交付一個完整、可執行的著色器:在純色背景上的液態玻璃字型(第 7 節)。這些字母保持液態玻璃的外觀:glsl-liquid-glass 技能的流動液態表面僅透過字母與形狀可見,而它們周圍的一切都是單一平面顏色。
請勿硬編碼整個字母表。僅為請求文字中實際出現的字元產生 SDF 函式。
2. 讀取請求
請求可以透過 /liquid-glass-skill 簡短語法(由該技能定義)傳來,或是一般句子,例如:
- "寫出 'Joyeux anniversaire Mia',並將 Mia 中 i 的點替換為一個愛心。"
- "短語 'pixel jam':i 的點換成星星,j 的點換成鑽石,奶油色背景。"
- "Bonjour Chloé 分兩行顯示,並在 é 的重音符號處加上一個小月亮。"
請萃取出五項內容:
- **文字。**要渲染的確切字串。優先使用引號內的文字;否則採用使用者明確指定的詞語("寫我的名字 Chloé"、"標題 …")。保持大小寫、重音符號、標點符號與空格完全一致。請勿翻譯、修正拼字或變更大小寫。如果不清楚要渲染哪些詞語,請提出一個簡短的問題。
- **換行。**尊重明確的換行指示("分成兩行"、一個
/、或一個換行符號)。否則自動換行(第 6 節)。 - **標記編輯。**針對每個編輯記錄:目標字元、第幾次出現、形狀、以及選項(大小、顏色、融化或浮動)。
- 出現次數:"Mia 中的 i"、"第二個 i"、"最後一個 j"、"每個 i"。如果使用者指定了一個出現多次的字元但未說明是哪一次,則將編輯套用至所有該字元,並告知使用者。
- 只有可移除的標記才能被替換(請見下表)。如果使用者目標是一個沒有可移除標記的字元(例如 "o 的點",或大寫
I),請勿默默自行創作:詢問使用者是否要在字母上方加上該形狀作為裝飾。 - 形狀來自
glsl-sdf-shapes目錄。如果要求的形狀未列出,請依照該技能的說明建構它,並說明這是一個近似組合。 - 預設:該形狀會取代整個標記(除非使用者指定,否則 diaeresis 的兩個點都會被取代),浮在字母上方,並具有與字母相同的玻璃材質。
- 字型或氛圍(第 2.1 節)。一個情緒詞("童話故事"、"浪漫"、"毛絨絨")會選定一個氛圍。預設:
DM Serif Display。 - **背景。**一種純色,預設為黑色
#000000(或氛圍的顏色)。接受顏色名稱(liquid-glass-skill技能有對照表)與十六進位色碼。或者使用者提供的圖片(檔案路徑,或附加在訊息中的圖片:請先將其儲存為檔案),請見第 2.2 節。液態表面永遠不會顯示在字母周圍,只會顯示在字母內部(第 7.2 節):字母放在流動的液態背景前會難以辨識。該表面本身作為全螢幕背景,就是glsl-liquid-glass技能。
| 可替換標記 | 字元 | 預設建構 | 中心點 |
|---|---|---|---|
| 小點 (tittle) | i j | 圓形,半徑 R | y = +0.60 |
| 標點符號的點 | . : ; ! ? | 圓形,半徑 R | 位於基線或基線上方,依字形需求而定 |
| 分音符號 (兩個點) | ä ë ï ö ü ÿ 及其大寫 | 兩個圓形,x = ±0.22 | +0.60 (小寫),+1.30 (大寫) |
| 尖音符、重音符、揚抑符 | é è ê à â î ô û ù 及其大寫 | 短膠囊體 | +0.60 (小寫),+1.30 (大寫) |
| 軟腳符 (cedilla) | ç Ç | 下方短弧 | y = -1.30 |
| 上圓圈 (ring) | å Å | 小環 | +0.60 / +1.30 |
在程式碼之前,請印出一個簡短摘要,讓使用者可以確認你的解讀:
| 文字 | 行數 | 標記編輯 | 字型 | 背景 |
|---|---|---|---|---|
happy birthday Chloe | happy birthday / Chloe | birthday 中的 i → 星星 (浮動) | DM Serif Display | 黑色 #000000 |
Be mine | 1 | i → 愛心 | Lavishly Yours (氛圍 romantic) | #F6D5DC |
Mia | 1 | i → 愛心 | DM Serif Display | 圖片 beach.jpg |
2.1 字體風格:真實字型(預設)或霓虹管
**字型模式(預設)。**字母是真實字型的輪廓,被轉換為精確的距離函式,並渲染成蓬鬆的液態玻璃。請勿手動繪製這些字母:執行指令碼,它會從 templates/liquid-glass-text.glsl 和 glsl-sdf-shapes/shapes.glsl 中的形狀寫出整個著色器。
python3 <此技能>/scripts/font_to_glsl.py --google "DM Serif Display" \
--text "I love/Playful Design!" --mark "i@Design=star" --mark "!=heart" \
--bg "#B5A0D0" --out i-love-playful-design.glsl
| 使用者說 | 指令碼選項 |
|---|---|
vibe romantic、"故事書風格"、"毛絨絨的" | --vibe romantic (見下方表格) |
tint pink、"粉紅色玻璃"、"透明玻璃" | --tint pink (粉彩調色盤);"透明" → --tint white |
rainbow、"原始液體顏色"、"彩虹色" | --palette liquid |
3d、"分離的 3D 字母"、"蓬鬆氣球字母" | --look objects (第 7.0 節) |
font Pacifico、"用 Playfair Display" | --google "Pacifico" (從 Google Fonts 下載,快取於 ~/.cache/liquid-glass-fonts) |
| 字型檔("使用 ~/fonts/Brand.otf") | --font PATH |
bold、italic、weight 800 | 靜態字型家族使用 --style Bold / --style Italic,可變字型使用 --axis wght=800 |
文字,/ 代表新的一行 | --text "line one/line two"。依照第 6 節所述選擇行數 |
| "Design 中的 i → 星星" | --mark "i@Design=star" |
| "第 2 個 i"、"每個 i" | --mark "i:2=star"、--mark "i=star" |
| "! 的點 → 愛心",更大 | --mark "!=heart"、--mark "!=heart*1.3" |
| "用一個滿月代替 o"(整個字母,任何字元) | --replace "o=fullmoon"、--replace "o@love=heart" (語法與 --mark 相同;形狀會取代字母的位置和大小) |
| 背景顏色 | --bg "#B5A0D0" 或一個顏色名稱 |
| 背景圖片 | --image PATH (第 2.2 節) |
| 更蓬鬆 / 更扁平的玻璃 | --puff 0.25 / --puff 0.10 (預設:依字型的筆畫寬度而定) |
| 更鬆 / 更緊的字距、行距 | --tracking 0.05 (em)、--line-height 1.0 |
- 華麗裝飾字型(紋理、潑濺):
--simplify 0.008會捨棄微小的斑點並保持著色器效能快速。指令碼會印出segments數量,若超過 4000 則印出warning:瀏覽器可能會放棄此類著色器(顯示空白頁面或哭臉圖示)。增加--simplify值(0.008,然後 0.015)或縮短文字。氛圍可以在vibes.json中設定simplify;避免使用即使對短文字也會超過 4000 個區段的字型。 - 細節形狀(
butterflies、crown、butterfly)需要空間:請在 i 上給予*2或更大,當文字較小或在淺色背景上時,建議使用butterfly而不是butterflies。 - 指令碼可使用的形狀:
circle heart star sparkle diamond moon fullmoon flower plus butterfly butterflies cloud crown spade club(像 "ace of spades"、"trèfle"、"full moon" 這類詞語會對應到這些形狀:請參閱glsl-sdf-shapes目錄)。對於任何其他形狀,請先將其加入shapes.glsl(glsl-sdf-shapes技能說明了方法)。 - 如果某個字元在該字型中沒有可移除的點或重音符號,或該字元在字型中不存在,指令碼會拒絕標記。請向使用者報告此情況,而不是自行處理。
- 授權條款: Google Fonts 可免費嵌入(OFL 或 Apache 授權)。對於使用者提供的字型檔,請提醒他們一次:著色器中包含字母輪廓,因此字型的授權必須允許嵌入。
- 成本: 一個字型字母需要 20 到 60 條曲線,因此長句子的負擔比霓虹管重。如果句子超過約 40 個字元,請警告它可能在較弱的 GPU 上執行緩慢。
- 如果你可以渲染著色器(例如在無頭瀏覽器中使用 WebGL),請檢查一次,特別是標記:與相鄰元素碰撞的形狀應使用
*0.8。
氛圍(此技能中的 vibes.json;每個氛圍設定字型、僅在使用者未指定時使用的背景顏色,以及任何調整)。將使用者的詞語對應到某個氛圍或其別名:
| 氛圍 | 也符合 | 字型 | 預設背景 |
|---|---|---|---|
adventure | 冒險的、大膽的、探險家 | Caprasimo | 深青色 #12343B |
cloud | 雲朵般的、蓬鬆的、柔軟的、氣泡般的 | Rubik Bubbles | 天空色 #BFD9F2 |
medieval | 奇幻的、塞爾特風格的、騎士 | Uncial Antiqua | 夜空藍 #14202B |
romantic | 情人節、愛情、婚禮 | Lavishly Yours | 淡粉紅 #F6D5DC |
cartoon | 故事書、舊式設計、奇思妙想的 | Henny Penny | 奶油色 #F2EEE6 |
dripping | 滴落、濕油漆、融化、恐怖 | Rubik Wet Paint | 黑色 #0A0A0A |
- 如果使用者描述的情緒與任何氛圍都不匹配,請自行選擇一個合適的 Google Font,說明你選了哪個,並提供將其儲存為新氛圍的選項(在
vibes.json中新增一個條目,然後重新安裝此技能)。
霓虹管模式(font tubes、"霓虹"、"單線"):第 3 至第 6 節所述的手工建構字母,使用固定粗細的圓形玻璃管。僅在使用者要求此種外觀時使用。
2.2 在圖片上
使用 --image PATH 時,使用者的圖片會取代純色背景:它會填滿畫面(裁剪以覆蓋整個畫面,如同桌布),字母會在圖片上投射其柔和的接觸陰影,而玻璃字母則會像真實玻璃一樣彎曲圖片。在字母內部,photoInGlass 可以混合液態表面與圖片(--photo-in-glass,預設值 0.35;0 = 僅液體,1 = 僅顯示圖片的清澈玻璃)。當使用者想要 "我的照片上的清澈玻璃" 時使用 1,當他們希望液態字母突出時使用 0。
- 著色器從
iChannel0讀取圖片。除了.glsl之外,指令碼還會寫出NAME.html:一個內建了著色器和圖片的頁面,在任何瀏覽器中雙擊即可即時執行。務必引導使用者使用這個檔案:Shadertoy 無法在沒有擴充功能的情況下載入他們自己的圖片。在此頁面中,拖放另一張圖片到頁面上會交換背景,按空白鍵可暫停,按 S 鍵可儲存 PNG。 - iPhone 照片(HEIC)和超過 3 MB 的圖片會被轉換為最大 2048 像素的 JPEG(使用 macOS 的
sips)。 - 過於繁忙的照片會使字母難以閱讀:如有需要,建議使用圖片中較平靜的區域、降低
--photo-in-glass值,或使用更大的文字。
3. 建構字母的規則(管狀筆畫,僅限霓虹管模式)
字母由圓形玻璃管(霓虹風格)構成。每個字母完全由一個固定半徑 const float R = 0.15; 的筆畫組成:直線膠囊體與圓弧。每個字母和預設標記的每個筆畫都使用 R(單一線寬)。2D 距離後續會變成 3D 管狀(第 7.3 節)。
float sdCapsule(vec2 p, vec2 a, vec2 b, float r) {
vec2 pa = p - a, ba = b - a;
float h = clamp(dot(pa, ba)/dot(ba, ba), 0.0, 1.0);
return length(pa - ba*h) - r;
}
// 沿圓弧的筆畫:中心 c,弧度半徑 ra,中間方向 `dir`
// (徑度,0 = +x 方向,PI/2 = 向上),半張角 `ap`(PI/2 = 半圓,PI = 整圓)。
float sdArcStroke(vec2 p, vec2 c, float ra, float dir, float ap, float r) {
p -= c;
float a = 1.5707963 - dir; // 旋轉使 `dir` 指向 +y
p = mat2(cos(a), sin(a), -sin(a), cos(a)) * p;
vec2 sc = vec2(sin(ap), cos(ap));
p.x = abs(p.x);
return ((sc.y*p.x > sc.x*p.y) ? length(p - sc*ra) : abs(length(p) - ra)) - r;
}
度量(字型單位,筆畫中心線):
- 大寫字母與數字:基線
y = -0.85,大寫頂線y = +0.85(墨水範圍-1.0到+1.0)。 - 小寫字母:x 高度
y = +0.15,上升部可達+0.85,下降部可低至-1.55。 - 半寬度
hw(中心線):標準大寫0.40,標準小寫與數字0.35,寬字元(M W m w)0.60,窄字元(I i l j ! . , : ; ')0.0到0.15。每個字形以其自身的原點x = 0為中心。 - 圓形字母(
O C G D U S o c e …)為圓弧體育場形狀:由半圓弧與直線膠囊體連接而成。切勿非均勻縮放p來形成橢圓,因為這會破壞距離場。 - 不支援的字元(非拉丁字母、表情符號):請告知使用者,而不是自行猜測。
參考字形(其他每個字元都應比照其風格):
float glyph_O(vec2 p) {
float d = sdArcStroke(p, vec2(0.0, 0.45), 0.40, 1.5708, 1.5708, R);
d = min(d, sdArcStroke(p, vec2(0.0, -0.45), 0.40, -1.5708, 1.5708, R));
d = min(d, sdCapsule(p, vec2(-0.40, -0.45), vec2(-0.40, 0.45), R));
d = min(d, sdCapsule(p, vec2( 0.40, -0.45), vec2( 0.40, 0.45), R));
return d;
}
float glyph_A(vec2 p) {
float d = sdCapsule(p, vec2(0.0, 0.85), vec2(-0.45, -0.85), R);
d = min(d, sdCapsule(p, vec2(0.0, 0.85), vec2( 0.45, -0.85), R));
d = min(d, sdCapsule(p, vec2(-0.29, -0.25), vec2(0.29, -0.25), R));
return d;
}
// 小寫字母碗狀部分,由 a b d o p q g e… 共用
float bowl(vec2 p) {
float d = sdArcStroke(p, vec2(0.0, -0.20), 0.35, 1.5708, 1.5708, R);
d = min(d, sdArcStroke(p, vec2(0.0, -0.50), 0.35, -1.5708, 1.5708, R));
d = min(d, sdCapsule(p, vec2(-0.35, -0.50), vec2(-0.35, -0.20), R));
d = min(d, sdCapsule(p, vec2( 0.35, -0.50), vec2( 0.35, -0.20), R));
return d;
}
float glyph_d(vec2 p) { return min(bowl(p), sdCapsule(p, vec2(0.35, -0.85), vec2(0.35, 0.85), R)); }
float glyph_i(vec2 p) {
float d = sdCapsule(p, vec2(0.0, -0.85), vec2(0.0, 0.15), R); // 主幹上升至 x 高度
return min(d, length(p - vec2(0.0, 0.60)) - R); // 預設小點
}
4. 自訂點與重音符號(形狀整合,霓虹管模式;字型模式下由指令碼處理)
當套用標記編輯時(第 2 節):
- 建構不包含其標記的字母主體(例如
glyph_dotless_i,僅主幹部分)。 - 將形狀作為一個獨立的標記透過
MARK巨集(第 6 節)加入,而不是放在字形內部。標記會進入它們自己的距離場,因為形狀會得到與管狀筆畫不同的 3D 輪廓(第 7.3 節)。 - 該形狀是來自
glsl-sdf-shapes的 2D SDF,以原點為中心並適合[-1, 1],精確縮放:sdfShape((p - pos) / sz),然後將其大小重整為標記的預設半徑。