npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@yanini/graph-atlas-3d

v0.2.5

Published

Spherical 3D relationship graph for React: force layout baked at build time, instanced nodes, bezier ribbon edges, duotone or per-group colors.

Readme

@yanini/graph-atlas-3d

球状 3D 关系图谱的 React 组件。给它节点和边,它画出一颗会自转、会呼吸的球:hover 高亮邻居,点击转到正对、粒子沿边流动。适合 30–500 个节点、每节点 3–10 条边的"一个主题下互相有关的东西"。

作品Yanini's LLM Anatomy · 大模型图鉴 —— 76 个大模型概念、227 条关系,半透明节点、图例聚焦、导览、收集进度、开屏动画,用到了引擎的每一个口子。

起点三国人物关系图谱 是最小示例,代码在 graph-atlas-templatenpx degit fyannnnt/graph-atlas-template my-atlas 就能跑。

pnpm add @yanini/graph-atlas-3d three @react-three/fiber @react-three/drei @react-three/postprocessing postprocessing
import { GraphAtlas } from '@yanini/graph-atlas-3d'

<GraphAtlas
  data={{
    nodes: [{ id: 'a', label: 'Alpha' }, { id: 'b', label: 'Beta' }],
    edges: [{ source: 'a', target: 'b' }],
  }}
  onSelectChange={(id, node) => console.log(id, node)}
/>

画布里面的是包的,画布外面的是你的:状态往里传,事件往外抛。抽屉、搜索框、图例都是你页面上的普通 HTML。

数据

type GraphData<N extends AtlasNode> = { nodes: N[]; edges: AtlasEdge[]; groups?: AtlasGroup[] }
type AtlasNode = { id; label; group?; weight?; layout? }   // 其余字段随意,回调里拿到完整的 N
type AtlasEdge = { source; target; group?; control? }
  • weight 决定节点大小,缺省 = 入度
  • layout 缺省时挂载时在浏览器里跑布局;建议构建期用 layoutGraph 烘焙,每次打开一样:
import { layoutGraph } from '@yanini/graph-atlas-3d/layout'   // 纯函数,Node 里能跑
writeFileSync('graph.json', JSON.stringify(layoutGraph(data)))

球壳半径按 170 × √(N / 69) 自动缩放;节点、字号、线宽都和球成比例(theme.unit 可手动定)。节点少时云团轮廓读不出球,用 shellSnap: 0.7 把节点往球面靠拢;clusterByGroup: 0.3 让同组节点在球面上连成一片。

预设

import { GraphAtlas, presets, palettes } from '@yanini/graph-atlas-3d'

<GraphAtlas {...presets.night} data={data} color="group" />   // 暗色大屏:发光、颗粒、远近拉开
<GraphAtlas {...presets.paper} data={data} />                 // 浅色双色调
<GraphAtlas data={data} palette={palettes.teal} />            // 只换配色

presets 是摊进 props 的一组值,自己再传的同名 prop 会覆盖;palettes 是命名的墨 / 纸组合;groupColorscolor="group" 用的色阶。

Props

| 类别 | prop | 说明 | |---|---|---| | 状态 | selected defaultSelected onSelectChange | 传了 selected 就是受控,像 <input value> | | | hovered onHoverChange | 同上 | | | visible | 只显示这些 id(及两端都在的边);搜索过滤用 | | 事件 | onNodeClick onBackgroundClick | 默认行为之外的钩子 | | 外观 | label(node) font | 标签文字;字体 URL 或按节点返回(中英混排) | | | palette={{ ink, paper }} | 双色调的墨 / 纸 | | | color edgeColor(edge) | 传了 color 进彩色模式:'group' 用内置色阶按分组上色,或回调自己定;回调返回空的节点画墨色,可以只给选中的或某一组上色;边缺省两端渐变 | | | grain | 颗粒强度 0–1,加在双色调之前,是纸的纹理 | | | bloom | 发光后处理(暗底 + 彩色时开),true{ intensity, threshold, radius } | | | depthOfField | 景深,{ focus, range, bokeh },焦点在球的前部 | | | theme | 所有视觉参数,深合并,见 defaultThemenode.glow 圆片径向明暗、node.opacity 圆片透明度(<1 重叠处透出后面的节点和线)、label.edgeOpacity / label.edgeOutline 关系名的浓淡和描边、edge.byWeight 小节点的边闲置时压低(重要关系才常驻)、edge.additive 暗底加法混色、fade.desaturate 远处降饱和、motion.attract hover 时邻居靠拢的拉力 | | | labels particles shockwave edgeLabels | 开关;edgeLabels 只给激活节点的边显示关系名(默认 edge.group) | | 相机 | rotateOnSelect focus focusZoom idleSpin viewOffset fill fov distance polar | 选中转正、把某个节点转到正面但不选中(首次直接摆好,之后变了转过去)、选中推近倍数、空闲自转、投影中心平移(抽屉让位;数字是横向,[x, y] 可以同时纵向)、撑满系数、视角(大一点纵深更强)、距离范围、俯仰角范围(度) | | 容器 | transparent className style dpr onCreated children | transparent 画布透明、背景交给 CSS;children 放进 Canvas,可以加自己的 R3F 层;onCreated 拿到 R3F 的 gl / scene / camera |

