@urmzd/github-insights 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/assets/insights/index.svg +1 -1
  3. package/assets/insights/metrics-constellation.svg +1 -1
  4. package/assets/insights/metrics-impact.svg +1 -1
  5. package/assets/insights/metrics-rhythm.svg +1 -1
  6. package/assets/insights/metrics-velocity.svg +1 -1
  7. package/examples/classic/README.md +16 -37
  8. package/examples/classic/index.svg +1 -1
  9. package/examples/classic/metrics-constellation.svg +1 -1
  10. package/examples/classic/metrics-impact.svg +1 -1
  11. package/examples/classic/metrics-rhythm.svg +1 -1
  12. package/examples/classic/metrics-velocity.svg +1 -1
  13. package/examples/ecosystem/README.md +51 -43
  14. package/examples/ecosystem/index.svg +1 -1
  15. package/examples/ecosystem/metrics-constellation.svg +1 -1
  16. package/examples/ecosystem/metrics-impact.svg +1 -1
  17. package/examples/ecosystem/metrics-rhythm.svg +1 -1
  18. package/examples/ecosystem/metrics-velocity.svg +1 -1
  19. package/examples/minimal/README.md +16 -37
  20. package/examples/minimal/index.svg +1 -1
  21. package/examples/minimal/metrics-constellation.svg +1 -1
  22. package/examples/minimal/metrics-impact.svg +1 -1
  23. package/examples/minimal/metrics-rhythm.svg +1 -1
  24. package/examples/minimal/metrics-velocity.svg +1 -1
  25. package/examples/modern/README.md +50 -74
  26. package/examples/modern/index.svg +1 -1
  27. package/examples/modern/metrics-constellation.svg +1 -1
  28. package/examples/modern/metrics-impact.svg +1 -1
  29. package/examples/modern/metrics-rhythm.svg +1 -1
  30. package/examples/modern/metrics-velocity.svg +1 -1
  31. package/package.json +1 -1
  32. package/src/templates.test.ts +17 -42
  33. package/src/templates.ts +142 -57
@@ -52,4 +52,4 @@
52
52
  .fade-4 { animation: fadeIn 0.6s ease-out 0.55s both; }
53
53
  .fade-5 { animation: fadeIn 0.6s ease-out 0.7s both; }
54
54
  .fade-6 { animation: fadeIn 0.6s ease-out 0.85s both; }
