ui/napalmoverlay.razor.scss
// NAPALM OVERLAY — the game's own fullscreen fire, played as a sprite sheet.
//
// ⛔ THIS IS THE REAL ASSET AND THE FIRST VERSION OF THIS FILE WAS NOT. I wrote a pair of CSS
// radial gradients and called it fire; the pack ships `nz_moo/overlay/fullscreen_fire` — the actual
// texture, whose own .vmt is a SpriteCard with `animatedTextureFrameRate 30`. Its VTF header says
// 256x128 and SIXTEEN frames, and the shipped PNG is 1024x512: a 4x4 sheet, exactly.
//
// ⚠️ THE MOD ITSELF ONLY EVER DRAWS IT 40x40. Every `zmhud_player_onfire` call in every one of the
// nine HUD variants is a small icon on the player-status card — so the fullscreen use here is OURS,
// built on their texture rather than copied from their code. The texture is plainly authored for it:
// nothing needs a 16-frame 30fps animation to fill forty pixels.
//
// ⚠️ ADDITIVE, AS THE .vmt ASKS (`$Additive 1`). Fire adds light, it does not tint — over a dark map
// the difference is the whole look, and `mix-blend-mode` is what carries it here.
.napalm
{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
// ⚠️ ABOVE the ash and the damage vignette, below anything the player reads. Heat is the most
// urgent of the three ambient overlays because it is a warning rather than a report.
z-index: 42;
.layer
{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
}
// ── the sheet ────────────────────────────────────────────────────────────
//
// ⛔ `background-size: 400% 400%` IS WHAT MAKES ONE FRAME FILL THE SCREEN. The sheet is four
// frames wide and four tall, so scaling it to four screens in each axis puts exactly one frame
// in view, and the keyframes below pick which. Getting this wrong shows all sixteen at once,
// which reads as a broken texture rather than as a wrong number.
//
// ⚠️ POSITIONS ARE 0/33.33/66.67/100%, NOT 0/25/50/75. Percentage background-position is a
// RATIO of the leftover space, not a distance — with a 4-wide sheet the four frames sit at
// thirds. This is the classic sprite-sheet trap and it looks like a slight drift, not a bug.
.flame
{
background-image: url( "ui/nz/napalm/fullscreen_fire.png" );
background-size: 400% 400%;
background-repeat: no-repeat;
// Fire adds light rather than covering what is behind it.
mix-blend-mode: lighten;
// 16 frames at 30fps = 0.5333s, the rate the .vmt states.
animation: napalm-fire 0.5333s step-end infinite;
}
// A slow swell underneath, so the heat reads as building rather than just flickering.
.wash
{
background-image: radial-gradient(
ellipse at center,
rgba(255, 90, 20, 0) 42%,
rgba(255, 80, 12, 0.45) 78%,
rgba(190, 35, 0, 0.85) 100%
);
animation: napalm-breathe 1.9s ease-in-out infinite;
}
}
// Row 0 then row 1, 2, 3 — reading order, which is how the VTF stacks its frames.
@keyframes napalm-fire
{
0.00% { background-position: 0% 0%; }
6.25% { background-position: 33.33% 0%; }
12.50% { background-position: 66.67% 0%; }
18.75% { background-position: 100% 0%; }
25.00% { background-position: 0% 33.33%; }
31.25% { background-position: 33.33% 33.33%; }
37.50% { background-position: 66.67% 33.33%; }
43.75% { background-position: 100% 33.33%; }
50.00% { background-position: 0% 66.67%; }
56.25% { background-position: 33.33% 66.67%; }
62.50% { background-position: 66.67% 66.67%; }
68.75% { background-position: 100% 66.67%; }
75.00% { background-position: 0% 100%; }
81.25% { background-position: 33.33% 100%; }
87.50% { background-position: 66.67% 100%; }
93.75% { background-position: 100% 100%; }
100% { background-position: 0% 0%; }
}
@keyframes napalm-breathe
{
0% { transform: scale(1.00); }
50% { transform: scale(1.06); }
100% { transform: scale(1.00); }
}