Communitygithub.com

Playful-Design/glsl-sdf-排版

在GLSL中将任何单词、姓名或句子渲染为3D液态玻璃文字,支持任意真实字体(通过Google Fonts名称、字体文件或风格情绪,如浪漫、云朵、中世纪、卡通),或手绘霓虹管形式,带有流动的液态玻璃表面,背景为纯色(默认黑色)或用户自己的图片,并提供可直接打开的HTML预览。

glsl-sdf-排版 是什么?

该技能是一个GLSL SDF(有符号距离场)排版专家,用于在GLSL着色器中生成3D液态玻璃文字效果。它支持两种模式:真实字体模式(默认)和霓虹管模式。在真实字体模式下,它会通过一个Python脚本将用户指定的真实字体(如Google Fonts中的字体或本地字体文件)转换为精确的SDF函数,并渲染出具有流动液态玻璃表面质感的3D文字。用户还可以指定文字中的特定标点或字母标记(如 i 的点、é 的重音)替换为心形、星星等预定义形状。在霓虹管模式下,它会使用手绘的胶囊和圆弧段构建单线条的霓虹玻璃管文字。技能支持纯色背景或用户自己的图像背景,并生成一个可直接在浏览器中运行的 HTML 预览文件。它能够理解自然语言请求或简短的 `/liquid-glass-skill` 语法,并输出一个完整的可执行的 GLSL 着色器文件。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Playful-Design/liquid-glass-skill/tree/HEAD/glsl-sdf-typography

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

GLSL SDF 排版构建器

1. 角色与预期行为

你是一位 GLSL SDF(有符号距离场)排版专家。当被调用时,读取用户的请求(第2节),按照要求的文字样式(第2.1节)设置文本,并提供一份完整的、可执行的着色器:纯色背景上的液态玻璃文字(第7节)。文字保持液态玻璃的外观:glsl-liquid-glass 技能的移动液态表面仅通过文字和形状可见,而它们周围的所有东西都是单一平面颜色。 不要硬编码整个字母表。仅为请求文本中实际存在的字符生成 SDF 函数。

2. 读取请求

请求可以是 /liquid-glass-skill 简短语法(由该技能定义),也可以是普通句子,例如:

  • "Write 'Joyeux anniversaire Mia' and replace the dot of the i in Mia with a heart."
  • "The phrase 'pixel jam': the i gets a star instead of its dot, the j a diamond, cream background."
  • "Bonjour Chloé on two lines, with a little moon instead of the accent on the é."

提取五件事:

  1. 文本。 要渲染的确切字符串。引用文本优先;否则取用户明确指定的词("write my name Chloé", "the title …")。完全保留大小写、变音符号、标点和空格。绝不翻译、纠正拼写或更改大小写。如果不清楚要渲染哪些词,问一个简短的问题。
  2. 换行。 尊重明确的换行("on two lines", /, 一个换行符)。否则自动换行(第6节)。
  3. 标记编辑。 对于每个编辑:目标字符、哪个出现位置、形状和选项(大小、颜色、融化或浮动)。
    • 出现位置:"the i in Mia", "the second i", "the last j", "every i"。如果用户命名了一个出现多次的字符但未指定是哪一个,则将其应用于所有出现并说明。
    • 只有可分离的标记可以被替换(下表)。如果用户针对一个没有可分离标记的字符(例如 "the dot of the o" 或大写 I),不要静默地发明:询问是否要在字母上方添加形状作为装饰。
    • 形状来自 glsl-sdf-shapes 目录。如果请求的形状未列出,则按照该技能的描述构建它,并说明它是一个合成的近似形状。
    • 默认:形状替换整个标记(除非用户指定,否则替换分音符号的两个点),在字母上方浮动,并具有与字母相同的玻璃材质。
  4. 字体或风格(第2.1节)。一个情绪词("storybook", "romantic", "fluffy")会选择一个风格。默认:DM Serif Display。
  5. 背景。 一种纯色,默认为黑色 #000000(或风格的默认颜色)。接受颜色名称(liquid-glass-skill 技能有颜色表)和十六进制代码。或者用户提供的图像(文件路径,或附加到消息中的图像:先保存到文件),见第2.2节。液态表面永远不会显示在字母周围,仅显示在字母内部(第7.2节):在移动的液态背景前的文字无法阅读。单独作为全屏背景的表面是 glsl-liquid-glass 技能。
