Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions assets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ its anti-aliased distance to the stroked outline:
| `icons/skrog-128.png` | VS Code Marketplace icon (the extension copies this file) |
| `icons/skrog-256.png`, `-512.png` | general raster use |
| `icons/social-preview.png` | 1280×640 GitHub social preview (upload in repo Settings) |
| `icons/avatar-512.png` | 512×512 GitHub **organisation avatar** — the icon beside `wslkit / skrog`. Upload at [the org's profile settings](https://github.com/organizations/wslkit/settings/profile); there is no API for it, and GitHub has no per-repository avatar |

> **Use `avatar-512.png`, not `skrog-512.png`, for the avatar.** The latter is
> the bare mark on a *transparent* ground, which is right for a page that
> supplies its own background and wrong for an avatar: the mark is `#2F3B45`
> and GitHub's dark theme is `#0d1117`, so a transparent upload would very
> nearly disappear for every dark-theme visitor. An avatar is an `<img>` on
> whatever background the viewer's theme picked, with no styling hook to fix
> it, so it has to carry its own contrast — hence the opaque off-white ground,
> the same one the social card uses.
>
> The mark is centred on its **ink**, not its raster box: a hull body plan
> sits low in its own square, and box-centring left it 13px low at 512.
> `writeAvatar` measures rather than correcting by a constant, so it stays
> right if the geometry in `tools/internal/mark` changes.

The tray status icons (`cmd/skrogtray/icons_windows.go`) are the mark tinted to
the engine state — green (running) / grey (idle) / red (down) — generated by the
Expand Down
Binary file added assets/icons/avatar-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
75 changes: 74 additions & 1 deletion tools/genicons/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,90 @@ import (
// brand is the slate mark color, matching the SVG masters.
var brand = color.RGBA{0x2F, 0x3B, 0x45, 0xFF}

// ground is the off-white the social card and the avatar sit on. Shared so the
// two cannot drift into two different whites.
var ground = color.RGBA{0xF7, 0xF6, 0xF3, 0xFF}

// writeSocial renders a 1280x640 GitHub social-preview card: the mark centered
// on the off-white brand ground. Uploaded via the repo's settings, not embedded.
func writeSocial(path string) {
const w, h, markPx = 1280, 640, 440
dst := image.NewRGBA(image.Rect(0, 0, w, h))
draw.Draw(dst, dst.Bounds(), &image.Uniform{color.RGBA{0xF7, 0xF6, 0xF3, 0xFF}}, image.Point{}, draw.Src)
draw.Draw(dst, dst.Bounds(), &image.Uniform{ground}, image.Point{}, draw.Src)
m := mark.Raster(markPx, brand)
ox, oy := (w-markPx)/2, (h-markPx)/2
draw.Draw(dst, image.Rect(ox, oy, ox+markPx, oy+markPx), m, image.Point{}, draw.Over)
writePNG(path, dst)
}

// writeAvatar renders the square org/user avatar GitHub shows beside
// "wslkit / skrog", and anywhere else an account is named.
//
// It is NOT skrog-512.png, which is the bare mark on a transparent ground.
// That file is right for a docs page that supplies its own background and
// wrong here: the mark is #2F3B45, GitHub's dark theme is #0d1117, and a
// transparent avatar would put one on the other and very nearly disappear.
// An avatar has no styling hook to fix that with — it is an <img> on whatever
// background the viewer's theme picked.
//
// So it gets the same treatment as the social card: an opaque off-white
// ground, which reads on both themes because it carries its own contrast.
//
// GitHub downscales to 460px and then to ~40px in the repo header, so the
// mark is inset rather than bled to the edge — at header size a full-bleed
// mark loses its outline to the crop.
func writeAvatar(path string) {
const size, markPx = 512, 360
dst := image.NewRGBA(image.Rect(0, 0, size, size))
draw.Draw(dst, dst.Bounds(), &image.Uniform{ground}, image.Point{}, draw.Src)

m := mark.Raster(markPx, brand)

// Centre the INK, not the raster box. The mark's drawing does not fill its
// own square evenly -- a hull body plan is wider than it is tall and sits
// low in the frame -- so centring the box left the glyph 13px low at this
// size, which reads as a misaligned logo rather than as the shape's own
// proportions.
//
// Measured rather than corrected by a constant, so this stays true if the
// geometry in tools/internal/mark ever changes.
b := inkBounds(m)
ox := (size - b.Dx()) / 2
oy := (size - b.Dy()) / 2
draw.Draw(dst,
image.Rect(ox-b.Min.X, oy-b.Min.Y, ox-b.Min.X+markPx, oy-b.Min.Y+markPx),
m, image.Point{}, draw.Over)
writePNG(path, dst)
}

// inkBounds is the tight box around everything non-transparent in img.
func inkBounds(img image.Image) image.Rectangle {
b := img.Bounds()
minX, minY, maxX, maxY := b.Max.X, b.Max.Y, b.Min.X-1, b.Min.Y-1
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
if _, _, _, a := img.At(x, y).RGBA(); a > 0 {
if x < minX {
minX = x
}
if y < minY {
minY = y
}
if x > maxX {
maxX = x
}
if y > maxY {
maxY = y
}
}
}
}
if maxX < minX || maxY < minY {
return b // nothing drawn; centre the box and let the caller see it
}
return image.Rect(minX, minY, maxX+1, maxY+1)
}

func writePNG(path string, img image.Image) {
f, err := os.Create(path)
must(err)
Expand All @@ -66,6 +138,7 @@ func main() {
writePNG("assets/icons/skrog-512.png", mark.Raster(512, brand))
writePNG("assets/icons/favicon-32.png", mark.Raster(32, brand))
writeSocial("assets/icons/social-preview.png")
writeAvatar("assets/icons/avatar-512.png")

// Windows .ico with the sizes Explorer, the taskbar and the tray use.
writeICO("assets/icons/skrog.ico", []int{16, 24, 32, 48, 64, 128, 256}, brand)
Expand Down
Loading