Skip to content

Commit e364015

Browse files
vupleaclaude
andcommitted
Improve search discoverability of the docs and Pages site
README leads with the logo (keyworded alt text), PROFILES.md titles itself by what it offers (NVIDIA overclock & undervolt profiles), and the Pages config gains canonical url/baseurl, a tagline that becomes the homepage title suffix, a sitemap, and the icon as JSON-LD logo and default og:image. assets/render_social_preview.py renders the GitHub social preview card (1280x640) in the icon's visual language, reusing render_icon.py's palette and drawing helpers; the card must be uploaded manually in repo Settings, as GitHub has no API for it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0127xi8PYUSabiLV6YUD29Cb
1 parent 2aed56e commit e364015

6 files changed

Lines changed: 137 additions & 4 deletions

File tree

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ profiles/out/
99
.idea/
1010
*.user
1111
*.suo
12+
13+
# Python (assets render scripts)
14+
__pycache__/

‎PROFILES.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Ready-made tuning profiles
1+
# Ready-made NVIDIA overclock & undervolt profiles
22

33
Folders of profile shortcuts per card range are offered. They are based on instrumented reviews
44
and large owner discussion threads, cited inline below.

‎README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
<img src="assets/icon.png" alt="simple-nvidia-undervolt logo: an NVIDIA GPU voltage/frequency curve flattening at the voltage cap" width="96" align="right">
2+
13
# simple-nvidia-undervolt
24

35
A small Windows command-line alternative to MSI Afterburner for overclocking or undervolting an NVIDIA GPU.

‎_config.yml‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
title: simple-nvidia-undervolt
2+
tagline: Overclock & undervolt NVIDIA GPUs from the Windows command line
23
description: >-
3-
Command-line NVIDIA GPU undervolting for Windows — a lightweight MSI
4-
Afterburner alternative. Caps voltage by flattening the V/F curve,
5-
no background process. Tested on RTX 5090 (Blackwell).
4+
Overclock or undervolt your NVIDIA GPU from the Windows command line — a
5+
lightweight MSI Afterburner alternative. Caps voltage by flattening the
6+
V/F curve, no background process. Tested on RTX 5090 (Blackwell).
7+
url: https://vuplea.github.io
8+
baseurl: /simple-nvidia-undervolt
9+
lang: en
10+
logo: /assets/icon.png
611
theme: jekyll-theme-slate
712
plugins:
813
- jekyll-seo-tag
14+
- jekyll-sitemap
15+
defaults:
16+
- scope:
17+
path: ""
18+
values:
19+
image: /assets/icon.png