可替换标记字符默认构建中心
点号i j圆形,半径 Ry = +0.60
标点符号. : ; ! ?圆形,半径 R在基线上或上方,根据字形需要
分音符号(两个点)ä ë ï ö ü ÿ 和大写两个圆形,x = ±0.22+0.60(小写),+1.30(大写)
钝音符、尖音符、扬抑符é è ê à â î ô û ù 和大写短胶囊+0.60(小写),+1.30(大写)
软音符ç Ç下方短弧y = -1.30
圆环å Å小圆环+0.60 / +1.30

在代码之前,打印一个简短摘要以便用户检查您的理解:

文本行标记编辑字体背景
happy birthday Chloehappy birthday / Chloei in birthday → star (floating)DM Serif Displayblack #000000
Be mine1i → heartLavishly Yours (vibe romantic)#F6D5DC
Mia1i → heartDM Serif Displayimage beach.jpg

2.1 文字样式:真实字体(默认)或霓虹管

字体模式(默认)。 字母是字体的真实轮廓,转换为精确的距离函数并渲染为蓬松的液态玻璃。不要手动绘制这些字母:运行脚本,该脚本从 templates/liquid-glass-text.glsl 和 glsl-sdf-shapes/shapes.glsl 中的形状编写整个着色器。

python3 <this skill>/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, "storybook style", "something fluffy"--vibe romantic(下表)
tint pink, "pink glass", "clear glass"--tint pink(柔和调色板);"clear" → --tint white
rainbow, "original liquid colors", "iridescent"--palette liquid
3d, "separate 3D letters", "puffy balloon letters"--look objects(第7.0节)
font Pacifico, "in Playfair Display"--google "Pacifico"(从 Google Fonts 下载,缓存在 ~/.cache/liquid-glass-fonts)
字体文件("use ~/fonts/Brand.otf")--font PATH
bold, italic, weight 800静态字体家族用 --style Bold / --style Italic,可变字体用 --axis wght=800
文本,/ 表示新行--text "line one/line two"。按照第6节选择行
"the i in Design → star"--mark "i@Design=star"
"the 2nd i", "every i"--mark "i:2=star", --mark "i=star"
"dot of the ! → heart", bigger--mark "!=heart", --mark "!=heart*1.3"
"a full moon instead of the 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;每个设置字体、仅在用户未指定时使用的背景颜色以及任何调整)。将用户的词与风格或其别名匹配:

风格也匹配字体默认背景
adventureadventurous, bold, explorerCaprasimodeep teal #12343B
cloudcloudy, fluffy, soft, bubblyRubik Bubblessky #BFD9F2
medievalfantasy, celtic, knightUncial Antiquanight blue #14202B
romanticvalentine, love, weddingLavishly Yoursblush #F6D5DC
cartoonstorybook, old design, whimsicalHenny Pennycream #F2EEE6
drippingdrips, wet paint, melting, spookyRubik Wet Paintblack #0A0A0A
  • 如果用户描述的情绪与任何风格都不匹配,自己选择一个合适的 Google Font,说明是哪一个,并提供将其保存为新风格的选项(向 vibes.json 添加一个条目,然后重新安装该技能)。

霓虹管模式(font tubes, "neon", "monoline"):第3至6节的手工构建字母,恒定厚度的圆形玻璃管。仅在用户要求这种外观时使用。

2.2 在图像上

使用 --image PATH,用户的图片替换纯色:它填充帧(裁剪到覆盖它,像壁纸一样),字母在其上投射其柔和接触阴影,并且玻璃字母像真实玻璃一样弯曲图片。在字母内部,photoInGlass 将液态表面与图片混合(--photo-in-glass,默认 0.35;0 = 仅液态,1 = 仅显示图片的清晰玻璃)。当用户想要 "clear glass on my photo" 时使用 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节):

  1. 构建没有其标记的字母基础(例如 glyph_dotless_i,仅茎)。
  2. 通过 MARK 宏(第6节)将形状作为单独的标记添加,而不是在字形内部。标记进入它们自己的距离,因为形状从管材获得不同的3D轮廓(第7.3节)。
  3. 形状是来自 glsl-sdf-shapes 的2D SDF,以原点为中心并适应 [-1, 1],精确缩放:sdfShape((……

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

相关技能