INKPOND / 墨池六卷用法GitHubEN

常见问题 · 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:用字符在页面背后养一片会游动的海。墨池把它换成了水墨和汉字,代码从头写起,没有使用原仓库的代码。