The 4-Category Model

At the heart of RCE is a reactive state machine with four combat categories. Each category holds its own independent set of shapes that define the reticle's appearance for that state. When the active state changes, RCE handles the transition animation automatically.

CategoryEnum ValueTypical Use
HUD LoadoutState.HUD Always-on elements. Shapes in this category render continuously regardless of the active combat state. Use for static crosshairs, compass widgets, or persistent UI anchors.
Situational Awareness LoadoutState.SituationalAwareness The idle/scanning state. Typically a wider, lower-profile reticle for general navigation. Active when no weapon actions are occurring.
Hip Fire LoadoutState.HipFire Firing from the hip. Often a tighter, more dynamic reticle with spread indicators or animated elements that react to fire rate.
Aim Down Sight LoadoutState.AimDownSight Precision aiming. Usually the most detailed reticle — stadia marks, fine crosshairs, ranging indicators.
Note

HUD layers render on top of every state. The other three categories (SA, HF, ADS) are mutually exclusive — only one is active at a time, and switching between them triggers a category transition.

Global Category

In addition to the four standard categories, RCE provides a Global category for transient effects like hit markers, damage flashes, and kill confirmations. Global layers render on a dedicated renderer instance, completely isolated from the main reticle pipeline. This means global animations are never interrupted by category transitions. See the GlobalFX API for runtime control.


Loadouts

A loadout is the top-level container for all reticle configuration. It holds:

Loadouts are serialized as versioned JSON (currently schema v8) and stored on disk. The ILoadoutStorage interface handles persistence, and the LoadoutSerializer manages migration between schema versions automatically.

Modding Support

Because loadouts are plain JSON files, they're inherently modding-friendly. Players or community tools can create and share loadout files. RCE's version migration ensures older loadouts always load correctly in newer engine versions.


Layers

Each category contains an ordered list of layers. A layer represents a single SDF shape (circle, polygon, lineburst, etc.) with its own set of properties:

Property GroupWhat It Controls
Shape TypeThe SDF primitive — Circle, Ring, Polygon, LineBurst, Chevron, Stadia, ChamferBox, or Custom
TransformPosition (X, Y), rotation, scale (X, Y)
ColorFill color with alpha, plus separate outline color
GlowIntensity and size of the outer glow emanating from the shape boundary
OutlineTrue outline: a separate colored border rendered outside the shape fill
FeatherEdge softness. 0 = hard pixel-perfect edges, higher = softer anti-aliasing
HollowDonut/ring mode: thickness of the hollow interior
GapGap mode (Radial, Grid, Lines, CenterCutout) with inversion and SDF geometry options
Shape ParamsType-specific parameters (polygon sides, lineburst count, stadia marks, etc.)
AnimationsPer-layer property animations — see Animations

Layers are rendered back-to-front in list order. Each layer occupies one ShapeData slot in the GPU structured buffer.


Boolean Groups

Layers can be combined into boolean groups using union or subtraction operations. A group consists of a base layer (the primary shape) and one or more operand layers that modify it.

Because these operations happen at the SDF level, glow and outline effects follow the true combined boundary of the group, not the individual shape edges. This means glow pools naturally in concavities and outlines wrap around the merged silhouette — a significant visual quality advantage over simple alpha masking.

Editor Tip

In the editor, operand layers are shown indented under their base layer. Collapsing a group hides its operands. Deleting a base layer removes the entire group. The Link Operands toggle makes transform changes on the base layer propagate to all operands as a parent-child relationship.


Rendering Pipeline

Understanding the data flow helps when debugging or extending RCE. Here's how a frame gets from your game state to pixels on screen:

LoadoutManager
CategoryTransitionAnimator
ShapePropertyAnimator
LoadoutRendererBridge
ReticleRenderer
GPU
  1. LoadoutManager receives SetActiveState() calls and emits the current category's shapes as an array of ShapeData structs.
  2. CategoryTransitionAnimator (CTA) intercepts state changes. If a transition is configured for this state pair, it interpolates between the old and new shape arrays over the transition duration using the selected transition type and easing.
  3. ShapePropertyAnimator (SPA) applies per-layer continuous animations — spin, oscillate, pulse, tween, etc. — as additive deltas on top of the base shape data. Animations pause during active transitions.
  4. LoadoutRendererBridge sanitizes the final shape array, uploads it to the GPU structured buffer, and triggers the render pass.
  5. ReticleRenderer issues a single draw call. The ReticleSDF fragment shader evaluates every shape's SDF, applies glow, outline, feathering, gaps, and boolean operations, then composites the result.

For Global category layers, a parallel pipeline exists: LoadoutManager.EmitGlobalShapes()GlobalFXBridge (visibility filtering) → ShapePropertyAnimator → a dedicated second ReticleRenderer instance. This keeps global effects fully isolated from combat state rendering.


Signed Distance Fields (SDF)

Every shape in RCE is defined mathematically as a signed distance field. For any point on screen, the SDF function returns the distance from that point to the nearest shape boundary: negative values are inside, positive values are outside, and zero is exactly on the edge.

This representation has several advantages over sprite-based approaches:

For custom freeform shapes, RCE computes an exact Bézier SDF using a compute shader that evaluates the distance to cubic Bézier curves analytically — no approximation or rasterization. The result is stored in a texture array and sampled in the same fragment shader pass as all other shapes.


What's Next