s&box Package Code Search

Search C# source code, UI razor templates, shaders, and configs across s&box packages.

Showing code results for query: * (86 total matches found)
facepunch.breakout / .obj/__compiler_extra.cs
Game game
global using static Sandbox.Internal.GlobalGameNamespace;
global using Microsoft.AspNetCore.Components;
global using Microsoft.AspNetCore.Components.Rendering;
[assembly: global::System.Reflection.AssemblyMetadata( "AddonTitle", "Breakout" )]
[assembly: global::System.Reflection.AssemblyMetadata( "AddonIdent", "breakout" )]
[assembly: global::System.Reflection.AssemblyMetadata( "OrgIdent", "facepunch" )]
[assembly: global::System.Reflection.AssemblyMetadata( "Ident", "facepunch.breakout" )]
[assembly: global::System.Reflection.AssemblyMetadata( "EngineVersion", "27" )]
[assembly: global::System.Reflection.AssemblyMetadata( "EngineMinorVersion", "1" )]

[assembly: System.Runtime.Versioning.TargetFramework( ".NETCoreApp,Version=v9.0", FrameworkDisplayName = ".NET 9.0" )]
[assembly: global::System.Reflection.AssemblyMetadata( "CompileTime", "2026-07-08T09:04:56.5456514Z" )]
[assembly: global::System.Reflection.AssemblyVersion("0.0.111.0")]
[assembly: global::System.Reflection.AssemblyFileVersion("0.0.111.0")]
facepunch.breakout / Game/GameFeedback.cs
Game game
using System;
using Sandbox;

namespace Breakout;

/// <summary>
/// Owns purely-cosmetic game juice: the center banner, the damage flash, camera shake, brick
/// debris, wall-hit sparks, confetti and the board-clear sting. BreakoutGame delegates here and
/// re-exposes the banner/damage state for the HUD.
/// </summary>
[Title( "Game Feedback" ), Category( "Breakout" ), Icon( "auto_awesome" )]
public sealed class GameFeedback : Component
{
	[Property] public GameObject DebrisPrefab { get; set; }
	[Property] public GameObject WallHitPrefab { get; set; }
	[Property] public GameObject ConfettiPrefab { get; set; }
	[Property] public float LifeLostShake { get; set; } = 0.65f;

	/// <summary>
	/// Big center banner text, like "LEVEL 1" or "BOARD CLEAR!".
	/// </summary>
	public string BannerText { get; private set; }

	/// <summary>
	/// Smaller line shown beneath the banner (may be null).
	/// </summary>
	public string BannerSub { get; private set; }

	/// <summary>
	/// Ticks up each time a new banner is shown, so the HUD can restart its animation.
	/// </summary>
	public int BannerSeq { get; private set; }

	/// <summary>
	/// True while the banner should currently be visible.
	/// </summary>
	public bool BannerActive => !string.IsNullOrEmpty( BannerText ) && bannerSince < bannerHold;

	/// <summary>
	/// Ticks up each time the player takes damage, so the HUD can restart the red flash.
	/// </summary>
	public int DamageSeq { get; private set; }

	/// <summary>
	/// True while the red damage flash should currently be showing.
	/// </summary>
	public bool DamageActive => DamageSeq > 0 && damageSince < DamageFlashHold;

	private RealTimeSince bannerSince;
	private float bannerHold;
	private RealTimeSince damageSince;
	private const float DamageFlashHold = 0.05f;

	/// <summary>
	/// Shows the center banner with optional sub-text for hold seconds.
	/// </summary>
	public void ShowBanner( string text, string sub = null, float hold = 1.1f )
	{
		BannerText = text;
		BannerSub = sub;
		bannerSince = 0f;
		bannerHold = hold;
		BannerSeq++;
	}

	/// <summary>
	/// Kicks off the red screen flash and a small camera shake when the player loses a life.
	/// </summary>
	public void TriggerDamageFeedback()
	{
		damageSince = 0f;
		DamageSeq++;
		ShakeCamera( LifeLostShake );
	}

	/// <summary>
	/// Shakes the camera. Bigger amount means a stronger, longer shake.
	/// </summary>
	public void ShakeCamera( float amount )
	{
		if ( amount <= 0f )
			return;

		Scene.Camera.AddShake( amount * 20, amount * 10f, 0.5f );
	}

	/// <summary>
	/// Spawns the shatter particles for a broken brick, tinted to match it.
	/// </summary>
	public void SpawnDebris( Block block )
	{
		if ( !block.IsValid() || DebrisPrefab is null )
			return;

		var go = DebrisPrefab.Clone( new CloneConfig( new Transform( block.WorldPosition ), startEnabled: false ) );

		foreach ( var fx in go.Components.GetAll<ParticleEffect>( FindMode.EverythingInSelfAndDescendants ) )
			fx.Tint = block.HealthyTint;

		go.Enabled = true;
	}

	/// <summary>
	/// Spawns a spark burst facing inward where the ball hit a wall or the paddle.
	/// </summary>
	public void SpawnWallHit( Vector3 worldPos, Vector3 inwardNormal )
	{
		if ( WallHitPrefab is null )
			return;

		var n = inwardNormal.Normal;
		var up = MathF.Abs( n.z ) > 0.99f ? Vector3.Forward : Vector3.Up;
		var rot = Rotation.LookAt( n, up );
		WallHitPrefab.Clone( new CloneConfig( new Transform( worldPos, rot ), name: "wall_hit" ) );
	}

	/// <summary>
	/// Spawns the celebratory confetti burst used on a board clear.
	/// </summary>
	public void SpawnConfetti( Vector3 worldPos ) => ConfettiPrefab?.Clone( worldPos );

	/// <summary>
	/// Plays the rising three-note chime used when a board is cleared.
	/// </summary>
	public void PlayClearSting()
	{
		float[] pitches = { 1.15f, 1.5f, 1.9f };
		foreach ( var pitch in pitches )
		{
			var note = Sound.Play( "brick_break_01" );
			if ( note is not null )
				note.Pitch = pitch;
		}
	}
}
facepunch.breakout / UI/Controls.razor
Game game
@using System
@using Sandbox
@using Sandbox.UI
@namespace Breakout
@inherits Panel

@if ( Game.IsValid() && Game.State != GameState.Menu && Game.Level <= 1 )
{
    <root>
        <div class="container">
            <span class="controls-label">CONTROLS</span>
            <div class="column">
                <div class="input">
                    @*There is no mouse/ controller move input hint so we do this.*@
                    @if(Input.UsingController)
                    {
                        <label class="type">Move</label><img src="ui/glyphs/xbox/leftjoystickbutton.svg" class="mouse-glyph" />
                    }
                    else
                    {
                        <label class="type">Move Paddle</label><img src="ui/glyphs/default/mouse.svg" class="mouse-glyph" />
                    }
                </div>
                <div class="input">
                    <label class="type">Launch</label><InputHint Action="attack1" class="key-glyph" Dark=@true />
                </div>
            </div>
        </div>

    </root>
}

@code
{
    /// <summary>
    /// The game this bar reads score, lives, level and mode from.
    /// </summary>
    [Parameter] public BreakoutGame Game { get; set; }

    // Update the ui when the game state changes or when the input method changes.
    protected override int BuildHash() => System.HashCode.Combine(Game?.State, Game?.Mode, Game?.Level, Input.UsingController);
}
facepunch.breakout / UI/HelpScreen.razor
Game game
@using System
@using Sandbox
@using Sandbox.UI
@namespace Breakout
@inherits Panel

@*
    HelpScreen is the "how to play" page you reach from the menu's HELP button. It shows a guide
    of every block type and what it does. Pressing BACK runs the Back callback, which tells the
    menu to show itself again.
*@

<root>
    <div class="help">
        <button class="back-btn" onclick=@(() => Back?.Invoke())>
            <span class="back-icon">◀</span>
            BACK
        </button>

        <div class="help-body">
            <div class="help-title">HELP</div>
            <div class="help-sub">Here is what each brick does when you hit it.</div>

            <div class="block-grid">
                @foreach ( var block in Blocks )
                {
                    <div class="block-card">
                        <img class="block-icon" src="@block.Icon" />
                        <div class="block-info">
                            <div class="block-name">@block.Name</div>
                            <div class="block-desc">@block.Description</div>
                        </div>
                    </div>
                }
            </div>
        </div>
    </div>
