<# make-icon.ps1 - generate a Claude-styled multi-size app icon (icon.ico) + preview.png. Coral rounded tile with a white radial "spark" mark. #> $ErrorActionPreference = 'Stop' Add-Type -AssemblyName System.Drawing $root = Split-Path -Parent $MyInvocation.MyCommand.Path function New-Tile([int]$S) { $bmp = New-Object System.Drawing.Bitmap($S, $S, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb) $g = [System.Drawing.Graphics]::FromImage($bmp) $g.SmoothingMode = 'AntiAlias' $g.InterpolationMode = 'HighQualityBicubic' $g.PixelOffsetMode = 'HighQuality' $g.Clear([System.Drawing.Color]::Transparent) # rounded tile $pad = [math]::Max(1, [int]($S * 0.06)) $rect = New-Object System.Drawing.Rectangle($pad, $pad, ($S - 2 * $pad), ($S - 2 * $pad)) $rad = [int]($S * 0.225) $path = New-Object System.Drawing.Drawing2D.GraphicsPath $d = $rad * 2 $path.AddArc($rect.X, $rect.Y, $d, $d, 180, 90) $path.AddArc($rect.Right - $d, $rect.Y, $d, $d, 270, 90) $path.AddArc($rect.Right - $d, $rect.Bottom - $d, $d, $d, 0, 90) $path.AddArc($rect.X, $rect.Bottom - $d, $d, $d, 90, 90) $path.CloseFigure() # coral gradient $c1 = [System.Drawing.Color]::FromArgb(226, 138, 101) # lighter coral $c2 = [System.Drawing.Color]::FromArgb(193, 95, 60) # deeper terracotta $brush = New-Object System.Drawing.Drawing2D.LinearGradientBrush($rect, $c1, $c2, 90) $g.FillPath($brush, $path) # subtle top sheen $sheen = New-Object System.Drawing.Drawing2D.LinearGradientBrush( $rect, [System.Drawing.Color]::FromArgb(38, 255, 255, 255), [System.Drawing.Color]::FromArgb(0, 255, 255, 255), 90) $g.FillPath($sheen, $path) # toggle-switch glyph (white track + coral knob) - the "рубильник", distinct from Claude's spark $tw = $S * 0.54; $th = $S * 0.30 $tx = ($S - $tw) / 2.0; $ty = ($S - $th) / 2.0 $tp = New-Object System.Drawing.Drawing2D.GraphicsPath $tp.AddArc($tx, $ty, $th, $th, 90, 180) $tp.AddArc($tx + $tw - $th, $ty, $th, $th, 270, 180) $tp.CloseFigure() $trackBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(240, 248, 246, 239)) $g.FillPath($trackBrush, $tp) # knob on the ON (right) side, coral so it reads as cut out of the white track $knobD = $th - ($S * 0.09) $knobX = $tx + $tw - $knobD - ($S * 0.045) $knobY = $ty + (($th - $knobD) / 2.0) $knobBrush = New-Object System.Drawing.SolidBrush($c2) $g.FillEllipse($knobBrush, $knobX, $knobY, $knobD, $knobD) $g.Dispose(); $brush.Dispose(); $sheen.Dispose(); $trackBrush.Dispose(); $knobBrush.Dispose(); $tp.Dispose() $bmp } # preview $preview = New-Tile 256 $preview.Save((Join-Path $root 'preview.png'), [System.Drawing.Imaging.ImageFormat]::Png) # build .ico (PNG-compressed entries, Vista+) $sizes = @(16, 24, 32, 48, 64, 128, 256) $pngs = @() foreach ($s in $sizes) { $b = New-Tile $s $ms = New-Object System.IO.MemoryStream $b.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png) $pngs += , @{ size = $s; bytes = $ms.ToArray() } $b.Dispose(); $ms.Dispose() } $icoPath = Join-Path $root 'icon.ico' $fs = New-Object System.IO.FileStream($icoPath, [System.IO.FileMode]::Create) $bw = New-Object System.IO.BinaryWriter($fs) # ICONDIR $bw.Write([uint16]0) # reserved $bw.Write([uint16]1) # type = icon $bw.Write([uint16]$pngs.Count) # count $offset = 6 + 16 * $pngs.Count foreach ($p in $pngs) { $wh = if ($p.size -ge 256) { 0 } else { $p.size } $bw.Write([byte]$wh) # width $bw.Write([byte]$wh) # height $bw.Write([byte]0) # palette $bw.Write([byte]0) # reserved $bw.Write([uint16]1) # planes $bw.Write([uint16]32) # bpp $bw.Write([uint32]$p.bytes.Length) $bw.Write([uint32]$offset) $offset += $p.bytes.Length } foreach ($p in $pngs) { $bw.Write($p.bytes) } $bw.Flush(); $bw.Close(); $fs.Close() Write-Host "icon.ico : $icoPath ($([math]::Round((Get-Item $icoPath).Length/1KB)) KB, sizes: $($sizes -join ','))" Write-Host "preview : $(Join-Path $root 'preview.png')"