Skip to main content
net10.0

The ScissorHands.NET static site generation engine for Markdown content and Razor themes.

Published
Sep 13, 2026
1mo ago
Total Downloads
950
950

Install

dotnet add package ScissorHands.Web --version 1.0.0-preview.20260913.1
ProductVersions
.NET
net10.0

README

ScissorHands.Web

NuGet License

ScissorHands.Web is the static site generation engine for ScissorHands.NET. It turns Markdown documents with YAML frontmatter into static HTML using Razor themes and optional content plugins.

Features

  • Markdown and YAML frontmatter processing
  • Razor-based layouts and page views
  • Automatic theme discovery from configuration
  • Pre-Markdown, post-Markdown, and post-HTML plugin stages
  • Posts, pages, tags, custom 404 pages, and content assets
  • Locale-aware and date-based URL options
  • Local preview server with automatic content regeneration
  • Responsive built-in theme with light and dark modes

Install

dotnet add package ScissorHands.Web --prerelease

ScissorHands.NET currently targets .NET 10.

Create an application

Create an empty ASP.NET Core application:

dotnet new web -n MyScissorHandsApp
cd MyScissorHandsApp
dotnet add package ScissorHands.Web --prerelease

Replace Program.cs with:

using ScissorHands.Web;

var app = new ScissorHandsApplicationBuilder(args).Build();
await app.RunAsync();

No theme component types need to be registered in Program.cs. The built-in theme is used when Site:Theme is default.

Configure the site

Add the Site and Plugins sections to appsettings.json:

{
  "Site": {
    "Title": "My site",
    "Description": "Notes about .NET, software, and the web.",
    "Locale": "en-US",
    "Author": "Your name",
    "Theme": "default",
    "SiteUrl": "https://example.com",
    "BaseUrl": "/",
    "UseLocaleInUrl": false,
    "UseDateInPostUrl": true,
    "Debug": false
  },
  "Plugins": []
}

Use BaseUrl when publishing below a subpath, such as /docs/.

Add content

ScissorHands reads Markdown from:

contents/
├── images/
├── pages/
└── posts/

Example post:

---
title: Hello, ScissorHands
description: My first generated post.
slug: hello-scissorhands
published: 2026-09-11
author: Your name
locale: en-US
tags:
  - dotnet
  - static-site
draft: false
---

# Hello, ScissorHands

Write the post in Markdown.

Supported frontmatter fields are:

  • title
  • slug
  • description
  • locale
  • author
  • twitter_handle
  • hero_image
  • published
  • tags
  • draft

Invalid frontmatter, unsafe routes, and duplicate output paths fail the build with the source file included in the error.

To provide a custom not-found page, add a page with slug: 404.html.

Preview and build

Start the local preview server:

dotnet run -- --preview

Generate the static site into dist/:

dotnet run -- --build

Preview mode regenerates the site after content or theme-file changes. Refresh the browser to display regenerated HTML. Razor or C# changes still require recompilation, typically with dotnet watch.

Themes

A custom theme provides concrete Razor components derived from:

  • MainLayoutBase
  • IndexViewBase
  • PostViewBase
  • PageViewBase
  • NotFoundViewBase

TagListViewBase and TagViewBase are optional; the built-in tag views are used when they are omitted.

Keep the components in one namespace whose normalized suffix matches the configured theme slug. For example:

Site:Theme = minimal-blog
Namespace  = ScissorHands.Theme.MinimalBlog

Theme assets and metadata live under themes/{slug}/, including a theme.json manifest.

Plugins

Install plugin packages and configure each enabled plugin by its stable, unique kebab-case ID:

{
  "Plugins": [
    {
      "Id": "example-plugin",
      "Name": "Example Plugin",
      "Options": {
        "Enabled": true
      }
    }
  ]
}

Plugins can transform a document before Markdown conversion, after Markdown conversion, or after the final Razor HTML render.

At every stage, each plugin's output feeds the next. IDs must be lowercase ASCII kebab-case and are matched ordinally; installed plugins without a manifest remain disabled. Manifest Name values are optional display labels, not identifiers. Missing or invalid IDs, duplicate IDs, and unmatched manifests fail without name fallback or automatic normalization.

Execution order is resolved from optional, stage-scoped DependsOn declarations provided by plugins, not the Plugins array position or registration order. Declared dependencies must be installed and enabled. Missing or disabled dependencies, invalid declarations, and cycles fail when the runner is constructed, before any plugin hooks execute. Dependencies are never automatically installed or enabled.

Within each stage, the engine chooses among ready plugins by ordinal ID ordering for deterministic output. A plugin without dependency declarations must not rely on another plugin's execution order.

Migration: plugin implementations must now expose Id, configured manifests must include it, dependency references must use IDs, and Razor plugin components must select with Id instead of Name. Rebuild existing plugin and consuming assemblies; name-only configuration is no longer accepted. Follow the plugin ID migration guide.

Learn more

License

ScissorHands.NET is licensed under the MIT License.

The built-in theme is adapted from PlainPage. Its attribution is included in THIRD-PARTY-NOTICES.md.

Changes from Previous Version

No structural changes between v1.0.0-preview.20260912.1 and v1.0.0-preview.20260913.1.

Adoption Assessment

Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.

This version is marked prerelease. Validate its API and upgrade path before production use.Compatibility metadata lists 1 target framework; confirm the exact target used by your application.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.