agentsclimarketplace

Blazing story addon

Skill BlazingStory/agent-skills/skills/blazing-story-addon

Collection of agent skills for Blazing Story, enabling AI coding assistants to implement stories and addons in Blazing Story projects.

Install
npx -y skills add BlazingStory/agent-skills --skill blazing-story-addon

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Implement a custom addon for a Blazing Story application. Use when the user asks to create, add, or implement an addon with specific functionality — such as toolbar buttons, panel tabs, or preview decorators — in a Blazing Story (.NET / Blazor / Storybook) project.

The file declares its own license as Unlicense. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

14.4 KB, as published. Nobody here has run it

Blazing Story — Addon Implementation

Create and register a custom addon in the currently open Blazing Story project.

Investigation policy

The main goal of this policy is to free the developer from the hassle of approving "may I run this command?" prompts one by one. Many of those prompts come from operations that poke around outside the project — and most of the knowledge needed to build an addon is already available without them.

Implement the addon relying primarily on:

  • The guidance in this skill file
  • Your own knowledge of C#, .NET, Blazor, and general web/UI development
  • Other relevant skills available in this environment
  • Already-configured MCP servers and tools
  • Read-only exploration of the current project (ls, Glob, Grep, Read)

Avoid operations that inspect the NuGet package cache folder, decompile Blazing Story DLLs, or otherwise probe the installed package contents. These are slow, require the developer's per-command approval, and disrupt the flow of work.

If implementation details that are not covered above become necessary, consult the published source code on GitHub at https://github.com/jsakamoto/BlazingStory instead of digging into the local NuGet cache or decompiling DLLs.

This policy may be relaxed only when strictly unavoidable.

Step 1: Understand the requirements

From $ARGUMENTS or the user's message, identify:

  • What UI to add: toolbar button/toggle, popup menu, panel tab, preview decorator, or a combination
  • What behavior is needed: toggle state, CSS injection, JavaScript invocation, panel content, etc.
  • Whether toolbar ↔ decorator communication is needed (i.e., toolbar action affects the preview frame)

Step 2: Locate the stories project

Find the stories project (typically *.Stories/) and its App.razor or equivalent file that contains <BlazingStoryApp>. This is where the addon will be registered.

Also check for an existing _Imports.razor to understand which namespaces are globally available.

Step 3: Determine which components to create

An addon can consist of up to three Razor components:

Component typeWhen to create
Toolbar contentWhen you need a button, toggle, or menu in the top toolbar
PanelWhen you need a new tab in the bottom panel area
Preview decoratorWhen you need to inject CSS/JS or react to toolbar state inside the preview frame

Create only the components that are needed. A simple toggle+CSS addon needs just a toolbar component and a decorator.

Step 4: Create the Razor components

Folder convention

Place all files for one addon in a dedicated subfolder inside the stories project:

MyApp.Stories/
└── Addons/
    └── MyFeature/
        ├── MyFeatureToolbarContent.razor
        ├── MyFeaturePanel.razor          (if needed)
        └── MyFeaturePreviewDecorator.razor  (if needed)

Toolbar content component

Receives mutable GlobalArguments as a cascading parameter. Write to it to propagate state to the preview decorator.

@using BlazingStory.Addons
@using BlazingStory.ToolKit.Buttons
@using BlazingStory.ToolKit.Icons
@inject IJSRuntime JSRuntime

<IconButton Icon="SvgIconType.Grid"
            Title="Toggle my feature"
            Active="@_enabled"
            OnClick="OnClick" />

@code {
    [CascadingParameter]
    public GlobalArguments Globals { get; set; } = default!;

    private bool _enabled = false;

    private void OnClick()
    {
        _enabled = !_enabled;
        Globals["myfeature.enabled"] = _enabled ? "true" : null;
    }
}

Key rules for toolbar content:

  • Cascading parameter type is GlobalArguments (mutable, from BlazingStory.Addons).
  • Use Globals["key"] = value to share state with the decorator. Keys are arbitrary strings; use namespaced names (e.g., "myaddon.key").
  • Values stored in GlobalArguments are serialized as strings in the decorator — booleans become "True"/"False" or use "true"/null explicitly.
  • To persist state across page loads, use @inject IJSRuntime JSRuntime and call localStorage (e.g., pattern used in built-in addons).
  • Use ToolKit components for visual consistency (see ToolKit section below).

Panel component

Receives IStory as a cascading parameter. Use <PanelTitle> for the tab label.

@using BlazingStory.Abstractions
@using BlazingStory.Addons

