terminalCode Example

Decal component — projecting bullet holes, scorch marks, and surface details

calendar_today May 5, 2026 schedule ~1 min read person patrickjr verified 50

Decal Component — Projecting Surface Marks

Decal projects a texture onto surfaces in the world. Use it for bullet holes, blood splats, scorch marks, graffiti, and any surface detail that needs to conform to geometry.

Basic Decal Placement

CSHARP
public sealed class BulletImpact : Component
{
    [Property] public DecalDefinition ImpactDecal { get; set; }

    public void PlaceAt( Vector3 position, Vector3 normal )
    {
        var go = Scene.CreateObject();
        go.WorldPosition = position;
        // Face the decal along the surface normal
        go.WorldRotation = Rotation.LookAt( -normal, Vector3.Up );

        var decal = go.Components.Create<Decal>();
        decal.DecalDefinition = ImpactDecal;
        decal.Width  = 8f;
        decal.Height = 8f;
        decal.Depth  = 16f;   // projection depth into the surface

        // Auto-remove after 30 seconds
        go.DestroyAsync( 30f );
    }
}

DecalDefinition Asset

Create a DecalDefinition asset (Asset Browser → New Asset → Decal Definition) to define the material, size, and randomization:

  • Set Rotation to a range (e.g. 0–360) for random orientation on spawn
  • Define multiple definitions on one Decal component for random variety
  • Set Lifetime on the definition for automatic fade-out

Transient Decals

Mark a decal as transient so it's automatically removed when the scene's decal limit is exceeded (oldest removed first):

CSHARP
decal.Transient = true;

Tracing to Find Placement

Typical usage — trace a ray and place a decal at the hit point:

CSHARP
var tr = Scene.Trace
    .Ray( WorldPosition, WorldPosition + WorldRotation.Forward * 1000f )
    .WithoutTags( "player" )
    .Run();

if ( tr.Hit )
{
    var go = Scene.CreateObject();
    go.WorldPosition = tr.HitPosition + tr.Normal * 0.5f;  // slight offset
    go.WorldRotation = Rotation.LookAt( -tr.Normal );

    var decal = go.Components.Create<Decal>();
    decal.DecalDefinition = BulletHoleDecal;
    decal.Transient = true;
}
Was this helpful?