55
- </style></defs><rect width="808" height="250" rx="12" class="bg-fill" fill="#0d1117"/><text x="24" y="40" class="t t-h">LANGUAGE VELOCITY</text><text x="24" y="56" class="t t-sub">How language usage has evolved over the past year</text><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.24865831842575 150.66666666666669,205.24865831842575 C 182.33333333333334,205.24865831842575 182.33333333333334,204.4973166368515 214,204.4973166368515 C 245.66666666666669,204.4973166368515 245.66666666666669,205.49910554561717 277.33333333333337,205.49910554561717 C 309,205.49910554561717 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,195.98211091234347 404,195.98211091234347 C 435.6666666666667,195.98211091234347 435.6666666666667,203.9964221824687 467.33333333333337,203.9964221824687 C 499.00000000000006,203.9964221824687 499.00000000000006,198.23613595706618 530.6666666666667,198.23613595706618 C 562.3333333333334,198.23613595706618 562.3333333333334,204.4973166368515 594,204.4973166368515 C 625.6666666666667,204.4973166368515 625.6666666666667,157.66368515205724 657.3333333333334,157.66368515205724 C 689,157.66368515205724 689,87.28801431127013 720.6666666666667,87.28801431127013 C 752.3333333333334,87.28801431127013 752.3333333333334,66 784,66 L 784,67.25223613595705 C 752.3333333333334,67.25223613595705 752.3333333333334,88.28980322003578 720.6666666666667,88.28980322003578 C 689,88.28980322003578 689,158.16457960644007 657.3333333333334,158.16457960644007 C 625.6666666666667,158.16457960644007 625.6666666666667,204.4973166368515 594,204.4973166368515 C 562.3333333333334,204.4973166368515 562.3333333333334,198.23613595706618 530.6666666666667,198.23613595706618 C 499.00000000000006,198.23613595706618 499.00000000000006,203.9964221824687 467.33333333333337,203.9964221824687 C 435.6666666666667,203.9964221824687 435.6666666666667,195.98211091234347 404,195.98211091234347 C 372.33333333333337,195.98211091234347 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.49910554561717 277.33333333333337,205.49910554561717 C 245.66666666666669,205.49910554561717 245.66666666666669,204.4973166368515 214,204.4973166368515 C 182.33333333333334,204.4973166368515 182.33333333333334,205.24865831842575 150.66666666666669,205.24865831842575 C 119.00000000000001,205.24865831842575 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#DA5B0B" fill-opacity="0.75" class="fade-1"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.24865831842575 150.66666666666669,205.24865831842575 C 182.33333333333334,205.24865831842575 182.33333333333334,204.4973166368515 214,204.4973166368515 C 245.66666666666669,204.4973166368515 245.66666666666669,205.49910554561717 277.33333333333337,205.49910554561717 C 309,205.49910554561717 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,195.98211091234347 404,195.98211091234347 C 435.6666666666667,195.98211091234347 435.6666666666667,203.9964221824687 467.33333333333337,203.9964221824687 C 499.00000000000006,203.9964221824687 499.00000000000006,198.23613595706618 530.6666666666667,198.23613595706618 C 562.3333333333334,198.23613595706618 562.3333333333334,204.4973166368515 594,204.4973166368515 C 625.6666666666667,204.4973166368515 625.6666666666667,158.16457960644007 657.3333333333334,158.16457960644007 C 689,158.16457960644007 689,88.28980322003578 720.6666666666667,88.28980322003578 C 752.3333333333334,88.28980322003578 752.3333333333334,67.25223613595705 784,67.25223613595705 L 784,72.76207513416816 C 752.3333333333334,72.76207513416816 752.3333333333334,93.04830053667264 720.6666666666667,93.04830053667264 C 689,93.04830053667264 689,160.16815742397137 657.3333333333334,160.16815742397137 C 625.6666666666667,160.16815742397137 625.6666666666667,204.4973166368515 594,204.4973166368515 C 562.3333333333334,204.4973166368515 562.3333333333334,198.4865831842576 530.6666666666667,198.4865831842576 C 499.00000000000006,198.4865831842576 499.00000000000006,203.9964221824687 467.33333333333337,203.9964221824687 C 435.6666666666667,203.9964221824687 435.6666666666667,196.4830053667263 404,196.4830053667263 C 372.33333333333337,196.4830053667263 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.49910554561717 277.33333333333337,205.49910554561717 C 245.66666666666669,205.49910554561717 245.66666666666669,204.4973166368515 214,204.4973166368515 C 182.33333333333334,204.4973166368515 182.33333333333334,205.24865831842575 150.66666666666669,205.24865831842575 C 119.00000000000001,205.24865831842575 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#b07219" fill-opacity="0.75" class="fade-2"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.24865831842575 150.66666666666669,205.24865831842575 C 182.33333333333334,205.24865831842575 182.33333333333334,204.4973166368515 214,204.4973166368515 C 245.66666666666669,204.4973166368515 245.66666666666669,205.49910554561717 277.33333333333337,205.49910554561717 C 309,205.49910554561717 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,196.4830053667263 404,196.4830053667263 C 435.6666666666667,196.4830053667263 435.6666666666667,203.9964221824687 467.33333333333337,203.9964221824687 C 499.00000000000006,203.9964221824687 499.00000000000006,198.4865831842576 530.6666666666667,198.4865831842576 C 562.3333333333334,198.4865831842576 562.3333333333334,204.4973166368515 594,204.4973166368515 C 625.6666666666667,204.4973166368515 625.6666666666667,160.16815742397137 657.3333333333334,160.16815742397137 C 689,160.16815742397137 689,93.04830053667264 720.6666666666667,93.04830053667264 C 752.3333333333334,93.04830053667264 752.3333333333334,72.76207513416816 784,72.76207513416816 L 784,87.28801431127013 C 752.3333333333334,87.28801431127013 752.3333333333334,105.32021466905186 720.6666666666667,105.32021466905186 C 689,105.32021466905186 689,165.17710196779964 657.3333333333334,165.17710196779964 C 625.6666666666667,165.17710196779964 625.6666666666667,204.74776386404292 594,204.74776386404292 C 562.3333333333334,204.74776386404292 562.3333333333334,199.23792486583184 530.6666666666667,199.23792486583184 C 499.00000000000006,199.23792486583184 499.00000000000006,204.24686940966012 467.33333333333337,204.24686940966012 C 435.6666666666667,204.24686940966012 435.6666666666667,197.48479427549194 404,197.48479427549194 C 372.33333333333337,197.48479427549194 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.49910554561717 277.33333333333337,205.49910554561717 C 245.66666666666669,205.49910554561717 245.66666666666669,204.74776386404292 214,204.74776386404292 C 182.33333333333334,204.74776386404292 182.33333333333334,205.24865831842575 150.66666666666669,205.24865831842575 C 119.00000000000001,205.24865831842575 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#3572A5" fill-opacity="0.75" class="fade-3"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.24865831842575 150.66666666666669,205.24865831842575 C 182.33333333333334,205.24865831842575 182.33333333333334,204.74776386404292 214,204.74776386404292 C 245.66666666666669,204.74776386404292 245.66666666666669,205.49910554561717 277.33333333333337,205.49910554561717 C 309,205.49910554561717 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,197.48479427549194 404,197.48479427549194 C 435.6666666666667,197.48479427549194 435.6666666666667,204.24686940966012 467.33333333333337,204.24686940966012 C 499.00000000000006,204.24686940966012 499.00000000000006,199.23792486583184 530.6666666666667,199.23792486583184 C 562.3333333333334,199.23792486583184 562.3333333333334,204.74776386404292 594,204.74776386404292 C 625.6666666666667,204.74776386404292 625.6666666666667,165.17710196779964 657.3333333333334,165.17710196779964 C 689,165.17710196779964 689,105.32021466905186 720.6666666666667,105.32021466905186 C 752.3333333333334,105.32021466905186 752.3333333333334,87.28801431127013 784,87.28801431127013 L 784,103.8175313059034 C 752.3333333333334,103.8175313059034 752.3333333333334,119.34525939177102 720.6666666666667,119.34525939177102 C 689,119.34525939177102 689,170.93738819320214 657.3333333333334,170.93738819320214 C 625.6666666666667,170.93738819320214 625.6666666666667,204.99821109123434 594,204.99821109123434 C 562.3333333333334,204.99821109123434 562.3333333333334,200.2397137745975 530.6666666666667,200.2397137745975 C 499.00000000000006,200.2397137745975 499.00000000000006,204.4973166368515 467.33333333333337,204.4973166368515 C 435.6666666666667,204.4973166368515 435.6666666666667,198.737030411449 404,198.737030411449 C 372.33333333333337,198.737030411449 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.49910554561717 277.33333333333337,205.49910554561717 C 245.66666666666669,205.49910554561717 245.66666666666669,204.99821109123434 214,204.99821109123434 C 182.33333333333334,204.99821109123434 182.33333333333334,205.24865831842575 150.66666666666669,205.24865831842575 C 119.00000000000001,205.24865831842575 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#00ADD8" fill-opacity="0.75" class="fade-4"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.24865831842575 150.66666666666669,205.24865831842575 C 182.33333333333334,205.24865831842575 182.33333333333334,204.99821109123434 214,204.99821109123434 C 245.66666666666669,204.99821109123434 245.66666666666669,205.49910554561717 277.33333333333337,205.49910554561717 C 309,205.49910554561717 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,198.737030411449 404,198.737030411449 C 435.6666666666667,198.737030411449 435.6666666666667,204.4973166368515 467.33333333333337,204.4973166368515 C 499.00000000000006,204.4973166368515 499.00000000000006,200.2397137745975 530.6666666666667,200.2397137745975 C 562.3333333333334,200.2397137745975 562.3333333333334,204.99821109123434 594,204.99821109123434 C 625.6666666666667,204.99821109123434 625.6666666666667,170.93738819320214 657.3333333333334,170.93738819320214 C 689,170.93738819320214 689,119.34525939177102 720.6666666666667,119.34525939177102 C 752.3333333333334,119.34525939177102 752.3333333333334,103.8175313059034 784,103.8175313059034 L 784,124.35420393559927 C 752.3333333333334,124.35420393559927 752.3333333333334,136.87656529516994 720.6666666666667,136.87656529516994 C 689,136.87656529516994 689,177.9499105545617 657.3333333333334,177.9499105545617 C 625.6666666666667,177.9499105545617 625.6666666666667,205.24865831842575 594,205.24865831842575 C 562.3333333333334,205.24865831842575 562.3333333333334,201.49194991055455 530.6666666666667,201.49194991055455 C 499.00000000000006,201.49194991055455 499.00000000000006,204.74776386404292 467.33333333333337,204.74776386404292 C 435.6666666666667,204.74776386404292 435.6666666666667,200.2397137745975 404,200.2397137745975 C 372.33333333333337,200.2397137745975 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.49910554561717 277.33333333333337,205.49910554561717 C 245.66666666666669,205.49910554561717 245.66666666666669,205.24865831842575 214,205.24865831842575 C 182.33333333333334,205.24865831842575 182.33333333333334,205.49910554561717 150.66666666666669,205.49910554561717 C 119.00000000000001,205.49910554561717 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#89e051" fill-opacity="0.75" class="fade-5"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.49910554561717 150.66666666666669,205.49910554561717 C 182.33333333333334,205.49910554561717 182.33333333333334,205.24865831842575 214,205.24865831842575 C 245.66666666666669,205.24865831842575 245.66666666666669,205.49910554561717 277.33333333333337,205.49910554561717 C 309,205.49910554561717 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,200.2397137745975 404,200.2397137745975 C 435.6666666666667,200.2397137745975 435.6666666666667,204.74776386404292 467.33333333333337,204.74776386404292 C 499.00000000000006,204.74776386404292 499.00000000000006,201.49194991055455 530.6666666666667,201.49194991055455 C 562.3333333333334,201.49194991055455 562.3333333333334,205.24865831842575 594,205.24865831842575 C 625.6666666666667,205.24865831842575 625.6666666666667,177.9499105545617 657.3333333333334,177.9499105545617 C 689,177.9499105545617 689,136.87656529516994 720.6666666666667,136.87656529516994 C 752.3333333333334,136.87656529516994 752.3333333333334,124.35420393559927 784,124.35420393559927 L 784,156.912343470483 C 752.3333333333334,156.912343470483 752.3333333333334,164.4257602862254 720.6666666666667,164.4257602862254 C 689,164.4257602862254 689,189.22003577817532 657.3333333333334,189.22003577817532 C 625.6666666666667,189.22003577817532 625.6666666666667,205.49910554561717 594,205.49910554561717 C 562.3333333333334,205.49910554561717 562.3333333333334,203.24508050089446 530.6666666666667,203.24508050089446 C 499.00000000000006,203.24508050089446 499.00000000000006,205.24865831842575 467.33333333333337,205.24865831842575 C 435.6666666666667,205.24865831842575 435.6666666666667,202.4937388193202 404,202.4937388193202 C 372.33333333333337,202.4937388193202 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.74955277280858 277.33333333333337,205.74955277280858 C 245.66666666666669,205.74955277280858 245.66666666666669,205.49910554561717 214,205.49910554561717 C 182.33333333333334,205.49910554561717 182.33333333333334,205.74955277280858 150.66666666666669,205.74955277280858 C 119.00000000000001,205.74955277280858 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#3178c6" fill-opacity="0.75" class="fade-6"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.74955277280858 150.66666666666669,205.74955277280858 C 182.33333333333334,205.74955277280858 182.33333333333334,205.49910554561717 214,205.49910554561717 C 245.66666666666669,205.49910554561717 245.66666666666669,205.74955277280858 277.33333333333337,205.74955277280858 C 309,205.74955277280858 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,202.4937388193202 404,202.4937388193202 C 435.6666666666667,202.4937388193202 435.6666666666667,205.24865831842575 467.33333333333337,205.24865831842575 C 499.00000000000006,205.24865831842575 499.00000000000006,203.24508050089446 530.6666666666667,203.24508050089446 C 562.3333333333334,203.24508050089446 562.3333333333334,205.49910554561717 594,205.49910554561717 C 625.6666666666667,205.49910554561717 625.6666666666667,189.22003577817532 657.3333333333334,189.22003577817532 C 689,189.22003577817532 689,164.4257602862254 720.6666666666667,164.4257602862254 C 752.3333333333334,164.4257602862254 752.3333333333334,156.912343470483 784,156.912343470483 L 784,206 C 752.3333333333334,206 752.3333333333334,206 720.6666666666667,206 C 689,206 689,206 657.3333333333334,206 C 625.6666666666667,206 625.6666666666667,206 594,206 C 562.3333333333334,206 562.3333333333334,206 530.6666666666667,206 C 499.00000000000006,206 499.00000000000006,206 467.33333333333337,206 C 435.6666666666667,206 435.6666666666667,206 404,206 C 372.33333333333337,206 372.33333333333337,206 340.6666666666667,206 C 309,206 309,206 277.33333333333337,206 C 245.66666666666669,206 245.66666666666669,206 214,206 C 182.33333333333334,206 182.33333333333334,206 150.66666666666669,206 C 119.00000000000001,206 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#dea584" fill-opacity="0.75" class="fade-6"/><rect x="24" y="212" width="8" height="8" rx="2" fill="#dea584" opacity="0.85"/><text x="36" y="220" class="t t-value">Rust</text><rect x="80" y="212" width="8" height="8" rx="2" fill="#3178c6" opacity="0.85"/><text x="92" y="220" class="t t-value">TypeScript</text><rect x="178" y="212" width="8" height="8" rx="2" fill="#89e051" opacity="0.85"/><text x="190" y="220" class="t t-value">Shell</text><rect x="241" y="212" width="8" height="8" rx="2" fill="#00ADD8" opacity="0.85"/><text x="253" y="220" class="t t-value">Go</text><rect x="283" y="212" width="8" height="8" rx="2" fill="#3572A5" opacity="0.85"/><text x="295" y="220" class="t t-value">Python</text><rect x="353" y="212" width="8" height="8" rx="2" fill="#b07219" opacity="0.85"/><text x="365" y="220" class="t t-value">Java</text><rect x="409" y="212" width="8" height="8" rx="2" fill="#DA5B0B" opacity="0.85"/><text x="421" y="220" class="t t-value">Jupyter Notebook</text><text x="24" y="220" class="t t-value" text-anchor="start" opacity="0">Feb</text><text x="150.66666666666669" y="220" class="t t-value" text-anchor="start" opacity="0">Apr</text><text x="277.33333333333337" y="220" class="t t-value" text-anchor="start" opacity="0">Jun</text><text x="404" y="220" class="t t-value" text-anchor="start" opacity="0">Aug</text><text x="530.6666666666667" y="220" class="t t-value" text-anchor="start" opacity="0">Oct</text><text x="657.3333333333334" y="220" class="t t-value" text-anchor="start" opacity="0">Dec</text><text x="784" y="220" class="t t-value" text-anchor="start" opacity="0">Feb</text></svg>
55
+ </style></defs><rect width="808" height="250" rx="12" class="bg-fill" fill="#0d1117"/><text x="24" y="40" class="t t-h">LANGUAGE VELOCITY</text><text x="24" y="56" class="t t-sub">How language usage has evolved over the past year</text><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.3913043478261 150.66666666666669,205.3913043478261 C 182.33333333333334,205.3913043478261 182.33333333333334,204.7826086956522 214,204.7826086956522 C 245.66666666666669,204.7826086956522 245.66666666666669,205.59420289855072 277.33333333333337,205.59420289855072 C 309,205.59420289855072 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,198.08695652173913 404,198.08695652173913 C 435.6666666666667,198.08695652173913 435.6666666666667,204.57971014492753 467.33333333333337,204.57971014492753 C 499.00000000000006,204.57971014492753 499.00000000000006,199.91304347826087 530.6666666666667,199.91304347826087 C 562.3333333333334,199.91304347826087 562.3333333333334,204.7826086956522 594,204.7826086956522 C 625.6666666666667,204.7826086956522 625.6666666666667,167.04347826086956 657.3333333333334,167.04347826086956 C 689,167.04347826086956 689,109.21739130434783 720.6666666666667,109.21739130434783 C 752.3333333333334,109.21739130434783 752.3333333333334,66 784,66 L 784,67.01449275362319 C 752.3333333333334,67.01449275362319 752.3333333333334,110.02898550724638 720.6666666666667,110.02898550724638 C 689,110.02898550724638 689,167.2463768115942 657.3333333333334,167.2463768115942 C 625.6666666666667,167.2463768115942 625.6666666666667,204.7826086956522 594,204.7826086956522 C 562.3333333333334,204.7826086956522 562.3333333333334,199.91304347826087 530.6666666666667,199.91304347826087 C 499.00000000000006,199.91304347826087 499.00000000000006,204.57971014492753 467.33333333333337,204.57971014492753 C 435.6666666666667,204.57971014492753 435.6666666666667,198.08695652173913 404,198.08695652173913 C 372.33333333333337,198.08695652173913 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.59420289855072 277.33333333333337,205.59420289855072 C 245.66666666666669,205.59420289855072 245.66666666666669,204.7826086956522 214,204.7826086956522 C 182.33333333333334,204.7826086956522 182.33333333333334,205.3913043478261 150.66666666666669,205.3913043478261 C 119.00000000000001,205.3913043478261 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#DA5B0B" fill-opacity="0.75" class="fade-1"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.3913043478261 150.66666666666669,205.3913043478261 C 182.33333333333334,205.3913043478261 182.33333333333334,204.7826086956522 214,204.7826086956522 C 245.66666666666669,204.7826086956522 245.66666666666669,205.59420289855072 277.33333333333337,205.59420289855072 C 309,205.59420289855072 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,198.08695652173913 404,198.08695652173913 C 435.6666666666667,198.08695652173913 435.6666666666667,204.57971014492753 467.33333333333337,204.57971014492753 C 499.00000000000006,204.57971014492753 499.00000000000006,199.91304347826087 530.6666666666667,199.91304347826087 C 562.3333333333334,199.91304347826087 562.3333333333334,204.7826086956522 594,204.7826086956522 C 625.6666666666667,204.7826086956522 625.6666666666667,167.2463768115942 657.3333333333334,167.2463768115942 C 689,167.2463768115942 689,110.02898550724638 720.6666666666667,110.02898550724638 C 752.3333333333334,110.02898550724638 752.3333333333334,67.01449275362319 784,67.01449275362319 L 784,72.08695652173913 C 752.3333333333334,72.08695652173913 752.3333333333334,113.47826086956522 720.6666666666667,113.47826086956522 C 689,113.47826086956522 689,168.66666666666666 657.3333333333334,168.66666666666666 C 625.6666666666667,168.66666666666666 625.6666666666667,204.7826086956522 594,204.7826086956522 C 562.3333333333334,204.7826086956522 562.3333333333334,200.1159420289855 530.6666666666667,200.1159420289855 C 499.00000000000006,200.1159420289855 499.00000000000006,204.57971014492753 467.33333333333337,204.57971014492753 C 435.6666666666667,204.57971014492753 435.6666666666667,198.28985507246378 404,198.28985507246378 C 372.33333333333337,198.28985507246378 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.59420289855072 277.33333333333337,205.59420289855072 C 245.66666666666669,205.59420289855072 245.66666666666669,204.7826086956522 214,204.7826086956522 C 182.33333333333334,204.7826086956522 182.33333333333334,205.3913043478261 150.66666666666669,205.3913043478261 C 119.00000000000001,205.3913043478261 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#b07219" fill-opacity="0.75" class="fade-2"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.3913043478261 150.66666666666669,205.3913043478261 C 182.33333333333334,205.3913043478261 182.33333333333334,204.7826086956522 214,204.7826086956522 C 245.66666666666669,204.7826086956522 245.66666666666669,205.59420289855072 277.33333333333337,205.59420289855072 C 309,205.59420289855072 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,198.28985507246378 404,198.28985507246378 C 435.6666666666667,198.28985507246378 435.6666666666667,204.57971014492753 467.33333333333337,204.57971014492753 C 499.00000000000006,204.57971014492753 499.00000000000006,200.1159420289855 530.6666666666667,200.1159420289855 C 562.3333333333334,200.1159420289855 562.3333333333334,204.7826086956522 594,204.7826086956522 C 625.6666666666667,204.7826086956522 625.6666666666667,168.66666666666666 657.3333333333334,168.66666666666666 C 689,168.66666666666666 689,113.47826086956522 720.6666666666667,113.47826086956522 C 752.3333333333334,113.47826086956522 752.3333333333334,72.08695652173913 784,72.08695652173913 L 784,85.47826086956522 C 752.3333333333334,85.47826086956522 752.3333333333334,122.81159420289856 720.6666666666667,122.81159420289856 C 689,122.81159420289856 689,172.31884057971013 657.3333333333334,172.31884057971013 C 625.6666666666667,172.31884057971013 625.6666666666667,204.9855072463768 594,204.9855072463768 C 562.3333333333334,204.9855072463768 562.3333333333334,200.7246376811594 530.6666666666667,200.7246376811594 C 499.00000000000006,200.7246376811594 499.00000000000006,204.7826086956522 467.33333333333337,204.7826086956522 C 435.6666666666667,204.7826086956522 435.6666666666667,199.1014492753623 404,199.1014492753623 C 372.33333333333337,199.1014492753623 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.59420289855072 277.33333333333337,205.59420289855072 C 245.66666666666669,205.59420289855072 245.66666666666669,204.9855072463768 214,204.9855072463768 C 182.33333333333334,204.9855072463768 182.33333333333334,205.3913043478261 150.66666666666669,205.3913043478261 C 119.00000000000001,205.3913043478261 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#3572A5" fill-opacity="0.75" class="fade-3"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.3913043478261 150.66666666666669,205.3913043478261 C 182.33333333333334,205.3913043478261 182.33333333333334,204.9855072463768 214,204.9855072463768 C 245.66666666666669,204.9855072463768 245.66666666666669,205.59420289855072 277.33333333333337,205.59420289855072 C 309,205.59420289855072 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,199.1014492753623 404,199.1014492753623 C 435.6666666666667,199.1014492753623 435.6666666666667,204.7826086956522 467.33333333333337,204.7826086956522 C 499.00000000000006,204.7826086956522 499.00000000000006,200.7246376811594 530.6666666666667,200.7246376811594 C 562.3333333333334,200.7246376811594 562.3333333333334,204.9855072463768 594,204.9855072463768 C 625.6666666666667,204.9855072463768 625.6666666666667,172.31884057971013 657.3333333333334,172.31884057971013 C 689,172.31884057971013 689,122.81159420289856 720.6666666666667,122.81159420289856 C 752.3333333333334,122.81159420289856 752.3333333333334,85.47826086956522 784,85.47826086956522 L 784,104.55072463768116 C 752.3333333333334,104.55072463768116 752.3333333333334,136 720.6666666666667,136 C 689,136 689,177.59420289855072 657.3333333333334,177.59420289855072 C 625.6666666666667,177.59420289855072 625.6666666666667,205.18840579710144 594,205.18840579710144 C 562.3333333333334,205.18840579710144 562.3333333333334,201.53623188405797 530.6666666666667,201.53623188405797 C 499.00000000000006,201.53623188405797 499.00000000000006,204.9855072463768 467.33333333333337,204.9855072463768 C 435.6666666666667,204.9855072463768 435.6666666666667,200.1159420289855 404,200.1159420289855 C 372.33333333333337,200.1159420289855 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.59420289855072 277.33333333333337,205.59420289855072 C 245.66666666666669,205.59420289855072 245.66666666666669,205.18840579710144 214,205.18840579710144 C 182.33333333333334,205.18840579710144 182.33333333333334,205.3913043478261 150.66666666666669,205.3913043478261 C 119.00000000000001,205.3913043478261 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#89e051" fill-opacity="0.75" class="fade-4"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.3913043478261 150.66666666666669,205.3913043478261 C 182.33333333333334,205.3913043478261 182.33333333333334,205.18840579710144 214,205.18840579710144 C 245.66666666666669,205.18840579710144 245.66666666666669,205.59420289855072 277.33333333333337,205.59420289855072 C 309,205.59420289855072 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,200.1159420289855 404,200.1159420289855 C 435.6666666666667,200.1159420289855 435.6666666666667,204.9855072463768 467.33333333333337,204.9855072463768 C 499.00000000000006,204.9855072463768 499.00000000000006,201.53623188405797 530.6666666666667,201.53623188405797 C 562.3333333333334,201.53623188405797 562.3333333333334,205.18840579710144 594,205.18840579710144 C 625.6666666666667,205.18840579710144 625.6666666666667,177.59420289855072 657.3333333333334,177.59420289855072 C 689,177.59420289855072 689,136 720.6666666666667,136 C 752.3333333333334,136 752.3333333333334,104.55072463768116 784,104.55072463768116 L 784,128.08695652173913 C 752.3333333333334,128.08695652173913 752.3333333333334,152.231884057971 720.6666666666667,152.231884057971 C 689,152.231884057971 689,184.28985507246375 657.3333333333334,184.28985507246375 C 625.6666666666667,184.28985507246375 625.6666666666667,205.3913043478261 594,205.3913043478261 C 562.3333333333334,205.3913043478261 562.3333333333334,202.55072463768116 530.6666666666667,202.55072463768116 C 499.00000000000006,202.55072463768116 499.00000000000006,205.18840579710144 467.33333333333337,205.18840579710144 C 435.6666666666667,205.18840579710144 435.6666666666667,201.53623188405797 404,201.53623188405797 C 372.33333333333337,201.53623188405797 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.59420289855072 277.33333333333337,205.59420289855072 C 245.66666666666669,205.59420289855072 245.66666666666669,205.3913043478261 214,205.3913043478261 C 182.33333333333334,205.3913043478261 182.33333333333334,205.59420289855072 150.66666666666669,205.59420289855072 C 119.00000000000001,205.59420289855072 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#00ADD8" fill-opacity="0.75" class="fade-5"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.59420289855072 150.66666666666669,205.59420289855072 C 182.33333333333334,205.59420289855072 182.33333333333334,205.3913043478261 214,205.3913043478261 C 245.66666666666669,205.3913043478261 245.66666666666669,205.59420289855072 277.33333333333337,205.59420289855072 C 309,205.59420289855072 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,201.53623188405797 404,201.53623188405797 C 435.6666666666667,201.53623188405797 435.6666666666667,205.18840579710144 467.33333333333337,205.18840579710144 C 499.00000000000006,205.18840579710144 499.00000000000006,202.55072463768116 530.6666666666667,202.55072463768116 C 562.3333333333334,202.55072463768116 562.3333333333334,205.3913043478261 594,205.3913043478261 C 625.6666666666667,205.3913043478261 625.6666666666667,184.28985507246375 657.3333333333334,184.28985507246375 C 689,184.28985507246375 689,152.231884057971 720.6666666666667,152.231884057971 C 752.3333333333334,152.231884057971 752.3333333333334,128.08695652173913 784,128.08695652173913 L 784,156.4927536231884 C 752.3333333333334,156.4927536231884 752.3333333333334,171.91304347826087 720.6666666666667,171.91304347826087 C 689,171.91304347826087 689,192.20289855072463 657.3333333333334,192.20289855072463 C 625.6666666666667,192.20289855072463 625.6666666666667,205.59420289855072 594,205.59420289855072 C 562.3333333333334,205.59420289855072 562.3333333333334,203.768115942029 530.6666666666667,203.768115942029 C 499.00000000000006,203.768115942029 499.00000000000006,205.3913043478261 467.33333333333337,205.3913043478261 C 435.6666666666667,205.3913043478261 435.6666666666667,203.15942028985506 404,203.15942028985506 C 372.33333333333337,203.15942028985506 372.33333333333337,206 340.6666666666667,206 C 309,206 309,205.79710144927537 277.33333333333337,205.79710144927537 C 245.66666666666669,205.79710144927537 245.66666666666669,205.59420289855072 214,205.59420289855072 C 182.33333333333334,205.59420289855072 182.33333333333334,205.79710144927537 150.66666666666669,205.79710144927537 C 119.00000000000001,205.79710144927537 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#3178c6" fill-opacity="0.75" class="fade-6"/><path d="M 24,206 C 55.66666666666667,206 55.66666666666667,206 87.33333333333334,206 C 119.00000000000001,206 119.00000000000001,205.79710144927537 150.66666666666669,205.79710144927537 C 182.33333333333334,205.79710144927537 182.33333333333334,205.59420289855072 214,205.59420289855072 C 245.66666666666669,205.59420289855072 245.66666666666669,205.79710144927537 277.33333333333337,205.79710144927537 C 309,205.79710144927537 309,206 340.6666666666667,206 C 372.33333333333337,206 372.33333333333337,203.15942028985506 404,203.15942028985506 C 435.6666666666667,203.15942028985506 435.6666666666667,205.3913043478261 467.33333333333337,205.3913043478261 C 499.00000000000006,205.3913043478261 499.00000000000006,203.768115942029 530.6666666666667,203.768115942029 C 562.3333333333334,203.768115942029 562.3333333333334,205.59420289855072 594,205.59420289855072 C 625.6666666666667,205.59420289855072 625.6666666666667,192.20289855072463 657.3333333333334,192.20289855072463 C 689,192.20289855072463 689,171.91304347826087 720.6666666666667,171.91304347826087 C 752.3333333333334,171.91304347826087 752.3333333333334,156.4927536231884 784,156.4927536231884 L 784,206 C 752.3333333333334,206 752.3333333333334,206 720.6666666666667,206 C 689,206 689,206 657.3333333333334,206 C 625.6666666666667,206 625.6666666666667,206 594,206 C 562.3333333333334,206 562.3333333333334,206 530.6666666666667,206 C 499.00000000000006,206 499.00000000000006,206 467.33333333333337,206 C 435.6666666666667,206 435.6666666666667,206 404,206 C 372.33333333333337,206 372.33333333333337,206 340.6666666666667,206 C 309,206 309,206 277.33333333333337,206 C 245.66666666666669,206 245.66666666666669,206 214,206 C 182.33333333333334,206 182.33333333333334,206 150.66666666666669,206 C 119.00000000000001,206 119.00000000000001,206 87.33333333333334,206 C 55.66666666666667,206 55.66666666666667,206 24,206 Z" fill="#dea584" fill-opacity="0.75" class="fade-6"/><rect x="24" y="212" width="8" height="8" rx="2" fill="#dea584" opacity="0.85"/><text x="36" y="220" class="t t-value">Rust</text><rect x="80" y="212" width="8" height="8" rx="2" fill="#3178c6" opacity="0.85"/><text x="92" y="220" class="t t-value">TypeScript</text><rect x="178" y="212" width="8" height="8" rx="2" fill="#00ADD8" opacity="0.85"/><text x="190" y="220" class="t t-value">Go</text><rect x="220" y="212" width="8" height="8" rx="2" fill="#89e051" opacity="0.85"/><text x="232" y="220" class="t t-value">Shell</text><rect x="283" y="212" width="8" height="8" rx="2" fill="#3572A5" opacity="0.85"/><text x="295" y="220" class="t t-value">Python</text><rect x="353" y="212" width="8" height="8" rx="2" fill="#b07219" opacity="0.85"/><text x="365" y="220" class="t t-value">Java</text><rect x="409" y="212" width="8" height="8" rx="2" fill="#DA5B0B" opacity="0.85"/><text x="421" y="220" class="t t-value">Jupyter Notebook</text><text x="24" y="220" class="t t-value" text-anchor="start" opacity="0">Feb</text><text x="150.66666666666669" y="220" class="t t-value" text-anchor="start" opacity="0">Apr</text><text x="277.33333333333337" y="220" class="t t-value" text-anchor="start" opacity="0">Jun</text><text x="404" y="220" class="t t-value" text-anchor="start" opacity="0">Aug</text><text x="530.6666666666667" y="220" class="t t-value" text-anchor="start" opacity="0">Oct</text><text x="657.3333333333334" y="220" class="t t-value" text-anchor="start" opacity="0">Dec</text><text x="784" y="220" class="t t-value" text-anchor="start" opacity="0">Feb</text></svg>
package/package.json CHANGED
@@ -31,5 +31,5 @@
31
31
  "typecheck": "tsc --noEmit"
