the symptom, in your words
"Editing .razor safely (shell/emoji mojibake)"
✓ verified on engine 26.07lane: Tooling & environmentposted
▸ SYMPTOM
- Hotbar / toast / button emoji become garbage (
🥚, etc.). - Em-dashes in copy become
—. - Panel still compiles but looks broken; git diff is unreadable noise.
▸ CAUSE
.razor files are UTF-8 (often BOM-less) and frequently contain emoji as icons (20–30px font-size is a common HUD pattern). PowerShell 5.1 Get-Content/Set-Content re-encodes them as ANSI — same trap as general source corruption (powershell-mojibake-utf8).
▸ FIX
Do:
- Edit
.razor/.razor.scssin a real editor (Cursor/VS), or - Python / byte-safe .NET read-modify-write:
snippet
$f = "Code\UI\Hud.razor"
$c = [System.Text.Encoding]::UTF8.GetString([System.IO.File]::ReadAllBytes($f))
# edit $c
[System.IO.File]::WriteAllBytes($f, [System.Text.Encoding]::UTF8.GetBytes($c))Don't:
snippet
# destroys emoji
(Get-Content $f) -replace 'old','new' | Set-Content $fIf already corrupted: restore from git if possible; otherwise apply the cp1252 round-trip recovery on a copy first (powershell-mojibake-utf8).
After edits: confirm @namespace, and that BuildHash() still covers markup reads (ui-frozen-buildhash).
▸ WHY IT WORKS
Razor source is plain UTF-8 text the compiler feeds to the UI generator. Shell tools that assume the system ANSI code page mutate bytes before the compiler ever sees them — byte-preserving APIs leave the emoji codepoints intact.
✓
Verified on engine 26.07 — seen in a real project.
s&box moves fast; an undated fix is a liability. Spot a stale detail?
related gotchas
Windows/PowerShell traps that corrupt s&box source
Get-Content/Set-Content re-encodes BOM-less UTF-8 as ANSI; CRLF files break \n-only search-replace — use byte-safe APIs.
Building an s&box HUD
One ScreenPanel host, static UIState for modals, self-closing panels, toast stack — BuildHash every flag the markup reads.
My s&box UI won't update / is frozen
BuildHash() is the only re-render trigger — hash everything the markup reads, including collection contents and flags.
The Razor @namespace trap
Razor classes get a RootNamespace/folder-derived namespace — declare @namespace and global using or C# can't find your panels.