我用 WorkBuddy 做了个「GitHub 考古所」:输入一个用户名,出土你的编程人格档案

我用 WorkBuddy 做了个「GitHub 考古所」:输入一个用户名,出土你的编程人格档案

在线体验:github-archaeology.app.workbuddy.host/?sharecode=...

不用登录,只读 GitHub 公开数据,全部计算在浏览器本地完成。

写了这么多年代码,你有没有想过,自己的 GitHub 账号其实是一座遗址?

哪些仓库是最早的地层,哪个是你最重的藏品,你习惯几点提交,有没有给变量乱起过名------这些痕迹都留在里面,只是从来没人替你挖一遍。

这个 1024,我用 WorkBuddy 做了个「GitHub 考古所」。输入一个 GitHub 用户名,它把你的仓库当考古现场翻一遍,最后出土一份《编程人格档案》。


它挖了些什么

档案分四块。

一、语言年轮

把有推送的仓库按语言分类,画成环形图,占比精确合到 100%。

示例账号 18 个仓库:JavaScript 33%、TypeScript 17%、Vue 11%、HTML 11%、Python 6%、其他 22%。是偏科还是万金油,一眼就看出来。

二、四维探方

四个维度,每一项旁边都标了计算依据,不是拍脑袋给分:

维度 算法 示例值
夜行指数 提交时间的小时分布,深夜占比越高分越高 92
命名洁癖 命名规范的仓库数 / 仓库总数 14/18 → 78
涉猎广度 语言种类数 + 仓库规模 9 种语言 / 18 个仓库 → 100
开源社交 关注者与 Star 的量级 128 关注 / 268 星 → 85

三、出土器物

自动挖出四个"文物":最古老的一层、最重的藏品、最亮的展品、命名化石。

示例账号挖出来的是:最早 7 年前的 untitled-game、24.2MB 的 dm-supply-next、86 星的 juejin-csdn-extension,还有那个一看就是凌晨三点随手敲的 test。

说实话,看到自己第一个仓库叫 untitled-game 的时候,是有点恍惚的。

四、编程人格 + 判词

四维分数组合成 16 型里的一种,配一句判词。示例账号是「夜掘·地层编年史官」:

「你把每个深夜都折进仓库,用 commit 给时间做碳十四测年。」

最后可以一键导出 1080×1440 的档案卡,带印章、带话题标签。


几个值得说的实现决策

1. 先定隐喻,再定功能

一开始列的功能清单很无聊:统计语言、统计仓库数、算活跃度。做完自己都不想看。

后来换了个思路:把数据当成一个已经埋在地下的遗址,我做的是发掘和断代,不是做报表。

这一下结构就清楚了------仓库是地层,语言是年轮,仓库体积是器物,提交时间是作息剖面。连页面的牛皮纸底纹、印章、"档案编号 No. CA-ARCHAE-1150",都是从这一个比喻里长出来的。

信息架构的本质不是功能分类,是给用户一个能记住的解释框架。 比喻先定,剩下的都是填细节。

2. 只读三个公开接口,全部本地计算

不申请 OAuth,不要任何授权,就三个公开端点,Promise.all 并发拿:

js 复制代码
async function fetchGithub(username){
  const base = "https://api.github.com";
  const headers = { "Accept": "application/vnd.github+json" };

  const [pr, rr, er] = await Promise.all([
    fetch(`${base}/users/${encodeURIComponent(username)}`, { headers }),
    fetch(`${base}/users/${encodeURIComponent(username)}/repos?per_page=100&sort=pushed`, { headers }),
    // events 是可选数据源,失败不该拖垮整个流程
    fetch(`${base}/users/${encodeURIComponent(username)}/events/public?per_page=100`, { headers })
      .catch(() => null)
  ]);

  if (pr.status === 404) throw new Error("NOT_FOUND");
  if (pr.status === 403 || pr.status === 429) throw new Error("RATE_LIMIT");
  if (!pr.ok) throw new Error("API_FAIL");

  const profile = await pr.json();
  const repos  = rr.ok ? await rr.json() : [];
  const events = (er && er.ok) ? await er.json().catch(() => []) : [];

  return { profile, repos, events };
}

两个细节:

  • events 单独 catch 。/events/public 对某些账号返回空数组甚至失败,但它只影响"夜行指数"这一项,不该让整个档案挂掉,所以降级成空数组。
  • 错误要分级 。404 是用户不存在,403/429 是限流,提示语完全不同------前者该让用户检查拼写,后者该告诉他"等一会儿再来"。

