基于开源库 @chenglou/pretext(MIT License)构建的精准文本测量与布局引擎。
> GitHub: chenglou/pretext · 42.1K Stars
> 版权声明见本文件末尾 ## 开源许可 章节。
当用户需要以下任何一种计算时,调用此 Skill:
| 用户意图 | Skill 做什么 |
|:---|:---|
| "这段文字在 300px 宽、16px 字体下有多高?" | 精确计算高度 + 行数 |
| "帮我判断这段文字会不会换行" | 返回行数和每行内容 |
| "这 50 条消息列表,每条在 375px 下多高?" | 批量测量所有条目 |
| "计算这段富文本(带 @提及、标签)的高度" | 富文本内联布局 |
| "找出让文本恰好不换行的最小宽度" | 收缩包裹宽度测量 |
| "这段文字在 Canvas 里怎么分行绘制?" | 返回逐行绘制坐标 |
node "${CLAUDE_SKILL_DIR}/scripts/measure.js" \
--text "你好,世界!这是一段测试文本。" \
--font "16px Inter, sans-serif" \
--width 300 \
--lineHeight 20
返回示例:
{
"success": true,
"text": "你好,世界!这是一段测试文本。",
"font": "16px Inter, sans-serif",
"width": 300,
"lineHeight": 20,
"height": 44.8,
"lineCount": 3,
"unit": "px"
}
node "${CLAUDE_SKILL_DIR}/scripts/batch.js" \
--items "第一条消息内容" \
--items "第二条消息内容" \
--items "第三条消息内容" \
--font "14px -apple-system, sans-serif" \
--width 375 \
--lineHeight 20
node "${CLAUDE_SKILL_DIR}/scripts/layout-lines.js" \
--text "Hello 世界 🚀" \
--font "18px Inter" \
--width 320 \
--lineHeight 26
node "${CLAUDE_SKILL_DIR}/scripts/line-stats.js" \
--text "多行文本内容,每行长度不一" \
--font "16px Inter" \
--width 200
node "${CLAUDE_SKILL_DIR}/scripts/rich-inline.js" \
--items '[{"text":"普通文字 ","font":"16px Inter"},{"text":"@用户名","font":"bold 14px Inter","break":"never","extraWidth":10},{"text":".","font":"16px Inter"}]' \
--width 300
适用于文字围绕图片/侧边栏排版的场景:
node "${CLAUDE_SKILL_DIR}/scripts/wrap-layout.js" \
--text "长文本内容,填充整段..." \
--font "16px Inter" \
--width 600 \
--floatWidth 200 \
--floatHeight 300 \
--lineHeight 22
node "${CLAUDE_SKILL_DIR}/scripts/clear-cache.js"
无需触碰 DOM 测量,Pretext 预先算出每条内容的高度,直接渲染。
# 生成 HTML 片段
node "${CLAUDE_SKILL_DIR}/scripts/render-dom.js" \
--text "小兔子豆豆睡不着,看见窗外有一艘发光的月亮船..." \
--font "17px sans-serif" \
--width 400 \
--lineHeight 34 \
--align left
# 输出逐行 HTML,可直接粘贴到浏览器控制台
node "${CLAUDE_SKILL_DIR}/scripts/render-dom.js" \
--text "欢迎使用 Pretext!" \
--width 300 \
--output snippet
也可作为模块导入:
const { renderToDOM, renderAccordion, renderChatBubbles } = require('./scripts/render-dom');
// Accordion 示例
const result = renderAccordion([
{ title: "月亮船", text: "小兔子睡不着...", duration: 300 },
{ title: "小海龟", text: "奇奇第一次旅行...", duration: 300 },
], '16px sans-serif', 400, 24);
// 返回 { items, accordionHtml, totalClosedHeight, totalOpenHeight }
console.log(result.accordionHtml);
适用场景:
每个字符变成物理粒子,在 Canvas 上自由飘动——用 Pretext 精确测量每个字符宽度,保证字符间距自然。
# 生成粒子动画 HTML(直接用浏览器打开)
node "${CLAUDE_SKILL_DIR}/scripts/particle-text.js" \
--text "你好,世界!Hello World! 🎉" \
--font "32px sans-serif" \
--width 800 \
--height 500
# 分析文本粒子数量
node "${CLAUDE_SKILL_DIR}/scripts/particle-text.js" \
--text "欢迎来到 Pretext 世界!" \
--output info
# 自定义风格
node "${CLAUDE_SKILL_DIR}/scripts/particle-text.js" \
--text "Pretext 粒子引擎" \
--bg "#1a0a2e" \
--color "#C77DFF" \
--mouseRadius 150
交互功能:
动画原理:
每帧 loop:
1. 读取鼠标位置 → 计算粒子受推力
2. 更新粒子速度(+阻尼 +微风)
3. Pretext 宽度估算 → 粒子位置更新
4. Canvas 渲染(带发光效果)
5. requestAnimationFrame → 回到 1
| 语言 | 推荐字体 | 示例 |
|:---|:---|:---|
| 英文/通用 | Inter | 16px Inter |
| 中文 | 系统默认 | 16px -apple-system, "PingFang SC", "Microsoft YaHei" |
| 中文 + 英文混排 | 混合 | 16px "PingFang SC", Inter |
| 代码 | 等宽字体 | 14px "Fira Code", "Consolas", monospace |
| 粗体/斜体 | 组合 | bold 16px Inter 或 italic 16px Inter |
[style] [variant] [weight] [size] [font-family]
示例:bold 14px Inter、italic 16px "PingFang SC"、500 17px Inter
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|:---|:---|:---|:---|:---|
| --text | string | ✅ | — | 要测量的文本内容 |
| --font | string | ✅ | — | Canvas 字体简写,如 16px Inter |
| --width | number | ✅ | — | 容器最大宽度(像素) |
| --lineHeight | number | ❌ | 20 | 行高(像素),需与 CSS line-height 同步 |
| --whiteSpace | string | ❌ | normal | normal 或 pre-wrap(保留空格/换行) |
| --wordBreak | string | ❌ | normal | normal 或 keep-all(CJK 不自动换行) |
| 参数 | 类型 | 必填 | 说明 |
|:---|:---|:---|:---|
| --text | string | ✅ | 文本内容 |
| --font | string | ✅ | 字体 |
| --width | number | ✅ | 宽度 |
| --lineHeight | number | ❌ | 行高,默认 24 |
| --whiteSpace | string | ❌ | pre-wrap 保留空格 |
返回每行的 text、width,以及 startCursor 和 endCursor 坐标。
| 参数 | 类型 | 说明 |
|:---|:---|:---|
| --items | string[] | 多个文本,可多次指定 |
| --font | string | 字体 |
| --width | number | 宽度 |
| --lineHeight | number | 行高 |
当在浏览器环境中使用时,Pretext 可以调用 @chenglou/pretext 原版 Canvas API,精度达到 100%,完整支持所有功能。
在 HTML 中引入 UMD 构建:
<script src="https://unpkg.com/@chenglou/pretext/dist/pretext.umd.min.js"></script>
或通过 npm 安装:
npm install @chenglou/pretext
| API | 说明 | 返回值 |
|:---|:---|:---|
| pretext.layout(text, fontSize, lineHeightRatio, maxWidth) | 最常用,快速布局 | {height, lineCount, estimatedWidth} |
| pretext.measureNaturalWidth(text, fontSize) | 测量字符串宽度 | number (像素) |
| pretext.prepare(text, fontSize, maxWidth) | 预处理文本 | {lines, _chars} |
| pretext.layoutNextLine(text, fontSize, lineHeightRatio, maxWidth, startAt) | 逐行增量布局 | 行对象 |
| pretext.setLocale(locale) | 设置语言区域 | void |
<script src="https://unpkg.com/@chenglou/pretext/dist/pretext.umd.min.js"></script>
<script>
const text = '小兔子豆豆今天又睡不着了。窗外突然亮了起来!';
const result = pretext.layout(text, 17, 2.1, 560);
console.log('高度:', result.height); // 例如: 71.4
console.log('行数:', result.lineCount); // 例如: 3
console.log('最宽行:', result.estimatedWidth); // 例如: 340
</script>
完整可操作的 API 演示页面:
pretext/pretext-browser-demo.html
包含:
当 AI Agent 需要在浏览器中调用 pretext 时,可以:
measure-browser.js 输出浏览器端代码片段
pretext-browser-demo.html 作为参考
pretext.*
| 限制 | 说明 | 规避方案 |
|:---|:---|:---|
| macOS system-ui | macOS 下精度不稳定 | 使用具名字体如 Inter、-apple-system |
| 字体未加载 | prepare() 时字体必须已加载 | 确保使用系统已安装字体 |
| white-space | 仅支持 normal 和 pre-wrap | 不支持 pre、nowrap 等 |
| word-break | 仅支持 normal 和 keep-all | — |
| 空字符串 | 返回 {lineCount: 0, height: 0} | 浏览器实际保留一行高度,需注意 |
| 方案 | 测量方式 | 精度 |
|:---|:---|:---|
| Pretext(本 Skill) | 纯算术 + Canvas measureText | ✅ 高精度,与浏览器一致 |
| getBoundingClientRect | DOM 渲染 + 重排 | ✅ 高精度,但有性能损耗 |
| 浏览器自动布局 | CSS text-wrap | ❌ 高度值不可读出 |
| RTL 语言 | — | ❌ 暂不支持阿拉伯文/希伯来文 |
输入:文本 + 字体 + 宽度
↓
┌─────────────────────────────┐
│ prepare() [预处理,一次] │
│ · Unicode 分词(CJK/emoji) │
│ · Canvas measureText 测量 │
│ · 缓存字符宽度数组 │
└─────────────────────────────┘
↓ prepared 句柄
┌─────────────────────────────┐
│ layout() [计算,无数次] │
│ · 纯算术遍历宽度数组 │
│ · 模拟浏览器换行规则 │
│ · 返回 { height, lineCount }│
└─────────────────────────────┘
↓
输出:精确像素高度 + 行数
当 AI Agent 需要计算文本在特定容器中的布局时:
text、font、width、lineHeight
measure.js 或 layout-lines.js
典型用户话术 → Skill 调用映射:
| 用户说 | 调用的脚本 |
|:---|:---|
| "计算高度" | measure.js |
| "会不会换行" | measure.js(看 lineCount > 1) |
| "每行分别多长" | layout-lines.js |
| "批量算" | batch.js |
| "带 @提及的" | rich-inline.js |
本 Skill 基于 @chenglou/pretext 开发,遵循 MIT License。
本 Skill 以「现状」(AS IS)提供,不附带任何明示或暗示的保证。
canvas 可显著提升测量精度;未安装时使用纯 JS Unicode 估算模式,功能完整但精度略低。
@chenglou/pretext 构建,版权归原作者 Cheng Lou(@chenglou)所有。
@chenglou/pretext:MIT License(见 LICENSES.md)
canvas(可选):node-canvas,GPL/FreeType License
canvas,本 Skill 将自动降级为纯 JS Unicode 估算模式,功能完整但精度略低。
MIT License
Copyright (c) 2026 Cheng Lou and Pretext contributors
https://github.com/chenglou/pretext
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
本 Skill 封装层(SKILL.md + scripts/*)版权归属 Skill 作者,遵循相同 MIT License。
共 2 个版本