Add-Type -AssemblyName System.Drawing Add-Type -AssemblyName System.Windows.Forms $ErrorActionPreference = 'Stop' $Root = Split-Path -Parent $PSScriptRoot $OutDir = Join-Path $Root 'store-assets' $IconPath = Join-Path $Root '1.0.3.2_mv3\icons\128.png' if (-not (Test-Path $OutDir)) { New-Item -ItemType Directory -Force -Path $OutDir | Out-Null } function Color-Hex($hex) { return [System.Drawing.ColorTranslator]::FromHtml($hex) } function New-Font($size, $style = [System.Drawing.FontStyle]::Regular) { return New-Object System.Drawing.Font('Segoe UI', $size, $style, [System.Drawing.GraphicsUnit]::Pixel) } function New-Canvas($width, $height) { $bitmap = New-Object System.Drawing.Bitmap($width, $height, [System.Drawing.Imaging.PixelFormat]::Format24bppRgb) $graphics = [System.Drawing.Graphics]::FromImage($bitmap) $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias $graphics.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::ClearTypeGridFit $graphics.Clear((Color-Hex '#f4f6fb')) return [pscustomobject]@{ Bitmap = $bitmap; Graphics = $graphics } } function New-RoundRectPath($x, $y, $w, $h, $r) { $path = New-Object System.Drawing.Drawing2D.GraphicsPath $d = $r * 2 $path.AddArc($x, $y, $d, $d, 180, 90) $path.AddArc($x + $w - $d, $y, $d, $d, 270, 90) $path.AddArc($x + $w - $d, $y + $h - $d, $d, $d, 0, 90) $path.AddArc($x, $y + $h - $d, $d, $d, 90, 90) $path.CloseFigure() return $path } function Fill-RoundRect($g, $x, $y, $w, $h, $r, $color) { $brush = New-Object System.Drawing.SolidBrush($color) $path = New-RoundRectPath $x $y $w $h $r $g.FillPath($brush, $path) $path.Dispose() $brush.Dispose() } function Draw-RoundRect($g, $x, $y, $w, $h, $r, $color, $width = 1) { $pen = New-Object System.Drawing.Pen($color, $width) $path = New-RoundRectPath $x $y $w $h $r $g.DrawPath($pen, $path) $path.Dispose() $pen.Dispose() } function Draw-Text($g, $text, $x, $y, $size, $colorHex, $style = [System.Drawing.FontStyle]::Regular, $maxWidth = 0, $maxHeight = 0) { $font = New-Font $size $style $brush = New-Object System.Drawing.SolidBrush((Color-Hex $colorHex)) if ($maxWidth -gt 0) { $rect = New-Object System.Drawing.RectangleF($x, $y, $maxWidth, $(if ($maxHeight -gt 0) { $maxHeight } else { 1000 })) $format = New-Object System.Drawing.StringFormat $format.Trimming = [System.Drawing.StringTrimming]::EllipsisWord $g.DrawString($text, $font, $brush, $rect, $format) $format.Dispose() } else { $g.DrawString($text, $font, $brush, [float]$x, [float]$y) } $brush.Dispose() $font.Dispose() } function Draw-CenteredText($g, $text, $x, $y, $w, $h, $size, $colorHex, $style = [System.Drawing.FontStyle]::Regular) { $font = New-Font $size $style $brush = New-Object System.Drawing.SolidBrush((Color-Hex $colorHex)) $rect = New-Object System.Drawing.RectangleF($x, $y, $w, $h) $format = New-Object System.Drawing.StringFormat $format.Alignment = [System.Drawing.StringAlignment]::Center $format.LineAlignment = [System.Drawing.StringAlignment]::Center $g.DrawString($text, $font, $brush, $rect, $format) $format.Dispose() $brush.Dispose() $font.Dispose() } function Draw-Header($g, $subtitle) { Fill-RoundRect $g 64 48 1152 88 18 (Color-Hex '#ffffff') Draw-RoundRect $g 64 48 1152 88 18 (Color-Hex '#dfe3ec') 1 if (Test-Path $IconPath) { $icon = [System.Drawing.Image]::FromFile($IconPath) $g.DrawImage($icon, 88, 66, 48, 48) $icon.Dispose() } Draw-Text $g 'YouTube Line' 152 63 28 '#151922' ([System.Drawing.FontStyle]::Bold) Draw-Text $g $subtitle 152 98 17 '#667085' } function Draw-Browser($g, $x, $y, $w, $h, $url = 'youtube.com/watch') { Fill-RoundRect $g $x $y $w $h 16 (Color-Hex '#ffffff') Draw-RoundRect $g $x $y $w $h 16 (Color-Hex '#d6dce8') 1 Fill-RoundRect $g ($x + 1) ($y + 1) ($w - 2) 56 16 (Color-Hex '#f0f3f8') $dotColors = @('#ef4444', '#f59e0b', '#22c55e') for ($i = 0; $i -lt 3; $i++) { $brush = New-Object System.Drawing.SolidBrush((Color-Hex $dotColors[$i])) $g.FillEllipse($brush, $x + 24 + ($i * 24), $y + 22, 12, 12) $brush.Dispose() } Fill-RoundRect $g ($x + 118) ($y + 14) ($w - 154) 30 14 (Color-Hex '#ffffff') Draw-Text $g $url ($x + 140) ($y + 19) 14 '#667085' } function Draw-Player($g, $x, $y, $w, $h, $progress, $lineColor, $showControls = $false) { Fill-RoundRect $g $x $y $w $h 10 (Color-Hex '#111827') $sky = New-Object System.Drawing.Drawing2D.LinearGradientBrush( (New-Object System.Drawing.Rectangle($x, $y, $w, $h)), (Color-Hex '#172033'), (Color-Hex '#05070c'), 90 ) $path = New-RoundRectPath $x $y $w $h 10 $g.FillPath($sky, $path) $path.Dispose() $sky.Dispose() Fill-RoundRect $g ($x + 78) ($y + 82) ($w - 156) ($h - 188) 18 (Color-Hex '#1e293b') Draw-CenteredText $g 'Video player' ($x + 78) ($y + 92) ($w - 156) 72 28 '#e5e7eb' ([System.Drawing.FontStyle]::Bold) Draw-CenteredText $g 'Native controls hidden' ($x + 78) ($y + 145) ($w - 156) 38 17 '#9ca3af' $barY = $y + $h - 18 Fill-RoundRect $g ($x + 24) $barY ($w - 48) 6 3 (Color-Hex '#9ca3af') Fill-RoundRect $g ($x + 24) $barY ([int](($w - 48) * $progress)) 6 3 (Color-Hex $lineColor) if ($showControls) { Fill-RoundRect $g ($x + 30) ($y + $h - 74) ($w - 60) 44 10 (Color-Hex '#000000') Draw-Text $g '0:42 / 4:15' ($x + 84) ($y + $h - 63) 17 '#ffffff' Fill-RoundRect $g ($x + 44) ($y + $h - 58) 18 18 3 (Color-Hex '#ffffff') } } function Draw-Badge($g, $x, $y, $text, $bgHex, $fgHex) { $font = New-Font 16 ([System.Drawing.FontStyle]::Bold) $size = $g.MeasureString($text, $font) $w = [int]$size.Width + 34 $h = 34 Fill-RoundRect $g $x $y $w $h 17 (Color-Hex $bgHex) Draw-CenteredText $g $text $x $y $w $h 16 $fgHex ([System.Drawing.FontStyle]::Bold) $font.Dispose() return $w } function Draw-OptionRow($g, $x, $y, $label, $valueHex) { Draw-Text $g $label $x ($y + 8) 18 '#344054' Fill-RoundRect $g ($x + 230) $y 112 40 8 (Color-Hex '#f9fafb') Draw-RoundRect $g ($x + 230) $y 112 40 8 (Color-Hex '#d0d5dd') 1 Fill-RoundRect $g ($x + 244) ($y + 10) 20 20 4 (Color-Hex $valueHex) Draw-Text $g $valueHex ($x + 274) ($y + 9) 15 '#344054' } function Save-Canvas($canvas, $path) { $canvas.Bitmap.Save($path, [System.Drawing.Imaging.ImageFormat]::Png) $canvas.Graphics.Dispose() $canvas.Bitmap.Dispose() } function New-MainScreenshot { $c = New-Canvas 1280 800 $g = $c.Graphics Draw-Header $g 'A persistent progress line for the YouTube player' Draw-Browser $g 96 170 1088 536 Draw-Player $g 140 252 790 394 0.43 '#ff2f2f' $false Draw-Text $g 'Progress stays visible' 965 274 28 '#101828' ([System.Drawing.FontStyle]::Bold) 205 120 Draw-Text $g 'Keep track of video playback even when the native controls fade out.' 965 390 19 '#475467' ([System.Drawing.FontStyle]::Regular) 185 150 Draw-Badge $g 965 500 'Always on' '#fee4e2' '#b42318' | Out-Null Draw-Badge $g 965 547 'Clean UI' '#e0f2fe' '#026aa2' | Out-Null Draw-Badge $g 965 594 'YouTube only' '#ecfdf3' '#027a48' | Out-Null Save-Canvas $c (Join-Path $OutDir 'youtube-line-screenshot-main-1280x800.png') } function New-OptionsScreenshot { $c = New-Canvas 1280 800 $g = $c.Graphics Draw-Header $g 'Customize the line color, progress color, and height' Draw-Browser $g 96 170 1088 536 'chrome-extension://options' Fill-RoundRect $g 165 244 420 376 18 (Color-Hex '#ffffff') Draw-RoundRect $g 165 244 420 376 18 (Color-Hex '#d0d5dd') 1 Draw-Text $g 'YouTube Line Settings' 205 287 27 '#101828' ([System.Drawing.FontStyle]::Bold) Draw-OptionRow $g 205 356 'Background color' '#808080' Draw-OptionRow $g 205 424 'Progress color' '#ff0000' Draw-Text $g 'Line height' 205 500 18 '#344054' Fill-RoundRect $g 435 492 112 40 8 (Color-Hex '#f9fafb') Draw-RoundRect $g 435 492 112 40 8 (Color-Hex '#d0d5dd') 1 Draw-CenteredText $g '2 px' 435 492 112 40 16 '#344054' Fill-RoundRect $g 205 560 342 44 8 (Color-Hex '#ef4444') Draw-CenteredText $g 'Save' 205 560 342 44 17 '#ffffff' ([System.Drawing.FontStyle]::Bold) Draw-Player $g 650 272 445 282 0.62 '#ff0000' $false Draw-Text $g 'Live preview' 650 582 22 '#101828' ([System.Drawing.FontStyle]::Bold) Draw-Text $g 'Your settings are stored locally in Chrome.' 650 616 17 '#667085' ([System.Drawing.FontStyle]::Regular) 420 Save-Canvas $c (Join-Path $OutDir 'youtube-line-screenshot-options-1280x800.png') } function New-BeforeAfterScreenshot { $c = New-Canvas 1280 800 $g = $c.Graphics Draw-Header $g 'See playback progress without opening the controls' Draw-Browser $g 96 170 1088 536 Draw-Text $g 'Without extension' 158 242 24 '#475467' ([System.Drawing.FontStyle]::Bold) Draw-Text $g 'With YouTube Line' 676 242 24 '#101828' ([System.Drawing.FontStyle]::Bold) Draw-Player $g 150 292 450 292 0.00 '#111827' $false Fill-RoundRect $g 176 558 398 5 3 (Color-Hex '#111827') Draw-CenteredText $g 'Progress is hidden with controls' 150 604 450 38 17 '#667085' Draw-Player $g 668 292 450 292 0.47 '#ff2f2f' $false Draw-CenteredText $g 'Progress remains visible' 668 604 450 38 17 '#667085' $pen = New-Object System.Drawing.Pen((Color-Hex '#d0d5dd'), 2) $g.DrawLine($pen, 640, 248, 640, 652) $pen.Dispose() Save-Canvas $c (Join-Path $OutDir 'youtube-line-screenshot-before-after-1280x800.png') } function New-SmallPromoTile { $c = New-Canvas 440 280 $g = $c.Graphics $g.Clear((Color-Hex '#111827')) if (Test-Path $IconPath) { $icon = [System.Drawing.Image]::FromFile($IconPath) $g.DrawImage($icon, 28, 28, 56, 56) $icon.Dispose() } Draw-Text $g 'YouTube Line' 104 30 30 '#ffffff' ([System.Drawing.FontStyle]::Bold) Draw-Text $g 'Keep video progress visible' 104 70 17 '#cbd5e1' Fill-RoundRect $g 28 168 384 8 4 (Color-Hex '#94a3b8') Fill-RoundRect $g 28 168 224 8 4 (Color-Hex '#ff3030') Fill-RoundRect $g 28 202 180 36 18 (Color-Hex '#fee4e2') Draw-CenteredText $g 'Always visible' 28 202 180 36 16 '#b42318' ([System.Drawing.FontStyle]::Bold) Save-Canvas $c (Join-Path $OutDir 'youtube-line-promo-small-440x280.png') } function New-MarqueePromoTile { $c = New-Canvas 1400 560 $g = $c.Graphics $g.Clear((Color-Hex '#101828')) if (Test-Path $IconPath) { $icon = [System.Drawing.Image]::FromFile($IconPath) $g.DrawImage($icon, 90, 88, 96, 96) $icon.Dispose() } Draw-Text $g 'YouTube Line' 220 84 56 '#ffffff' ([System.Drawing.FontStyle]::Bold) Draw-Text $g 'Keep video progress visible when YouTube controls fade out.' 224 154 27 '#cbd5e1' ([System.Drawing.FontStyle]::Regular) 570 Draw-Badge $g 224 240 'Always visible' '#fee4e2' '#b42318' | Out-Null Draw-Badge $g 420 240 'Customizable' '#e0f2fe' '#026aa2' | Out-Null Draw-Badge $g 618 240 'YouTube only' '#ecfdf3' '#027a48' | Out-Null Fill-RoundRect $g 90 390 610 10 5 (Color-Hex '#94a3b8') Fill-RoundRect $g 90 390 356 10 5 (Color-Hex '#ff3030') Draw-Browser $g 820 78 470 340 Draw-Player $g 850 158 410 230 0.57 '#ff3030' $false Fill-RoundRect $g 850 450 410 44 22 (Color-Hex '#ffffff') Draw-CenteredText $g 'Progress line stays visible' 850 450 410 44 20 '#101828' ([System.Drawing.FontStyle]::Bold) Save-Canvas $c (Join-Path $OutDir 'youtube-line-promo-marquee-1400x560.png') } New-MainScreenshot New-OptionsScreenshot New-BeforeAfterScreenshot New-SmallPromoTile New-MarqueePromoTile Get-ChildItem -LiteralPath $OutDir -Filter '*.png' | Sort-Object Name | Select-Object FullName, Length