Neko

Changelog

Neko is under active development and follows a calendar-versioning (vYY.M) scheme. The most recent release is listed first.

v26.6

New components

New

Version badge

A compact, theme-agnostic package pill — a muted label, a bold monospace version, an optional link and a one-click copy button: Curiosity.FrontEndv26.6.1753. Place several next to each other and they flow inline, wrapping onto the same line: Tesseraev2026.6.67285 Curiosity.CLIv26.6.1718. Documented at components/version-badge.md, with a version-badge skill and a neko-version-badge snippet.

New

Link card

A ```links fenced block renders a titled card of links — each row is a labelled link on the left and a version pill on the right, one row per line as text | url | version:

Documented at components/link-card.md, with a link-card skill and a neko-link-card snippet.

New

Folder-based changelogs

Changelogs are now built from a folder instead of a single hand-maintained file. Drop a folder anywhere in your project, mark it with changelog: true in its index.yml (plus a title/description), and add one Markdown file per release named after its version (v26.6.md, 1.2.0.md, …). Neko parses each file name as a version, sorts the entries newest-first, and renders a single timeline page at the folder URL. The folder collapses to one sidebar entry, the version files are not emitted as standalone pages, and the aggregated page is what gets indexed for search and listed in the sitemap. The Neko changelog you are reading now uses this model.

New

Quiz component

Added a ```quiz fenced block whose YAML body defines a self-scoring multiple-choice comprehension check. Questions render radio buttons for a single correct answer or checkboxes for multiple answers: [..], with an optional per-question explain. Check answers grades client-side, highlights correct/incorrect options, and reveals explanations; score and answered-state persist per-browser in localStorage (no backend). Documented at components/quiz.md, with a quiz skill and a neko-quiz snippet.

Improvements

Improved

Redesigned changelog timeline

The changelog timeline now renders as sections with entries. Each release's section headings (#) become labelled headers with an icon, and each entry — authored as a ::: change {badge="…" title="…"} block — renders its badge in a left column, vertically aligned, with the title and description next to it. Every version header is sticky and links to the closest NuGet package for that month, so the version you are reading stays pinned until the next release scrolls into view.

Fixes

Fixed

gen-images skips commented directives

