paperjs-offset 是一个面向 Paper.js 的路径偏移辅助库。它接受 paper.Path 和 paper.CompoundPath,可以生成闭合路径偏移、可填充的描边轮廓,并提供用于检查结果几何质量的分析信息。
这个库刻意保持较小的 API 面:扩张或收缩一个闭合路径,把中心线描边转换成闭合轮廓,然后检查生成结果是否足够可靠。

闭合路径偏移
正距离会把闭合形状向外扩张,负距离会向内收缩。源路径仍由调用方控制,因此可以保留它用于对比,也可以在生成后移除。
const expanded = offset(source, 14, {
join: "round",
insert: false
});
const contracted = offset(source, -10, {
join: "round",
insert: false
});
这是大多数基础 demo 和 Gallery case 的核心操作。
描边轮廓
offsetStroke 把开放或闭合中心线作为独立操作处理。Join 决定拐角如何重建,cap 决定开放路径端点如何闭合。对自然形状来说,round 通常是最稳妥的默认值;miter 和 bevel 更适合锐角构造几何。
const outline = offsetStroke(centerline, 8, {
join: "round",
cap: "round",
insert: false
});
质量分析
默认的 algorithm: "auto" 会先生成 adaptive 结果。质量检查没有发现自交、意外空结果、包含关系错误或负向偏移距离坍缩等结构性问题时,它会直接返回;只有发现异常,才继续比较其他策略。
同一套评分信息也可以通过 analyze 读取。分析时应传入实际使用的 join、cap 和 stroke 语义,避免把 bevel 连接或 butt 端点的预期形状误判为距离坍缩。
const result = offset(source, 12, {
algorithm: "auto",
join: "round",
insert: false
});
const quality = analyze(source, result, 12, {
join: "round"
});
策略选择
| 模式 | 适用情况 |
|---|---|
auto | 推荐的应用默认值;先走 adaptive,必要时再比较其他候选。 |
adaptive | 保持请求的偏移距离;激进内缩接近塌缩边界时,会比较原 join 与更安全的 round join。 |
robust | 对凹角和自交描边轮廓执行额外清理。 |
split | 拆分自交曲线,保留比 robust 更多的原始结构。 |
legacy | 尽量维持旧版本输出,用于兼容已有结果。 |
auto 的目标不是让调用方猜测哪种算法适合某个图形,而是在常见输入上避免不必要的多策略计算,并在困难几何出现时才扩大搜索范围。需要复现历史输出或检查某个特定策略时,仍然可以显式选择模式。
交互指南
下面的例子来自项目仓库生成的 Dev Site Export Contract。详情页只读取 manifest.json、data/guide.json 和 runtime,具体示例内容仍由 paperjs-offset 仓库维护。

Playground
Playground 使用同一套导出的 data 和 runtime。你可以选择预设形状,调整偏移参数,并立即观察生成路径。

Gallery
Gallery 由 data/gallery.json 驱动,包含 198 个确定性 case。页面默认先显示 12 个轻量精选案例,基础、进阶、边界与特殊 case 会在切换 tab 后再渲染。每个 case 都带有 SVG path、operation、distance、options 和 expected 质量信息。
除常规的星形、平滑曲线、孔洞和开放描边外,用例还覆盖嵌套岛屿轮廓、尺寸悬殊的分离组件、深度细分、包含关系泄漏、数值精度敏感的侵蚀,以及应当完全消失的负向偏移。这些输入既用于页面展示,也直接来自项目的压力测试语料。

用例与验证
固定 Gallery 之外,测试还会使用固定 seed 生成 400 个 fuzz case,覆盖随机多边形、Bezier 曲线、复合路径和开放描边。失败输入可以用 seed 和 case 编号重放,再收录为新的确定性回归用例。
Benchmark 使用同一批语料比较不同算法,输出总耗时、P50、P95、最大耗时和最慢案例。它不设置容易受机器差异影响的硬性时间阈值,主要用于观察策略调整是否引入明显退化。
安装
使用这个库的应用需要自行安装 Paper.js:
npm install paper paperjs-offset
推荐 API
新代码推荐使用具名函数:
import paper from "paper";
import { analyze, offset, offsetStroke } from "paperjs-offset";
paper.setup(new paper.Size(400, 300));
核心函数包括:
offset(path, distance, options);
offsetStroke(path, distance, options);
analyze(source, result, distance, options);
offset 负责闭合路径的扩张或收缩。offsetStroke 把中心线描边转换成闭合轮廓。analyze 对生成结果打分,并报告困难几何 case 的警告信号。
说明
Bezier 几何偏移是近似问题,尤其在紧曲线、凹角、自交、复合路径和激进负偏移附近更明显。
adaptive 会保留调用方请求的偏移距离,不再通过缩小负向偏移来换取看起来更安全的图形。激进内缩接近临界区时,它会比较请求的 bevel/miter join 与 round 候选,避免退化轮廓面积重新增长,或在完全消失后再次出现。对于过度侵蚀后理应消失的形状,空结果本身可能就是正确结果;是否可接受,应结合业务语义和 analyze 的报告判断。