3. 分享卡:Canvas 导出 + 绕开画布污染

把头像画进 Canvas 再 toBlob 导出,是这类"生成图片"需求的标准做法,也是标准坑:

js 复制代码
const img = new Image();
img.crossOrigin = "anonymous";   // 关键:不加这行,canvas 会被标记为污染
img.src = avatarUrl;             // GitHub 头像走 CDN,需要 CORS 放行

img.onload = () => {
  // 统一做旧:灰度 + 降对比 + 轻微 sepia,和牛皮纸底纹统一
  ctx.filter = "grayscale(.35) contrast(1.05) sepia(.12)";
  ctx.drawImage(img, x, y, w, h);
};

// 导出
canvas.toBlob(done, "image/png");

示例账号那头像我干脆转成 base64 内嵌进 HTML 了------顺带解决了断网、限流时示例档案缺头像的问题,一举两得。

4. 单文件 HTML,零依赖零构建

整个应用就是一个 71KB 的 index.html,原生 JS,不引任何 CDN、不用打包工具、字体全走系统字体。

好处很直接:发布即上线,改一行重新发布就行,链接不变。也避免了"高峰期 CDN 挂了、字体没加载出来、页面样式全崩"这类在分享场景特别致命的问题。

bash 复制代码
code-archaeologist/
├── index.html          # 单文件应用,双击即可打开
├── assets/
│   └── demo-avatar.png # 演示头像(已内嵌进 HTML)
└── screenshots/

想本地跑,下载 index.html 双击就行,不需要起服务。


踩的两个坑

第一是匿名接口限流。 GitHub 未认证请求每小时只有 60 次,超了直接 403。所以除了分级报错,还做了离线兜底:接口不可用时可以切到内置示例档案,保证打开的人永远有东西看,不会对着白屏。

第二是画布污染。 就是上面那段 crossOrigin。值得一提的是它有个隐蔽点:图片加载成功、但没设 crossOrigin 时,drawImage 不报错,直到 toBlob 才抛 SecurityError,报错位置和真正原因隔了好几行,第一次很容易查错方向。

这两件事都不难,但都属于"不实际跑一遍就发现不了"的类别。用 WorkBuddy 做的好处是它可以直接跑一遍再报错,比自己盲改快很多。


关于隐私

这个工具只读三个公开接口,不涉及任何授权登录。拿到的数据全部在浏览器本地计算和渲染,不上传、不落库、不留存。关掉页面,什么都没留下。

如果你也在做读取用户第三方数据的工具,这条建议值得抄:能不申请授权就不申请。只读公开数据的方案,隐私说明一句话就能写完,用户的心理门槛也低得多。


最后

想看自己是什么人格,点这里直接测,三秒出结果:

github-archaeology.app.workbuddy.host/?sharecode=...

也可以直接拼用户名,打开就是他自己的档案:

ini 复制代码
https://github-archaeology.app.workbuddy.host/?sharecode=HVE7YZLNGQ&u=你的GitHub用户名

测完欢迎在评论区报一下你的人格式,我挺想知道「夜掘·地层编年史官」到底有多少同款。


本文作品参加 WorkBuddy「1024 造物挑战」程序员节应用创作大赛。

技术栈:单文件 HTML + 原生 JS | GitHub REST API | Canvas 2D

相关推荐
乘风gg1 小时前
AI coding 时代最值钱的东西,软件工程(下)
前端·ai编程·claude
用户11481867894841 小时前
虚拟滚动与无限滚动的完整心法
前端
核验笔记的老王1 小时前
前端表单防呆实践:如何排查自动填充导致的提交失败?
前端
用户406122081111 小时前
Vue vs React 核心差异全对比
前端
李纲明1 小时前
微信小程序 web-view 打开空白或提示未配置业务域名:校验文件、HTTPS 与跳转域名排查
前端·微信小程序·https·web-view·小程序开发·业务域名
涛涛ing1 小时前
一个框架为了“不水合”,把HTML注释都删了
前端
计算机魔术师2 小时前
AI渗透框架3小时破云,中国黑客组织正在升级打法
前端
蒲公英内测分发2 小时前
智能手环出海测试,海外合作方分散在不同国家,Android 测试包怎么持续分发和更新?
android·前端·人工智能·测试工具·智能手表