</root>

@code
{
    /// <summary>
    /// Called when the player presses BACK, so the menu can show itself again.
    /// </summary>
    [Parameter] public Action Back { get; set; }

    /// <summary>
    /// One row in the block guide: the icon to show, the block's name, and a short description.
    /// </summary>
    private record BlockGuideEntry( string Icon, string Name, string Description );

    // The list shown on the help page. Add a new line here to document another block type.
    private static readonly BlockGuideEntry[] Blocks =
    {
        new( "textures/blocks/normal.png", "Brick", "Breaks in a single hit." ),
        new( "textures/blocks/armoured.png", "Armoured", "Takes two hits to break." ),
        new( "textures/blocks/unbreakable.png", "Unbreakable", "Can't be broken, so play around it." ),
        new( "textures/blocks/explosion.png", "Explosive", "Blows up nearby bricks when it breaks." ),
        new( "textures/blocks/speed.png", "Fast Ball", "Turns your ball into a faster one." ),
        new( "textures/blocks/big_ball.png", "Big Ball", "Makes your ball big enough to smash armour in one hit." ),
        new( "textures/blocks/fire_ball.png", "Fireball", "Turns your ball into a fireball that burns straight through bricks." ),
        new( "textures/blocks/split.png", "Multi-Ball", "Drops a pickup that splits your ball into more." ),
        new( "textures/blocks/expand.png", "Expand", "Drops a pickup that makes your paddle wider." ),
    };
}
facepunch.breakout / styles/form/_coloreditor.scss
Game game
$primary: red !default;
$primary-alt: white !default;

$switch-padding: 6px !default;

