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

@ccgf/red-dot

v0.1.5

Published

红点树:条件树求值 + 脏传播 + 帧末批量重算。零资源、零工程脚本 —— 装上即用,删掉即消失。

Readme

@ccgf/red-dot

红点树 —— id 就是路径的一套红点系统。

npm i @ccgf/red-dot

装完之后,在希望红点生效的入口 import 一次(它自带模块,负责把"已读"接进存档):

import '@ccgf/red-dot';

默认样式预制体 resources/reddot/default.prefab 由编辑器扩展在安装本模块时自动生成 ✓ (预制体只能放在工程里,所以它不随包发布 ✓)。

只有两件事要做

// ① 业务:这一格有新东西了
Reddot.trigger('bag.tabs.0.item.1001');

// ② UI:挂到哪个节点上 / 玩家看过了
import { Reddot, EReddotAlign } from '@ccgf/red-dot';
Reddot.bind('bag.tabs.0.item.1001', itemNode, EReddotAlign.RIGHT_TOP);
Reddot.markRead('bag.tabs.0.item.1001');

规则(全部由内核保证)

  • id 就是路径:trigger / bind 用哪个路径,整条链自动长出来 —— 不需要提前 define;
  • 叶子 = 没有子节点的节点,传进来的路径最后一段默认是叶子; 叶子一旦长了子节点就不再是叶子(它原来的状态作废);
  • 触发只在最底层叶子上生效:trigger(path) 只有一个参数,意思就是"有新东西了";
  • 向上传递:父节点 on = 任一子亮,count = 底下亮着几个叶子 —— 所以上层一行都不用写(底部 Tab、主界面入口都是自动汇总出来的);
  • UI 与状态无关:界面没打开时业务照样建树;界面创建/销毁都不影响红点状态;
  • 一个 id 对应一个 UI;每次 bind 都 instantiate 一份样式;owner 销毁时自动退绑;
  • 已读由红点自己记(ReddotModule + @Persistent)—— 业务模块不用维护任何"读没读"。

接口

| 接口 | 说明 | | --- | --- | | Reddot.trigger(path) | 触发(有新东西了);路径不存在会自动建;幂等 | | Reddot.markRead(path) | 玩家看过了:灭 + 记已读(跟着存档走) | | Reddot.markReadTree(prefix) | 一条链下的叶子全标已读(顶层"全部已读") | | Reddot.clear(path) | 熄灭但不记已读(数据还在、只是不再提示) | | Reddot.remove(path) | 数据没了:摘掉(空祖先一并上收) | | Reddot.get(path) / find(path) / listNodes() | 读状态 / 取节点 / 列全部(调试、体检用) | | Reddot.addStyle(name, path) | 注册样式(路径相对 resources,不带扩展名) | | Reddot.bind(path, owner, align?, offset?, style?) | 挂红点;九宫格对齐 + 偏移 | | Reddot.unbind(path) | 解绑(一般不用手调:owner 销毁会自动退) |

文件

| 文件 | 说明 | | --- | --- | | ReddotCore.ts | 纯逻辑(不 import cc,可在 Node 里单测) | | Reddot.ts | 表现层:addStyle / bind / 九宫格对齐 / owner 销毁自动退绑 | | ReddotModule.ts | 模块 + Model:@Persistent readPaths,已读持久化 |

两个坑(都实测踩过)

  1. 工作区里别按包名引框架/公共模块 —— 会加载第二份实例: A Class already exists with the same __cid__ 或红点报"没有这个节点(已有的:空)" ✓ (开发工作区里一律用相对路径,构建期会自动改写成包名 ✓)
  2. 不要把工程建在框架仓库内部 —— 仓库根有一个 @ccgf/framework 的链接, 工程在里面会同时解析到两份框架 ✓