label / font / color 变了会重建标签或重写颜色,传稳定的引用(useCallback)。

实现

| 文件 | 做什么 | 关键概念 | |---|---|---| | core/prepare.ts | GraphData → 索引、邻接、半径、尺度系数;缺 layout 时跑布局 | 每个 <GraphAtlas> 一份,场景层通过 context 拿 | | core/motion.ts | 每帧算节点漂移 + 呼吸 + 吸引(hover 时邻居被弹簧拉向激活节点,刚度各不相同),写进一张 DataTexture(xyz + 半径) | 位置纹理:所有 shader 按索引采样同一份位置,CPU 只写一处 | | scene/Nodes.tsx + nodeShader.ts | 一个 InstancedMesh 画全部 billboard 圆片 | 顶点 shader 在视空间撑开平面 → 永远面向相机;屏幕空间拾取代替 raycaster | | scene/Edges.tsx + edgeShader.ts | 所有边合成一个 mesh,每条边是 16 采样 × 2 侧的 ribbon | 顶点 shader 里算贝塞尔、屏幕空间恒定线宽、冲击波行波位移 | | scene/Particles.tsx | 固定大小的粒子池,沿激活节点的边流动 | gl_PointSizegl_PointCoord 画圆 | | scene/HoverRing.tsx | 激活节点外的描边圆环,billboard + 两个 smoothstep 相减 | 圆片本身不放大,反馈靠颜色和圆环 | | scene/Labels.tsx | drei <Text> + <Billboard>,全部显示,字号和透明度按半径插值 | SDF 文字;用透明度分层级而不是藏掉小标签 | | scene/EdgeLabels.tsx | 激活节点的边在贝塞尔中点放关系名,标签池常驻 | 只画几条到十几条,不会糊 | | scene/CameraRig.tsx | camera-controls;距离按视口算让球撑满;空闲慢转;选中时相机移到"原点 → 节点"的射线上 | 目标始终是原点,看起来是球转过来 | | scene/Duotone.tsx | postprocessing 自定义 Effect:整帧转亮度再映射到两色 | 场景只画墨和纸,最后一步决定墨和纸是什么颜色;彩色模式不挂它 | | core/depth.ts | 深度淡出:离相机越远越混向纸色,区间按球半径定;远处节点再额外缩小(fade.shrink) | 球感的来源 | | core/damp.ts | 非对称阻尼,pow(k, dt) 与帧率无关 | 变亮快、变暗慢 | | core/store.ts | zustand vanilla store:hovered / selected / visible | useFramegetState() 读,不触发 React 重渲染 |

hover / 选中一个节点时,所有节点和边的目标值一起变(激活 2、相邻 1.3、其余 0.12),每帧向目标阻尼过渡——"其它节点褪淡"是把墨色混向纸色,不是 alpha 变 0。

开发

pnpm dev          # tsup --watch
pnpm typecheck
pnpm build

发版:pnpm release(按提交历史算版本号、生成 CHANGELOG、提交、打 tag),然后 git push --tagspnpm publish(要过 2FA,手动跑;publishConfig.access 已设为 public)。CHANGELOG 由 git-cliff 从 emoji type(scope): 描述 格式的提交生成,chore 不进 changelog。

在消费者里联调:pnpm add file:../graph-atlas-3d(pnpm 会拷贝一份,peer 从消费者解析)。不要用 link:——软链会把这个仓库自己 node_modules 里的 three / R3F 一起带进去,出现两份 three。包重新 build 后在消费者里再跑一次同样的命令。

不做的事

壳组件(抽屉、搜索框)、节点形状、上千节点、有层级或流向的数据(球面布局会把方向抹掉)。