<PanelTitle>
    My Panel
</PanelTitle>

<div class="my-panel">
    <!-- panel content here -->
</div>

@code {
    [CascadingParameter(Name = "Story")]
    public IStory? Story { get; set; }
}

Key rules for panels:

  • <PanelTitle> content is rendered as the tab label via a SectionContent mechanism — it does not appear inline in the component output.
  • The Story cascading parameter gives access to the currently selected story metadata.
  • Scoped CSS is not supported in addon components. Use a regular .css file and load it with <ImportStyleSheet Href="..." /> or a <link> tag.

Preview decorator component

Rendered alongside (not wrapping) the story in the preview frame. Receives read-only cascading parameters.

@using BlazingStory.Abstractions

@code {
    [CascadingParameter(Name = "Globals")]
    public IReadOnlyDictionary<string, string>? Globals { get; set; }

    [CascadingParameter(Name = "Args")]
    public IReadOnlyDictionary<string, string>? Args { get; set; }

    [CascadingParameter(Name = "Story")]
    public IStory? Story { get; set; }
}

To inject a conditional <style> or invoke JS based on toolbar state:

@inject IJSRuntime JSRuntime

@if (_enabled)
{
    <style>* { outline: 1px solid red; }</style>
}

@code {
    [CascadingParameter(Name = "Globals")]
    public IReadOnlyDictionary<string, string>? Globals { get; set; }

    private bool _enabled = false;

    protected override async Task OnParametersSetAsync()
    {
        _enabled = Globals?.TryGetValue("myfeature.enabled", out var v) == true && v == "true";
    }
}

Key rules for preview decorators:

  • Cascading parameter type is IReadOnlyDictionary<string, string>? (read-only, string values only).
  • Values from GlobalArguments arrive as strings. Booleans written as "true"/null can be checked with v == "true".
  • The decorator is a sibling to the story component, not a wrapper around it.
  • Scoped CSS is not supported — use inline <style> tags or ImportStyleSheet.

IStory cascading parameter reference

Both the panel and the preview decorator receive the currently selected story as a [CascadingParameter(Name = "Story")] IStory? Story. Members on BlazingStory.Abstractions.IStory:

MemberTypeDescription
TitlestringDisplay title of the story (e.g., "Examples/UI/Button").
NamestringName of this story (e.g., "Primary").
DescriptionRenderFragment?Optional descriptive content render fragment.
ComponentTypeTypeCLR type of the target UI component.
StoriesRazorDescriptorStoriesRazorDescriptorDescriptor of the Stories Razor component defining this story.
ContextIStoryContextArguments and parameter state for the story (see below).
NavigationPathstringNavigation path string (e.g., "examples-ui-button--primary").

IStory.Context exposes IStoryContext with:

MemberTypeDescription
ArgsIReadOnlyDictionary<string, object?>Current argument values keyed by parameter name.
ParametersIEnumerable<IComponentParameter>Component parameters associated with this story.
ArgumentChangedevent AsyncEventHandler?Raised when any argument value changes.
ArgumentsResetevent AsyncEventHandler?Raised when arguments are reset to defaults.
ShouldRenderevent EventHandler?Raised to request a re-render of the story.
GetNoEventParameterCount()intCount of parameters that are not event callbacks.
InitArgument(name, value)voidInitialize an argument with a name and value.
ResetArgumentsAsync()ValueTaskReset all arguments to their defaults.
AddOrUpdateArgumentAsync(name, newValue)ValueTaskAdd or update an argument value.
InvokeShouldRender()voidNotify the story that it should re-render.

Each IComponentParameter in Context.Parameters exposes:

MemberTypeDescription
NamestringParameter name.
TypeTypeCLR type of the parameter.
TypeStructureTypeStructureNullability and generic structure of the parameter type.
SummaryMarkupStringSummary description from XML documentation.
RequiredboolWhether the parameter is required.
ControlControlTypeUI control type used to edit this parameter.
DefaultValueobject?Default value of the parameter.
UpdateSummaryFromXmlDocCommentAsync()ValueTaskRefresh Summary from the XML doc comment file.
GetParameterTypeStrings()IEnumerable<string>String representations of the parameter type.

Usage notes:

  • Subscribe to Context.ArgumentChanged / ArgumentsReset in OnParametersSet when a panel needs to re-render on argument updates; unsubscribe on IDisposable.Dispose.
  • Treat Args as read-only snapshots; mutate state via AddOrUpdateArgumentAsync instead of writing into the dictionary.
  • Story may be null before a story is selected — always null-check.