neko gen-images and neko gen-dark-images now skip [!img-gen] directives (and assets/img-gen/*.png references) that sit inside an HTML comment. After the first generation pass the original directive is preserved as a <!-- ... --> block above the rendered image — re-running the command was matching the commented-out directive again, burning API tokens and producing nested comments / orphan PNGs. The discovery regex is now paired with a comment-span filter so commented directives are detected and ignored.

v26.5

Features

New

redirectSlug frontmatter key

Added a redirectSlug page frontmatter key that exposes a page at a short, stable URL of the form /redirect/<slug>. When set, Neko writes a tiny HTML file at redirect/<slug>.html whose only job is to redirect the visitor to the page's actual URL via <meta http-equiv="refresh"> (with a JavaScript fallback and a visible link). The redirect page is marked noindex and carries a <link rel="canonical"> back to the real page, so it doesn't compete with the original in search engines. Useful for short, shareable, stable links — printed material, QR codes, emails, social posts — that survive future page re-organisation. Folder index pages collapse their target to the folder URL (docs/index.md/docs/), and the route prefix is applied automatically in multi-repo builds. Slugs are a flat namespace under /redirect/ and must not contain / or \; duplicate slugs across pages are detected at build time (first wins, the rest logged as warnings). Docs at configuration/page.md#redirectslug, and the frontmatter skill in the starter template has been updated.

New

pageLinks navigation in neko.yml

Added a pageLinks configuration in neko.yml for rendering site-wide links at the top of every page's "On this page" navigation. Each entry takes a label, icon, url, and optional target; the url template supports three URL-encoded placeholders resolved at click time — ${page} (page title), ${url} (absolute page URL), and ${selection} (the visitor's current text selection, or empty). Useful for "Report an issue", "Suggest an edit", and "Quote this page" actions. Links only render on pages where the TOC is visible. Docs live at configuration/core/project.md#pagelinks, and the neko-yml skill in the starter template has been updated.

New

neko gen-dark-images command

Added a neko gen-dark-images command that backfills missing dark-mode variants for images previously created by [!img-gen] (or any assets/img-gen/*.png reference authored manually). The command walks every .md file under --input, finds image references that don't already carry a {src-dark="…"} attribute, calls the OpenAI image-edit endpoint to regenerate each in dark mode using the configured imageGen.darkModePrompt, saves the result as <name>-dark.png next to the original, and rewrites the Markdown attribute — preserving any other attributes already on the image. Idempotent: paired images and <name>-dark.png files themselves are skipped, and dark variants already present on disk are relinked into the Markdown without a second API call. Where possible the dark generation matches the PNG header's pixel dimensions of the source image so the pair lines up visually; otherwise it falls back to imageGen.size. Docs at components/img-gen.md#backfilling-dark-variants-for-existing-images.

New

Expanded img-gen with project defaults and dark mode

Expanded [!img-gen] with project-level defaults, a sensible landscape default size, and automatic dark-mode variants. A new imageGen: section in neko.yml exposes a global systemPrompt appended to every image prompt, a size default (now 1536x1024 landscape out of the box, instead of the model's square default), and lightMode / darkMode toggles (both on by default). When lightMode is on, a "render for a light theme" instruction is appended to every prompt; when darkMode is on, Neko follows the light generation with a second call to the OpenAI image-edit endpoint using the freshly generated light image plus a "redo this in dark mode" prompt, producing a paired name-dark.png. The rewritten Markdown now carries a src-dark="…" attribute that the image renderer expands into two <img> tags (dark:hidden / hidden dark:inline-block) so the active theme picks the right variant automatically. The size attribute on a directive now accepts every TornadoImageSizes value (1024x1024, 1536x1024, 1024x1536, 2048x2048 / 2048x1152, 3840x2160 / 2160x3840, auto, plus any explicit <width>x<height> going through Custom), and two new per-directive overrides — light= and dark= — let an individual image opt out of the light-mode hint or the dark-variant pass. Docs at components/img-gen.md, snippets refreshed in templates.json, and both the img-gen and neko-yml skills updated accordingly.

New

sitemap.xml generated by default

sitemap.xml is now generated by default as part of every neko build / neko watch. The default for the sitemap configuration key in neko.yml flipped from false to true, so no opt-in is required. Each entry uses the page's clean (extensionless) URL — directory index.md pages collapse to their folder URL — and includes a <lastmod> derived from the source file's last-write time. Password-protected pages are excluded. Generation is skipped automatically when url is unset (or left at the placeholder localhost), since the resulting sitemap would not contain valid absolute URLs. In multi-repo / sub-project mode, only the root project writes the sitemap (sub-projects share the output directory and would otherwise clobber it).

New

searchExclude configuration option

Added a searchExclude configuration option for opting pages and folders out of the in-site search index. Set searchExclude: true in a page's frontmatter (or sibling .yml) to omit that single page from search.json, or set it in a folder's index.yml / <foldername>.yml to exclude every page under that folder recursively. Excluded pages are still built and reachable by direct link — they just do not appear in search results. Documentation lives at configuration/page.md#searchexclude and configuration/folder.md#searchexclude, and the page/folder skills (frontmatter, folder-index) have been updated accordingly.

New

neko update-skills command

Added a new neko update-skills command that refreshes the Neko-managed skills under an existing project's .claude/skills/ folder to match the versions bundled with the running CLI. Pass --path to point at a project (default: current directory) and --dry-run to preview the changes. The command requires a .claude/ folder to exist (otherwise it errors out and suggests neko new), replaces every Neko-shipped skill folder in place, and leaves any custom (non-Neko) skills untouched — reporting both the count of skills replaced/added and the names of the custom skills preserved.

New

img-gen component and neko gen-images

Added a new [!img-gen] component and a matching neko gen-images command that uses the LlmTornado NuGet package to generate images from inline prompts via OpenAI. Authors describe an image inside a [!img-gen ...] block; running neko gen-images --api-key sk-... [--image-model gpt-image-1] [--llm-model gpt-4o-mini] walks every Markdown file under --input, asks the chat model for a slug and alt-text (strict JSON), generates the PNG with the image model, saves it into the page's assets/img-gen/ folder, and rewrites the directive into a regular Markdown image with the original directive preserved as an HTML comment so it can be re-generated later. Only OpenAI is supported for now. The directive renders nothing in HTML until you run the command, and supports size, quality, background, and style attributes. Documentation lives at components/img-gen.md, with two neko-img-gen* snippets in templates.json and a new img-gen skill in the starter template.

New

neko new scaffolding command

Added a new neko new command that scaffolds a fresh hello-world documentation project (with neko.yml, three sample pages, and a .claude/ folder of skills) into the current directory or a directory passed via --path. The starter lives under .template/ in the repository and is zipped at build time and embedded as a resource in the CLI assembly. Pass --force to overwrite a non-empty target.

New

Roadmap component

Added a new Roadmap component that renders a kanban-style product roadmap board. Lanes (:::: lane) carry a title, count badge and accent colour; items (::: roadmap-item) carry a title, tag pill, optional date, vote count, and optional clickable link. Lane count badges reuse the icon-badge tint+ring style from grid cards, item tag pills follow the soft bg-{color}-100 / text-{color}-800 palette from [!badge], and lanes/items use rounded-2xl / rounded-xl with hover:border-primary-* to match Neko cards. Documentation lives at components/roadmap.md, with three neko-roadmap* snippets in templates.json.

New

Drag-and-drop sidebar reordering

Added drag-and-drop reordering of sidebar items while running neko watch. Items can be reordered within their parent group; on drop, the corresponding .md frontmatter order (or folder index.yml order) values are rewritten as multiples of 10, and the site reloads automatically. A new POST /api/neko/reorder endpoint handles the update.

New

neko snap screenshot command

Split screenshot capture into a dedicated neko snap command. neko build and neko watch no longer call Playwright; instead, run neko snap to capture missing screenshots, or neko snap --all to re-capture everything.

New

Lesson component

Added a new [!lesson] Markdown component that renders a curriculum-style track. Steps are auto-discovered from sibling .md files in the folder, ordered by their order frontmatter. User progress is persisted to localStorage per lesson.

New

Lesson step navigation block

Pages inside a [!lesson] folder now render a dedicated Go back: … / Next step: … navigation block at the bottom, with chevron icons and links to the previous and next siblings in the same curriculum order as the parent lesson page. Detected automatically — no per-page configuration required.

New

Learn Neko sample track

Added a Learn Neko sample track under lesson/ showcasing the new component end-to-end.

Improvements

Improved

HtmlGenerator split into partial classes

Split HtmlGenerator into focused partial-class files by concern (HtmlGenerator.Head.cs, HtmlGenerator.Navbar.cs, HtmlGenerator.Sidebar.cs, HtmlGenerator.Content.cs, HtmlGenerator.WatchMode.cs, HtmlGenerator.Scripts.cs). The 1,345-line Generate method is now a ~50-line orchestrator that delegates to single-purpose render methods (RenderBanner, RenderNavbar, RenderBreadcrumbs, RenderArticleBody, RenderPageNavigation, RenderFooter, RenderTocSidebar, RenderPageScripts, etc.), and the 327-line GenerateHead follows the same shape (RenderHeadMeta, RenderHeadTailwindAndTheme, RenderHeadMermaid, RenderHeadHighlightJs, …). Pure code reorganization with no behavioral changes — the emitted HTML for every page in Neko.Documentation is byte-identical to the previous output (only the intentionally-random encrypted-page payloads and tab GUIDs differ).

Improved

Search works across multi-repo builds

Search now works across every sub-project in a multi-repo build. Each sub-project's search.json is still written next to its own output, but at the end of the build (and every watch-mode rebuild) every sub-project's entries are merged into a single aggregated search.json at the root output. Document ids are now route-prefixed (workspace/core-concepts/graph-model.html instead of bare core-concepts/graph-model.html), and the client always fetches the root index — so a search from /workspace-deployment/ can find pages under /workspace/ and vice versa. The route-prefix segments also become slug tokens, so a query like workspace graph model boosts the right pages. Results from the sub-site the visitor is currently browsing also get a 1.6× score boost, so "local" hits surface first while other sub-sites stay reachable below them.

Improved

Friendlier search result breadcrumbs

Search results now show a friendly, extension-less breadcrumb under each hit (.../workspace/core-concepts/graph-model) instead of the raw .html URL, and a trailing index segment collapses to its folder. Pages living under any folder whose name starts with . or _ (e.g. _helpers, _reference-material, .template) are no longer indexed — these are treated as private scaffolding.

Improved

More prominent search result titles

Search results now make the page title visually more prominent — the title renders at text-base font-semibold (up from text-sm font-medium) so it dominates the snippet/breadcrumb beneath it. The indexed title also now falls back to the frontmatter label: (when title: is absent) and then to the first heading at any level (not just H1), so a page that opens with ## Graph Model and only declares label: "Graph Model" is indexed as Graph Model instead of the bare filename graph-model. Finally, the search slug drops trailing index segments (blog/index.html → slug blog, root index.html → empty), so a query for index no longer blanket-matches every section landing page via the slug. Pages named index.md remain indexed and findable through their title and content.

Improved

Deeper, more relevant search results

Overhauled the in-page search to surface deeper, more relevant results. The build-time indexer now emits one document per H2/H3 in addition to the page-level document, so search results deep-link directly to a section anchor instead of just the page. Each page document carries new slug, headings, type, parentTitle, and parentId fields. The slug splits the path into separate tokens (e.g. blog/index.htmlblog index), so queries like index now reliably return index.md even when the page title is something else. The client (MiniSearch) was upgraded to AND-combine multi-word queries, boost slug and title above body content, apply fuzzy matching only to longer terms, and de-duplicate page+section hits in favour of the deeper link. The results UI now shows a highlighted snippet around the first match, a parent-page breadcrumb on section hits, a loading state while the index is fetched on first use, and a recent-searches list (stored in localStorage) when the input is empty.

Improved

csharp-docs preserves accessor declarations

The csharp-docs block now preserves property and indexer accessor declarations ({ get; }, { get; set; }, { get; init; }, { get; private set; }, etc.) in the rendered signature. Accessor bodies and expression bodies are stripped but the accessor keywords themselves are kept, so the rendered API doc shows what is actually readable / writable at a glance.

Improved

Cleaner DocFx-style csharp-docs layout

The csharp-docs block now renders a much cleaner DocFx-style layout and stops leaking the parent class body into the type signature. Class declarations are rebuilt from their modifiers, keyword, identifier, type-parameter list, base list, and constraint clauses, so the body — fields, private members, etc. — never appears in the signature. The parent type now renders as a sticky header (kind badge, name with a small unobtrusive anchor link after it, signature, summary) that floats at the top of the csharp-docs section while the visitor scrolls through the constructors / properties / methods listed below it. Members are grouped by kind (Constructors → Properties → Methods → Events → Fields), each prefixed with a kind badge (Constructor, Property, Method, etc.) and qualified with the parent class name (e.g. DetailsList.OnColumnClick). The link anchor was moved to after the name, shrunk, and stripped of its underline. Signatures are now whitespace-normalized at render time, so column-aligned source code like public void OnColumnClick() renders as public void OnColumnClick(). Standalone members (fragments without an enclosing class) still render via SourceCodeKind.Script parsing so the legacy snippet form on components/csharp-docs.md keeps working.

Improved

Refreshed default light / dark themes

Refreshed the default light / dark themes to match the look-and-feel of docs.curiosity.ai. Introduced a new curiosity default theme (deep navy #050914 background in dark mode), a paired accent palette, and a neko-text-gradient utility used by the hero accent word.

Improved

Redesigned grid card variant

Redesigned the grid card variant to match the curiosity card style — rounded icon badge with palette-coloured tint, hover glow, no image required. Added a new palette attribute and a deterministic palette fallback.

Improved

Redesigned hero component

Redesigned the [!hero] component with an eyebrow label, gradient accent word (title-accent), and subtle radial glow accents. Default alignment is now left to match the reference.

Improved

Removed gradient card options

Removed all gradient card options (gradient, gradient-mode, gradient-colors, gradient-noise, gradient-speed) and the bundled makegradient.js asset. Use the new icon-badge style instead.

Improved

Removed --disable-snapframe flag

Removed the --disable-snapframe build/watch flag — capturing is now opt-in via neko snap.

Fixes

Fixed

label honored consistently

The frontmatter label: is now honored consistently wherever a page's display name is derived. Previously only the left sidebar fell back to label; the top navigation entry and the page <title> tag used title only and ignored label. Now the top-nav entry resolves label → title → file name (matching the sidebar), and the <title> tag falls back to label when no title is set. This means pages that follow the recommended pattern of setting label: (instead of the discouraged title:) get a meaningful title and nav label everywhere, not just in the sidebar.

Fixed

Heading anchor link spacing

The hover # anchor link next to headings no longer abuts the heading text. It's now positioned by its own width (-translate-x-full) with a fixed pr-2 gap, so the spacing stays consistent regardless of heading size — previously the fixed -left-6 offset was too small for larger headings, leaving the icon touching the text.

Fixed

Header logos resolve route prefix

Header logos (branding.logo / branding.logoDark) on multi-site builds are now resolved with the project's route prefix, so a sub-project at /tesserae emits <img src="/tesserae/assets/tesserae-logo.png"> instead of /assets/tesserae-logo.png. Previously the root-relative path generated by ResolveLogoPath was written out verbatim, which only happened to work when the same asset filename also existed at the site root.

Fixed

Favicon path HTML-escaping and auto-detection

Favicon injection now HTML-escapes the configured path before writing it into the <link rel="icon" href="..."> tag, so values containing &, ", <, or > (e.g. favicon.ico?v=1&cache=2) no longer produce broken markup. In addition, the long-documented default behavior is now actually implemented: when branding.favicon is not set, Neko auto-detects favicon.ico or favicon.png at the input root, sets the favicon link to /favicon.<ext>, and copies the file to the output root so the link resolves.

Fixed

neko.yml link normalization

Links in neko.yml (top-navigation links, dropdown items / footerItems, and banner.link) are now normalized at load time the same way Markdown links are — a trailing .md or .html is stripped so authors can paste the on-disk filename (e.g. link: /workspace/core-concepts/graph-model.md) and get the clean URL (/workspace/core-concepts/graph-model) in the rendered nav. Fragments (#section), query strings (?x=1) and external :// URLs are preserved unchanged.

Fixed

Centered-alignment pipe tables

Pipe tables whose delimiter row used centered-alignment markers (:---:) were rendered as a paragraph instead of a table. The EmojiParser was greedily matching :---: as an emoji named ---, consuming the alignment markers before Markdig's pipe-table parser could see them. Emoji names now require at least one alphanumeric character, so alignment markers are left intact. This restores the rendering of the All Icons table on the Icon component documentation page.

Fixed

Search shows H1 for untitled pages

Search results now display the page's first # H1 heading when the page has no title: set in its frontmatter, falling back to the file name only if neither is present. Previously, untitled pages always showed the bare file name in the search modal.

Fixed

Search indexes rendered content

Search now indexes the rendered page content instead of the raw markdown source. Auto-injected blog and changelog listings, callouts, tabs, and other component bodies are searchable, while YAML frontmatter is no longer mixed into the indexed text. Password-protected pages are skipped entirely (previously their frontmatter password and body leaked into search.json). The client honours --route-prefix for both the search.json fetch and result links.

Documentation

Docs

Styled inline code

Inline code (text wrapped in single backticks) is now styled with a subtle background, border, and rounded corners in both light and dark mode, matching standard documentation rendering. The Tailwind Typography default of showing literal backtick characters around inline code has been replaced with this visual style.

v26.3.16

Features

New

Inline PDF component

Added a new component for rendering PDF files inline in the text. You can now use the standard markdown image syntax pointing to a .pdf file to automatically render it in an iframe using pdf.js.

v26.3.12

Features

New

Global password protection

Added support for configuring a global password in neko.yml. You can now protect the entire documentation by defining password: "my-secret" in your global configuration. Individual pages can bypass this global protection by setting password: none in their frontmatter.

Documentation

Docs

Tesserae TODO sample app

Updated the Tesserae component documentation (components/tesserae.md) to include a full interactive TODO sample application that demonstrates building UI components and persisting state via window.localStorage.

v26.3.11

Features

New

csharp-docs code block

Added csharp-docs code block language mode which leverages Roslyn to parse C# code blocks containing XML comments and beautifully renders them with DocFx-like layouts detailing the summary, parameters, remarks, return types, and exceptions.

New

sitemap.xml generation

Added a sitemap boolean configuration option in neko.yml to automatically generate a sitemap.xml file containing all generated HTML pages, utilizing the configured url as the base address.

New

Monaco template auto-completion

Added Monaco Editor support for auto-completing templates for all valid components of neko starting with the "neko-" prefix. The template list is loaded dynamically from templates.json on the first render of the editor.

Improvements

Improved

Sticky sidebar search box

Made the sidebar search box sticky when scrolling the sidebar, allowing quick access to the filter functionality. This was achieved by updating the HTML generation in Neko/Builder/HtmlGenerator.cs to wrap the search input in a sticky container while maintaining the proper layout for the rest of the navigation list.

Documentation

Docs

Live Editing guide

Added a new guide for the Live Editing feature in Watch mode, including details on auto-completing templates.

v26.3.3

Snapframe Component

Features

New

Snapframe component

Added a new [!snapframe] Markdown extension that automatically generates screenshots of external websites using the SnapFrame .NET tool during the build process.

Improvements

Improved

Multi-line snapframe commands

Extended the [!snapframe] Markdown extension to support multi-line command execution, allowing interaction with the page before taking the screenshot.

Documentation

Docs

Merged image alignment docs

Merged the image alignment documentation into the main image.md file.

v26.3

Initial Release

Highlights

New

Initial Release of Neko v26.3

We are excited to announce the initial release of Neko, a powerful static site generator designed to help you create beautiful, documentation-first websites with ease.

Key Features

  • Markdown First: Write your documentation in standard Markdown. Neko handles the rest.
  • Rich Components: Enhance your docs with built-in components like Alerts, Badges, Tabs, and more.
  • Theming: Dynamic Tailwind themes configurable via neko.yml under the theme key. Users can specify a built-in palette (e.g., name: violet) and override specific shades.
  • Blog Support: Neko supports a 'Blog Mode' where files in a blog/ directory are processed as posts, sorted by date (descending), and displayed in a responsive grid layout of cards.
  • Changelog Support: Neko supports a 'Changelog Mode' where a folder marked with changelog: true collects version-named files, sorts them newest-first, and displays them in a vertical timeline layout.
  • Watch Mode: The CLI supports a watch command that serves the site on localhost and auto-reloads on file changes, including a built-in Monaco editor for quick edits.
  • Multi-Repo Mode: Simultaneously build, watch, and serve multiple sub-projects located in immediate subdirectories containing a neko.yml file.
  • Tesserae Support: Write and compile Tesserae C# code blocks directly in your Markdown, generating live interactive components.

Other Important Features

  • Markdown Custom Containers: Support for custom Markdown syntax like Icons, Badges, Alerts, Tabs, Columns, Steps, Generic Components, Code Snippets, Panels, Emojis, and Cards.
  • Navigation History: Tracks the last visited pages in browser localStorage, with a flyover popup UI.
  • Built-in Search: Full-text client-side search across your documentation using Minisearch.
  • Dynamic Card Backgrounds: makegradient.js integration for beautiful, dynamic card backgrounds.
  • Mathematical Formulas & Diagrams: Integrated support for KaTeX math formulas and Mermaid diagrams.

Features

New

Icon Search in Watch Mode Editor

  • Added a searchable list of icons in the watch mode editor modal.
  • Accessible via the Ctrl+I or Cmd+I keyboard shortcut.
  • Allows inserting the selected icon's name directly into the editor at the current cursor position.
New

Mermaid Diagram Zoom Controls

  • Added built-in zoom controls to Mermaid diagrams.
  • Hover over any Mermaid diagram to access Zoom In, Zoom Out, and Reset buttons.
  • Applied a minimum height of 400px to all Mermaid diagrams to give ample space for interacting with diagrams.

Improvements

Improved

Workflow LeaderLines Clipping Improvements

  • Modified the workflow component javascript to appropriately clip connection lines within the workflow container.