Brand mark: scallop ribbon shape, app icon in light / dark / tinted (#11)
CI / build-and-deploy (push) Successful in 18s
CI / build-and-deploy (push) Successful in 18s
This commit was merged in pull request #11.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
<!doctype html>
|
||||
<!--
|
||||
App icon artwork for Marks. Rendered to PNG by generate.sh — do not edit the
|
||||
PNGs in AppIcon.appiconset directly, they are build output.
|
||||
|
||||
The path below is the same geometry as ScallopMark in
|
||||
Marks/Views/Library/MarksMark.swift, in the same canonical 88 x 98 box. If you
|
||||
change one, change the other; there is no shared source between Swift and SVG.
|
||||
|
||||
Three variants, per Apple's iOS 18+ app icon model:
|
||||
light — full-bleed artwork on the paper ground, flattened (icons may not
|
||||
carry an alpha channel).
|
||||
dark — artwork only, on transparency. The system supplies the dark
|
||||
background, so the bands are the palette's dark counterparts,
|
||||
which are lifted rather than dimmed.
|
||||
tinted — greyscale on transparency. The system maps luminance to the user's
|
||||
chosen tint, so the three bands are carried as three greys whose
|
||||
relative luminance matches the colour version. Flattening them to
|
||||
one grey would throw away the band reading in exactly the mode
|
||||
that has nothing else left.
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Marks app icon</title>
|
||||
<style>
|
||||
html,body{margin:0;padding:0;background:transparent}
|
||||
#tile{width:1024px;height:1024px;display:flex;align-items:center;justify-content:center}
|
||||
svg{display:block}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="tile"></div>
|
||||
<script>
|
||||
// 88 x 98 canonical box. 4 tails => 3 steps of 88/3.
|
||||
const W = 88, H = 98, R = 10, DEPTH = 16, TAILS = 4
|
||||
const step = W / (TAILS - 1)
|
||||
|
||||
let d = `M${R} 0 H${W - R} A${R} ${R} 0 0 1 ${W} ${R} V${H}`
|
||||
for (let i = 1; i < TAILS; i++) {
|
||||
d += ` L${(W - step * (i - 0.5)).toFixed(3)} ${H - DEPTH}`
|
||||
d += ` L${(W - step * i).toFixed(3)} ${H}`
|
||||
}
|
||||
d += ` V${R} A${R} ${R} 0 0 1 ${R} 0 Z`
|
||||
|
||||
const VARIANTS = {
|
||||
// navy, vermilion, yellow on the paper sheet
|
||||
light: {ground: '#F8F5EF', bands: ['#001A55', '#ED663F', '#FECD00']},
|
||||
// the palette's dark counterparts, lifted so they carry on a dark ground
|
||||
dark: {ground: null, bands: ['#5B8FD0', '#E07A5C', '#D8AD10']},
|
||||
// greys ordered by the colour version's relative luminance
|
||||
tinted: {ground: null, bands: ['#737373', '#B8B8B8', '#F2F2F2']},
|
||||
}
|
||||
|
||||
const v = VARIANTS[new URLSearchParams(location.search).get('v') || 'light']
|
||||
// Mark occupies 62% of the tile's height, which lands it inside Apple's grid
|
||||
// with the margin the squircle mask wants.
|
||||
const markH = 1024 * 0.62
|
||||
|
||||
const svg = [`<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024">`]
|
||||
if (v.ground) svg.push(`<rect width="1024" height="1024" fill="${v.ground}"/>`)
|
||||
svg.push(`<defs><clipPath id="mark"><path d="${d}"/></clipPath></defs>`)
|
||||
svg.push(`<g transform="translate(${512 - markH * W / H / 2} ${512 - markH / 2}) scale(${markH / H})">`)
|
||||
svg.push(`<g clip-path="url(#mark)">`)
|
||||
v.bands.forEach((color, i) => {
|
||||
svg.push(`<rect x="${(W / 3 * i).toFixed(3)}" y="0" width="${(W / 3).toFixed(3)}" height="${H}" fill="${color}"/>`)
|
||||
})
|
||||
svg.push(`</g></g></svg>`)
|
||||
document.getElementById('tile').innerHTML = svg.join('')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
# Renders the three app-icon variants from appicon.html into the asset catalog.
|
||||
#
|
||||
# scripts/appicon/generate.sh
|
||||
#
|
||||
# Chrome is the rasteriser because it is the only thing on a stock Mac that
|
||||
# renders SVG the same way the browser preview sheets in docs/ do. The PNGs it
|
||||
# writes are build output — edit appicon.html, not them.
|
||||
set -euo pipefail
|
||||
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
OUT="$HERE/../../Marks/Assets.xcassets/AppIcon.appiconset"
|
||||
CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
||||
|
||||
[ -x "$CHROME" ] || { echo "Google Chrome not found at $CHROME" >&2; exit 1; }
|
||||
command -v magick >/dev/null || { echo "ImageMagick (magick) not found" >&2; exit 1; }
|
||||
|
||||
render() {
|
||||
local variant=$1 name=$2
|
||||
"$CHROME" --headless=new --disable-gpu --hide-scrollbars \
|
||||
--default-background-color=00000000 \
|
||||
--screenshot="$OUT/$name" --window-size=1024,1024 \
|
||||
--virtual-time-budget=2000 \
|
||||
"file://$HERE/appicon.html?v=$variant" >/dev/null 2>&1
|
||||
echo " $name"
|
||||
}
|
||||
|
||||
echo "rendering app icon ->"
|
||||
render light AppIcon.png
|
||||
render dark AppIcon-Dark.png
|
||||
render tinted AppIcon-Tinted.png
|
||||
|
||||
# The light icon is the one shipped as the home-screen artwork, and iOS rejects
|
||||
# an alpha channel there. The dark and tinted variants are composited by the
|
||||
# system over a background it supplies, so they must keep theirs.
|
||||
magick "$OUT/AppIcon.png" -background '#F8F5EF' -alpha remove -alpha off "$OUT/AppIcon.png"
|
||||
|
||||
echo "done"
|
||||
Reference in New Issue
Block a user