feat(parity): G3 visual parity harness; first old-vs-gpui comparison recorded

Fixed sample sheet (boxdraw families, blocks/shades/quadrants/sextants, Powerline separators, CJK alignment ruler, 256/truecolor bars) injected via the focus-free ConPTY injector, captured with PrintWindow PW_RENDERFULLCONTENT. First pass: structural parity across the board - boxes closed and seamless, CJK ruler column-aligned, Powerline triangles crisper on the GPUI side thanks to boxdraw geometry. Follow-ups: same-theme comparison after config sharing, real fastfetch once installed, zoomed stroke-weight audit.
This commit is contained in:
kuddev committed 2026-08-13 11:20:41 +08:00
1 parent b46dee5cf9
commit ebfa958e54
2 files changed
+149 -2

No files matched your search

+8 -2
View File
@@ -56,8 +56,14 @@
全部 0% CPU)。旧壳发行版始终带侧载对所以从未暴露。修复列入 P2;
运维规则:任何 nebula 系 exe 旁必须部署侧载对。
- **1b IME 清单**:输出一页人工验收清单,等用户有空亲手敲。
- **1c 视觉对账集**:fastfetch + powerline 提示符 + TUI 边框在新旧两壳的
并排截图脚本与基准图。
- **1c 视觉对账集**:`scripts/visual_parity.ps1`——固定样张(boxdraw 全家
桶、块/浓度/象限、Powerline 分隔符、CJK 对齐标尺、256 色/真彩)注入
两壳并截图(`.tmp_parity_<tag>.png`)。
**首轮对账 2026-08-13:结构级持平**——框线闭合无缝、CJK 标尺逐列对
齐、Powerline 三角在 GPUI 侧(boxdraw 几何)边缘更干净;`mixed/half/
trans` 几行两壳同样偏怪(旧壳像素栅格化的既有观感,非回归)。
待办:config 共享后做同主题对比;fastfetch 未安装(装上即可入集);
放大级笔画粗细对账。
### P2 实验场补齐终端体验(在 `nebula_gpui` 快速迭代)
+141
View File
@@ -0,0 +1,141 @@
# 视觉对账(G3 闸门):向终端注入一份固定样张,截图存档,供新旧两壳
# 并排对比。样张覆盖 GPUI 迁移最容易翻车的渲染面:
# boxdraw 全家桶(单/重/双线、圆角、虚线、对角线)、块元素与浓度块、
# 象限块、Powerline 分隔符(三角/箭头/圆头)、CJK 对齐标尺、
# 256 色与真彩渐变。
# fastfetch 若在 PATH 上则追加真实 fastfetch 输出。
#
# 用法:
# .\scripts\visual_parity.ps1 -Exe <nebula.exe> -Tag winit-old -ExeArgs '--working-directory D:\temp_build\nebula'
# .\scripts\visual_parity.ps1 -Exe <nebula-gpui.exe> -Tag gpui-lab
param(
[Parameter(Mandatory = $true)][string]$Exe,
[Parameter(Mandatory = $true)][string]$Tag,
[string]$ExeArgs = '',
[int]$SettleSec = 4
)
$ErrorActionPreference = 'Stop'
$root = Split-Path -Parent $PSScriptRoot
$contentFile = Join-Path $root '.tmp_parity_content.ps1'
$injector = Join-Path $PSScriptRoot 'perf_inject.ps1'
$outPng = Join-Path $root ".tmp_parity_$Tag.png"
# ---- 1. 样张(每次重写,保持权威版本在本脚本内)---------------------------
$e = [char]27
@"
`$e = [char]27
Write-Host "== visual parity sample =="
Write-Host '-- boxdraw: light / heavy / double / rounded / dashes / diagonals'
Write-Host '┌───┬───┐ ┏━━━┳━━━┓ ╔═══╦═══╗ ╭───╮'
Write-Host '│ a │ b │ ┃ c ┃ d ┃ ║ e ║ f ║ │ g │'
Write-Host '├───┼───┤ ┣━━━╋━━━┫ ╠═══╬═══╣ ╰───╯'
Write-Host '└───┴───┘ ┗━━━┻━━━┛ ╚═══╩═══╝ ┄┄┅┅┈┈┉┉ ╌╌╍╍'
Write-Host 'mixed: ┍┑┕┙ ┎┒┖┚ ╒╕╘╛ ╓╖╙╜ half: ╴╵╶╷╸╹╺╻ trans: ╼╽╾╿'
Write-Host 'diag: ╱╲╳╱╲╳ vertical dashes: ┆┇┊┋╎╏'
Write-Host '-- blocks / shades / quadrants'
Write-Host '▁▂▃▄▅▆▇█ ▏▎▍▌▋▊▉█ ░░▒▒▓▓██ ▀▄▌▐▔▕'
Write-Host '▖▗▘▝▚▞▙▛▜▟ legacy: 🬀🬁🬂🬃🬄🬅🬆🬇🬈🬉🬊'
Write-Host '-- powerline separators'
Write-Host "`$e[48;5;25m`$e[38;5;15m one `$e[0m`$e[38;5;25m`$e[48;5;208m$([char]0xE0B0)`$e[38;5;15m two `$e[0m`$e[38;5;208m`$e[48;5;28m$([char]0xE0B0)`$e[38;5;15m three `$e[0m`$e[38;5;28m$([char]0xE0B0)`$e[0m done"
Write-Host "chevrons: $([char]0xE0B1) $([char]0xE0B1) rtl: $([char]0xE0B2) $([char]0xE0B3) round: $([char]0xE0B4) $([char]0xE0B6)"
Write-Host '-- CJK alignment ruler (竖线必须逐列对齐)'
Write-Host '|12345678901234567890123456789012|'
Write-Host '|中文宽字符对齐测试一二三四五六七八|'
Write-Host '|あいうえおかきくけこさしすせそたち|'
Write-Host '|ab中cd文ef字gh宽ij齐kl测mn试op对qr|'
Write-Host '-- colors'
`$bar = ''
foreach (`$i in 16..51) { `$bar += "`$e[48;5;`${i}m " }
Write-Host "`$bar`$e[0m"
`$grad = ''
foreach (`$i in 0..31) { `$r = `$i * 8; `$grad += "`$e[48;2;`${r};64;`$((255 - `$r))m " }
Write-Host "`$grad`$e[0m"
if (Get-Command fastfetch -ErrorAction SilentlyContinue) { fastfetch }
Write-Host '== end of sample =='
"@ | Set-Content -Path $contentFile -Encoding UTF8
# ---- 2. Win32 助手 ----------------------------------------------------------
Add-Type @'
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
public class ParityWin {
[DllImport("user32.dll")] static extern bool EnumWindows(EnumProc cb, IntPtr lp);
[DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
[DllImport("user32.dll")] static extern bool IsWindowVisible(IntPtr h);
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);
[DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr h, IntPtr after, int x, int y, int w, int hh, uint flags);
[DllImport("user32.dll")] public static extern bool PrintWindow(IntPtr h, IntPtr dc, uint flags);
public struct RECT { public int L, T, R, B; }
delegate bool EnumProc(IntPtr h, IntPtr lp);
public static List<IntPtr> WindowsOf(uint pid) {
var list = new List<IntPtr>();
EnumWindows((h, lp) => {
uint p; GetWindowThreadProcessId(h, out p);
if (p == pid && IsWindowVisible(h)) list.Add(h);
return true;
}, IntPtr.Zero);
return list;
}
}
'@
Add-Type -AssemblyName System.Drawing
Add-Type -MemberDefinition '[DllImport("shcore.dll")] public static extern int SetProcessDpiAwareness(int value);' -Name Dpi -Namespace ParityDpi
[void][ParityDpi.Dpi]::SetProcessDpiAwareness(2)
function Get-MainWindow([int]$ProcessId) {
for ($i = 0; $i -lt 40; $i++) {
$wins = [ParityWin]::WindowsOf($ProcessId)
if ($wins.Count -gt 0) {
$best = $null; $bestW = -1
foreach ($h in $wins) {
$r = New-Object ParityWin+RECT
[void][ParityWin]::GetWindowRect($h, [ref]$r)
if (($r.R - $r.L) -gt $bestW) { $bestW = $r.R - $r.L; $best = $h }
}
return $best
}
Start-Sleep -Milliseconds 500
}
throw "no visible window for pid $ProcessId"
}
# ---- 3. 驱动:启动 → 注入 → 截图 → 清理 ------------------------------------
Write-Host "launching $Exe $ExeArgs"
$proc = if ($ExeArgs) {
Start-Process -FilePath $Exe -ArgumentList $ExeArgs -PassThru
} else {
Start-Process -FilePath $Exe -PassThru
}
Start-Sleep -Seconds 7
if ($proc.HasExited) { throw "terminal exited immediately (mux hand-over? pass -ExeArgs)" }
$hwnd = Get-MainWindow -ProcessId $proc.Id
# 可见但不抢焦点(HWND_TOPMOST, SWP_NOSIZE|NOMOVE|NOACTIVATE)。
[void][ParityWin]::SetWindowPos($hwnd, [IntPtr](-1), 0, 0, 0, 0, 0x13)
$command = "powershell -NoProfile -ExecutionPolicy Bypass -File $contentFile"
$ok = $false
for ($attempt = 0; $attempt -lt 5; $attempt++) {
$out = & powershell -NoProfile -ExecutionPolicy Bypass -File $injector `
-HostPid $proc.Id -Text $command -Enter 2>&1 | Out-String
if ($out -match 'ok=True') { $ok = $true; break }
Start-Sleep -Seconds 2
}
if (-not $ok) { Stop-Process -Id $proc.Id -Force; throw "inject failed: $out" }
Start-Sleep -Seconds $SettleSec
$r = New-Object ParityWin+RECT
[void][ParityWin]::GetWindowRect($hwnd, [ref]$r)
$w = $r.R - $r.L; $h = $r.B - $r.T
$bmp = New-Object System.Drawing.Bitmap $w, $h
$g = [System.Drawing.Graphics]::FromImage($bmp)
$dc = $g.GetHdc()
# PW_RENDERFULLCONTENT = 2:GPU 合成(D3D/GL)表面必需。
$shot = [ParityWin]::PrintWindow($hwnd, $dc, 2)
$g.ReleaseHdc($dc); $g.Dispose()
$bmp.Save($outPng, [System.Drawing.Imaging.ImageFormat]::Png)
$bmp.Dispose()
Write-Host "shot ok=$shot ${w}x${h} -> $outPng"
Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue