Skip to content

Commit 86741b5

Browse files
committed
Redesign open source contribution cards
1 parent e7aab54 commit 86741b5

3 files changed

Lines changed: 74 additions & 31 deletions

File tree

‎app/globals.css‎

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -290,19 +290,36 @@ html.is-at-top .nav-contact:hover, html.is-at-top .nav-contact:focus-visible { b
290290
.project-arrow { position: absolute; top: 35px; right: 14px; color: var(--blue); transition: transform 180ms ease; }
291291
.project-row:hover .project-arrow { transform: translate(4px, -4px); }
292292

293-
.opensource-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); border-top: 1px solid var(--line-strong); border-left: 1px solid var(--line); }
294-
.opensource-row { position: relative; display: grid; grid-template-columns: 30px 42px 150px minmax(0, 0.8fr) minmax(0, 1.35fr) 20px; gap: 12px; align-items: start; min-height: 160px; padding: 23px 18px; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--white); transition: color 180ms ease, background 180ms ease, transform 180ms ease; }
295-
.opensource-row:hover { z-index: 2; color: var(--blue); background: #f8faff; transform: translateY(-3px); }
296-
.opensource-row > span { color: var(--blue); font-family: var(--font-geist-mono), monospace; font-size: 9px; }
297-
.opensource-row > img { width: 42px; height: 42px; padding: 5px; border: 1px solid var(--line); background: var(--white); object-fit: contain; }
298-
.opensource-name h3 { margin: 0; color: var(--ink); font-size: 15px; line-height: 1.35; }
299-
.opensource-name small { display: block; margin-top: 7px; color: var(--blue); font-family: var(--font-geist-mono), monospace; font-size: 8px; }
300-
.repo-stars { display: inline-flex; align-items: center; gap: 5px; width: fit-content; margin-top: 10px; color: #875800; font-family: var(--font-geist-mono), monospace; font-size: 8px; font-weight: 750; white-space: nowrap; }
301-
.repo-stars svg { width: 11px; height: 11px; color: var(--orange); }
302-
.opensource-row > p { margin: 0; color: #4b5565; font-size: 10px; line-height: 1.6; }
303-
.opensource-row > p strong { display: block; margin-bottom: 4px; color: var(--ink); font-size: 9px; }
304-
.opensource-row > svg { color: var(--blue); transition: transform 180ms ease; }
305-
.opensource-row:hover > svg { transform: translate(3px, -3px); }
293+
.opensource-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); border-top: 1px solid var(--line-strong); border-left: 1px solid var(--line); }
294+
.opensource-card { position: relative; isolation: isolate; min-height: 348px; overflow: hidden; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--white); transition: border-color 260ms ease, box-shadow 320ms ease, transform 360ms cubic-bezier(0.22, 1, 0.36, 1); }
295+
.opensource-card::before { position: absolute; z-index: -1; inset: 0; background: linear-gradient(145deg, #ffffff 0%, #f4f7ff 44%, #e9f1ff 100%); content: ""; opacity: 0; transition: opacity 360ms ease; }
296+
.opensource-card::after { position: absolute; z-index: 3; top: 0; right: 0; left: 0; height: 3px; background: linear-gradient(90deg, var(--blue), #6f9dff 62%, #b5caff); content: ""; transform: scaleX(0); transform-origin: left; transition: transform 420ms cubic-bezier(0.22, 1, 0.36, 1); }
297+
.opensource-card:hover, .opensource-card:focus-visible { z-index: 2; border-color: #a9c0ea; box-shadow: 0 20px 42px rgba(21, 94, 239, 0.14); transform: translateY(-7px); }
298+
.opensource-card:hover::before, .opensource-card:focus-visible::before { opacity: 1; }
299+
.opensource-card:hover::after, .opensource-card:focus-visible::after { transform: scaleX(1); }
300+
.opensource-face { position: absolute; inset: 0; display: grid; padding: 24px; transition: opacity 260ms ease, transform 420ms cubic-bezier(0.22, 1, 0.36, 1), filter 260ms ease; }
301+
.opensource-front { grid-template-rows: auto 1fr auto; opacity: 1; transform: translateY(0); }
302+
.opensource-back { grid-template-rows: auto 1fr auto; background: linear-gradient(160deg, rgba(255, 255, 255, 0.88), rgba(235, 242, 255, 0.96)); opacity: 0; transform: translateY(28px); }
303+
.opensource-card:hover .opensource-front, .opensource-card:focus-visible .opensource-front { opacity: 0; filter: blur(2px); transform: translateY(-24px) scale(0.985); }
304+
.opensource-card:hover .opensource-back, .opensource-card:focus-visible .opensource-back { opacity: 1; transform: translateY(0); }
305+
.opensource-card-top { display: flex; align-items: center; justify-content: space-between; gap: 18px; }
306+
.opensource-card-top > img { width: 48px; height: 48px; padding: 7px; border: 1px solid var(--line); background: var(--white); object-fit: contain; }
307+
.repo-stars { display: inline-flex; align-items: center; gap: 6px; width: fit-content; color: #875800; font-family: var(--font-geist-mono), monospace; font-size: 9px; font-weight: 750; white-space: nowrap; }
308+
.repo-stars svg { width: 12px; height: 12px; color: var(--orange); }
309+
.opensource-project { align-self: center; padding: 28px 0 18px; }
310+
.opensource-project small { display: block; color: var(--blue); font-family: var(--font-geist-mono), monospace; font-size: 8px; font-weight: 750; letter-spacing: 0.11em; }
311+
.opensource-project h3 { margin: 9px 0 0; color: var(--ink); font-size: 20px; letter-spacing: -0.025em; line-height: 1.25; }
312+
.opensource-project p { margin: 16px 0 0; color: #4b5565; font-size: 12px; line-height: 1.72; }
313+
.opensource-card-link { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 15px; color: var(--blue); font-family: var(--font-geist-mono), monospace; font-size: 9px; font-weight: 750; border-top: 1px solid var(--line); }
314+
.opensource-card-link svg { width: 15px; height: 15px; transition: transform 220ms ease; }
315+
.opensource-card:hover .opensource-card-link svg, .opensource-card:focus-visible .opensource-card-link svg { transform: translate(3px, -3px); }
316+
.opensource-back-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding-bottom: 13px; border-bottom: 1px solid #c9d7ed; }
317+
.opensource-back-head strong { color: var(--ink); font-size: 12px; line-height: 1.3; }
318+
.opensource-back-head span { color: var(--blue); font-family: var(--font-geist-mono), monospace; font-size: 7px; font-weight: 750; letter-spacing: 0.08em; white-space: nowrap; }
319+
.opensource-story { display: grid; align-content: center; gap: 12px; padding: 13px 0; }
320+
.opensource-story > div { display: grid; grid-template-columns: 54px minmax(0, 1fr); gap: 9px; align-items: start; }
321+
.opensource-story span { padding-top: 2px; color: var(--blue); font-size: 9px; font-weight: 750; }
322+
.opensource-story p { margin: 0; color: #3f4b5d; font-size: 10px; line-height: 1.58; }
306323

307324
.contact-section { position: relative; isolation: isolate; overflow: hidden; padding: 96px 0 30px; color: var(--ink); background: var(--white); }
308325
.contact-section::before, .contact-section::after { content: none; }
@@ -345,8 +362,7 @@ html.is-at-top .nav-contact:hover, html.is-at-top .nav-contact:focus-visible { b
345362
.paper-detail { padding-left: 180px; }
346363
.project-row { grid-template-columns: 54px 250px minmax(0, 1fr); }
347364
.metric-grid { grid-column: 2 / -1; }
348-
.opensource-row { grid-template-columns: 26px 40px 130px minmax(0, 1fr) 18px; }
349-
.opensource-row > p:first-of-type { display: none; }
365+
.opensource-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
350366
}
351367

352368
@media (min-width: 1161px) {
@@ -389,7 +405,7 @@ html.is-at-top .nav-contact:hover, html.is-at-top .nav-contact:focus-visible { b
389405
.workstream-card { min-height: 0; }
390406
.project-row { grid-template-columns: 48px 1fr; padding-right: 45px; }
391407
.project-copy, .metric-grid { grid-column: 2; }
392-
.opensource-grid { grid-template-columns: 1fr; }
408+
.opensource-face { padding: 22px; }
393409
.contact-layout { grid-template-columns: 1fr; gap: 54px; }
394410
}
395411

@@ -435,8 +451,9 @@ html.is-at-top .nav-contact:hover, html.is-at-top .nav-contact:focus-visible { b
435451
.metric-grid { grid-template-columns: 1fr; border-top: 1px solid var(--line); border-left: 0; }
436452
.metric-grid-split > div { grid-column: auto; grid-row: auto; }
437453
.metric-grid > div { min-height: 58px; border-right: 0; border-bottom: 1px solid var(--line); }
438-
.opensource-row { grid-template-columns: 24px 38px 1fr 18px; }
439-
.opensource-row > p { grid-column: 3 / -1; }
454+
.opensource-grid { grid-template-columns: 1fr; }
455+
.opensource-card { min-height: 330px; }
456+
.opensource-face { padding: 22px 20px; }
440457
.contact-section { padding-top: 78px; }
441458
.contact-section h2 { font-size: 39px; }
442459
.contact-section footer { align-items: flex-start; flex-direction: column; gap: 9px; margin-top: 65px; }

‎app/open-source-grid.tsx‎

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ type OpenSourceItem = {
88
logo: string;
99
href: string;
1010
function: string;
11-
contribution: string;
11+
problem: string;
12+
reasoning: string;
13+
solution: string;
1214
};
1315

1416
const cacheDuration = 30 * 60 * 1000;
@@ -74,8 +76,32 @@ export default function OpenSourceGrid({ items }: { items: OpenSourceItem[] }) {
7476
return difference || left.originalIndex - right.originalIndex;
7577
}), [items, stars]);
7678

77-
return <div className="opensource-grid" data-reveal>{orderedItems.map(({ item }, index) => {
79+
return <div className="opensource-grid" data-reveal>{orderedItems.map(({ item }) => {
7880
const count = stars?.[item.href];
79-
return <a className="opensource-row" href={item.href} key={item.name} target="_blank" rel="noopener noreferrer"><span>{String(index + 1).padStart(2, '0')}</span><img src={item.logo} alt="" /><div className="opensource-name"><h3>{item.name}</h3><small>Contributor</small><span className="repo-stars" title={typeof count === 'number' ? `${count.toLocaleString('en-US')} GitHub Stars` : '正在获取 GitHub Star'}><PiStarFill aria-hidden="true" />{typeof count === 'number' ? `${formatStars(count)} Stars` : 'Stars'}</span></div><p><strong>项目功能</strong>{item.function}</p><p><strong>我的贡献</strong>{item.contribution}</p><PiArrowUpRightBold aria-hidden="true" /></a>;
81+
const starsLabel = typeof count === 'number' ? `${formatStars(count)} Stars` : 'Stars';
82+
83+
return <a className="opensource-card" href={item.href} key={item.name} target="_blank" rel="noopener noreferrer" aria-label={`前往 ${item.name} GitHub 项目`}>
84+
<div className="opensource-face opensource-front">
85+
<div className="opensource-card-top">
86+
<img src={item.logo} alt="" />
87+
<span className="repo-stars" title={typeof count === 'number' ? `${count.toLocaleString('en-US')} GitHub Stars` : '正在获取 GitHub Star'}><PiStarFill aria-hidden="true" />{starsLabel}</span>
88+
</div>
89+
<div className="opensource-project">
90+
<small>CONTRIBUTOR</small>
91+
<h3>{item.name}</h3>
92+
<p>{item.function}</p>
93+
</div>
94+
<div className="opensource-card-link"><span>查看我的贡献</span><PiArrowUpRightBold aria-hidden="true" /></div>
95+
</div>
96+
<div className="opensource-face opensource-back" aria-hidden="true">
97+
<div className="opensource-back-head"><strong>{item.name}</strong><span>ENGINEERING NOTE</span></div>
98+
<div className="opensource-story">
99+
<div><span>发现问题</span><p>{item.problem}</p></div>
100+
<div><span>问题思考</span><p>{item.reasoning}</p></div>
101+
<div><span>解决方法</span><p>{item.solution}</p></div>
102+
</div>
103+
<div className="opensource-card-link"><span>前往 GitHub 项目</span><PiArrowUpRightBold aria-hidden="true" /></div>
104+
</div>
105+
</a>;
80106
})}</div>;
81107
}

‎app/page.tsx‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -147,16 +147,16 @@ const projects = [
147147
];
148148

149149
const openSource = [
150-
{ name: 'LM Evaluation Harness', logo: 'https://github.com/EleutherAI.png?size=128', href: 'https://github.com/EleutherAI/lm-evaluation-harness', function: '统一模型、任务、few-shot、生成参数与推理后端的大语言模型评测框架。', contribution: '修复 postponed annotations 下 f.type is dict 恒为假的配置解析缺陷,改用 DICT_KEYS 统一识别字典字段,并将 YAML 字符串规范化前移到共享配置流水线,使 CLI 与纯 YAML 入口行为一致。' },
151-
{ name: 'NumPyro', logo: 'https://github.com/pyro-ppl.png?size=128', href: 'https://github.com/pyro-ppl/numpyro', function: '基于 JAX 的概率编程与贝叶斯推断框架,支持 HMC、NUTS、SVI 及跨设备加速。', contribution: '修复 JAX 0.11.1 闭包常量导致的 provenance 输入错位,使用公共 jax.make_jaxpr 获取 ClosedJaxpr,分离常量与动态输入并移除对私有 tracing API 的耦合。' },
152-
{ name: 'OpenCV', logo: '/logos/opencv.svg', href: 'https://github.com/opencv/opencv', function: '跨平台计算机视觉与图像处理基础库。', contribution: '将极端反射坐标的逐次循环改为 int64 周期模运算,修复溢出与十亿级循环,将最坏复杂度从 O(N) 降为 O(1)。' },
153-
{ name: 'OpenAI Agents SDK', logo: '/logos/openai.png', href: 'https://github.com/openai/openai-agents-python', function: '面向生产级多 Agent 编排的轻量工作流框架。', contribution: '修复同名 Agent、Tool 与 MCP Server 在 Graphviz 中被合并或形成伪自环的问题,以实体身份解耦显示名与节点标识。' },
154-
{ name: 'PEFT', logo: '/logos/huggingface.png', href: 'https://github.com/huggingface/peft', function: 'Transformer 与 Diffusion 模型的参数高效微调框架。', contribution: '阻止重复 adapter_name 静默覆盖配置并重新注入层,将校验前移到任何状态修改之前,保护已训练权重。' },
155-
{ name: 'Ultralytics YOLO', logo: '/logos/ultralytics.png', href: 'https://github.com/ultralytics/ultralytics', function: '覆盖检测、分割、分类、姿态与跟踪的视觉平台。', contribution: '修复非等比例预处理后的坐标反变换失真,组合前置 resize 与 LetterBox 的 x/y 双轴比例分轴恢复坐标。' },
156-
{ name: 'timm', logo: '/logos/huggingface.png', href: 'https://github.com/huggingface/pytorch-image-models', function: '大规模 PyTorch 图像模型与训练工具库。', contribution: '修正 CutMix minmax 边界采样 off-by-one,补回最右与最下合法裁剪起点,消除边界位置分布偏差。' },
157-
{ name: 'Supervision', logo: '/logos/supervision.png', href: 'https://github.com/roboflow/supervision', function: '检测结果处理、标注、几何计算与视频分析工具库。', contribution: '修复大坐标多边形质心计算中的 int32 溢出与浮点消减,通过 float64 与局部坐标系提升数值稳定性。' },
158-
{ name: 'FunASR', logo: '/logos/funasr.png', href: 'https://github.com/modelscope/FunASR', function: '支持训练、推理、流式识别与说话人日志的 ASR 工具箱。', contribution: '为已知说话人数的大输入新增归一化、确定性固定 K K-means 路径,绕开 O(N²) 稠密谱聚类。' },
159-
{ name: 'Burn', logo: '/logos/burn.png', href: 'https://github.com/tracel-ai/burn', function: '面向跨平台训练与推理的 Rust 深度学习框架。', contribution: '修复卷积快速路径在 Inf / NaN 权重下与通用路径不一致的 IEEE 754 语义,同时保留有限权重的向量化热路径。' },
150+
{ name: 'LM Evaluation Harness', logo: 'https://github.com/EleutherAI.png?size=128', href: 'https://github.com/EleutherAI/lm-evaluation-harness', function: '统一模型、任务、few-shot、生成参数与推理后端的大语言模型评测框架。', problem: '延迟注解使 dataclass 字段类型不再等同于运行时 dict,CLI 与 YAML 两条配置入口行为不一致。', reasoning: '定位到 f.type is dict 恒为假,核心不是单个配置,而是共享规范化边界缺失。', solution: '用 DICT_KEYS 统一识别字典字段,并将 YAML 字符串规范化前移到共享配置流水线。' },
151+
{ name: 'NumPyro', logo: 'https://github.com/pyro-ppl.png?size=128', href: 'https://github.com/pyro-ppl/numpyro', function: '基于 JAX 的概率编程与贝叶斯推断框架,支持 HMC、NUTS、SVI 及跨设备加速。', problem: 'JAX 0.11.1 将闭包常量提升进 jaxpr 后,provenance 动态输入与变量发生错位。', reasoning: '问题来自私有 tracing API 对常量布局的隐式假设,需要显式拆分常量与动态参数。', solution: '改用公共 jax.make_jaxpr 获取 ClosedJaxpr,重建输入映射并解除私有 API 耦合。' },
152+
{ name: 'OpenCV', logo: '/logos/opencv.svg', href: 'https://github.com/opencv/opencv', function: '跨平台计算机视觉与图像处理基础库。', problem: '极端反射坐标在逐次修正中触发整数溢出,并可能执行十亿级循环。', reasoning: '反射边界本质是周期映射,可以一次定位,无需模拟每一次反射。', solution: '改为 int64 周期模运算,在完整坐标域内把最坏复杂度从 O(N) 降至 O(1)。' },
153+
{ name: 'OpenAI Agents SDK', logo: '/logos/openai.png', href: 'https://github.com/openai/openai-agents-python', function: '面向生产级多 Agent 编排的轻量工作流框架。', problem: '同名 Agent、Tool 与 MCP Server 以显示名为键,导致 Graphviz 合并节点或产生伪自环。', reasoning: '显示标签不等于实体身份,图遍历与节点注册必须分离可读名称和唯一标识。', solution: '以对象身份注册节点,显示名仅作为 label,并重构遍历与边生成链路。' },
154+
{ name: 'PEFT', logo: '/logos/huggingface.png', href: 'https://github.com/huggingface/peft', function: 'Transformer 与 Diffusion 模型的参数高效微调框架。', problem: '重复 adapter_name 会静默覆盖配置并再次注入层,已有训练权重存在被破坏风险。', reasoning: '这是状态原子性问题,重复校验必须发生在任何模型或配置突变之前。', solution: '将唯一性校验前移,冲突时立即失败,确保失败路径不修改既有 Adapter 状态。' },
155+
{ name: 'Ultralytics YOLO', logo: '/logos/ultralytics.png', href: 'https://github.com/ultralytics/ultralytics', function: '覆盖检测、分割、分类、姿态与跟踪的计算机视觉平台。', problem: '非等比例 resize 与 LetterBox 组合后仍按单一比例恢复坐标,导致预测框位置失真。', reasoning: 'x、y 轴经历不同缩放和留白,逆变换必须沿完整预处理链逐轴求逆。', solution: '组合前置 resize 与 LetterBox 参数,使用双轴比例和偏移恢复原图坐标。' },
156+
{ name: 'timm', logo: '/logos/huggingface.png', href: 'https://github.com/huggingface/pytorch-image-models', function: '大规模 PyTorch 图像模型、预训练权重与训练工具库。', problem: 'CutMix minmax 边界使用上界排除采样,遗漏最右与最下的合法裁剪起点。', reasoning: '这是离散坐标区间的 off-by-one,会长期造成位置分布偏差而非直接崩溃。', solution: '修正采样上界并补齐边界位置,恢复覆盖全部合法区域的均匀采样。' },
157+
{ name: 'Supervision', logo: '/logos/supervision.png', href: 'https://github.com/roboflow/supervision', function: '检测结果处理、标注、几何计算与视频分析工具库。', problem: '大坐标多边形计算质心时出现 int32 溢出与浮点消减,结果漂移甚至失真。', reasoning: '面积矩依赖坐标乘积,只提升精度仍不足以消除大基数带来的数值损失。', solution: '统一使用 float64 与局部坐标系完成计算,最后再映射回全局坐标。' },
158+
{ name: 'FunASR', logo: '/logos/funasr.png', href: 'https://github.com/modelscope/FunASR', function: '支持训练、推理、流式识别与说话人日志的语音识别工具箱。', problem: '已知说话人数的大输入仍进入谱聚类,O(N²) 相似矩阵造成显著内存开销。', reasoning: '已知 K 时无需再估计簇数,可按规模与先验选择更直接、可重复的聚类路径。', solution: '新增归一化、确定性固定 K K-means 分支,让大输入绕开稠密谱分解。' },
159+
{ name: 'Burn', logo: '/logos/burn.png', href: 'https://github.com/tracel-ai/burn', function: '面向跨平台模型训练与推理的 Rust 深度学习框架。', problem: '卷积快速路径对 Inf / NaN 权重的处理与通用实现不一致,破坏 IEEE 754 语义。', reasoning: '不能用全面回退牺牲有限权重性能,需要只在非有限值分支守住正确性。', solution: '为非有限权重选择语义一致的路径,同时保留普通权重的向量化热路径。' },
160160
];
161161

162162
function SectionHeading({ index, label, english }: { index: string; label: string; english: string }) {

0 commit comments

Comments
 (0)