ab2d3ed8cd
Windows tray "switch" that routes all Claude MSIX-app traffic through a SOCKS5/HTTP proxy or a VLESS+Reality tunnel (embedded Xray-core), with a fail-closed Windows Firewall lock. Runs de-elevated so it launches the user's normal Claude instance; elevates only for firewall changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
100 lines
4.0 KiB
PowerShell
100 lines
4.0 KiB
PowerShell
<#
|
|
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')"
|