32
32
  },
33
33
  "type": "module",
34
- "version": "2.3.0"
34
+ "version": "2.4.0"
35
35
  }
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
2
2
  import { makeContributionData, makeUserProfile } from "./__fixtures__/repos.js";
3
3
  import {
4
4
  buildSocialBadges,
5
+ descriptiveAlt,
5
6
  extractFirstName,
6
7
  getTemplate,
7
8
  shieldsBadgeLabel,
@@ -219,9 +220,11 @@ describe("classicTemplate", () => {
219
220
  expect(output).toContain("A software developer in Austin, TX.");
220
221
  });
221
222
 
222
- it("includes SVG embeds", () => {
223
+ it("includes SVG embeds with descriptive alt text", () => {
223
224
  const output = getTemplate("classic")(makeContext());
224
- expect(output).toContain("![GitHub Metrics](assets/insights/index.svg)");
225
+ expect(output).toContain(
226
+ `![${descriptiveAlt("GitHub Metrics", "Urmzd Maharramoff")}](assets/insights/index.svg)`,
227
+ );
225
228
  });
226
229
 
227
230
  it("includes social badges", () => {
@@ -246,7 +249,7 @@ describe("classicTemplate", () => {
246
249
  expect(output).toContain("/ˈʊrm.zəd/");
247
250
  });
248
251
 
249
- it("includes archived section for archived projects", () => {
252
+ it("omits archived section", () => {
250
253
  const output = getTemplate("classic")(
251
254
  makeContext({
252
255
  archivedProjects: [
@@ -259,12 +262,6 @@ describe("classicTemplate", () => {
259
262
  ],
260
263
  }),
261
264
  );
262
- expect(output).toContain("## Archived");
263
- expect(output).toContain("[old-project]");
264
- });
265
-
266
- it("omits archived section when no archived projects", () => {
267
- const output = getTemplate("classic")(makeContext());
268
265
  expect(output).not.toContain("## Archived");
269
266
  });
270
267
 
@@ -293,7 +290,7 @@ describe("modernTemplate", () => {
293
290
  expect(output).toContain(
294
291
  "### [resume-generator](https://github.com/urmzd/resume-generator)",
295
292
  );
296
- expect(output).toContain("\u2605 42");
293
+ expect(output).toContain("Stars: 42");
297
294
  });
298
295
 
299
296
  it("includes maintained projects section with h3 headings", () => {
@@ -334,7 +331,7 @@ describe("modernTemplate", () => {
334
331
  expect(output).toContain("assets/insights/metrics-constellation.svg");
335
332
  });
336
333
 
337
- it("includes archived section separate from active/maintained", () => {
334
+ it("omits archived section", () => {
338
335
  const output = getTemplate("modern")(
339
336
  makeContext({
340
337
  archivedProjects: [
@@ -347,8 +344,7 @@ describe("modernTemplate", () => {
347
344
  ],
348
345
  }),
349
346
  );
350
- expect(output).toContain("## Archived");
351
- expect(output).toContain("[legacy-lib]");
347
+ expect(output).not.toContain("## Archived");
352
348
  });
353
349
 
354
350
  it("includes social badges", () => {
@@ -375,9 +371,11 @@ describe("minimalTemplate", () => {
375
371
  expect(output).toContain("A software developer in Austin, TX.");
376
372
  });
377
373
 
378
- it("includes SVG embeds", () => {
374
+ it("includes SVG embeds with descriptive alt text", () => {
379
375
  const output = getTemplate("minimal")(makeContext());
380
- expect(output).toContain("![GitHub Metrics](assets/insights/index.svg)");
376
+ expect(output).toContain(
377
+ `![${descriptiveAlt("GitHub Metrics", "Urmzd Maharramoff")}](assets/insights/index.svg)`,
378
+ );
381
379
  });
382
380
 
383
381
  it("includes social badges", () => {
@@ -390,7 +388,7 @@ describe("minimalTemplate", () => {
390
388
  expect(output).toContain("@urmzd/github-insights");
391
389
  });
392
390
 
393
- it("includes archived section for archived projects", () => {
391
+ it("omits archived section", () => {
394
392
  const output = getTemplate("minimal")(
395
393
  makeContext({
396
394
  archivedProjects: [
@@ -403,8 +401,7 @@ describe("minimalTemplate", () => {
403
401
  ],
404
402
  }),
405
403
  );
406
- expect(output).toContain("## Archived");
407
- expect(output).toContain("[old-util]");
404
+ expect(output).not.toContain("## Archived");
408
405
  });
409
406
 
410
407
  it("ends with trailing newline", () => {
@@ -466,7 +463,7 @@ describe("ecosystemTemplate", () => {
466
463
  expect(output).toContain("@urmzd/github-insights");
467
464
  });
468
465
 
469
- it("separates archived projects from category tables", () => {
466
+ it("omits archived section", () => {
470
467
  const output = getTemplate("ecosystem")(
471
468
  makeContext({
472
469
  archivedProjects: [
@@ -478,31 +475,9 @@ describe("ecosystemTemplate", () => {
478
475
  category: "Applications",
479
476
  },
480
477
  ],
481
- categorizedProjects: {
482
- Applications: [
483
- {
484
- name: "resume-generator",
485
- url: "https://github.com/urmzd/resume-generator",
486
- description: "CLI tool for professional resumes",
487
- stars: 42,
488
- category: "Applications",
489
- },
490
- {
491
- name: "old-app",
492
- url: "https://github.com/urmzd/old-app",
493
- description: "A retired application",
494
- stars: 3,
495
- category: "Applications",
496
- },
497
- ],
498
- },
499
478
  }),
500
479
  );
501
- expect(output).toContain("### Archived");
502
- expect(output).toContain("[old-app]");
503
- // old-app should NOT appear in the Applications table
504
- const appSection = output.split("### Applications")[1].split("###")[0];
505
- expect(appSection).not.toContain("old-app");
480
+ expect(output).not.toContain("### Archived");
506
481
  });
507
482
 
508
483
  it("ends with trailing newline", () => {
package/src/templates.ts CHANGED
@@ -10,7 +10,51 @@ import type {
10
10
 
11
11
  function attribution(templateName: string): string {
12
12
  const now = new Date().toISOString().split("T")[0];
13
- return `<sub>Last generated on ${now} using [@urmzd/github-insights](https://github.com/urmzd/github-insights) · Template: \`${templateName}\`</sub>`;
13
+ return `<!-- section: footer -->\n<sub>Last generated on ${now} using [@urmzd/github-insights](https://github.com/urmzd/github-insights) · Template: \`${templateName}\`</sub>`;
14
+ }
15
+
16
+ function frontmatter(ctx: TemplateContext): string {
17
+ const langs = ctx.languages.slice(0, 10).map((l) => l.name);
18
+ const lines = [
19
+ "<!-- ai-metadata",
20
+ `type: github-profile`,
21
+ `name: ${ctx.name}`,
22
+ `username: ${ctx.username}`,
23
+ ...(ctx.title ? [`title: ${ctx.title}`] : []),
24
+ `languages: [${langs.join(", ")}]`,
25
+ `profile: https://github.com/${ctx.username}`,
26
+ "-->",
27
+ ];
28
+ return lines.join("\n");
29
+ }
30
+
31
+ const ALT_TEXT_MAP: Record<string, string> = {
32
+ "GitHub Metrics":
33
+ "Combined visualization of language velocity, contribution rhythm, project constellation, and open source impact for {name}",
34
+ "Language Velocity":
35
+ "Streamgraph of {name}'s programming language usage over the past year",
36
+ "Contribution Rhythm":
37
+ "Radar chart of {name}'s contribution patterns by day of week",
38
+ "Project Constellation":
39
+ "Map of {name}'s projects positioned by language ecosystem and complexity",
40
+ "Impact Trail":
41
+ "Bar chart of {name}'s open source contributions by repository star count",
42
+ };
43
+
44
+ export function descriptiveAlt(label: string, name: string): string {
45
+ const template = ALT_TEXT_MAP[label];
46
+ if (template) return template.replace(/\{name\}/g, name);
47
+ return label;
48
+ }
49
+
50
+ function inlineMetadata(ctx: TemplateContext): string {
51
+ const parts: string[] = [];
52
+ if (ctx.title) parts.push(`**Role:** ${ctx.title}`);
53
+ const topLangs = ctx.languages.slice(0, 5).map((l) => l.name);
54
+ if (topLangs.length > 0)
55
+ parts.push(`**Top Languages:** ${topLangs.join(", ")}`);
56
+ if (parts.length === 0) return "";
57
+ return parts.join(" | ");
14
58
  }
15
59
 
16
60
  export function extractFirstName(fullName: string): string {
@@ -77,8 +121,9 @@ function renderProjectSection(title: string, projects: ProjectItem[]): string {
77
121
  .map((p) => {
78
122
  const desc = p.summary || p.description || "No description";
79
123
  const meta: string[] = [];
80
- if (p.stars > 0) meta.push(`\u2605 ${p.stars}`);
81
- if (p.languages?.length) meta.push(p.languages.slice(0, 3).join(", "));
124
+ if (p.stars > 0) meta.push(`Stars: ${p.stars}`);
125
+ if (p.languages?.length)
126
+ meta.push(`Languages: ${p.languages.slice(0, 3).join(", ")}`);
82
127
  const metaLine = meta.length > 0 ? `${meta.join(" \u00b7 ")}` : "";
83
128
  return `### [${p.name}](${p.url})\n${desc}${metaLine ? `\n${metaLine}` : ""}`;
84
129
  })
@@ -92,12 +137,16 @@ function renderProjectSection(title: string, projects: ProjectItem[]): string {
92
137
  function renderProjectTable(title: string, projects: ProjectItem[]): string {
93
138
  if (projects.length === 0) return "";
94
139
 
95
- const header = `| Project | Description |\n|---------|-------------|`;
140
+ const header = `| Project | Description | Stars | Languages |\n|---------|-------------|-------|-----------|`;
96
141
  const rows = projects
97
142
  .map((p) => {
98
143
  const desc = p.summary || p.description || "No description";
99
144
  const safeDesc = desc.replace(/\|/g, "\\|").replace(/\n/g, " ");
100
- return `| [${p.name}](${p.url}) | ${safeDesc} |`;
145
+ const stars = p.stars > 0 ? String(p.stars) : "-";
146
+ const langs = p.languages?.length
147
+ ? p.languages.slice(0, 3).join(", ")
148
+ : "-";
149
+ return `| [${p.name}](${p.url}) | ${safeDesc} | ${stars} | ${langs} |`;
101
150
  })
102
151
  .join("\n");
103
152
 
@@ -109,6 +158,8 @@ function renderProjectTable(title: string, projects: ProjectItem[]): string {
109
158
  function classicTemplate(ctx: TemplateContext): string {
110
159
  const parts: string[] = [];
111
160
 
161
+ parts.push(frontmatter(ctx));
162
+
112
163
  if (ctx.pronunciation) {
113
164
  parts.push(`# ${ctx.name} <sub><i>(${ctx.pronunciation})</i></sub>`);
114
165
  } else {
@@ -123,16 +174,18 @@ function classicTemplate(ctx: TemplateContext): string {
123
174
  parts.push(ctx.preamble);
124
175
  }
125
176
 
126
- if (ctx.socialBadges) {
127
- parts.push(ctx.socialBadges);
128
- }
177
+ const meta = inlineMetadata(ctx);
178
+ if (meta) parts.push(meta);
129
179
 
130
- for (const svg of ctx.svgs) {
131
- parts.push(`![${svg.label}](${svg.path})`);
180
+ if (ctx.socialBadges) {
181
+ parts.push(`<!-- section: social -->\n${ctx.socialBadges}`);
132
182
  }
133
183
 
134
- if (ctx.archivedProjects.length > 0) {
135
- parts.push(renderProjectSection("Archived", ctx.archivedProjects));
184
+ if (ctx.svgs.length > 0) {
185
+ const svgLines = ctx.svgs
186
+ .map((svg) => `![${descriptiveAlt(svg.label, ctx.name)}](${svg.path})`)
187
+ .join("\n");
188
+ parts.push(`<!-- section: visualizations -->\n${svgLines}`);
136
189
  }
137
190
 
138
191
  if (ctx.bio) {
@@ -149,66 +202,82 @@ function classicTemplate(ctx: TemplateContext): string {
149
202
  function modernTemplate(ctx: TemplateContext): string {
150
203
  const parts: string[] = [];
151
204
 
205
+ parts.push(frontmatter(ctx));
206
+
152
207
  parts.push(`# Hi, I'm ${ctx.firstName} 👋`);
153
208
 
154
209
  if (ctx.preamble) {
155
210
  parts.push(ctx.preamble);
156
211
  }
157
212
 
213
+ const meta = inlineMetadata(ctx);
214
+ if (meta) parts.push(meta);
215
+
158
216
  if (ctx.socialBadges) {
159
- parts.push(ctx.socialBadges);
217
+ parts.push(`<!-- section: social -->\n${ctx.socialBadges}`);
160
218
  }
161
219
 
220
+ // Projects
221
+ const projectSections: string[] = [];
162
222
  const activeSection = renderProjectSection(
163
223
  "Active Projects",
164
224
  ctx.activeProjects,
165
225
  );
166
- if (activeSection) parts.push(activeSection);
226
+ if (activeSection) projectSections.push(activeSection);
167
227
 
168
228
  const maintainedSection = renderProjectSection(
169
229
  "Maintained Projects",
170
230
  ctx.maintainedProjects,
171
231
  );
172
- if (maintainedSection) parts.push(maintainedSection);
232
+ if (maintainedSection) projectSections.push(maintainedSection);
173
233
 
174
234
  const inactiveSection = renderProjectSection(
175
235
  "Inactive Projects",
176
236
  ctx.inactiveProjects,
177
237
  );
178
- if (inactiveSection) parts.push(inactiveSection);
238
+ if (inactiveSection) projectSections.push(inactiveSection);
179
239
 
180
- const archivedSection = renderProjectSection(
181
- "Archived",
182
- ctx.archivedProjects,
183
- );
184
- if (archivedSection) parts.push(archivedSection);
240
+ if (projectSections.length > 0) {
241
+ parts.push(`<!-- section: projects -->\n${projectSections.join("\n\n")}`);
242
+ }
243
+
244
+ // Visualizations
245
+ const vizParts: string[] = [];
185
246
 
186
247
  // Constellation
187
248
  if (ctx.sectionSvgs.constellation) {
188
- parts.push(
189
- `## Project Map\n\n![Project Constellation](${ctx.sectionSvgs.constellation})`,
249
+ vizParts.push(
250
+ `## Project Map\n\n![${descriptiveAlt("Project Constellation", ctx.name)}](${ctx.sectionSvgs.constellation})`,
190
251
  );
191
252
  }
192
253
 
193
254
  // GitHub Stats section: rhythm + velocity
194
255
  const statsImages: string[] = [];
195
256
  if (ctx.sectionSvgs.velocity) {
196
- statsImages.push(`![Language Velocity](${ctx.sectionSvgs.velocity})`);
257
+ statsImages.push(
258
+ `![${descriptiveAlt("Language Velocity", ctx.name)}](${ctx.sectionSvgs.velocity})`,
259
+ );
197
260
  }
198
261
  if (ctx.sectionSvgs.rhythm) {
199
- statsImages.push(`![Contribution Rhythm](${ctx.sectionSvgs.rhythm})`);
262
+ statsImages.push(
263
+ `![${descriptiveAlt("Contribution Rhythm", ctx.name)}](${ctx.sectionSvgs.rhythm})`,
264
+ );
200
265
  }
201
266
  if (statsImages.length > 0) {
202
- parts.push(`## GitHub Stats\n\n${statsImages.join("\n")}`);
267
+ vizParts.push(`## GitHub Stats\n\n${statsImages.join("\n")}`);
203
268
  }
204
269
 
205
270
  // Impact
206
271
  if (ctx.sectionSvgs.impact) {
207
- parts.push(
208
- `## Open Source Impact\n\n![Impact Trail](${ctx.sectionSvgs.impact})`,
272
+ vizParts.push(
273
+ `## Open Source Impact\n\n![${descriptiveAlt("Impact Trail", ctx.name)}](${ctx.sectionSvgs.impact})`,
209
274
  );
210
275
  }
211
276
 
277
+ if (vizParts.length > 0) {
278
+ parts.push(`<!-- section: visualizations -->\n${vizParts.join("\n\n")}`);
279
+ }
280
+
212
281
  parts.push(attribution(ctx.templateName));
213
282
 
214
283
  return `${parts.join("\n\n")}\n`;
@@ -219,22 +288,26 @@ function modernTemplate(ctx: TemplateContext): string {
219
288
  function minimalTemplate(ctx: TemplateContext): string {
220
289
  const parts: string[] = [];
221
290
 
291
+ parts.push(frontmatter(ctx));
292
+
222
293
  parts.push(`# ${ctx.firstName}`);
223
294
 
224
295
  if (ctx.preamble) {
225
296
  parts.push(ctx.preamble);
226
297
  }
227
298
 
228
- if (ctx.socialBadges) {
229
- parts.push(ctx.socialBadges);
230
- }
299
+ const meta = inlineMetadata(ctx);
300
+ if (meta) parts.push(meta);
231
301
 
232
- for (const svg of ctx.svgs) {
233
- parts.push(`![${svg.label}](${svg.path})`);
302
+ if (ctx.socialBadges) {
303
+ parts.push(`<!-- section: social -->\n${ctx.socialBadges}`);
234
304
  }
235
305
 
236
- if (ctx.archivedProjects.length > 0) {
237
- parts.push(renderProjectSection("Archived", ctx.archivedProjects));
306
+ if (ctx.svgs.length > 0) {
307
+ const svgLines = ctx.svgs
308
+ .map((svg) => `![${descriptiveAlt(svg.label, ctx.name)}](${svg.path})`)
309
+ .join("\n");
310
+ parts.push(`<!-- section: visualizations -->\n${svgLines}`);
238
311
  }
239
312
 
240
313
  parts.push(attribution(ctx.templateName));
@@ -254,70 +327,82 @@ const CATEGORY_ORDER = [
254
327
  function ecosystemTemplate(ctx: TemplateContext): string {
255
328
  const parts: string[] = [];
256
329
 
330
+ parts.push(frontmatter(ctx));
331
+
257
332
  parts.push(`# Hi, I'm ${ctx.firstName} 👋`);
258
333
 
259
334
  if (ctx.preamble) {
260
335
  parts.push(ctx.preamble);
261
336
  }
262
337
 
338
+ const meta = inlineMetadata(ctx);
339
+ if (meta) parts.push(meta);
340
+
263
341
  if (ctx.socialBadges) {
264
- parts.push(ctx.socialBadges);
342
+ parts.push(`<!-- section: social -->\n${ctx.socialBadges}`);
265
343
  }
266
344
 
267
- // Build a set of archived project names to filter them out of category tables
268
- const archivedNames = new Set(ctx.archivedProjects.map((p) => p.name));
345
+ // Projects
346
+ const projectParts: string[] = [];
269
347
 
270
- // Render project tables grouped by category (excluding archived)
348
+ // Render project tables grouped by category
271
349
  for (const category of CATEGORY_ORDER) {
272
- const projects = ctx.categorizedProjects[category]?.filter(
273
- (p) => !archivedNames.has(p.name),
274
- );
350
+ const projects = ctx.categorizedProjects[category];
275
351
  if (projects && projects.length > 0) {
276
- parts.push(renderProjectTable(category, projects));
352
+ projectParts.push(renderProjectTable(category, projects));
277
353
  }
278
354
  }
279
355
 
280
- // Render any uncategorized projects that don't match known categories (excluding archived)
356
+ // Render any uncategorized projects that don't match known categories
281
357
  for (const [category, projects] of Object.entries(ctx.categorizedProjects)) {
282
358
  if (!CATEGORY_ORDER.includes(category)) {
283
- const nonArchived = projects.filter((p) => !archivedNames.has(p.name));
284
- if (nonArchived.length > 0) {
285
- parts.push(renderProjectTable(category, nonArchived));
359
+ if (projects.length > 0) {
360
+ projectParts.push(renderProjectTable(category, projects));
286
361
  }
287
362
  }
288
363
  }
289
364
 
290
- // Render all archived projects in one consolidated section
291
- if (ctx.archivedProjects.length > 0) {
292
- parts.push(renderProjectTable("Archived", ctx.archivedProjects));
365
+ if (projectParts.length > 0) {
366
+ parts.push(`<!-- section: projects -->\n${projectParts.join("\n\n")}`);
293
367
  }
294
368
 
369
+ // Visualizations
370
+ const vizParts: string[] = [];
371
+
295
372
  // Constellation
296
373
  if (ctx.sectionSvgs.constellation) {
297
- parts.push(
298
- `## Project Map\n\n![Project Constellation](${ctx.sectionSvgs.constellation})`,
374
+ vizParts.push(
375
+ `## Project Map\n\n![${descriptiveAlt("Project Constellation", ctx.name)}](${ctx.sectionSvgs.constellation})`,
299
376
  );
300
377
  }
301
378
 
302
379
  // GitHub Stats section: velocity + rhythm
303
380
  const statsImages: string[] = [];
304
381
  if (ctx.sectionSvgs.velocity) {
305
- statsImages.push(`![Language Velocity](${ctx.sectionSvgs.velocity})`);
382
+ statsImages.push(
383
+ `![${descriptiveAlt("Language Velocity", ctx.name)}](${ctx.sectionSvgs.velocity})`,
384
+ );
306
385
  }
307
386
  if (ctx.sectionSvgs.rhythm) {
308
- statsImages.push(`![Contribution Rhythm](${ctx.sectionSvgs.rhythm})`);
387
+ statsImages.push(
388
+ `![${descriptiveAlt("Contribution Rhythm", ctx.name)}](${ctx.sectionSvgs.rhythm})`,
389
+ );
309
390
  }
310
391
  if (statsImages.length > 0) {
311
- parts.push(`## GitHub Stats\n\n${statsImages.join("\n")}`);
392
+ vizParts.push(`## GitHub Stats\n\n${statsImages.join("\n")}`);
312
393
  }
313
394
 
314
395
  // Impact
315
396
  if (ctx.sectionSvgs.impact) {
316
- parts.push(
317
- `## Open Source Impact\n\n![Impact Trail](${ctx.sectionSvgs.impact})`,
397
+ vizParts.push(
398
+ `## Open Source Impact\n\n![${descriptiveAlt("Impact Trail", ctx.name)}](${ctx.sectionSvgs.impact})`,
318
399
  );
319
400
  }
320
401
 
402
+ if (vizParts.length > 0) {
403
+ parts.push(`<!-- section: visualizations -->\n${vizParts.join("\n\n")}`);
404
+ }
405
+
321
406
  parts.push(attribution(ctx.templateName));
322
407
 
323
408
  return `${parts.join("\n\n")}\n`;