s&box/field-guide
the symptom, in your words

"Whitespace next to a Razor tag or expression boundary collapses to nothing"

✓ verified on engine 26.07lane: Writing gameplayposted
▸ SYMPTOM

Spaces between Razor expressions or between inline elements and text disappear at render time. For example, chunks <span class="cval">@x</span> more text renders as chunks123more with no spacing. A plain multi-expression line like @_worldSize × @_worldSize also loses its spacing, rendering as 256×256 instead of 256 × 256. Using &nbsp; (U+00A0) doesn't help — it vanishes too.

▸ CAUSE

The engine's Razor rendering pipeline collapses whitespace that is immediately adjacent to a tag or expression boundary. A literal space right before <span> and right after </span> both vanish, while a space in the middle of one uninterrupted text run (no tag or expression boundary crossed) survives. The &nbsp; workaround fails because U+00A0 still satisfies char.IsWhiteSpace in .NET, so the collapse logic treats it identically to a regular space.

▸ FIX

Two approaches, in order of preference:

  1. Collapse into a single interpolated string — when no per-fragment styling is needed, merge multiple @expr/literal fragments into one C# expression: @($"{worldSize} × {worldSize}"). This produces a single text node with no tag/expression boundary for the collapse logic to act on.

  2. Use CSS margin on inner elements — when a styled inner <span> genuinely needs breathing room from its neighbours, apply margin on the span's class (e.g. .cval { margin: 0 3px; }) instead of relying on a text-node space. Box-model spacing doesn't go through the whitespace-collapse pass at all and is the only reliable fix once &nbsp; has already failed.

HTML entities that aren't whitespace (&middot;, &times;, etc.) decode and render correctly — entities themselves aren't the problem. Only whitespace-class characters are collapsed.

▸ WHY IT WORKS

The whitespace collapse targets characters that pass .NET's char.IsWhiteSpace check when they sit at a tag/expression boundary. Approach 1 eliminates those boundaries entirely (one text node, nothing to collapse). Approach 2 moves the spacing into the CSS box model, which is resolved after text-node processing, so the whitespace pass never sees it. The key insight: whitespace in the middle of a continuous text run is safe — the collapse only fires at structural boundaries.

Verified on engine 26.07 — seen in a real project.
s&box moves fast; an undated fix is a liability. Spot a stale detail?