Editor toolset wrapper for MCP (bridge_scaffold_polish) exposing generator functions. It defines static methods that call McpGate.Run to emit code/assets for polish/game-feel systems like flicker lights, camera shake, combo meter, cutscene director, dialogue, floating combat text, proxy nametag, and world-panel UI.
// AUTO-GENERATED by scripts/emit-mcp-wrappers.mjs — DO NOT EDIT.
// Regenerate: node scripts/extract-manifest.mjs && node scripts/emit-mcp-wrappers.mjs
// Source of truth: sbox-mcp-server/src/tools/ (zod schemas) → scripts/tools-manifest.json
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Editor.Mcp;
/// <summary>
/// Generate game-feel and presentation components: camera shake, flickering lights, floating combat
/// text, combo meters, nametags, world-panel UIs, cutscene directors, and dialogue systems.
/// </summary>
[McpToolset( "bridge_scaffold_polish", "Generate game-feel and presentation components: camera shake, flickering lights, floating combat text, combo meters, nametags, world-panel UIs, cutscene directors, and dialogue systems." )]
public static class BridgeScaffoldPolishTools
{
/// <summary>
/// Generate a light-flicker animator and optionally attach it to an existing light GameObject by
/// GUID. Five presets: Candle (soft organic sway), Fluorescent (mostly steady with random dips),
/// Faulty (hard on/off cuts), Pulse (slow sine breathing), Lightning (dim baseline with rare bright
/// flashes). Modulates the sibling Light component's LightColor around the color it found on enable
/// (works on PointLight / SpotLight / DirectionalLight) and restores it exactly on disable;
/// intensity 0..1 sets flicker depth, speed scales the whole pattern. The single biggest atmosphere
/// win per call for horror/night scenes — pairs with apply_atmosphere. LOCAL/visual-only.
/// </summary>
/// <param name="name">Class name for the generated component. Defaults to 'FlickerLight'.</param>
/// <param name="directory">Subdirectory for the generated .cs file. Defaults to 'Code'.</param>
/// <param name="style">Default flicker preset baked into the component (editable per-instance in the inspector). Defaults to 'Candle'. One of: Candle | Fluorescent | Faulty | Pulse | Lightning.</param>
/// <param name="intensity">Flicker depth 0..1: 0 = steady, 1 = full blackouts / double-bright flashes. Defaults to 0.5.</param>
/// <param name="speed">Speed multiplier for the whole pattern. Defaults to 1.</param>
/// <param name="lightId">GUID of a GameObject holding a light component to attach to (only attaches if the type is already loaded — hotload first).</param>
[McpTool( "add_flicker_light" )]
public static Task<object> AddFlickerLight( string name = null, string directory = null, string style = null, double? intensity = null, double? speed = null, string lightId = null )
=> McpGate.Run( "add_flicker_light", McpGate.Args( ( "name", name ), ( "directory", directory ), ( "style", style ), ( "intensity", intensity ), ( "speed", speed ), ( "lightId", lightId ) ) );
/// <summary>
/// Generate a trauma-based camera shake component (the standard game-feel model: events add Trauma
/// 0..1, shake magnitude = Trauma², smooth Perlin offsets — not white-noise jitter — and Trauma
/// decays every frame, so explosions slam and footsteps barely register). Attach the generated
/// component to the CAMERA GameObject; fire from any game code via the static
/// <Name>.Shake(0.4f). Applies in OnPreRender AFTER controllers position the camera, with an
/// un-apply guard so it neither fights a controller-driven camera nor accumulates on a static one,
/// and restores the camera when trauma hits zero. LOCAL-only (no [Sync]) — call Shake inside an
/// [Rpc.Broadcast] handler if every client should feel it. Optionally attached to an existing
/// GameObject by GUID (after a hotload).
/// </summary>
/// <param name="name">Class name for the generated component. Defaults to 'CameraShake'.</param>
/// <param name="directory">Subdirectory for the generated .cs file. Defaults to 'Code'.</param>
/// <param name="maxOffset">Positional shake at full trauma, in world units. Defaults to 6.</param>
/// <param name="maxAngle">Rotational shake at full trauma, in degrees (applied to pitch/yaw/roll). Defaults to 4.</param>
/// <param name="frequency">Noise speed — higher = violent rattle, lower = drunken sway. Defaults to 10.</param>
/// <param name="decayPerSecond">How much trauma drains per second. Defaults to 1.5.</param>
/// <param name="targetId">GUID of the camera GameObject to attach to (only attaches if the type is already loaded — hotload first).</param>
[McpTool( "create_camera_shake" )]
public static Task<object> CreateCameraShake( string name = null, string directory = null, double? maxOffset = null, double? maxAngle = null, double? frequency = null, double? decayPerSecond = null, string targetId = null )
=> McpGate.Run( "create_camera_shake", McpGate.Args( ( "name", name ), ( "directory", directory ), ( "maxOffset", maxOffset ), ( "maxAngle", maxAngle ), ( "frequency", frequency ), ( "decayPerSecond", decayPerSecond ), ( "targetId", targetId ) ) );
/// <summary>
/// Generate a combo system: a sealed Component (the authoritative, headless state) PLUS a small
/// Razor HUD (PanelComponent + scss). Three files: <Name>.cs + <Name>Hud.razor +
/// <Name>Hud.razor.scss. The component exposes a static Bump() — call it on every hit and the
/// Count rises; an idle window (ComboWindowSeconds, tracked with TimeSince) resets it; the
/// Multiplier steps up through [Property] tier thresholds (Tier2Hits/Tier3Hits/Tier4Hits =>
/// 2x/3x/4x); and a static OnComboChanged(int count, float multiplier) event fires so any HUD/audio
/// reacts without a reference (Bump() targets the active instance, so callers never need a handle —
/// attach ONE to a persistent object). The HUD subscribes to OnComboChanged, shows "<count>
/// HITS x<mult>", and pulses via a CSS animation on every change (razor_lint-safe: BuildHash
/// folds count/mult/pulse, no switch-expressions / non-ASCII in @code, class-selector SCSS root;
/// host it under a ScreenPanel via add_screen_panel). Pairs with create_health_system /
/// create_floating_combat_text — call Bump() from the damage path and Spawn a popup that reflects
/// the multiplier.
/// </summary>
/// <param name="name">Class name for the combo component; the HUD is generated as <Name>Hud. Defaults to 'ComboMeter'.</param>
/// <param name="directory">Subdirectory for the generated .cs + .razor + .razor.scss. Defaults to 'Code'.</param>
/// <param name="comboWindowSeconds">Idle seconds before the combo resets back to zero (clamped to >= 0.25). Defaults to 3.</param>
[McpTool( "create_combo_meter" )]
public static Task<object> CreateComboMeter( string name = null, string directory = null, double? comboWindowSeconds = null )
=> McpGate.Run( "create_combo_meter", McpGate.Args( ( "name", name ), ( "directory", directory ), ( "comboWindowSeconds", comboWindowSeconds ) ) );
/// <summary>
/// Generate a hand-authored cutscene player component that needs NO .movie asset — the zero-asset
/// alternative to the MovieMaker family (add_movie_player/play_movie, which play keyframed .movie
/// clips authored in the editor's Movie Maker dock). You author the shots directly in the inspector
/// as parallel lists: ShotPositions (Vector3), ShotAngles (pitch/yaw/roll — Angles, not raw
/// quaternions), ShotHoldSeconds, ShotBlendSeconds, and an optional per-shot ShotLookAt GameObject
/// (aim at a target instead of using ShotAngles). At runtime it takes over the main camera
/// (Scene.Camera) in OnPreRender ONLY while playing — smoothstep-eased Vector3.Lerp +
/// Rotation.Slerp between shots — captures the camera's prior transform and restores it exactly
/// when finished (same un-apply discipline as create_camera_shake). Play from any game code via the
/// static <Name>.Play() (first director) or <Name>.Play("name") (matches CutsceneName);
/// subscribe the static <Name>.OnCutsceneFinished, or gate game logic on the static
/// <Name>.IsCutscenePlaying. LockInput freezes player input each frame via
/// Input.ClearActions() while still reading the SkipAction press first so the cutscene stays
/// skippable. Optional letterbox generates a razor_lint-safe black-bars overlay panel (host under a
/// ScreenPanel) shown while IsCutscenePlaying. LOCAL-only (each client renders its own view) —
/// trigger inside an [Rpc.Broadcast] for all clients. Attach to ANY GameObject; it drives the
/// camera itself and does not need to sit on the camera. Returns { created, path, className,
/// skipAction, lockInput, letterbox, nextSteps } — path is the generated .cs (letterbox lists the
/// overlay files when enabled). Follow with trigger_hotload, then get_compile_errors, then attach
/// via add_component_with_properties (component=className).
/// </summary>
/// <param name="name">Class name for the generated component. Defaults to 'CutsceneDirector'.</param>
/// <param name="directory">Subdirectory for the generated files. Defaults to 'Code'.</param>
/// <param name="skipAction">Input action that ends the cutscene early (read before input is cleared, so a locked cutscene is still skippable). Sanitized to a safe token. Empty = not skippable. Defaults to 'jump'.</param>
/// <param name="lockInput">Freeze player input during playback via Input.ClearActions() each frame. Defaults to true.</param>
/// <param name="letterbox">Also generate a razor_lint-safe letterbox overlay (two black bars, shown while IsCutscenePlaying — host it under a ScreenPanel). Defaults to false.</param>
[McpTool( "create_cutscene_director" )]
public static Task<object> CreateCutsceneDirector( string name = null, string directory = null, string skipAction = null, bool? lockInput = null, bool? letterbox = null )
=> McpGate.Run( "create_cutscene_director", McpGate.Args( ( "name", name ), ( "directory", directory ), ( "skipAction", skipAction ), ( "lockInput", lockInput ), ( "letterbox", letterbox ) ) );
/// <summary>
/// Generate an NPC/story dialogue system — a sealed state+data Component paired with a
/// razor_lint-safe Razor HUD panel. Lines are authored in the inspector as a List<string>
/// using the 'Speaker: text' convention (the part before the first colon is the speaker). The
/// generated HUD panel binds to <Name>.Current automatically (no wiring) and renders the
/// current line with a TimeSince-driven typewriter reveal at CharsPerSecond, folding the visible
/// substring into BuildHash so it re-renders as characters appear. Press the AdvanceAction once to
/// snap the whole line into view instantly, again to move to the next line; dismissing the last
/// line ends the conversation. Start from any game code via the static
/// <Name>.StartDialogue(string[] lines) or set Lines and call the instance Begin(). Static
/// events for hooks: OnLineShown(index, speaker) — pair with add_lipsync to drive facial morphs /
/// audio per line — and OnDialogueFinished when the conversation ends. Pairs with
/// create_interactable to trigger dialogue on use. LOCAL-only (per-client HUD) — call StartDialogue
/// inside an [Rpc.Broadcast] if every client should see it. Attach the panel under a ScreenPanel
/// (add_screen_panel) so the HUD renders. Returns { created, path, className, charsPerSecond,
/// advanceAction, panel, nextSteps } — panel lists the generated '<Name>Panel' HUD files.
/// Follow with trigger_hotload, then get_compile_errors, then attach both components via
/// add_component_with_properties.
/// </summary>
/// <param name="name">Class name for the generated dialogue component (the HUD panel is generated as '<Name>Panel'). Defaults to 'DialogueSystem'.</param>
/// <param name="directory">Subdirectory for the generated files. Defaults to 'Code'.</param>
/// <param name="charsPerSecond">Typewriter reveal speed in characters per second (clamped to >= 1). Defaults to 40.</param>
/// <param name="advanceAction">Input action that completes the reveal / advances to the next line. Sanitized to a safe token. Defaults to 'use'.</param>
[McpTool( "create_dialogue_system" )]
public static Task<object> CreateDialogueSystem( string name = null, string directory = null, double? charsPerSecond = null, string advanceAction = null )
=> McpGate.Run( "create_dialogue_system", McpGate.Args( ( "name", name ), ( "directory", directory ), ( "charsPerSecond", charsPerSecond ), ( "advanceAction", advanceAction ) ) );
/// <summary>
/// Generate a floating combat text component — rising, fading, camera-billboarded world-space
/// popups for damage numbers, '+10 gold', pickup names. TextRenderer-based: no Razor, no
/// WorldPanel, zero UI setup. Nothing to place in the scene — the generated class carries a static
/// factory: <Name>.Spawn(position, "-25", Color.Red[, sizeMultiplier]) spawns a popup that
/// rises at RiseSpeed, fades over Lifetime, and destroys itself. Pairs with create_health_system
/// (spawn from the damage path so every hit prints its number). LOCAL-only — spawn inside an
/// [Rpc.Broadcast] handler if every client should see it.
/// </summary>
/// <param name="name">Class name for the generated component. Defaults to 'FloatingCombatText'.</param>
/// <param name="directory">Subdirectory for the generated .cs file. Defaults to 'Code'.</param>
/// <param name="riseSpeed">World units the popup rises per second. Defaults to 48.</param>
/// <param name="lifetime">Seconds until the popup is fully faded and destroyed. Defaults to 1.1.</param>
/// <param name="fontSize">Base font size baked into Spawn() (the optional Spawn size argument multiplies it). Defaults to 24.</param>
[McpTool( "create_floating_combat_text" )]
public static Task<object> CreateFloatingCombatText( string name = null, string directory = null, double? riseSpeed = null, double? lifetime = null, double? fontSize = null )
=> McpGate.Run( "create_floating_combat_text", McpGate.Args( ( "name", name ), ( "directory", directory ), ( "riseSpeed", riseSpeed ), ( "lifetime", lifetime ), ( "fontSize", fontSize ) ) );
/// <summary>
/// Generate a sealed Component that floats the OWNER'S display name above a networked player.
/// TextRenderer-based (not WorldPanel): a nametag is one short string with a distance fade, so a
/// TextRenderer on a managed child object is far simpler than a WorldPanel + Razor + WorldInput
/// stack — no UI assets, no panel host, per-frame alpha is a one-liner (mirrors
/// create_floating_combat_text). Reads GameObject.Network.Owner.DisplayName (Owner and
/// OwnerConnection are the same Connection on this SDK; falls back to the object name offline).
/// Visibility is the INVERSE of the usual proxy guard: it renders only when
/// GameObject.Network.IsProxy is true — i.e. on OTHER clients' copies of the player — so you never
/// see a tag over your own head (offline / no networking => IsProxy false everywhere => no
/// tags, expected). Spawns a CHILD GameObject for the text so billboarding never rotates the player
/// model; cleaned up on disable. [Property] MaxDistance fades the tag out with distance,
/// HeightOffset floats it above the head, FontSize sizes it. Attach to the ROOT of your networked
/// player object. Pairs with create_networked_player (add it to the generated player prefab so
/// every remote player is labeled). Returns { created, path, className, maxDistance, heightOffset,
/// note, nextSteps }. Follow with trigger_hotload, then get_compile_errors, then attach via
/// add_component_with_properties (component=className).
/// </summary>
/// <param name="name">Class name for the generated component. Defaults to 'ProxyNametag'.</param>
/// <param name="directory">Subdirectory for the generated .cs file. Defaults to 'Code'.</param>
/// <param name="maxDistance">Full alpha up close; fades to zero as the camera approaches this distance and is hidden past it, in world units. Defaults to 2000.</param>
/// <param name="heightOffset">Height above the object's origin to float the tag, in world units (~72 clears a Citizen's head). Defaults to 72.</param>
[McpTool( "create_proxy_nametag" )]
public static Task<object> CreateProxyNametag( string name = null, string directory = null, double? maxDistance = null, double? heightOffset = null )
=> McpGate.Run( "create_proxy_nametag", McpGate.Args( ( "name", name ), ( "directory", directory ), ( "maxDistance", maxDistance ), ( "heightOffset", heightOffset ) ) );
/// <summary>
/// Generate a diegetic, clickable world-space UI: a Razor PanelComponent (+ .razor.scss) meant to
/// sit on a GameObject that ALSO carries a Sandbox.WorldPanel — the WorldPanel is the world-space
/// render surface (PanelSize / RenderScale / InteractionRange), this component is the actual UI it
/// renders (PanelComponent has no world-panel mode of its own). Ships two example buttons wired to
/// @onclick that raise a static event OnButtonPressed(string id), so game code reacts WITHOUT
/// editing the panel (subscribe: <Name>.OnButtonPressed += id => ...). razor_lint-safe by
/// construction (BuildHash override, no switch-expressions / non-ASCII in @code, class-selector
/// SCSS root). SCENE PREREQUISITE FOR CLICKS: a WorldPanel's buttons only fire when a
/// Sandbox.WorldInput exists in the scene (typically on the camera or the player) with its
/// LeftMouseAction set to your click input action (e.g. "attack1"); on this SDK WorldInput drives
/// itself from the camera + that action — there is no manual ray to feed, and WorldInput.Hovered
/// (read-only) reflects the panel under the cursor. Without a WorldInput present, @onclick never
/// fires. Setup: add_world_panel to a GameObject, add this component to the same object, add a
/// WorldInput to the scene.
/// </summary>
/// <param name="name">Class name for the generated panel. Defaults to 'WorldPanelUi'.</param>
/// <param name="directory">Subdirectory for the generated .razor + .razor.scss. Defaults to 'Code/UI'.</param>
/// <param name="title">Heading text baked into the panel (editable per-instance via the Title [Property]). Defaults to 'Interact'.</param>
[McpTool( "create_worldpanel_ui" )]
public static Task<object> CreateWorldpanelUi( string name = null, string directory = null, string title = null )
=> McpGate.Run( "create_worldpanel_ui", McpGate.Args( ( "name", name ), ( "directory", directory ), ( "title", title ) ) );
}