digital-garden · 数字花园插件
该插件为安知鱼内容管理平台提供内容可视化功能,将文章映射为植物,通过阅读量、评论、字数和更新频率等指标驱动植物生长,并展示为三维花园全景、侧边栏盆栽和发文花瓣动效。插件采用eventhook和自带HTTP服务,版本为2.5.3,通过三维加权模型映射六个生长阶段,健康度跌破阈值则植物枯萎。三种展示形态均以<script>注入宿主页面,不依赖主题组件。功能特性包括分类、能力、生长模型、健康度、三维全景、侧边栏盆栽、发文动效、阅读上报、自然补给、文章同步、配置开关和公开接口。生长模型包括阳光、水分、养分和健康度等指标,季节模式有real、offset和custom三种,环境要求为Anheyu社区版或PRO并开启插件系统。安装后,需填写site_url、让插件端口对浏览器可达、挂载展示容器和等待一次同步。配置参数包括listen_port、listen_host、backend_url等,使用指南详细介绍了三种展示形态、阅读统计、自然补给、浇水、前端接入和HTTP API参考。安全说明强调公开接口免鉴权、限流,管理接口需管理员身份,端口不应发布到公网。故障排查部分列举了常见问题及处理方法。
本插件为安知鱼(Anheyu)内容管理平台提供内容可视化能力:把每篇文章当作一株植物,用阅读量、评论、字数与更新频率驱动生长,并输出三维花园全景、侧边栏盆栽与发文花瓣动效。
维护者:白夜
插件类型:
eventhook(评论浇水)+ 自带 HTTP 服务插件版本:
2.5.3(端口9802)
1. 概述
digital-garden 把站点文章映射成一座花园,四项指标各对应一个维度:
维度 | 数据来源 | 作用 |
|---|---|---|
阳光 | 阅读量 | 受欢迎程度 |
水分 | 评论数 | 互动程度 |
养分 | 字数与阅读时长 | 内容厚度 |
健康度 | 距最近更新或浇水的天数 | 是否长期停更 |
三项指标合成 vigor 决定生长阶段(种子 / 发芽 / 幼苗 / 成株 / 开花 / 结果),健康度跌破阈值转枯萎。三种展示形态均以 <script> 注入宿主页面,不依赖主题组件,详见 §8.1。
2. 功能特性
分类 | 能力 |
|---|---|
生长模型 | 阳光 / 水分 / 养分三维加权,映射六个生长阶段 |
健康度 | 超过 |
三维全景 | three.js 程序化建模,四季地表、风场、悬停与详情抽屉 |
侧边栏盆栽 | 迷你植株、趋势线、平均健康度 |
发文动效 | 按 |
阅读上报 | 插件自建计数,三重去重 |
自然补给 | 每日随机一株自动吸收水分与阳光 |
季节 |
|
文章同步 | 定时拉取公开接口,自动清理已删除文章的植物 |
配置开关 | 三种展示形态、阅读上报、自然补给可分别关闭 |
公开接口 | 免鉴权只读,按 IP 限流 |
3. 生长模型
3.1 阳光
阅读量先经对数压缩,再线性映射到 [26, 100]:
GO
raw := clampInt(int(math.Round(math.Log10(views+1)/4*100)), 0, 100) // 0..100
sun := 26 + int(math.Round(float64(raw)*(100-26)/100)) // 映射到 [26,100]
阅读量 | 0 | 1 | 10 | 100 | 1000 | 10000+ |
|---|---|---|---|---|---|---|
阳光 | 26 | 32 | 45 | 63 | 82 | 100 |
阅读量取插件自建 PageViews 与宿主 ViewCount 的较大者;再与自然吸收累计的 SunAbsorbed 相加,封顶 100。
3.2 水分
项目 | 规则 |
|---|---|
新建植物初始值 | 20 |
每条评论 | +8 |
上限 | 100 |
3.3 养分
字数每 100 字 1 分(上限 70),阅读时长每分钟 3 分(上限 30),合计上限 100。
3.4 阶段与健康度
vigor 按阳光 0.3、水分 0.3、养分 0.4 加权:sunshine*0.3 + water*0.3 + nutrient*0.4。
vigor | ≥85 | ≥65 | ≥45 | ≥28 | ≥12 | <12 |
|---|---|---|---|---|---|---|
阶段 | 结果 | 开花 | 成株 | 幼苗 | 发芽 | 种子 |
健康度按距最近一次更新或浇水的天数计算:
条件 | 健康度 |
|---|---|
| 恒为 100,永不枯萎 |
天数 ≤ | 100 |
天数 > | 每多一天下降 |
健康度 ≤ 15 | 阶段固定为枯萎 |
健康度 < 50 但 > 15 | 阶段下调一档 |
收到评论 | 恢复 100 |
water_decay_days 默认 30,即超过 30 天后开始下降,再经 30 天归零。
3.5 季节
| 判定方式 |
|---|---|
| 按服务器月份,北半球气象划分(3–5 春、6–8 夏、9–11 秋、12–2 冬) |
| 月份偏移六个月,南半球 |
| 固定为 |
季节决定三维地表配色、花瓣动效配色,以及自然补给系数:
季节 | 系数 | 基数 1 时实际补给 |
|---|---|---|
夏 | 1.00 | 水分 +1、阳光 +1 |
春 | 0.75 | 水分 +1、阳光 +1 |
秋 | 0.50 | 水分 +1、阳光 +1 |
冬 | 0.15 | 0 |
4. 环境要求
Anheyu(社区版或 PRO)开启插件系统。
插件进程可访问主程序后端(
backend_url),用于定时同步文章。展示脚本对浏览器可达:反代到插件端口,或填写
garden_entry指定公网入口。
5. 安装
后台进入「插件管理」。
上传安装包
digital-garden.zip(内含plugin.json与各平台二进制)。安装成功后状态变为「运行中」。升级同 ID 插件会保留既有配置与数据。
安装包内
plugin.json必须位于压缩包根目录。
6. 快速开始
填写
site_url:用于生成植物跳转链接。让插件端口对浏览器可达:反代到 9802,或填
garden_entry。挂载展示容器:侧边栏块写
data-garden-mode="widget",全景页写"page"。等待一次同步:插件启动时同步一次文章,之后每
sync_interval_min分钟同步。
7. 配置参数参考
以下参数在 plugin.json 的 config_schema 中声明,由后台保存后以环境变量注入插件进程。
参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| number |
| 插件 HTTP 服务端口。仅内网可达,禁止公网暴露。 |
| string | 空 | 监听地址。空=所有网卡;同机部署可填 |
| string |
| 主程序后端地址,用于同步文章与管理员校验。 |
| string |
| 一个"仅管理员可访问"的后端接口路径,返回 200 视为放行。 |
| string | 空 | 站点访问地址,用于生成植物跳转链接。留空则按相对路径 |
| string | 空 | 插件公网入口。填写后服务端在 |
| string | 空 | 植物图鉴与生长历史落盘目录。留空则落在插件安装目录之外的 |
| boolean |
| 启用侧边栏小部件。关闭后 |
| boolean |
| 启用花园全景页数据。关闭后 |
| boolean |
| 在插件 HTTP 服务根路径托管独立全景页。 |
| boolean |
| 启用发文粒子动效。关闭后前端不触发。 |
| boolean |
| 启用阅读量自建统计。关闭后 |
| boolean |
| 启用自然补给。 |
| number |
| 每日自然补给的水分基数,实际值 = 基数 × 季节系数,取整。上限 20。 |
| number |
| 每日自然补给的阳光基数,实际值 = 基数 × 季节系数,取整。上限 20。 |
| select |
| 季节模式,取值 |
| select |
| 仅 |
| number |
| 距最近更新或浇水超过此天数后健康度开始下降。 |
| number |
| 每个来源 IP 每分钟允许的公开接口请求次数(0=不限)。 |
| number |
| 管理员"通过"结果缓存秒数(0=不缓存)。 |
| number |
| 文章同步周期(分钟)。 |
| number |
| 单次 HTTP 请求超时秒数,可设范围 1–120。 |
8. 使用指南
8.1 三种展示形态
形态 | 容器 | 数据接口 | 开关 |
|---|---|---|---|
侧边栏盆栽 |
|
|
|
三维全景页 |
|
|
|
发文动效 |
|
|
|
garden.js 启动时扫描页面内所有 [data-garden-mode] 元素并按属性分别渲染。
脚本加载为两层结构:
路径 | 内容 | 缓存 |
|---|---|---|
| 固定名加载器 |
|
| 实现体 |
|
| 三维舞台模块 |
|
| three.js 运行时 |
|
| three.js 核心模块 |
|
页面里只需引用 /api/garden.js。带指纹的四件资源内容变更即换名,升级无需清缓存。three.js 已随插件内置,运行期不请求外部 CDN。
8.2 阅读统计
garden.js 在文章页从 location.pathname 反解 slug(匹配 /posts/、/article/、/post/),POST /api/public/garden-view 上报一次,插件累计 PageViews 并重算阳光。
三重去重:
层级 | 机制 |
|---|---|
前端 |
|
服务端 | 同一 IP 同一文章 30 分钟内只计一次 |
接口 | 按来源 IP 限流,受 |
重复上报返回 counted=false,但会回传当前阳光值,前端无需重试。
关闭 view_track_enabled 后接口返回 404,前端跳过上报,阳光退回基线 26。
8.3 自然补给
任意访客当天首次访问时,插件随机挑一株植物吸收当日水分与阳光。
项目 | 规则 |
|---|---|
触发 | 访客当天首次访问,单 IP 24 小时一次 |
对象 | 随机一株,与该访客正在阅读的文章无关 |
单株去重 | 同一株同一 UTC 日只吸收一次 |
补给量 | 基数 × 季节系数,取整 |
累计 | 记入 |
该逻辑挂在阅读上报接口上:关闭 view_track_enabled 时自然补给一并停止。
8.4 浇水
订阅 comment.created 事件。
项目 | 规则 |
|---|---|
触发 | 站点收到新评论 |
效果 | 对应植物水分 +8,健康度恢复 100 |
上限 | 水分 100 |
文章定位 | 优先使用事件内的文章 ID;无 ID 时从 |
9. 前端接入
9.1 侧边栏盆栽
在后台「侧边栏设置」添加一个自定义侧边栏块,不用输入标题,内容如下:
HTML
<div data-garden-mode="widget" data-garden-link="/garden"></div>
<script src="https://你的域名/garden/api/garden.js"></script>
属性 | 说明 |
|---|---|
| 必填,指定渲染为侧边栏盆栽 |
| 可选,点击跳转地址,留空默认 |
9.2 花园全景页
在后台「页面管理」新建一个页面,二选一:
正文方式:页面正文里放容器与脚本标签(渲染层对正文开启脚本执行)。
HTML
<div data-garden-mode="page"></div>
<script src="https://你的域名/garden/api/garden.js"></script>
自定义 JS 方式:在「自定义 JS」里粘贴纯 JS。该字段按 new Function 执行 JS 源码,直接粘贴 <script> 标签会报 Unexpected token '<'。
JS
(function () {
if (window.__GARDEN_PAGE_INJECTED__) return;
window.__GARDEN_PAGE_INJECTED__ = true;
var host = document.querySelector("article") || document.body;
host.style.minHeight = "0";
var hd = host.previousElementSibling;
if (hd && hd.tagName === "HEADER") hd.style.display = "none";
var box = document.createElement("div");
box.setAttribute("data-garden-mode", "page");
// 可选:强制某个季节,留空使用服务端返回的真实季节
// box.setAttribute("data-garden-season", "autumn");
host.appendChild(box);
var s = document.createElement("script");
s.src = "https://你的域名/garden/api/garden.js";
host.appendChild(s);
})();
容器需先创建、脚本后注入,garden.js 执行时才能命中该容器。
属性 | 说明 |
|---|---|
| 必填,指定渲染为全景页 |
| 可选,强制 |
9.3 发文动效
前端读取 /api/public/garden-state 的 last_post_at,与 localStorage 中记录的值比较,并判断时间差在十分钟内,命中即触发花瓣飘落。
启用方式二选一:
方式 | 做法 |
|---|---|
自定义页面 | 页面里放 |
全站生效 | 在「设置 → 页面样式 → 自定义 JS」中设置 |
花瓣配色随季节变化,prefers-reduced-motion 下不播放。
9.4 独立页
serve_ui=true 时,插件在 HTTP 服务根路径(如 https://你的域名/garden/)托管一个独立全景页,内部预置 <div data-garden-mode="page"> 与 garden.js 引用,无需主题参与。默认关闭。
花园配色跟随站点主题:读 <html> 的 dark 类或 data-theme,切换实时生效;站点未声明时退回系统 prefers-color-scheme。独立页的兜底底色同样跟随。
10. HTTP API 参考
直连插件时前缀为
/api/...。反代保留挂载前缀时插件会自行裁掉/api/之前的部分。
统一响应封装(业务成功以 code=200 判定):
JSON
{ "code": 200, "message": "ok", "data": { } }
接口一览:
方法 | 路径 | 鉴权 | 说明 |
|---|---|---|---|
GET |
| 否 | 健康检查,返回 |
GET |
| 否 | 侧边栏摘要,受 |
GET |
| 否 | 植物图鉴,返回 |
GET |
| 否 | 粒子动效状态,返回 |
GET |
| 否 | 最近 180 条按天聚合的生长历史 |
POST |
| 否 | 阅读上报,body 为 |
GET |
| 否 | 阅读上报,query 为 |
POST |
| 是 | 返回最新花园状态 |
GET |
| 是 | 完整花园状态 |
门控关闭时对应接口返回 404,前端据此静默隐藏。
GET /api/public/garden-plants 返回的每株植物字段:
字段 | 类型 | 用途 |
|---|---|---|
| string | 文章 ID,作为稳定键 |
| string | 标题 |
| string | 跳转链接 |
| string | 封面图 |
| string | 文章主色,决定花果色相 |
| string[] | 标签 |
| string | 生长阶段,取值见 §3.4 |
| number | 健康度 0–100 |
| number | 阳光 0–100 |
| number | 水分 0–100 |
| number | 养分 0–100 |
| string | 种植时间,格式 |
GET /api/public/garden-summary 另返回 total_plants、blooming_count、withered_count、season、avg_health、featured_title / featured_color / featured_stage(主视觉取最新一株未枯萎的)与 series(最近 14 条生长历史)。
11. 安全说明
公开接口:
/api/public/*免鉴权,仅返回聚合数据,按来源 IP 限流。管理接口:
/api/garden/*需管理员身份,插件将调用者 Bearer 透传给admin_check_path,返回 200 放行,否则 401/403。端口:插件端口(默认 9802)不应发布到公网,仅经反向代理访问。同机部署可将
listen_host设为127.0.0.1。跳转链接:植物跳转地址仅由
site_url与文章标识拼接,不接受外部输入。出站请求:插件不访问任何外部可控 URL,数据来源为主程序公开接口。
阅读上报:
key限制为字母、数字与-_.,长度不超过 128,非法值直接拒绝。
12. 故障排查
现象 | 可能原因 | 处理 |
|---|---|---|
侧边栏空白 | 未引入 | 检查侧边栏块是否带 |
全景页空白 | 容器与脚本顺序颠倒; | 容器先建、脚本后注;确认开关 |
花园是空的 | 尚未完成首次同步; | 查看插件日志同步结果;核对 |
阳光一直是 26 |
| 开启阅读统计;确认文章页路径匹配 |
植物迅速枯萎 |
| 调大阈值,或给文章发评论浇水 |
动效不触发 |
| 确认开关;检查 |
反代剥前缀后接口 404 | 脚本按自身 | 在 |
三维模型不显示 | WebGL 不可用或模块加载失败 | 自动回退静态插画;检查 |
13. 常见问题
Q:必须用主题页面吗? A:不必。容器可以是任意 HTML,只要带上 data-garden-mode 并引入 garden.js。也可开启 serve_ui 用插件自带的独立页。
Q:为什么关掉阅读统计后自然补给也没了? A:补给逻辑位于阅读上报接口内,接口关闭后整段逻辑不执行。需要补给时请保持 view_track_enabled 开启。
Q:能不能给单篇文章浇水? A:不能。浇水只由评论事件触发,每次 +8。
Q:文章删除后植物会消失吗? A:会。每次同步后用本次结果对账,不在列表中的植物会被清理。
Q:重新同步会不会重置生长进度? A:不会。水分、阅读计数、自然吸收累计与种植时间都会保留。
Q:花瓣动效刷新页面会重复播放吗? A:不会。last_post_at 与本地记录一致时跳过,且只在十分钟内视为新发文。
14. 限制与已知事项
不拉取正文:文章同步只取列表字段。阳光由插件自建阅读计数驱动,养分在字数为 0 时用标题估算兜底。
公开接口有短缓存:多次请求同一接口可能返回相同结果,属预期行为。
主色降级:文章主色为空或非法时,植物改用季节主色。
季节按 UTC 月份判定:跨时区部署时季节可能比本地日历提前或延后一天。
阅读上报只识别固定路径前缀:
/posts/、/article/、/post/,自定义文章路径不会计入阳光。