Step 5: Create the addon class

Create a C# class implementing IAddon in the same folder:

using BlazingStory.Addons;

namespace MyApp.Stories.Addons.MyFeature;

public class MyFeatureAddon : IAddon
{
    public void Initialize(IAddonBuilder builder)
    {
        builder.AddToolbarContent<MyFeatureToolbarContent>(order: 1000,
            match: viewMode => viewMode is ViewMode.Story or ViewMode.Docs);
        builder.AddPanel<MyFeaturePanel>(order: 1000,
            match: viewMode => viewMode == ViewMode.Story);
        builder.AddPreviewDecorator<MyFeaturePreviewDecorator>();
    }
}

Key rules for the addon class:

  • order controls position within each slot. Built-in addons use 100–900. Custom addons are typically placed after the built-ins (on the right), so 1000+ is the common choice. However, to place a custom addon before the built-ins (on the left), use a value below 100; to place it between specific built-ins, pick a value that fits the desired position within the 100–900 range.
  • match predicate controls visibility. ViewMode values: Story, Docs, CustomPage.
  • AddPreviewDecorator has no order or match — decorators are always active.
  • Omit AddPanel, AddToolbarContent, or AddPreviewDecorator calls for component types you are not using.

Step 6: Register the addon

Open the App.razor (or equivalent) file that contains <BlazingStoryApp> and add the registration:

<BlazingStoryApp OnInitialize="builder => builder.Addons.Register<MyFeatureAddon>()" />

If OnInitialize already has content, extract it into a method:

<BlazingStoryApp OnInitialize="Configure" />

@code {
    private static void Configure(IBlazingStoryConfigurator builder)
    {
        builder.Addons.Register<ExistingAddon>();
        builder.Addons.Register<MyFeatureAddon>();
    }
}

BlazingStory.ToolKit components

Use these components (already available in the stories project) to keep the addon UI consistent with the built-in addons:

ComponentUse for
<IconButton Icon="SvgIconType.X" Active="..." OnClick="...">Toolbar toggle buttons
<PopupMenu><Trigger>...</Trigger><MenuItems>...</MenuItems></PopupMenu>Dropdown menus in toolbar
<MenuItem OnClick="..." Active="...">Menu items inside <PopupMenu>
<MenuItemDivider />Dividers between menu item groups
<Badge Text="..." />Count badges in panel titles
<ImportStyleSheet Href="..." />Load/unload a stylesheet conditionally
<ToolBar>, <TabButton>, <TabButtonGroup>Tab UIs inside panels
<Separator />, <Spacer />Toolbar spacing

Namespace reference

Addon components and classes reference types from several BlazingStory packages. Add the matching @using (Razor) or using (C#) directive to each file that references the type. Namespace-per-type cheatsheet:

NamespaceTypes defined there
BlazingStory.AbstractionsIStory, IStoryContext, IComponentParameter
BlazingStory.AddonsIAddon, IAddonBuilder, GlobalArguments, PanelTitle, ViewMode
BlazingStory.ToolKit.ButtonsIconButton, ToggleButton, SquareButton, CornerButton, ResetButton
BlazingStory.ToolKit.IconsSvgIconType, SvgIcon, Badge
BlazingStory.ToolKit.MenusPopupMenu, MenuItem, MenuItemDivider
BlazingStory.ToolKit.StylesImportStyleSheet
BlazingStory.ToolKit.ToolBarToolBar, TabButton, TabButtonGroup, Separator, Spacer
BlazingStory.ToolKit.InputsColorInput, NumberInput, TextArea, Select, RadioGroup, NullInputRadio

Rules of thumb:

  • Toolbar content components typically need @using BlazingStory.Addons, plus ToolKit namespaces for whichever UI components are used (e.g., Buttons + Icons for <IconButton Icon="SvgIconType.X" />).
  • Panel components typically need @using BlazingStory.Abstractions (for IStory) and @using BlazingStory.Addons (for <PanelTitle>).
  • Preview decorator components need @using BlazingStory.Abstractions only when they consume the IStory cascading parameter.
  • Addon classes (C#) need using BlazingStory.Addons; (for IAddon, IAddonBuilder, ViewMode).

Step 7: Verify

After creating all files, summarize:

  • Files created (component(s), addon class)
  • Which slots are registered (toolbar / panel / decorator) and their order
  • The ViewMode match logic applied
  • The registration line added to App.razor
  • Any assumptions made (e.g., localStorage persistence omitted for simplicity)

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.