[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-81010":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":12,"contributorsCount":12,"subscribersCount":12,"size":12,"stars1d":14,"stars7d":14,"stars30d":15,"stars90d":12,"forks30d":12,"starsTrendScore":16,"compositeScore":12,"rankGlobal":9,"rankLanguage":9,"license":17,"archived":18,"fork":18,"defaultBranch":19,"hasWiki":20,"hasPages":20,"topics":21,"createdAt":9,"pushedAt":9,"updatedAt":29,"readmeContent":30,"aiSummary":31,"trendingCount":12,"starSnapshotCount":12,"syncStatus":32,"lastSyncTime":33,"discoverSource":34},81010,"github-readme-crisp-links","aza-ali\u002Fgithub-readme-crisp-links","aza-ali","🌈 Cleaner GitHub README link text. CLI + web app.",null,"Python",33,0,29,1,4,3,"MIT License",false,"main",true,[22,23,24,25,26,27,28],"cli","github-profile","github-readme","markdown","python","readme-template","svg","2026-06-12 02:04:09","# Crisp Links for GitHub READMEs\n\n\u003Ca href=\"https:\u002F\u002Faza-ali.github.io\u002Fgithub-readme-crisp-links\u002F\">\u003Cimg src=\"examples\u002Fbefore-after.png\" alt=\"Before and after\" \u002F>\u003C\u002Fa>\n\n\u003Ca href=\"https:\u002F\u002Faza-ali.github.io\u002Fgithub-readme-crisp-links\u002F\">\u003Cimg src=\"examples\u002Ftry-in-browser.svg?v=6\" align=\"absmiddle\" alt=\"Try it in your browser\" \u002F>\u003C\u002Fa>· pick a color or gradient, copy the markdown, paste into your README. No install required.\n\nGitHub's README CSS forces an underline on any `\u003Ca>` tag that contains text. That underline looks fine inline, but it makes project lists feel cluttered, especially when each entry already has an icon, a name, and a description. There's no markdown switch to turn it off. Inline `style=` is stripped. `\u003Cfont>` is stripped. `text-decoration: none` is stripped.\n\nWhat's *not* stripped: an `\u003Ca>` containing only `\u003Cimg>` elements. No text node, no underline. So if you render the project name as an SVG and drop the SVG inside the link, the underline goes away and the rest of the styling stays clean. You also get control of the color — pick whatever fits your project's brand instead of GitHub's default link blue.\n\nThis is a small Python CLI (and a [web app](https:\u002F\u002Faza-ali.github.io\u002Fgithub-readme-crisp-links\u002F)) that does that for you. It measures the width of your project name against Helvetica Bold (so the SVG canvas fits the glyphs without clipping or padding), writes the SVG, and prints the markdown snippet ready to paste into your README.\n\n## Install\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Faza-ali\u002Fgithub-readme-crisp-links.git\ncd github-readme-crisp-links\npip install -r requirements.txt\n```\n\nPillow is the only dependency. Tested on Python 3.8+.\n\n## Usage\n\nOne-off:\n\n```bash\npython3 crisp.py \"Retina\" --color D97757 --link https:\u002F\u002Fblendpixel.com\u002Fproducts\u002Fretina\n```\n\nOutput:\n\n```\nwrote retina.svg (59x22)\n\u003Ca href=\"https:\u002F\u002Fblendpixel.com\u002Fproducts\u002Fretina\">\u003Cimg src=\"retina.svg\" align=\"absmiddle\" alt=\"Retina\" \u002F>\u003C\u002Fa>\n```\n\nThe SVG is written to `retina.svg` and the snippet is printed to stdout. Paste the snippet into your README.\n\nMultiple at once via a JSON batch file:\n\n```bash\npython3 crisp.py --batch projects.json\n```\n\nWhere `projects.json` is an array of items, each item supporting any of: `name`, `color`, `gradient`, `gradient_angle`, `output`, `link`, `font`, `font_size`, `font_weight`, `height`, `leading`, `trailing`. CLI flags act as defaults; per-item fields override. See `examples\u002Fprojects.json`.\n\n### Gradients\n\nSingle-color SVGs are good, but the same SVG-as-link trick gives you gradients for free:\n\n```bash\npython3 crisp.py \"Pixelfox\" --gradient rainbow\npython3 crisp.py \"Drift\"    --gradient dusk --link https:\u002F\u002Fexample.com\npython3 crisp.py \"Echo\"     --gradient \"DC2626,F59E0B,EC4899\" --gradient-angle 90\n```\n\nPresets: `rainbow`, `sunset`, `ocean`, `mint`, `candy`, `dusk`. Custom: comma-separated hex codes (any number of stops). Angle uses CSS conventions (0=up, 90=right, 180=down, 270=left).\n\nGradient SVGs use **vector-path rendering**: the CLI bakes the glyph outlines into the SVG as `\u003Cpath>` data via fontTools, then fills with a `userSpaceOnUse` gradient. This avoids the fuzzy edges browsers produce when applying gradients to `\u003Ctext>` elements at small sizes (the OS text rasterizer can't handle multi-color fills, so it falls back to a lower-quality path rasterizer that loses font hinting). Solid colors still use `\u003Ctext>` because the native rasterizer is sharper for single-color text.\n\n## Options\n\n| Flag | Default | What it does |\n|---|---|---|\n| `name` | required | The text to render. |\n| `--color` | `0969DA` | Hex color of the text. Accepts `RRGGBB` or `#RRGGBB`, 3 or 6 digit. Ignored if `--gradient` is set. |\n| `--gradient` | none | Preset name (`rainbow`, `sunset`, `ocean`, `mint`, `candy`, `dusk`) or comma-separated hex codes. |\n| `--gradient-angle` | `90` | Gradient direction in degrees, CSS-style. `0`=top→bottom, `90`=left→right (default), `180`=bottom→top, `270`=right→left. |\n| `--output` | `\u003Cslug>.svg` | SVG output path. Slugified from the name if not provided. |\n| `--link` | none | Wrap the snippet in `\u003Ca href=\"...\">`. |\n| `--font` | auto-detect | Path to a TTF\u002FOTF\u002FTTC. Default tries Helvetica Bold, then DejaVu Sans Bold, then Arial Bold. |\n| `--font-size` | `16` | Font size in px. |\n| `--font-weight` | `600` | Font weight on the SVG `\u003Ctext>`. |\n| `--height` | `22` | SVG canvas height. The default leaves a few px of breathing room above and below the glyphs. |\n| `--leading` | `6` | Left padding in px before the text starts. |\n| `--trailing` | `4` | Right padding in px after the text ends. |\n| `--batch` | none | JSON array of items. |\n| `--quiet` | off | Suppress the stdout snippet. |\n\n## Why other \"fixes\" don't work\n\nIf you go looking for ways to remove README link underlines, you'll find a lot of suggestions that quietly fail because GitHub's markdown sanitizer is strict. Things I tried before landing on the SVG trick:\n\n- **Inline `style=` attributes.** Stripped on render. `\u003Ca href=\"...\" style=\"text-decoration:none\">name\u003C\u002Fa>` becomes `\u003Ca href=\"...\">name\u003C\u002Fa>`.\n- **`\u003Cfont color=\"...\">` tags.** Stripped completely.\n- **A `\u003Cstyle>` block at the top of the README.** Stripped. GitHub allows almost no inline CSS.\n- **HTML entities in the link text.** Doesn't matter, the underline applies to the `\u003Ca>` as a whole.\n- **`\u003Cpicture>` \u002F `\u003Csource>` with `srcset`.** Works for theme-aware images but doesn't help with text underline.\n- **Zero-width characters around the text.** Looks like cargo-cult magic and didn't change anything when I tested it.\n\nThe reason the SVG trick works: GitHub's primer CSS targets `.markdown-body a` and adds the underline. But the rule only paints text descendants. An `\u003Ca>` whose only descendant is an `\u003Cimg>` has no text to paint an underline under, so the link renders clean.\n\nIf the `\u003Ca>` contains *both* text and an image, you'll still get an underline under the text portion. That's why the snippet wraps a single `\u003Cimg>` only.\n\n## Width measurement\n\nThe CLI uses Pillow's `ImageFont.getlength()` to measure how wide the rendered text will be. By default it loads Helvetica Bold from your system (TTC index 1 on macOS) and measures against that.\n\nGitHub will display your SVG against the viewer's font stack at display time, which for most viewers is Helvetica or Arial. The two are close enough that the canvas fits without surprises. If you're using a long name or you notice clipping, bump `--trailing` by a few pixels.\n\nIf you'd rather calibrate against a different font (e.g., Inter Bold for parity with the rest of your site), pass `--font \u002Fpath\u002Fto\u002FInter-Bold.ttf`. The CLI will measure against that font for sizing, but the SVG itself still renders against the system font stack — Pillow's job is just to give you an accurate width.\n\n## Gotcha: GitHub camo caches your SVG aggressively\n\nOnce GitHub fetches your SVG through its image proxy, it caches the result hard. If you update the SVG and force-push, the README may keep showing the old version for hours.\n\nWorkarounds:\n\n1. Add a cache-busting query parameter when you reference the SVG: `\u003Cimg src=\"retina.svg?v=2\" ... \u002F>`. Bump the number when you update the file.\n2. Rename the file. `retina.svg` → `retina2.svg`.\n\nThe cache-buster is what I use on my own profile.\n\n## Gotcha: dark mode\n\nA single SVG has a single fill color. If you want one color in light mode and another in dark mode, GitHub supports `\u003Cpicture>` with `prefers-color-scheme`:\n\n```html\n\u003Ca href=\"https:\u002F\u002Fexample.com\">\n  \u003Cpicture>\n    \u003Csource media=\"(prefers-color-scheme: dark)\" srcset=\"my-project-dark.svg\" \u002F>\n    \u003Cimg src=\"my-project-light.svg\" align=\"absmiddle\" alt=\"my-project\" \u002F>\n  \u003C\u002Fpicture>\n\u003C\u002Fa>\n```\n\nGenerate two SVGs, one per theme, and reference both. This is also still text-free inside the `\u003Ca>`, so the underline still doesn't apply.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","该项目提供了一种清理GitHub README链接文本的方法，通过CLI和Web应用生成美观的SVG链接。核心功能是将项目名称渲染为SVG图像，并嵌入到Markdown链接中，从而去除默认的下划线并允许自定义颜色或渐变效果。技术上基于Python开发，依赖Pillow库处理图像，支持单次命令行调用或多条目JSON批量处理。适用于希望美化其GitHub个人资料页或项目README文件，同时保持页面整洁和品牌一致性的开发者。",2,"2026-06-11 04:03:10","CREATED_QUERY"]