‎assets/render_social_preview.py‎

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
"""
2+
Generates the GitHub social preview card (social-preview.png, 1280x640) in the
3+
icon's visual language: the V/F curve rising and hard-flattening at the voltage
4+
cap, glowing over pinstripes, with the project name and tagline set below.
5+
6+
Upload manually: repo Settings -> Social preview (GitHub has no API for it).
7+
8+
Requires Python 3 with numpy and pillow: python render_social_preview.py
9+
"""
10+
11+
import os
12+
13+
import numpy as np
14+
from PIL import Image, ImageDraw, ImageFilter, ImageFont
15+
16+
from render_icon import GREEN, HOT, INK, MINT, NEARBLK, over, sd_polyline, smoothstep
17+
18+
OUT_DIR = os.path.dirname(os.path.abspath(__file__))
19+
W, H = 1280, 640
20+
SS = 2
21+
NX, NY = W * SS, H * SS
22+
23+
TITLE = "simple-nvidia-undervolt"
24+
TAGLINE = "Overclock & undervolt NVIDIA GPUs from the Windows command line"
25+
26+
# V/F curve in card coordinates (x in [-2, 2], y in [-1, 1], y up):
27+
# rise starts at (X0, Y0), hard-flattens at the knee (XK, YC)
28+
X0, XK = -1.85, -0.45
29+
Y0, YC = -0.30, 0.42
30+
31+
32+
def curve_y(x):
33+
t = np.clip((x - X0) / (XK - X0), 0.0, 1.0)
34+
return Y0 + (YC - Y0) * t ** 1.6
35+
36+
37+
def render_background():
38+
xs = np.linspace(-2.0, 2.0, NX)
39+
ys = np.linspace(1.0, -1.0, NY)
40+
x, y = np.meshgrid(xs, ys)
41+
42+
# dark ground with a slight radial falloff
43+
r = np.hypot(x * 0.5, y)
44+
col = INK[None, None, :] * (1.0 - 0.35 * smoothstep(0.2, 1.4, r))[..., None]
45+
col = col + NEARBLK[None, None, :] * 0.5
46+
47+
fy = curve_y(x)
48+
dyc = y - fy
49+
below = smoothstep(0.015, -0.015, dyc)
50+
51+
# faint fill so the stripes sit in a body of tone, not a void
52+
col = col + GREEN[None, None, :] * (below * np.exp(dyc * 1.6) * 0.18)[..., None]
53+
54+
# pinstripes that relax toward horizontal with depth
55+
offsets = [0.16, 0.35, 0.56, 0.80, 1.06]
56+
for i, off in enumerate(offsets):
57+
relax = (i + 1) / (len(offsets) + 1)
58+
shape = fy * (1 - relax) + YC * relax
59+
swell = 0.028 * np.sin(x * 1.8 + i * 1.4) * relax
60+
sd = np.abs(y - (shape - off) + swell)
61+
alpha = 0.45 * (0.80 ** i)
62+
line = smoothstep(0.016, 0.004, sd) * below
63+
col = over(col, (GREEN * (0.9 - 0.09 * i))[None, None, :], line * alpha)
64+
65+
# the curve itself: broad green bloom, lime glow, white-hot core
66+
cx = np.linspace(-2.2, 2.2, 140)
67+
d = sd_polyline(x, y, list(zip(cx, curve_y(cx))))
68+
col = col + GREEN[None, None, :] * np.exp(-7.0 * d)[..., None] * 0.60
69+
col = col + MINT[None, None, :] * np.exp(-24.0 * d)[..., None] * 0.80
70+
col = over(col, HOT[None, None, :], smoothstep(0.022, 0.007, d))
71+
72+
# finish: vignette, subtle scanlines and grain, filmic tone curve
73+
col = col * (1.0 - 0.45 * smoothstep(0.45, 1.25, r))[..., None]
74+
col = col * (1.0 - 0.03 * (0.5 + 0.5 * np.sin(y * NY * 90.0)))[..., None]
75+
rng = np.random.default_rng(7)
76+
col = col * (1.0 + 0.012 * (rng.random((NY, NX)) - 0.5) * 2.0)[..., None]
77+
col = col / (col + 0.85) * 1.85
78+
79+
col = np.clip(col, 0, 1).reshape(H, SS, W, SS, 3).mean(axis=(1, 3))
80+
return Image.fromarray((col * 255 + 0.5).astype(np.uint8))
81+
82+
83+
def font(path, size):
84+
return ImageFont.truetype(os.path.join(os.environ["WINDIR"], "Fonts", path), size)
85+
86+
87+
def main():
88+
img = render_background()
89+
90+
title_font = font("consolab.ttf", 74)
91+
tag_font = font("segoeui.ttf", 34)
92+
93+
halo = Image.new("L", img.size, 0)
94+
hd = ImageDraw.Draw(halo)
95+
d = ImageDraw.Draw(img)
96+
97+
for cy, text, f in [(408, TITLE, title_font), (516, TAGLINE, tag_font)]:
98+
w = hd.textlength(text, font=f)
99+
hd.text(((W - w) / 2, cy), text, font=f, fill=255)
100+
halo = halo.filter(ImageFilter.GaussianBlur(24))
101+
img.paste(Image.new("RGB", img.size, (4, 7, 6)), (0, 0),
102+
halo.point(lambda a: min(int(a * 1.7), 215)))
103+
104+
for cy, text, f, fill in [
105+
(408, TITLE, title_font, (222, 255, 236)),
106+
(516, TAGLINE, tag_font, (148, 196, 168)),
107+
]:
108+
w = d.textlength(text, font=f)
109+
d.text(((W - w) / 2, cy), text, font=f, fill=fill)
110+
111+
out = os.path.join(OUT_DIR, "social-preview.png")
112+
img.save(out)
113+
print(f"wrote {out}")
114+
115+
116+
if __name__ == "__main__":
117+
main()

‎assets/social-preview.png‎

333 KB
Loading

0 commit comments

Comments
 (0)