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
Binary file modified Assets.xcassets/AppIcon.appiconset/128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Assets.xcassets/AppIcon.appiconset/128@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Assets.xcassets/AppIcon.appiconset/16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Assets.xcassets/AppIcon.appiconset/16@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Assets.xcassets/AppIcon.appiconset/256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Assets.xcassets/AppIcon.appiconset/256@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Assets.xcassets/AppIcon.appiconset/32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Assets.xcassets/AppIcon.appiconset/32@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Assets.xcassets/AppIcon.appiconset/512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Assets.xcassets/AppIcon.appiconset/512@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Assets.xcassets/AppIconDark.imageset/AppIconDark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Assets.xcassets/AppIconLight.imageset/AppIconLight.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions Assets.xcassets/MenuBarIconTemplate.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "MenuBarIconTemplate-16.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "MenuBarIconTemplate-32@2x.png",
"idiom" : "universal",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 28 additions & 16 deletions CLI/programa.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5761,33 +5761,45 @@ struct ProgramaCLI {

let isDark = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") == "Dark"

let c1 = trueColor(0, 212, 255)
let c2 = trueColor(24, 181, 250)
let c3 = trueColor(48, 150, 245)
let c4 = trueColor(72, 119, 241)
let c5 = trueColor(96, 88, 239)
let c6 = trueColor(110, 73, 238)
let c7 = trueColor(124, 58, 237)

// Row colors, light → dark red (develop gradient), plus the accent cursor cell.
let r1: String, r2: String, r3: String, r4: String, cursor: String
// Wordmark letter ramp (8 letters).
let w: [String]
let tagline: String
let subdued: String

if isDark {
tagline = trueColor(130, 130, 140)
r1 = trueColor(255, 107, 82) // #FF6B52
r2 = trueColor(240, 64, 42) // #F0402A
r3 = trueColor(220, 46, 30) // #DC2E1E
r4 = trueColor(194, 31, 22) // #C21F16
cursor = trueColor(255, 138, 102) // #FF8A66
w = [trueColor(255, 107, 82), trueColor(248, 90, 62), trueColor(240, 74, 46),
trueColor(230, 60, 36), trueColor(220, 46, 30), trueColor(210, 38, 26),
trueColor(194, 31, 22), trueColor(194, 31, 22)]
tagline = trueColor(140, 130, 136)
subdued = "\u{001B}[2m"
} else {
r1 = trueColor(232, 68, 46) // #E8442E
r2 = trueColor(212, 47, 31) // #D42F1F
r3 = trueColor(194, 31, 22) // #C21F16
r4 = trueColor(162, 24, 17) // #A21811
cursor = trueColor(232, 68, 46) // #E8442E
w = [trueColor(232, 68, 46), trueColor(222, 56, 38), trueColor(212, 47, 31),
trueColor(202, 39, 26), trueColor(194, 31, 22), trueColor(178, 27, 19),
trueColor(162, 24, 17), trueColor(162, 24, 17)]
tagline = trueColor(90, 90, 98)
subdued = trueColor(100, 100, 108)
}

let wordmark = "\(w[0])p\(w[1])r\(w[2])o\(w[3])g\(w[4])r\(w[5])a\(w[6])m\(w[7])a\(reset)"

// Shade-ramp cells are doubled so they stay square in 1:2 terminal cells.
let logo = """
\(c1) ::\(reset)
\(c2) ::::\(reset) \(c1)p\(c2)r\(c3)o\(c4)g\(c5)r\(c6)a\(c7)m\(c7)a\(reset)
\(c3) ::::::\(reset)
\(c4) ::::::\(reset) \(tagline)the open source terminal\(reset)
\(c5) ::::::\(reset) \(tagline)built for coding agents\(reset)
\(c6) ::::\(reset)
\(c7) ::\(reset)
\(r1)\u{2596}\u{2596} \u{2591}\u{2591} \u{2592}\u{2592} \u{2593}\u{2593}\(reset) \(wordmark)
\(r2)\u{2591}\u{2591} \u{2592}\u{2592} \u{2593}\u{2593} \u{2588}\u{2588}\(reset)
\(r3)\u{2592}\u{2592} \u{2593}\u{2593} \u{2588}\u{2588} \u{2588}\u{2588}\(reset) \(tagline)the open source terminal\(reset)
\(r4)\u{2593}\u{2593} \u{2588}\u{2588} \u{2588}\u{2588} \(cursor)\u{2588}\u{2588}\(reset) \(tagline)built for coding agents\(reset)
"""

let shortcuts = """
Expand Down
34 changes: 7 additions & 27 deletions Sources/MenuBarIconRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,8 @@ enum MenuBarIconRenderer {
image.lockFocus()
defer { image.unlockFocus() }

let glyphRect = NSRect(x: 1.2, y: 1.5, width: 11.6, height: 15.0)
// Template art is 16px drawn on integer pixels; keep the rect integral.
let glyphRect = NSRect(x: 1, y: 1, width: 16, height: 16)
drawGlyph(in: glyphRect)

if let text = badgeText {
Expand All @@ -619,32 +620,11 @@ enum MenuBarIconRenderer {
}

private static func drawGlyph(in rect: NSRect) {
// Match the canonical cmux center-mark path from Icon Center Image Artwork.svg.
let srcMinX: CGFloat = 384.0
let srcMinY: CGFloat = 255.0
let srcWidth: CGFloat = 369.0
let srcHeight: CGFloat = 513.0

func map(_ x: CGFloat, _ y: CGFloat) -> NSPoint {
let nx = (x - srcMinX) / srcWidth
let ny = (y - srcMinY) / srcHeight
return NSPoint(
x: rect.minX + nx * rect.width,
y: rect.minY + (1.0 - ny) * rect.height
)
}

let path = NSBezierPath()
path.move(to: map(384.0, 255.0))
path.line(to: map(753.0, 511.5))
path.line(to: map(384.0, 768.0))
path.line(to: map(384.0, 654.0))
path.line(to: map(582.692, 511.5))
path.line(to: map(384.0, 369.0))
path.close()

NSColor.black.setFill()
path.fill()
// Dedicated 16px template cut (pure black + alpha); the dither
// characters in the app icon break below ~24px, so never scale
// other assets down here.
guard let template = NSImage(named: "MenuBarIconTemplate") else { return }
template.draw(in: rect, from: .zero, operation: .sourceOver, fraction: 1.0)
}

private static func drawBadge(text: String, in rect: NSRect, config: MenuBarBadgeRenderConfig) {
Expand Down
Binary file added scripts/icon-gen/AppIcon-1024.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 2 additions & 10 deletions scripts/icon-gen/finalize.sh
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
#!/bin/bash
# Emit all Programa icon assets from the master renders (run gen.sh first).
# Emit all Programa icon assets from the master render (run gen.sh first).
set -euo pipefail
cd "$(dirname "$0")"
OUT=out; rm -rf $OUT; mkdir -p $OUT/main

# Small-size variant: no glow (kills contrast at 16/32), boosted glyph
magick bg.png -alpha off glyph.png -compose over -composite PNG32:art_small_square.png
A=824; S=1024; R=186; M=$(( (S - A) / 2 ))
magick art_small_square.png -resize ${A}x${A} -background none -gravity center -extent ${S}x${S} \
mask.png -compose CopyOpacity -composite -modulate 108,118 PNG32:icon_small_master.png

emit() { # emit <srcmaster> <px> <dest>
magick "$1" -resize "$2x$2" -unsharp 0x0.6+0.4+0 "PNG32:$3"
}

# Main appiconset (light + dark = same art; the icon IS the darkroom)
for spec in 16:16 32:16@2x 32:32 64:32@2x 128:128 256:128@2x 256:256 512:256@2x 512:512 1024:512@2x; do
px=${spec%%:*}; name=${spec##*:}
src=icon_master.png; [ "$px" -le 32 ] && src=icon_small_master.png
emit $src "$px" "$OUT/main/$name.png"
cp "$OUT/main/$name.png" "$OUT/main/${name}_dark.png"
emit icon_master.png "$px" "$OUT/main/$name.png"
done

# Icon Composer layer (full-bleed square, system applies mask/shadow)
Expand Down
56 changes: 6 additions & 50 deletions scripts/icon-gen/gen.sh
Original file line number Diff line number Diff line change
@@ -1,58 +1,14 @@
#!/bin/bash
# Programa app icon generator — pixel-art terminal prompt, darkroom-safelight red.
# Programa app icon pipeline — squircle-mask the committed master (AppIcon-1024.png).
# The master art (dark ground, glowing dither grid, darkroom-safelight red) is
# designed externally; this script only applies the macOS squircle + baked shadow.
set -euo pipefail
cd "$(dirname "$0")"

S=1024 # master canvas
C=44 # pixel cell size
GW=12; GH=8 # glyph grid
X0=$(( (S - GW*C) / 2 ))
Y0=$(( (S - GH*C) / 2 ))
S=1024
cp AppIcon-1024.png art_square.png

# --- 1. Pixel glyph: ">" chevron + "_" cursor on a 12x8 grid -----------------
# cells as col ranges per row: row:colstart-colend (inclusive)
CHEVRON="0:0-1 1:0-3 2:2-5 3:4-7 4:4-7 5:2-5 6:0-3 7:0-1"
CURSOR="7:9-11"

draw=""
row_color() { # brighter at top, deeper at bottom — retro ramp
case $1 in
0) echo "#FF6248";; 1) echo "#FF5940";; 2) echo "#FA5038";; 3) echo "#F44730";;
4) echo "#EE3F29";; 5) echo "#E63722";; 6) echo "#DE301C";; 7) echo "#D62A17";;
esac
}
for spec in $CHEVRON; do
r=${spec%%:*}; range=${spec##*:}; c1=${range%%-*}; c2=${range##*-}
x1=$(( X0 + c1*C )); y1=$(( Y0 + r*C )); x2=$(( X0 + (c2+1)*C - 1 )); y2=$(( y1 + C - 1 ))
draw+=" fill $(row_color $r) rectangle $x1,$y1 $x2,$y2"
done
for spec in $CURSOR; do
r=${spec%%:*}; range=${spec##*:}; c1=${range%%-*}; c2=${range##*-}
x1=$(( X0 + c1*C )); y1=$(( Y0 + r*C )); x2=$(( X0 + (c2+1)*C - 1 )); y2=$(( y1 + C - 1 ))
draw+=" fill #FF8A66 rectangle $x1,$y1 $x2,$y2"
done

magick -size ${S}x${S} xc:none -draw "$draw" glyph.png

# --- 2. Background: near-black vertical gradient + vignette ------------------
magick -size ${S}x${S} gradient:'#1A191D'-'#0A090C' bg_grad.png
magick -size ${S}x${S} radial-gradient:'#00000000'-'#000000B0' vignette.png
magick bg_grad.png vignette.png -compose over -composite bg.png

# --- 3. Safelight glow: glyph flattened on black, blurred, screened on ------
# (screen with black = no-op, so only the glow adds light)
magick glyph.png -fill '#FF2D14' -colorize 45 -background black -alpha remove -alpha off \
-blur 0x90 -evaluate multiply 0.62 glow_wide.png
magick glyph.png -background black -alpha remove -alpha off \
-blur 0x22 -evaluate multiply 0.85 glow_tight.png

magick bg.png -alpha off \
glow_wide.png -compose screen -composite \
glow_tight.png -compose screen -composite \
glyph.png -compose over -composite \
art_square.png

# --- 4. Squircle icon w/ baked shadow (for .appiconset) ----------------------
# --- Squircle icon w/ baked shadow (for .appiconset) ----------------------
A=824; R=186; M=$(( (S - A) / 2 ))
magick -size ${S}x${S} xc:none -draw "roundrectangle $M,$M $((S-M-1)),$((S-M-1)) $R,$R" mask.png
magick art_square.png -resize ${A}x${A} -background none -gravity center -extent ${S}x${S} art_plate.png
Expand Down
Loading