.coloreditor
{
	flex-direction: column;
	min-width: 250px;
	max-width: 250px;

	> .canvas
	{
		border-top: 1px solid rgba( white, 0.5 );
		flex-grow: 1;
		flex-direction: column;
		padding: 10px 15px;


		> textentry.textentry
		{
			flex-grow: 0;
			flex-shrink: 0;
			width: auto;
		}
	}

	.slider
	{
		padding: 6.5px;
	}

	.slider .track
	{
		height: 14px;
		border-radius: 14px;
		left: 0px;
		right: 0px;
		transition: all 0.1s ease-out;

		.inner
		{
			display: none;
		}
	}

	.slider:hover, .slider:active
	{
		padding: 7px;

		.track
		{
			height: 20px;
			border-radius: 6px;
		}

		.thumb
		{
			width: 10px;
			height: 16px;
			margin-left: 2px;
		}
	}

	.slider .thumb
	{
		width: 10px;
		height: 10px;
		box-shadow: 0px 0px 0px transparent;
		background-color: white;
		backdrop-filter: invert( 1 );
		margin-left: 1px;
		pointer-events: none;
	}

	.alpha_slider .track
	{
		background-image: linear-gradient( to right, rgba( #ccc, 0.05 ), rgba( #ccc, 0.9 ) );
	}

	.hue .track
	{
		background: linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);

		.inner
		{
			display: none;
		}
	}

	.satval
	{
		background: linear-gradient(to right, white, transparent);
		height: 200px;
		position: relative;

		&:active
		{
			z-index: 10;
			cursor: none;
		}

		.value_gradient
		{
			background: linear-gradient(to bottom, black, white);
			position: absolute;
			top: 0;
			left: 0;
			right: 0;
			bottom: 0;
			pointer-events: none;
			mix-blend-mode: multiply;
		}

		.thumb
		{
			z-index: 10;
		}
	}

	.presets
	{
		flex-wrap: wrap;
		align-content: center;
		justify-content: center;
		padding: 15px;
		border-top: 1px solid rgba( white, 0.5 );

		.preset
		{
			background-color: white;
			width: 16px;
			height: 16px;
			margin: 2px;
			border-radius: 20px;
			cursor: pointer;
			
			&:hover
			{
				box-shadow: 0px 0px 1px 2px white;
			}
		}
	}
}


.coloreditorrgba
{
	flex-direction: column;

	.slider
	{
		padding-right: 16px;
	}

	.slider .track
	{
		background-color: transparent;
		height: 14px;
		border-radius: 14px;
		left: 0px;
		right: 0px;

		.inner
		{
			display: none;
		}
	}

	.slider .thumb
	{
		width: 12px;
		height: 12px;
		box-shadow: 0px 0px 0px transparent;
		background-color: white;
		margin-left: 2px;
		backdrop-filter: invert( 1 );
	}

	.red_slider .track
	{
		background-image: linear-gradient( to right, rgba( #e63439, 0.1 ), rgba( #e63439, 0.9 ) );
	}

	.green_slider .track
	{
		background-image: linear-gradient( to right, rgba( #54be35, 0.1 ), rgba( #54be35, 0.9 ) );
	}

	.blue_slider .track
	{
		background-image: linear-gradient( to right, rgba( #3472e6, 0.1 ), rgba( #3472e6, 0.9 ) );
	}

	.alpha_slider .track
	{
		background-image: linear-gradient( to right, rgba( #ccc, 0.05 ), rgba( #ccc, 0.9 ) );
	}
}


.coloreditorhsva
{
	flex-direction: column;

	.slider
	{
		padding-right: 16px;
	}

	.slider .track
	{
		background-color: transparent;
		height: 14px;
		border-radius: 14px;
		left: 0px;
		right: 0px;

		.inner
		{
			display: none;
		}
	}

	.slider .thumb
	{
		width: 12px;
		height: 12px;
		box-shadow: 0px 0px 0px transparent;
		background-color: white;
		margin-left: 2px;
		backdrop-filter: invert( 1 );
	}
		
	.hue_slider .track
	{
		background-image: linear-gradient( to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00 );
	}

	.alpha_slider .track
	{
		background-image: linear-gradient( to right, rgba( #ccc, 0.05 ), rgba( #ccc, 0.9 ) );
	}
}
facepunch.breakout / ui/menupanel.razor.scss
Game game
menupanel
{
    position: absolute;
    z-index: 1000;
    pointer-events: all;
    font-size: 12px;
    flex-shrink: 0;

    .background
    {
        position: absolute;
        left: -5000px;
        right: -5000px;
        top: -5000px;
        bottom: -5000px;
    }

    > .inner
    {
        min-width: 200px;
        min-height: 20px;
        flex-direction: column;
        font-family: Poppins;
        font-weight: bold;
        border-radius: 10px;
        box-shadow: 5px 5px 30px #000e;
        background-color: #2a2a2a;
        flex-shrink: 0;

        .spacer
        {
            height: 1px;
            background-color: #0005;
        }

        .option
        {
            color: #fffa;
            padding: 0px 8px;
            cursor: pointer;
            flex-shrink: 0;
            height: 32px;

            &:first-child
            {
                border-top-left-radius: 10px;
                border-top-right-radius: 10px;
            }

            &:last-child
            {
                border-bottom-left-radius: 10px;
                border-bottom-right-radius: 10px;
            }

            .icon
            {
                padding: 8px;
                font-family: Material Icons;
                justify-content: center;
                align-items: center;
                flex-shrink: 0;
            }

            .text
            {
                padding: 8px;
                flex-shrink: 0;
            }

            &:hover
            {
                background-color: #3472e6;
                color: #f5f8fe;
            }
        }
    }
}
facepunch.breakout / ui/controls/vectorcontrol.cs.scss
Game game
VectorControl
{
	gap: 2px;
	flex-grow: 1;
}

VectorControl NumberEntry
{
	flex-basis: 50%;
}
facepunch.breakout / styles/form/_checkbox.scss
Game game
@import "/styles/_theme.scss";

$primary: $primary-blue !default;
$primary-alt: white !default;
$form-control-height: 24px !default;

.checkbox
{
	cursor: pointer;
	color: rgba( $primary-alt, 0.6 );
	align-items: center;
	gap: 8px;

	label
	{
		pointer-events: none;
	}

	> .checkmark
	{
		padding: 1px;
		font-size: 22px;
		border: 1px solid $primary;
		border-radius: $rounding-small;
		text-align: center;
		justify-content: center;
		align-items: center;
		color: transparent;
		min-height: $form-control-height;
		pointer-events: none;
		flex-shrink: 0;
	}

	&.checked
	{
		> .checkmark
		{
			color: $primary-alt;
			background-color: $primary;
		}
	}

	&:active
	{
		color: $primary-alt;
	}

	&:hover
	{
		color: $primary-alt;
	}
}
facepunch.breakout / Blocks/ExplodingBlock.cs
Game game
using Sandbox;

namespace Breakout;

/// <summary>
/// A brick that blows up when destroyed, taking out every other breakable brick within
/// BlastRadius. Those can be exploding bricks too, so one blast can chain into more.
/// </summary>
[Title( "Exploding Block" ), Category( "Breakout" ), Icon( "bolt" )]
public sealed class ExplodingBlock : Block
{
	[Property] public float BlastRadius { get; set; } = 80f;

	/// <summary>
	/// Breaks this brick and destroys every other breakable brick within BlastRadius, which can chain into further explosions.
	/// </summary>
	public override void OnDestroyed()
	{
		if ( Broken )
			return;

		var origin = WorldPosition;

		base.OnDestroyed();
		Game?.HitStop( 0.05f );

		foreach ( var other in Scene.GetAllComponents<Block>().ToList() )
		{
			if ( other == this || !other.IsValid() || !other.Breakable )
				continue;

			if ( other.WorldPosition.Distance( origin ) <= BlastRadius )
				other.OnDestroyed();
		}
	}
}
facepunch.breakout / Game/GameMode.cs
Game game
namespace Breakout;

/// <summary>
/// The three ways to play. Classic is the authentic original brick wall, Arcade shuffles through
/// the custom levels, and Weekly is a shared challenge board that changes each week.
/// </summary>
public enum GameMode
{
	Classic,
	Arcade,
	Weekly
}
facepunch.breakout / Paddle/PaddleEffect.cs
Game game
using Sandbox;

namespace Breakout;

/// <summary>
/// Base class for a timed effect living on the paddle (such as the wide-paddle boost). It runs
/// OnApply when added, then removes itself after Duration seconds, calling OnRemoved on its way out.
/// </summary>
public abstract class PaddleEffect : Component
{
	[Property] public float Duration { get; set; } = 8f;

	protected Paddle Paddle { get; private set; }

	private TimeUntil expires;

	protected override void OnStart()
	{
		Paddle = Components.Get<Paddle>( FindMode.EverythingInSelfAndAncestors );
		if ( Paddle is null )
		{
			Destroy();
			return;
		}

		expires = Duration;
		OnApply();
	}

	protected override void OnUpdate()
	{
		if ( Duration > 0f && expires )
			Destroy();
	}

	protected override void OnDestroy() => OnRemoved();

	/// <summary>
	/// Called once when the effect is added. Override to start the effect.
	/// </summary>
	protected virtual void OnApply() { }

	/// <summary>
	/// Called once when the effect expires or is removed. Override to undo the effect.
	/// </summary>
	protected virtual void OnRemoved() { }
}
facepunch.breakout / styles/form/_dropdown.scss
Game game
$primary: red !default;
$primary-alt: white !default;

$switch-padding: 6px !default;

.button.popupbutton.dropdown
{
	cursor: pointer;
	transition: all .1s ease-out;
	position: relative;

	> .dropdown_indicator
	{
		position: absolute;
		right: 8px;
	}

	&.open
	{
		border-bottom-left-radius: 1px;
		border-bottom-right-radius: 1px;
		transition: border-radius 0.2s ease-out;
	}
}

select
{
	min-height: 40px;

	> option
	{
		display: none;
	}
}
facepunch.breakout / ui/controls/color/colorcontrol.cs.scss
Game game
ColorControl
{
	gap: 0.5rem;
	flex-grow: 1;
	pointer-events: all;
	background-color: #000a;
	border-radius: 4px;
	padding: 2px;
	height: 32px;
}

ColorControl TextEntry
{
	flex-grow: 1;
	flex-shrink: 0;
	color: #aaa;
	font-size: 1.2rem;

	&:hover, &:focus
	{
		color: #ddd;

		.icon
		{
			color: #3af;
		}
	}

	&:active
	{
		color: white;
	}
}

ColorControl > .colorswatch
{
	aspect-ratio: 1;
	border-radius: 4px;
	height: 100%;
	flex-shrink: 0;
	cursor: pointer;
	border: 2px solid #000;
}
facepunch.breakout / ui/inputhint.razor.scss
Game game
@import "_theme.scss";

InputHint
{
	width: 28px;
	height: 28px;
	align-items: center;
	justify-content: center;
}

.glyph
{
	width: 100%;
	height: 100%;
	background-size: contain;
	background-position: center;
	background-repeat: no-repeat;

}

.glyph.dark
{
	filter: invert( 1 );
}
facepunch.breakout / styles/form/_switch.scss
Game game
$primary: red !default;
$primary-alt: white !default;

$switch-padding: 6px !default;

.checkbox.switch
{
	cursor: pointer;

	> .checkmark
	{
		font-size: 22px;
		border: 0px solid $primary;
		border-radius: 100px;
		text-align: center;
		justify-content: center;
		align-items: center;
		color: $primary-alt;
		padding: $switch-padding;
		padding-right: 32px;
		padding-left: $switch-padding;
		transition: all 0.3s ease;
		background-color: rgba( $primary, 0.1 );

		> .handle
		{
			background-color: $primary-alt;
			width: 20px;
			height: 20px;
			border-radius: 100px;
			box-shadow: 2px 2px 12px black;
		}
	}

	&.checked
	{
		> .checkmark
		{
			background-color: $primary;
			padding-left: 32px;
			padding-right: $switch-padding;
		}
	}

	&:active
	{
		transform: scale( 0.9 );
		transform-origin: 20px 50%;
	}
}
facepunch.breakout / ui/controls/switchcontrol.razor.scss
Game game
.switchcontrol
{
    flex-direction: row;
    width: 100px;
    min-height: 24px;
    align-items: center;
    cursor: pointer;

    .switch-frame
    {
        flex-grow: 0;
        flex-shrink: 1;
        width: 48px;
        height: 16px;
        background-color: #fff1;
        margin: 0px 5px;
        align-items: center;
        border-radius: 100px;
        transition: all 0.4s linear;

        .switch-inner
        {
            position: relative;
            flex-grow: 0;
            flex-shrink: 1;
            background-color: #999;
            width: 25px;
            height: 25px;
            border-radius: 100px;
            left: 20%;
            transform: translateX( -50% );
            transition: all 0.3s ease-out;
        }
    }

    &.active
    {
        .switch-frame
        {
            background-color: #fffa;
        }

        .switch-inner
        {
            left: 80%;
            background-color: #fff;
        }
    }
}
facepunch.breakout / styles/base/_navigator.scss
Game game
.navigator-body
{
	&.hidden
	{
		display: none;
	}
}
facepunch.breakout / ui/controls/color/colorhuecontrol.cs.scss
Game game
ColorHueControl
{
	gap: 0.5rem;
	flex-grow: 1;
	pointer-events: all;
	background: linear-gradient( to right, red, yellow, lime, cyan, blue, magenta, red );
	border-radius: 4px;
	padding: 2px;
	height: 12px;
	position: relative;
	cursor: pointer;
	margin: 10px 0;
	border: 1px solid #333;

	&:hover
	{
		border: 1px solid #08f;
	}

	&:active
	{
		border: 1px solid #fff;
	}

	.handle
	{
		top: -5px;
		bottom: -5px;
		aspect-ratio: 1;
		border-radius: 100px;
		border: 2px solid #444;
		position: absolute;
		background-color: white;
		box-shadow: 2px 2px 16px #000a;
		transform: translateX( -50% );
		pointer-events: none;
	}
}
facepunch.breakout / ui/components/packagelist.razor.scss
Game game
.package-list
{
    flex-shrink: 1;
    flex-wrap: wrap;
    flex-grow: 1;

    h1
    {
        width: 100%;
        margin-top: 50px;
        font-size: 40px;
    }

    PackageCard
    {
        &:hover
        {
            sound-in: "ui.button.over";
        }
    }

    VirtualGrid
    {
        width: 100%;
        height: 100%;

        .cell
        {
            
        }
    }
}
facepunch.breakout / Level/BlockPalette.cs
Game game
using Sandbox;

namespace Breakout;

/// <summary>
/// Maps level symbols to the colors used when drawing a level's thumbnail preview. This is only for
/// the editor preview image; the in-game bricks get their color from the spawner's palette.
/// </summary>
public static class BlockPalette
{
	public static readonly Color Background = new( 0.07f, 0.08f, 0.10f );
	public static readonly Color Empty = new( 0.16f, 0.17f, 0.19f );

	/// <summary>
	/// The preview color for a level symbol (falls back to the empty-cell color for unknown symbols).
	/// </summary>
	public static Color ColorFor( char symbol )
	{
		return symbol switch
		{
			'1' => new Color( 0.95f, 0.62f, 0.20f ), // normal
			'2' => new Color( 0.36f, 0.55f, 0.78f ), // multi-hit
			'P' => new Color( 0.35f, 0.78f, 0.42f ), // power-up (multi-ball)
			'E' => new Color( 0.30f, 0.78f, 0.80f ), // expand
			'X' => new Color( 0.86f, 0.27f, 0.27f ), // exploding
			'#' => new Color( 0.55f, 0.55f, 0.58f ), // unbreakable
			'S' => new Color( 1.00f, 0.45f, 0.20f ), // fast ball
			'B' => new Color( 0.40f, 0.70f, 1.00f ), // big ball
			'F' => new Color( 1.00f, 0.35f, 0.10f ), // fireball
			_ => Empty,
		};
	}
}
Debug: View Raw JSON Response
{
    "TotalCount": 86,
    "Files": [
        {
            "Ident": "facepunch.breakout",
            "Path": ".obj/__compiler_extra.cs",
            "FileName": "__compiler_extra.cs",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "global using static Sandbox.Internal.GlobalGameNamespace;\r\nglobal using Microsoft.AspNetCore.Components;\r\nglobal using Microsoft.AspNetCore.Components.Rendering;\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"AddonTitle\", \"Breakout\" )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"AddonIdent\", \"breakout\" )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"OrgIdent\", \"facepunch\" )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"Ident\", \"facepunch.breakout\" )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"EngineVersion\", \"27\" )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"EngineMinorVersion\", \"1\" )]\r\n\r\n[assembly: System.Runtime.Versioning.TargetFramework( \".NETCoreApp,Version=v9.0\", FrameworkDisplayName = \".NET 9.0\" )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"CompileTime\", \"2026-07-08T09:04:56.5456514Z\" )]\r\n[assembly: global::System.Reflection.AssemblyVersion(\"0.0.111.0\")]\r\n[assembly: global::System.Reflection.AssemblyFileVersion(\"0.0.111.0\")]"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "Game/GameFeedback.cs",
            "FileName": "GameFeedback.cs",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "using System;\r\nusing Sandbox;\r\n\r\nnamespace Breakout;\r\n\r\n/// <summary>\r\n/// Owns purely-cosmetic game juice: the center banner, the damage flash, camera shake, brick\r\n/// debris, wall-hit sparks, confetti and the board-clear sting. BreakoutGame delegates here and\r\n/// re-exposes the banner/damage state for the HUD.\r\n/// </summary>\r\n[Title( \"Game Feedback\" ), Category( \"Breakout\" ), Icon( \"auto_awesome\" )]\r\npublic sealed class GameFeedback : Component\r\n{\r\n\t[Property] public GameObject DebrisPrefab { get; set; }\r\n\t[Property] public GameObject WallHitPrefab { get; set; }\r\n\t[Property] public GameObject ConfettiPrefab { get; set; }\r\n\t[Property] public float LifeLostShake { get; set; } = 0.65f;\r\n\r\n\t/// <summary>\r\n\t/// Big center banner text, like \"LEVEL 1\" or \"BOARD CLEAR!\".\r\n\t/// </summary>\r\n\tpublic string BannerText { get; private set; }\r\n\r\n\t/// <summary>\r\n\t/// Smaller line shown beneath the banner (may be null).\r\n\t/// </summary>\r\n\tpublic string BannerSub { get; private set; }\r\n\r\n\t/// <summary>\r\n\t/// Ticks up each time a new banner is shown, so the HUD can restart its animation.\r\n\t/// </summary>\r\n\tpublic int BannerSeq { get; private set; }\r\n\r\n\t/// <summary>\r\n\t/// True while the banner should currently be visible.\r\n\t/// </summary>\r\n\tpublic bool BannerActive => !string.IsNullOrEmpty( BannerText ) && bannerSince < bannerHold;\r\n\r\n\t/// <summary>\r\n\t/// Ticks up each time the player takes damage, so the HUD can restart the red flash.\r\n\t/// </summary>\r\n\tpublic int DamageSeq { get; private set; }\r\n\r\n\t/// <summary>\r\n\t/// True while the red damage flash should currently be showing.\r\n\t/// </summary>\r\n\tpublic bool DamageActive => DamageSeq > 0 && damageSince < DamageFlashHold;\r\n\r\n\tprivate RealTimeSince bannerSince;\r\n\tprivate float bannerHold;\r\n\tprivate RealTimeSince damageSince;\r\n\tprivate const float DamageFlashHold = 0.05f;\r\n\r\n\t/// <summary>\r\n\t/// Shows the center banner with optional sub-text for hold seconds.\r\n\t/// </summary>\r\n\tpublic void ShowBanner( string text, string sub = null, float hold = 1.1f )\r\n\t{\r\n\t\tBannerText = text;\r\n\t\tBannerSub = sub;\r\n\t\tbannerSince = 0f;\r\n\t\tbannerHold = hold;\r\n\t\tBannerSeq++;\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Kicks off the red screen flash and a small camera shake when the player loses a life.\r\n\t/// </summary>\r\n\tpublic void TriggerDamageFeedback()\r\n\t{\r\n\t\tdamageSince = 0f;\r\n\t\tDamageSeq++;\r\n\t\tShakeCamera( LifeLostShake );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Shakes the camera. Bigger amount means a stronger, longer shake.\r\n\t/// </summary>\r\n\tpublic void ShakeCamera( float amount )\r\n\t{\r\n\t\tif ( amount <= 0f )\r\n\t\t\treturn;\r\n\r\n\t\tScene.Camera.AddShake( amount * 20, amount * 10f, 0.5f );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Spawns the shatter particles for a broken brick, tinted to match it.\r\n\t/// </summary>\r\n\tpublic void SpawnDebris( Block block )\r\n\t{\r\n\t\tif ( !block.IsValid() || DebrisPrefab is null )\r\n\t\t\treturn;\r\n\r\n\t\tvar go = DebrisPrefab.Clone( new CloneConfig( new Transform( block.WorldPosition ), startEnabled: false ) );\r\n\r\n\t\tforeach ( var fx in go.Components.GetAll<ParticleEffect>( FindMode.EverythingInSelfAndDescendants ) )\r\n\t\t\tfx.Tint = block.HealthyTint;\r\n\r\n\t\tgo.Enabled = true;\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Spawns a spark burst facing inward where the ball hit a wall or the paddle.\r\n\t/// </summary>\r\n\tpublic void SpawnWallHit( Vector3 worldPos, Vector3 inwardNormal )\r\n\t{\r\n\t\tif ( WallHitPrefab is null )\r\n\t\t\treturn;\r\n\r\n\t\tvar n = inwardNormal.Normal;\r\n\t\tvar up = MathF.Abs( n.z ) > 0.99f ? Vector3.Forward : Vector3.Up;\r\n\t\tvar rot = Rotation.LookAt( n, up );\r\n\t\tWallHitPrefab.Clone( new CloneConfig( new Transform( worldPos, rot ), name: \"wall_hit\" ) );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Spawns the celebratory confetti burst used on a board clear.\r\n\t/// </summary>\r\n\tpublic void SpawnConfetti( Vector3 worldPos ) => ConfettiPrefab?.Clone( worldPos );\r\n\r\n\t/// <summary>\r\n\t/// Plays the rising three-note chime used when a board is cleared.\r\n\t/// </summary>\r\n\tpublic void PlayClearSting()\r\n\t{\r\n\t\tfloat[] pitches = { 1.15f, 1.5f, 1.9f };\r\n\t\tforeach ( var pitch in pitches )\r\n\t\t{\r\n\t\t\tvar note = Sound.Play( \"brick_break_01\" );\r\n\t\t\tif ( note is not null )\r\n\t\t\t\tnote.Pitch = pitch;\r\n\t\t}\r\n\t}\r\n}\r\n"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "UI/Controls.razor",
            "FileName": "Controls.razor",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "@using System\r\n@using Sandbox\r\n@using Sandbox.UI\r\n@namespace Breakout\r\n@inherits Panel\r\n\r\n@if ( Game.IsValid() && Game.State != GameState.Menu && Game.Level <= 1 )\r\n{\r\n    <root>\r\n        <div class=\"container\">\r\n            <span class=\"controls-label\">CONTROLS</span>\r\n            <div class=\"column\">\r\n                <div class=\"input\">\r\n                    @*There is no mouse/ controller move input hint so we do this.*@\r\n                    @if(Input.UsingController)\r\n                    {\r\n                        <label class=\"type\">Move</label><img src=\"ui/glyphs/xbox/leftjoystickbutton.svg\" class=\"mouse-glyph\" />\r\n                    }\r\n                    else\r\n                    {\r\n                        <label class=\"type\">Move Paddle</label><img src=\"ui/glyphs/default/mouse.svg\" class=\"mouse-glyph\" />\r\n                    }\r\n                </div>\r\n                <div class=\"input\">\r\n                    <label class=\"type\">Launch</label><InputHint Action=\"attack1\" class=\"key-glyph\" Dark=@true />\r\n                </div>\r\n            </div>\r\n        </div>\r\n\r\n    </root>\r\n}\r\n\r\n@code\r\n{\r\n    /// <summary>\r\n    /// The game this bar reads score, lives, level and mode from.\r\n    /// </summary>\r\n    [Parameter] public BreakoutGame Game { get; set; }\r\n\r\n    // Update the ui when the game state changes or when the input method changes.\r\n    protected override int BuildHash() => System.HashCode.Combine(Game?.State, Game?.Mode, Game?.Level, Input.UsingController);\r\n}\r\n"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "UI/HelpScreen.razor",
            "FileName": "HelpScreen.razor",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "@using System\r\n@using Sandbox\r\n@using Sandbox.UI\r\n@namespace Breakout\r\n@inherits Panel\r\n\r\n@*\r\n    HelpScreen is the \"how to play\" page you reach from the menu's HELP button. It shows a guide\r\n    of every block type and what it does. Pressing BACK runs the Back callback, which tells the\r\n    menu to show itself again.\r\n*@\r\n\r\n<root>\r\n    <div class=\"help\">\r\n        <button class=\"back-btn\" onclick=@(() => Back?.Invoke())>\r\n            <span class=\"back-icon\">\u25c0</span>\r\n            BACK\r\n        </button>\r\n\r\n        <div class=\"help-body\">\r\n            <div class=\"help-title\">HELP</div>\r\n            <div class=\"help-sub\">Here is what each brick does when you hit it.</div>\r\n\r\n            <div class=\"block-grid\">\r\n                @foreach ( var block in Blocks )\r\n                {\r\n                    <div class=\"block-card\">\r\n                        <img class=\"block-icon\" src=\"@block.Icon\" />\r\n                        <div class=\"block-info\">\r\n                            <div class=\"block-name\">@block.Name</div>\r\n                            <div class=\"block-desc\">@block.Description</div>\r\n                        </div>\r\n                    </div>\r\n                }\r\n            </div>\r\n        </div>\r\n    </div>\r\n</root>\r\n\r\n@code\r\n{\r\n    /// <summary>\r\n    /// Called when the player presses BACK, so the menu can show itself again.\r\n    /// </summary>\r\n    [Parameter] public Action Back { get; set; }\r\n\r\n    /// <summary>\r\n    /// One row in the block guide: the icon to show, the block's name, and a short description.\r\n    /// </summary>\r\n    private record BlockGuideEntry( string Icon, string Name, string Description );\r\n\r\n    // The list shown on the help page. Add a new line here to document another block type.\r\n    private static readonly BlockGuideEntry[] Blocks =\r\n    {\r\n        new( \"textures/blocks/normal.png\", \"Brick\", \"Breaks in a single hit.\" ),\r\n        new( \"textures/blocks/armoured.png\", \"Armoured\", \"Takes two hits to break.\" ),\r\n        new( \"textures/blocks/unbreakable.png\", \"Unbreakable\", \"Can't be broken, so play around it.\" ),\r\n        new( \"textures/blocks/explosion.png\", \"Explosive\", \"Blows up nearby bricks when it breaks.\" ),\r\n        new( \"textures/blocks/speed.png\", \"Fast Ball\", \"Turns your ball into a faster one.\" ),\r\n        new( \"textures/blocks/big_ball.png\", \"Big Ball\", \"Makes your ball big enough to smash armour in one hit.\" ),\r\n        new( \"textures/blocks/fire_ball.png\", \"Fireball\", \"Turns your ball into a fireball that burns straight through bricks.\" ),\r\n        new( \"textures/blocks/split.png\", \"Multi-Ball\", \"Drops a pickup that splits your ball into more.\" ),\r\n        new( \"textures/blocks/expand.png\", \"Expand\", \"Drops a pickup that makes your paddle wider.\" ),\r\n    };\r\n}\r\n"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "styles/form/_coloreditor.scss",
            "FileName": "_coloreditor.scss",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "\r\n$primary: red !default;\r\n$primary-alt: white !default;\r\n\r\n$switch-padding: 6px !default;\r\n\r\n.coloreditor\r\n{\r\n\tflex-direction: column;\r\n\tmin-width: 250px;\r\n\tmax-width: 250px;\r\n\r\n\t> .canvas\r\n\t{\r\n\t\tborder-top: 1px solid rgba( white, 0.5 );\r\n\t\tflex-grow: 1;\r\n\t\tflex-direction: column;\r\n\t\tpadding: 10px 15px;\r\n\r\n\r\n\t\t> textentry.textentry\r\n\t\t{\r\n\t\t\tflex-grow: 0;\r\n\t\t\tflex-shrink: 0;\r\n\t\t\twidth: auto;\r\n\t\t}\r\n\t}\r\n\r\n\t.slider\r\n\t{\r\n\t\tpadding: 6.5px;\r\n\t}\r\n\r\n\t.slider .track\r\n\t{\r\n\t\theight: 14px;\r\n\t\tborder-radius: 14px;\r\n\t\tleft: 0px;\r\n\t\tright: 0px;\r\n\t\ttransition: all 0.1s ease-out;\r\n\r\n\t\t.inner\r\n\t\t{\r\n\t\t\tdisplay: none;\r\n\t\t}\r\n\t}\r\n\r\n\t.slider:hover, .slider:active\r\n\t{\r\n\t\tpadding: 7px;\r\n\r\n\t\t.track\r\n\t\t{\r\n\t\t\theight: 20px;\r\n\t\t\tborder-radius: 6px;\r\n\t\t}\r\n\r\n\t\t.thumb\r\n\t\t{\r\n\t\t\twidth: 10px;\r\n\t\t\theight: 16px;\r\n\t\t\tmargin-left: 2px;\r\n\t\t}\r\n\t}\r\n\r\n\t.slider .thumb\r\n\t{\r\n\t\twidth: 10px;\r\n\t\theight: 10px;\r\n\t\tbox-shadow: 0px 0px 0px transparent;\r\n\t\tbackground-color: white;\r\n\t\tbackdrop-filter: invert( 1 );\r\n\t\tmargin-left: 1px;\r\n\t\tpointer-events: none;\r\n\t}\r\n\r\n\t.alpha_slider .track\r\n\t{\r\n\t\tbackground-image: linear-gradient( to right, rgba( #ccc, 0.05 ), rgba( #ccc, 0.9 ) );\r\n\t}\r\n\r\n\t.hue .track\r\n\t{\r\n\t\tbackground: linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);\r\n\r\n\t\t.inner\r\n\t\t{\r\n\t\t\tdisplay: none;\r\n\t\t}\r\n\t}\r\n\r\n\t.satval\r\n\t{\r\n\t\tbackground: linear-gradient(to right, white, transparent);\r\n\t\theight: 200px;\r\n\t\tposition: relative;\r\n\r\n\t\t&:active\r\n\t\t{\r\n\t\t\tz-index: 10;\r\n\t\t\tcursor: none;\r\n\t\t}\r\n\r\n\t\t.value_gradient\r\n\t\t{\r\n\t\t\tbackground: linear-gradient(to bottom, black, white);\r\n\t\t\tposition: absolute;\r\n\t\t\ttop: 0;\r\n\t\t\tleft: 0;\r\n\t\t\tright: 0;\r\n\t\t\tbottom: 0;\r\n\t\t\tpointer-events: none;\r\n\t\t\tmix-blend-mode: multiply;\r\n\t\t}\r\n\r\n\t\t.thumb\r\n\t\t{\r\n\t\t\tz-index: 10;\r\n\t\t}\r\n\t}\r\n\r\n\t.presets\r\n\t{\r\n\t\tflex-wrap: wrap;\r\n\t\talign-content: center;\r\n\t\tjustify-content: center;\r\n\t\tpadding: 15px;\r\n\t\tborder-top: 1px solid rgba( white, 0.5 );\r\n\r\n\t\t.preset\r\n\t\t{\r\n\t\t\tbackground-color: white;\r\n\t\t\twidth: 16px;\r\n\t\t\theight: 16px;\r\n\t\t\tmargin: 2px;\r\n\t\t\tborder-radius: 20px;\r\n\t\t\tcursor: pointer;\r\n\t\t\t\r\n\t\t\t&:hover\r\n\t\t\t{\r\n\t\t\t\tbox-shadow: 0px 0px 1px 2px white;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\n\r\n.coloreditorrgba\r\n{\r\n\tflex-direction: column;\r\n\r\n\t.slider\r\n\t{\r\n\t\tpadding-right: 16px;\r\n\t}\r\n\r\n\t.slider .track\r\n\t{\r\n\t\tbackground-color: transparent;\r\n\t\theight: 14px;\r\n\t\tborder-radius: 14px;\r\n\t\tleft: 0px;\r\n\t\tright: 0px;\r\n\r\n\t\t.inner\r\n\t\t{\r\n\t\t\tdisplay: none;\r\n\t\t}\r\n\t}\r\n\r\n\t.slider .thumb\r\n\t{\r\n\t\twidth: 12px;\r\n\t\theight: 12px;\r\n\t\tbox-shadow: 0px 0px 0px transparent;\r\n\t\tbackground-color: white;\r\n\t\tmargin-left: 2px;\r\n\t\tbackdrop-filter: invert( 1 );\r\n\t}\r\n\r\n\t.red_slider .track\r\n\t{\r\n\t\tbackground-image: linear-gradient( to right, rgba( #e63439, 0.1 ), rgba( #e63439, 0.9 ) );\r\n\t}\r\n\r\n\t.green_slider .track\r\n\t{\r\n\t\tbackground-image: linear-gradient( to right, rgba( #54be35, 0.1 ), rgba( #54be35, 0.9 ) );\r\n\t}\r\n\r\n\t.blue_slider .track\r\n\t{\r\n\t\tbackground-image: linear-gradient( to right, rgba( #3472e6, 0.1 ), rgba( #3472e6, 0.9 ) );\r\n\t}\r\n\r\n\t.alpha_slider .track\r\n\t{\r\n\t\tbackground-image: linear-gradient( to right, rgba( #ccc, 0.05 ), rgba( #ccc, 0.9 ) );\r\n\t}\r\n}\r\n\r\n\r\n.coloreditorhsva\r\n{\r\n\tflex-direction: column;\r\n\r\n\t.slider\r\n\t{\r\n\t\tpadding-right: 16px;\r\n\t}\r\n\r\n\t.slider .track\r\n\t{\r\n\t\tbackground-color: transparent;\r\n\t\theight: 14px;\r\n\t\tborder-radius: 14px;\r\n\t\tleft: 0px;\r\n\t\tright: 0px;\r\n\r\n\t\t.inner\r\n\t\t{\r\n\t\t\tdisplay: none;\r\n\t\t}\r\n\t}\r\n\r\n\t.slider .thumb\r\n\t{\r\n\t\twidth: 12px;\r\n\t\theight: 12px;\r\n\t\tbox-shadow: 0px 0px 0px transparent;\r\n\t\tbackground-color: white;\r\n\t\tmargin-left: 2px;\r\n\t\tbackdrop-filter: invert( 1 );\r\n\t}\r\n\t\t\r\n\t.hue_slider .track\r\n\t{\r\n\t\tbackground-image: linear-gradient( to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00 );\r\n\t}\r\n\r\n\t.alpha_slider .track\r\n\t{\r\n\t\tbackground-image: linear-gradient( to right, rgba( #ccc, 0.05 ), rgba( #ccc, 0.9 ) );\r\n\t}\r\n}"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "ui/menupanel.razor.scss",
            "FileName": "menupanel.razor.scss",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "\r\nmenupanel\r\n{\r\n    position: absolute;\r\n    z-index: 1000;\r\n    pointer-events: all;\r\n    font-size: 12px;\r\n    flex-shrink: 0;\r\n\r\n    .background\r\n    {\r\n        position: absolute;\r\n        left: -5000px;\r\n        right: -5000px;\r\n        top: -5000px;\r\n        bottom: -5000px;\r\n    }\r\n\r\n    > .inner\r\n    {\r\n        min-width: 200px;\r\n        min-height: 20px;\r\n        flex-direction: column;\r\n        font-family: Poppins;\r\n        font-weight: bold;\r\n        border-radius: 10px;\r\n        box-shadow: 5px 5px 30px #000e;\r\n        background-color: #2a2a2a;\r\n        flex-shrink: 0;\r\n\r\n        .spacer\r\n        {\r\n            height: 1px;\r\n            background-color: #0005;\r\n        }\r\n\r\n        .option\r\n        {\r\n            color: #fffa;\r\n            padding: 0px 8px;\r\n            cursor: pointer;\r\n            flex-shrink: 0;\r\n            height: 32px;\r\n\r\n            &:first-child\r\n            {\r\n                border-top-left-radius: 10px;\r\n                border-top-right-radius: 10px;\r\n            }\r\n\r\n            &:last-child\r\n            {\r\n                border-bottom-left-radius: 10px;\r\n                border-bottom-right-radius: 10px;\r\n            }\r\n\r\n            .icon\r\n            {\r\n                padding: 8px;\r\n                font-family: Material Icons;\r\n                justify-content: center;\r\n                align-items: center;\r\n                flex-shrink: 0;\r\n            }\r\n\r\n            .text\r\n            {\r\n                padding: 8px;\r\n                flex-shrink: 0;\r\n            }\r\n\r\n            &:hover\r\n            {\r\n                background-color: #3472e6;\r\n                color: #f5f8fe;\r\n            }\r\n        }\r\n    }\r\n}\r\n"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "ui/controls/vectorcontrol.cs.scss",
            "FileName": "vectorcontrol.cs.scss",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "VectorControl\r\n{\r\n\tgap: 2px;\r\n\tflex-grow: 1;\r\n}\r\n\r\nVectorControl NumberEntry\r\n{\r\n\tflex-basis: 50%;\r\n}"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "styles/form/_checkbox.scss",
            "FileName": "_checkbox.scss",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "\r\n@import \"/styles/_theme.scss\";\r\n\r\n$primary: $primary-blue !default;\r\n$primary-alt: white !default;\r\n$form-control-height: 24px !default;\r\n\r\n.checkbox\r\n{\r\n\tcursor: pointer;\r\n\tcolor: rgba( $primary-alt, 0.6 );\r\n\talign-items: center;\r\n\tgap: 8px;\r\n\r\n\tlabel\r\n\t{\r\n\t\tpointer-events: none;\r\n\t}\r\n\r\n\t> .checkmark\r\n\t{\r\n\t\tpadding: 1px;\r\n\t\tfont-size: 22px;\r\n\t\tborder: 1px solid $primary;\r\n\t\tborder-radius: $rounding-small;\r\n\t\ttext-align: center;\r\n\t\tjustify-content: center;\r\n\t\talign-items: center;\r\n\t\tcolor: transparent;\r\n\t\tmin-height: $form-control-height;\r\n\t\tpointer-events: none;\r\n\t\tflex-shrink: 0;\r\n\t}\r\n\r\n\t&.checked\r\n\t{\r\n\t\t> .checkmark\r\n\t\t{\r\n\t\t\tcolor: $primary-alt;\r\n\t\t\tbackground-color: $primary;\r\n\t\t}\r\n\t}\r\n\r\n\t&:active\r\n\t{\r\n\t\tcolor: $primary-alt;\r\n\t}\r\n\r\n\t&:hover\r\n\t{\r\n\t\tcolor: $primary-alt;\r\n\t}\r\n}\r\n"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "Blocks/ExplodingBlock.cs",
            "FileName": "ExplodingBlock.cs",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "using Sandbox;\r\n\r\nnamespace Breakout;\r\n\r\n/// <summary>\r\n/// A brick that blows up when destroyed, taking out every other breakable brick within\r\n/// BlastRadius. Those can be exploding bricks too, so one blast can chain into more.\r\n/// </summary>\r\n[Title( \"Exploding Block\" ), Category( \"Breakout\" ), Icon( \"bolt\" )]\r\npublic sealed class ExplodingBlock : Block\r\n{\r\n\t[Property] public float BlastRadius { get; set; } = 80f;\r\n\r\n\t/// <summary>\r\n\t/// Breaks this brick and destroys every other breakable brick within BlastRadius, which can chain into further explosions.\r\n\t/// </summary>\r\n\tpublic override void OnDestroyed()\r\n\t{\r\n\t\tif ( Broken )\r\n\t\t\treturn;\r\n\r\n\t\tvar origin = WorldPosition;\r\n\r\n\t\tbase.OnDestroyed();\r\n\t\tGame?.HitStop( 0.05f );\r\n\r\n\t\tforeach ( var other in Scene.GetAllComponents<Block>().ToList() )\r\n\t\t{\r\n\t\t\tif ( other == this || !other.IsValid() || !other.Breakable )\r\n\t\t\t\tcontinue;\r\n\r\n\t\t\tif ( other.WorldPosition.Distance( origin ) <= BlastRadius )\r\n\t\t\t\tother.OnDestroyed();\r\n\t\t}\r\n\t}\r\n}\r\n"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "Game/GameMode.cs",
            "FileName": "GameMode.cs",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "namespace Breakout;\r\n\r\n/// <summary>\r\n/// The three ways to play. Classic is the authentic original brick wall, Arcade shuffles through\r\n/// the custom levels, and Weekly is a shared challenge board that changes each week.\r\n/// </summary>\r\npublic enum GameMode\r\n{\r\n\tClassic,\r\n\tArcade,\r\n\tWeekly\r\n}\r\n"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "Paddle/PaddleEffect.cs",
            "FileName": "PaddleEffect.cs",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "using Sandbox;\r\n\r\nnamespace Breakout;\r\n\r\n/// <summary>\r\n/// Base class for a timed effect living on the paddle (such as the wide-paddle boost). It runs\r\n/// OnApply when added, then removes itself after Duration seconds, calling OnRemoved on its way out.\r\n/// </summary>\r\npublic abstract class PaddleEffect : Component\r\n{\r\n\t[Property] public float Duration { get; set; } = 8f;\r\n\r\n\tprotected Paddle Paddle { get; private set; }\r\n\r\n\tprivate TimeUntil expires;\r\n\r\n\tprotected override void OnStart()\r\n\t{\r\n\t\tPaddle = Components.Get<Paddle>( FindMode.EverythingInSelfAndAncestors );\r\n\t\tif ( Paddle is null )\r\n\t\t{\r\n\t\t\tDestroy();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\texpires = Duration;\r\n\t\tOnApply();\r\n\t}\r\n\r\n\tprotected override void OnUpdate()\r\n\t{\r\n\t\tif ( Duration > 0f && expires )\r\n\t\t\tDestroy();\r\n\t}\r\n\r\n\tprotected override void OnDestroy() => OnRemoved();\r\n\r\n\t/// <summary>\r\n\t/// Called once when the effect is added. Override to start the effect.\r\n\t/// </summary>\r\n\tprotected virtual void OnApply() { }\r\n\r\n\t/// <summary>\r\n\t/// Called once when the effect expires or is removed. Override to undo the effect.\r\n\t/// </summary>\r\n\tprotected virtual void OnRemoved() { }\r\n}\r\n"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "styles/form/_dropdown.scss",
            "FileName": "_dropdown.scss",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "\r\n$primary: red !default;\r\n$primary-alt: white !default;\r\n\r\n$switch-padding: 6px !default;\r\n\r\n.button.popupbutton.dropdown\r\n{\r\n\tcursor: pointer;\r\n\ttransition: all .1s ease-out;\r\n\tposition: relative;\r\n\r\n\t> .dropdown_indicator\r\n\t{\r\n\t\tposition: absolute;\r\n\t\tright: 8px;\r\n\t}\r\n\r\n\t&.open\r\n\t{\r\n\t\tborder-bottom-left-radius: 1px;\r\n\t\tborder-bottom-right-radius: 1px;\r\n\t\ttransition: border-radius 0.2s ease-out;\r\n\t}\r\n}\r\n\r\nselect\r\n{\r\n\tmin-height: 40px;\r\n\r\n\t> option\r\n\t{\r\n\t\tdisplay: none;\r\n\t}\r\n}"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "ui/controls/color/colorcontrol.cs.scss",
            "FileName": "colorcontrol.cs.scss",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "ColorControl\r\n{\r\n\tgap: 0.5rem;\r\n\tflex-grow: 1;\r\n\tpointer-events: all;\r\n\tbackground-color: #000a;\r\n\tborder-radius: 4px;\r\n\tpadding: 2px;\r\n\theight: 32px;\r\n}\r\n\r\nColorControl TextEntry\r\n{\r\n\tflex-grow: 1;\r\n\tflex-shrink: 0;\r\n\tcolor: #aaa;\r\n\tfont-size: 1.2rem;\r\n\r\n\t&:hover, &:focus\r\n\t{\r\n\t\tcolor: #ddd;\r\n\r\n\t\t.icon\r\n\t\t{\r\n\t\t\tcolor: #3af;\r\n\t\t}\r\n\t}\r\n\r\n\t&:active\r\n\t{\r\n\t\tcolor: white;\r\n\t}\r\n}\r\n\r\nColorControl > .colorswatch\r\n{\r\n\taspect-ratio: 1;\r\n\tborder-radius: 4px;\r\n\theight: 100%;\r\n\tflex-shrink: 0;\r\n\tcursor: pointer;\r\n\tborder: 2px solid #000;\r\n}"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "ui/inputhint.razor.scss",
            "FileName": "inputhint.razor.scss",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "@import \"_theme.scss\";\r\n\r\nInputHint\r\n{\r\n\twidth: 28px;\r\n\theight: 28px;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n}\r\n\r\n.glyph\r\n{\r\n\twidth: 100%;\r\n\theight: 100%;\r\n\tbackground-size: contain;\r\n\tbackground-position: center;\r\n\tbackground-repeat: no-repeat;\r\n\r\n}\r\n\r\n.glyph.dark\r\n{\r\n\tfilter: invert( 1 );\r\n}\r\n"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "styles/form/_switch.scss",
            "FileName": "_switch.scss",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "\r\n$primary: red !default;\r\n$primary-alt: white !default;\r\n\r\n$switch-padding: 6px !default;\r\n\r\n.checkbox.switch\r\n{\r\n\tcursor: pointer;\r\n\r\n\t> .checkmark\r\n\t{\r\n\t\tfont-size: 22px;\r\n\t\tborder: 0px solid $primary;\r\n\t\tborder-radius: 100px;\r\n\t\ttext-align: center;\r\n\t\tjustify-content: center;\r\n\t\talign-items: center;\r\n\t\tcolor: $primary-alt;\r\n\t\tpadding: $switch-padding;\r\n\t\tpadding-right: 32px;\r\n\t\tpadding-left: $switch-padding;\r\n\t\ttransition: all 0.3s ease;\r\n\t\tbackground-color: rgba( $primary, 0.1 );\r\n\r\n\t\t> .handle\r\n\t\t{\r\n\t\t\tbackground-color: $primary-alt;\r\n\t\t\twidth: 20px;\r\n\t\t\theight: 20px;\r\n\t\t\tborder-radius: 100px;\r\n\t\t\tbox-shadow: 2px 2px 12px black;\r\n\t\t}\r\n\t}\r\n\r\n\t&.checked\r\n\t{\r\n\t\t> .checkmark\r\n\t\t{\r\n\t\t\tbackground-color: $primary;\r\n\t\t\tpadding-left: 32px;\r\n\t\t\tpadding-right: $switch-padding;\r\n\t\t}\r\n\t}\r\n\r\n\t&:active\r\n\t{\r\n\t\ttransform: scale( 0.9 );\r\n\t\ttransform-origin: 20px 50%;\r\n\t}\r\n}\r\n"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "ui/controls/switchcontrol.razor.scss",
            "FileName": "switchcontrol.razor.scss",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "\r\n.switchcontrol\r\n{\r\n    flex-direction: row;\r\n    width: 100px;\r\n    min-height: 24px;\r\n    align-items: center;\r\n    cursor: pointer;\r\n\r\n    .switch-frame\r\n    {\r\n        flex-grow: 0;\r\n        flex-shrink: 1;\r\n        width: 48px;\r\n        height: 16px;\r\n        background-color: #fff1;\r\n        margin: 0px 5px;\r\n        align-items: center;\r\n        border-radius: 100px;\r\n        transition: all 0.4s linear;\r\n\r\n        .switch-inner\r\n        {\r\n            position: relative;\r\n            flex-grow: 0;\r\n            flex-shrink: 1;\r\n            background-color: #999;\r\n            width: 25px;\r\n            height: 25px;\r\n            border-radius: 100px;\r\n            left: 20%;\r\n            transform: translateX( -50% );\r\n            transition: all 0.3s ease-out;\r\n        }\r\n    }\r\n\r\n    &.active\r\n    {\r\n        .switch-frame\r\n        {\r\n            background-color: #fffa;\r\n        }\r\n\r\n        .switch-inner\r\n        {\r\n            left: 80%;\r\n            background-color: #fff;\r\n        }\r\n    }\r\n}\r\n"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "styles/base/_navigator.scss",
            "FileName": "_navigator.scss",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": ".navigator-body\r\n{\r\n\t&.hidden\r\n\t{\r\n\t\tdisplay: none;\r\n\t}\r\n}\r\n"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "ui/controls/color/colorhuecontrol.cs.scss",
            "FileName": "colorhuecontrol.cs.scss",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "ColorHueControl\r\n{\r\n\tgap: 0.5rem;\r\n\tflex-grow: 1;\r\n\tpointer-events: all;\r\n\tbackground: linear-gradient( to right, red, yellow, lime, cyan, blue, magenta, red );\r\n\tborder-radius: 4px;\r\n\tpadding: 2px;\r\n\theight: 12px;\r\n\tposition: relative;\r\n\tcursor: pointer;\r\n\tmargin: 10px 0;\r\n\tborder: 1px solid #333;\r\n\r\n\t&:hover\r\n\t{\r\n\t\tborder: 1px solid #08f;\r\n\t}\r\n\r\n\t&:active\r\n\t{\r\n\t\tborder: 1px solid #fff;\r\n\t}\r\n\r\n\t.handle\r\n\t{\r\n\t\ttop: -5px;\r\n\t\tbottom: -5px;\r\n\t\taspect-ratio: 1;\r\n\t\tborder-radius: 100px;\r\n\t\tborder: 2px solid #444;\r\n\t\tposition: absolute;\r\n\t\tbackground-color: white;\r\n\t\tbox-shadow: 2px 2px 16px #000a;\r\n\t\ttransform: translateX( -50% );\r\n\t\tpointer-events: none;\r\n\t}\r\n}\r\n"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "ui/components/packagelist.razor.scss",
            "FileName": "packagelist.razor.scss",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": ".package-list\r\n{\r\n    flex-shrink: 1;\r\n    flex-wrap: wrap;\r\n    flex-grow: 1;\r\n\r\n    h1\r\n    {\r\n        width: 100%;\r\n        margin-top: 50px;\r\n        font-size: 40px;\r\n    }\r\n\r\n    PackageCard\r\n    {\r\n        &:hover\r\n        {\r\n            sound-in: \"ui.button.over\";\r\n        }\r\n    }\r\n\r\n    VirtualGrid\r\n    {\r\n        width: 100%;\r\n        height: 100%;\r\n\r\n        .cell\r\n        {\r\n            \r\n        }\r\n    }\r\n}"
        },
        {
            "Ident": "facepunch.breakout",
            "Path": "Level/BlockPalette.cs",
            "FileName": "BlockPalette.cs",
            "PackageType": "game",
            "CodeKind": "Game",
            "AssetVersionId": 307874,
            "IsPrivate": false,
            "Code": "using Sandbox;\r\n\r\nnamespace Breakout;\r\n\r\n/// <summary>\r\n/// Maps level symbols to the colors used when drawing a level's thumbnail preview. This is only for\r\n/// the editor preview image; the in-game bricks get their color from the spawner's palette.\r\n/// </summary>\r\npublic static class BlockPalette\r\n{\r\n\tpublic static readonly Color Background = new( 0.07f, 0.08f, 0.10f );\r\n\tpublic static readonly Color Empty = new( 0.16f, 0.17f, 0.19f );\r\n\r\n\t/// <summary>\r\n\t/// The preview color for a level symbol (falls back to the empty-cell color for unknown symbols).\r\n\t/// </summary>\r\n\tpublic static Color ColorFor( char symbol )\r\n\t{\r\n\t\treturn symbol switch\r\n\t\t{\r\n\t\t\t'1' => new Color( 0.95f, 0.62f, 0.20f ), // normal\r\n\t\t\t'2' => new Color( 0.36f, 0.55f, 0.78f ), // multi-hit\r\n\t\t\t'P' => new Color( 0.35f, 0.78f, 0.42f ), // power-up (multi-ball)\r\n\t\t\t'E' => new Color( 0.30f, 0.78f, 0.80f ), // expand\r\n\t\t\t'X' => new Color( 0.86f, 0.27f, 0.27f ), // exploding\r\n\t\t\t'#' => new Color( 0.55f, 0.55f, 0.58f ), // unbreakable\r\n\t\t\t'S' => new Color( 1.00f, 0.45f, 0.20f ), // fast ball\r\n\t\t\t'B' => new Color( 0.40f, 0.70f, 1.00f ), // big ball\r\n\t\t\t'F' => new Color( 1.00f, 0.35f, 0.10f ), // fireball\r\n\t\t\t_ => Empty,\r\n\t\t};\r\n\t}\r\n}\r\n"
        }
    ]
}