CellBar (luna:CellBar) is the celled combat bar: an Overwatch-style resource
pool rendered as discrete slanted cells. Health, armor and shield stack in one strip,
damage drains from the top of the stack with a white hit flash and a red ghost that
lingers under fire, heals sweep in, pickups pop per cell, and the whole bar pulses
faster and redder the closer you are to zero.
It shares the animation core with the rest of the family (see Architecture) but renders through the mesh painter, so cells, slant, gradients and the damage grammar are native. For a continuous meter with ruler ticks (League-style), use the linear Progress Bar instead: two idioms, two components.
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:luna="CupkekGames.Luna">
<luna:CellBar name="Vitals"
cell-size="25" slant="10" cell-gap="3"
threshold="0.334"
feel="../Presets/CellBarFeelOverwatch.asset"
style="width: 280px; height: 16px;" />
</ui:UXML>CellBar bar = root.Q<CellBar>("Vitals");
bar.SetResources(("health", 100f, 100f), ("armor", 50f, 50f));
bar.Damage(70f); // drains armor first, flash + ghost + drain play
bar.Heal("health", 45f); // clamps to the resource max, sweep plays
bar.Add("armor", 50f); // pickup, per-cell pop cascade playsValues are units, never normalized fractions. cell-size is units per cell, so 150
total pool at 25 per cell renders 6 cells, and a 700 pool renders 28. The pool comes
from SetResources; each entry is (id, current, max) in render order, and damage
always drains the last resource first.
Every mutation produces a delta that the component turns into motion:
| Beat | What plays |
|---|---|
| Damage | The lost span flashes white, the fill drains fast, and a red ghost holds at the pre-hit total before draining. New hits during the hold extend it (up to a cap), so a burst reads as one chunk. |
| Heal | The positive indicator leads, the fill follows, and a bright band sweeps across the healed span. |
Pickup (Add) | Cells the gain completes pop with a white flash, staggered left to right; partial fills get only the sweep. |
| Low pool | Below threshold, fill colors pulse toward the low tint. Rate and intensity scale with severity: 0.9 Hz at the threshold, up to 2 Hz near zero. |
The threshold evaluates on the animated values, not the raw data write: the pulse starts when the drain visually lands, which is what you want.
All grammar numbers live in a CellBarFeelAsset (Create > CupkekGames > Luna >
Cell Bar Feel): fill/drain durations and easings, duration mode, ghost hold and cap,
flash, sweep, pop and pulse settings. Assign it with the feel attribute (relative
path in samples) or bar.Feel = asset; swapping the asset swaps the whole feel.
Two presets ship with the Showcase sample under ProgressBar/Presets/:
CellBarFeelOverwatch (the reference numbers) and CellBarFeelSubtle (softer flash
and pop, gentler pulse). Assigning a feel also zeroes first-delay/second-delay so
the ghost hold is the only ghost timing authority.
Without an asset, the same values are settable directly: ghost-hold-ms and
ghost-hold-cap-ms are UXML attributes; flash/sweep/pop/pulse settings are C#
properties (FlashDurationMs, SweepColor, PulseRateMaxHz, LowTintColor, ...).
| Attribute | Default | Description |
|---|---|---|
cell-size | 25 | Units per cell. Cell count is ceil(max-value / cell-size). |
slant | 10 | Cell shear in degrees. 0 gives straight cells. |
cell-gap | 2 | Pixels between cells. |
sizing-mode | Stretch | Stretch fills the element's USS box. FixedCellWidth sizes the element from the pool. |
cell-width | 18 | Cell width in pixels (FixedCellWidth only). |
cell-height | 14 | Cell height in pixels (FixedCellWidth only). |
max-row-width | 0 | FixedCellWidth wrap limit; 0 means a single row. |
row-gap | 3 | Pixels between wrapped rows. |
edge-cap-width | 2 | Bright cap at the leading fill edge; 0 disables. |
threshold | 0 | Normalized low-pool threshold for the pulse and the cell-bar--below-threshold class. |
FixedCellWidth with max-row-width gives the tank read: bar length is proportional
to the pool and wraps to extra rows when it does not fit.
Colors resolve USS-first with attribute fallbacks:
.my-vitals {
--cell-bar-color-0: #ECE8E1; /* resource run colors by index, 0..9 */
--cell-bar-color-1: #69F5EA;
--cell-bar-bg-color: rgba(255, 255, 255, 0.08);
--cell-bar-outline-color: rgba(255, 255, 255, 0.10);
--cell-bar-indicator-negative-color: #ED3B4A;
--cell-bar-indicator-positive-color: #BFF5EF;
--cell-bar-edge-cap-color: rgba(255, 255, 255, 0.85);
}Attribute equivalents: color-background, color-outline, color-edge-cap, plus the
family's shared color-indicator-positive / color-indicator-negative. Segment
colors can also be set in code through bar.Progress[i].Color.
The cell-bar--below-threshold class toggles with the threshold, and the six external
transition slots from the family (fill, drain, complete, pulse-below, filled) are
available for element-level juice on top of the internal grammar.
The Showcase sample's ProgressBarOverwatchCelled scene is the flagship: the entire
controller is button wiring and label updates, the component owns the rest. The
sibling ProgressBarOverwatch scene keeps the manual approach on the linear bar for
comparison, and the EsportLobby experience drives its match HUD vitals with a CellBar
and an esl-skinned feel asset.
The CellBarLab scene pushes the same element into four less obvious shapes: an ammo
grid using FixedCellWidth wrap (30 rounds in two rows, instant shots, pop-cascade
reload), a versus split where the right bar is mirrored with scale: -1 1 so it
drains toward the center, a rainbow combo meter charged by scripted Add ticks, and
an extremes pair showing the same value on one 100-unit cell versus one hundred
1-unit cells. Everything in the lab is stock attributes plus the combat facade.
Settings
Theme
Light
Contrast
Material
Dark
Dim
Material Dark
System
Sidebar(Light & Contrast only)
Font Family
DM Sans
Wix
Inclusive Sans
AR One Sans
Direction