常见问题 · FAQ
关于墨池 Inkpond
墨池是给网页开发者用的水墨汉字背景库。下面直接回答最常被问到的问题;更完整的用法见 README,在线效果见 项目主页。
墨池是什么?
- 墨池(Inkpond)是一个网页背景库:在页面背后铺一层水墨风格的汉字动画。汉字按笔画疏密排成远山云雾、鲤鱼游动的荷塘,或缓缓展开的清明上河长卷;鼠标划过泛起水波,点击空白处落墨。
墨池给谁用?适合用在哪里?
- 给想让网页有东方水墨氛围的前端开发者和设计师:产品首页、登录页、AI 对话应用的空白起始页、个人主页、作品集、活动页,以及任何内容不多、需要一点氛围的页面。
墨池解决什么问题?
- 空白的首页或对话页显得冷清,而视频背景或大图又重又抢内容。墨池用很少的资源(每个场景十到三十 KiB 的字体子集,无运行时依赖)给页面一层会动、会回应鼠标的水墨背景,同时自动避开页面上的内容,不遮挡文字,也不拖慢页面。
怎么安装和使用?
- 用 npm 安装:
npm i inkpond(也可以从 GitHub 安装最新提交:npm i github:shin4/inkpond)。然后引入样式import "inkpond/inkpond.css",在 React 里放一个<InkPond />,或者用createInkPond(canvas)挂到任意画布上。 支持哪些框架?只能用 React 吗?
- 核心是不依赖任何框架的 TypeScript 库,
createInkPond(canvas, options)在原生 JavaScript、Vue、Svelte、Angular 里都能用。另外提供一个 React 组件inkpond/react(需要 React 18 及以上,是可选依赖)。 能在 Next.js(App Router)里用吗?
- 可以。
inkpond/react已经标了 "use client",在 App Router 的服务端组件里可以直接写<InkPond />;inkpond/inkpond.css引入一次即可(比如放在根 layout)。跨服务端边界只能传普通的属性;想在代码里调用ripple()或drop(),就在你自己的客户端组件里用pondRef。// app/page.tsx — a Server Component is fine: inkpond/react is "use client" import { InkPond } from "inkpond/react"; import "inkpond/inkpond.css"; export default function Page() { return ( <main style={{ position: "relative", minHeight: "100vh" }}> <InkPond scene="lotus" /> <h1 data-inkpond-avoid="">…</h1> </main> ); } 在 Vue 里怎么用?
- 用不依赖框架的接口:组件挂载时创建,卸载时销毁。画布要带
inkpond类名(或自己设置尺寸),父元素需要是定位元素。<script setup lang="ts"> import { onBeforeUnmount, onMounted, ref } from "vue"; import { createInkPond, type InkPond } from "inkpond"; import "inkpond/inkpond.css"; const canvas = ref<HTMLCanvasElement>(); let pond: InkPond | undefined; onMounted(() => { pond = createInkPond(canvas.value!, { scene: "qingming" }); }); onBeforeUnmount(() => pond?.destroy()); </script> <template> <main style="position: relative; min-height: 100vh"> <canvas ref="canvas" class="inkpond" /> <h1 data-inkpond-avoid>…</h1> </main> </template> 在 Svelte 里怎么用?
- 同样的做法:在
onMount里创建,返回它的destroy。<script lang="ts"> import { onMount } from "svelte"; import { createInkPond } from "inkpond"; import "inkpond/inkpond.css"; let canvas: HTMLCanvasElement; onMount(() => { const pond = createInkPond(canvas, { scene: "shanshui" }); return () => pond.destroy(); }); </script> <main style="position: relative; min-height: 100vh"> <canvas bind:this={canvas} class="inkpond"></canvas> <h1 data-inkpond-avoid>…</h1> </main> 有哪些场景?
- 有六个场景:
shanshui(山水,默认)是两重远山与云雾;lotus(荷塘)是荷叶荷花,鲤鱼会躲开鼠标、游向落墨处;qingming(清明上河)是一卷不断展开的长卷,有城郭、宝塔、虹桥、船只和行人;jieqi(二十四节气)一节一画,按日期自动切换,也可以用term固定某一个;beiming(北冥)俯看深海,浪下一头鲸的影子时浮时沉,鼠标触到会下潜,落墨引它游近;dafeijing(大肥鲸)是一条搞笑的胖鲸守着一碗白米饭(饭是留白),吃到撑就打嗝喷米,落墨处撒米引它来吃,戳它会笑。荷塘、清明、节气和两条鲸带淡彩,也可以只用墨色。 和 Vanta.js、tsParticles 有什么不同?
- Vanta.js 用 three.js 或 p5.js 做 3D、WebGL 效果,tsParticles 做可配置的粒子、彩带等效果,两者都有很多预设。墨池只做更窄的一件事:用汉字组成的水墨画面,并且会避开页面内容(留白区,鲤鱼、船、行人也会绕开),基于 Canvas 2D、零运行时依赖。想要东方水墨感、页面以文字为主或比较空时选墨池;想要 3D 或粒子效果时选它们。
会不会拖慢页面、耗电?
- 不会明显拖慢。每个字只栅格化一次,之后每帧只贴图;实测(1920×1080,DPR 1.5)静水时每帧脚本耗时中位数不到 1 ms,满屏搅动时 p95 约 2 ms;最繁忙的节气画面和清明上河相当。画面静下来会降帧,30 秒无操作就停帧;标签页隐藏时暂停;弱设备或软件渲染时自动降到轻量档或静止画面。
会遮挡或干扰页面上的内容吗?
- 不会。给内容元素加上
data-inkpond-avoid属性,它周围就会自动留白,鲤鱼、船和行人也会绕开;点击按钮、链接、输入框等可交互元素时不会落墨。画布铺在最近的定位父元素下面,不影响布局。 手机和触屏上效果怎样?
- 可以用。触屏上手指滑动不会起波(避免和页面滚动冲突),轻点空白处会落墨;CPU 或内存偏弱的设备从轻量档开始,字格更大、帧率更低。
对无障碍友好吗?
- 画布对读屏软件隐藏(
aria-hidden);系统开启「减少动画」时只画一张静止画面;高对比度(强制颜色)模式下隐藏画布,保证文字可读。 能改颜色、浓淡或换成自己的字吗?
- 可以换。墨色和四种淡彩(朱、胭脂、赭石、花青)都是 CSS 变量,支持暗色主题;浓淡、字号(
cellSize)、水波速度、留白宽度都有选项;levels可以替换主地面用的字(换字需要自备覆盖这些字的字体)。 可以商用吗?是什么许可?
- 可以。代码以 MIT 许可发布,个人和商业项目都能免费使用,保留版权声明即可。随包附带的字体是思源宋体的子集,按 SIL OFL 1.1 授权,同样允许商用。
字体从哪里来?要额外加载多少?
- 字形来自思源宋体 SC Medium(Source Han Serif),每个场景只带自己用到的字,约 6–29 KiB 一个(二十四节气共用一个),用到哪个场景才加载哪个。按 OFL 规定改名为 Inkpond Glyphs。
和 ascii-sharks 是什么关系?
- 墨池的想法来自 stackedlol/ascii-sharks:用字符在页面背后养一片会游动的海。墨池把它换成了水墨和汉字,代码从头写起,没有使用原仓库的代码。