Diffinery

codician/diffinerypublic

Open-source, agent-first GitHub and GitHub Actions alternative that runs on your own Cloudflare account: git hosting, pull requests, code review and drop-in GitHub Actions YAML on Workers, Durable Objects, R2 and Containers.

70 lines · 3.1 KBRaw History
1"""Generate the extension's icons from Diffinery's mark.
2
3 python3 -m venv /tmp/v && /tmp/v/bin/pip install fonttools picosvg brotli pillow
4 /tmp/v/bin/python apps/vscode/scripts/make-icons.py
5
6Writes apps/vscode/media/icon.png (the extension's 128 px icon, the site's app icon scaled
7down) and apps/vscode/media/diffinery-icons.woff (a one-glyph icon font, so the clone picker
8can show the mark as `$(diffinery)` next to "Clone from Diffinery", the way GitHub's shows its
9logo). The output is committed, so builds need none of these tools.
10"""
11import base64
12import io
13import os
14import re
15
16from fontTools.fontBuilder import FontBuilder
17from fontTools.pens.cu2quPen import Cu2QuPen
18from fontTools.pens.transformPen import TransformPen
19from fontTools.pens.ttGlyphPen import TTGlyphPen
20from fontTools.svgLib.path import SVGPath
21from PIL import Image
22from picosvg.svg import SVG
23
24HERE = os.path.dirname(os.path.abspath(__file__))
25MEDIA = os.path.join(HERE, "..", "media")
26SITE_ICONS = os.path.join(HERE, "..", "..", "diffinery", "src", "web", "icons.generated.ts")
27# The mark, as in apps/diffinery/src/web/assets.ts (ICONS.logo), on a 24-unit grid.
28MARK = """<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="12" r="2.5"/><path d="M6 8.5v7M8.3 7.2c4 1 7.4 2.2 7.6 3.3M8.3 16.8c4-1 7.4-2.2 7.6-3.3"/></svg>"""
29CODEPOINT = 0xE001
30UPM = 1000
31
32
33def extension_icon():
34 src = open(SITE_ICONS).read()
35 m = re.search(r'"icon-512\.png":\s*"([A-Za-z0-9+/=]+)"', src)
36 if not m:
37 raise SystemExit("icon-512.png not found in icons.generated.ts")
38 img = Image.open(io.BytesIO(base64.b64decode(m.group(1)))).convert("RGBA")
39 img.resize((128, 128), Image.LANCZOS).save(os.path.join(MEDIA, "icon.png"), optimize=True)
40
41
42def icon_font():
43 # Strokes become filled outlines, as a font needs.
44 flat = SVG.fromstring(MARK).topicosvg()
45 fb = FontBuilder(UPM, isTTF=True)
46 fb.setupGlyphOrder([".notdef", "diffinery"])
47 fb.setupCharacterMap({CODEPOINT: "diffinery"})
48 pen = TTGlyphPen(None)
49 # 24 units -> 1000, y up, baseline at the bottom of the grid.
50 scale = UPM / 24
51 for el in flat.shapes():
52 SVGPath.fromstring(f'<svg xmlns="http://www.w3.org/2000/svg"><path d="{el.d}"/></svg>').draw(
53 TransformPen(Cu2QuPen(pen, 1.0, reverse_direction=True), (scale, 0, 0, -scale, 0, UPM))
54 )
55 glyphs = {".notdef": TTGlyphPen(None).glyph(), "diffinery": pen.glyph()}
56 fb.setupGlyf(glyphs)
57 fb.setupHorizontalMetrics({".notdef": (UPM, 0), "diffinery": (UPM, 0)})
58 fb.setupHorizontalHeader(ascent=UPM, descent=0)
59 fb.setupNameTable({"familyName": "diffinery-icons", "styleName": "Regular"})
60 fb.setupOS2(sTypoAscender=UPM, sTypoDescender=0, usWinAscent=UPM, usWinDescent=0)
61 fb.setupPost()
62 fb.font.flavor = "woff"
63 fb.save(os.path.join(MEDIA, "diffinery-icons.woff"))
64
65
66if __name__ == "__main__":
67 os.makedirs(MEDIA, exist_ok=True)
68 extension_icon()
69 icon_font()
70 print("wrote media/icon.png and media/diffinery-icons.woff")