How Instatic Handles CSS Generation Through Core Framework

Instatic generates CSS via a two-pass architecture that produces both :root CSS custom properties and locked utility classes from design tokens, orchestrated by the buildFrameworkPlan function in src/core/framework/generate.ts.

The Core Framework powers Instatic's visual design system by converting user-defined settings into optimized stylesheets. This repository (CoreBunch/Instatic) implements a deterministic generation pipeline that creates matching CSS variables and utility classes without duplicating token traversal.

The Architecture: buildFrameworkPlan Orchestration

The generation process centers on buildFrameworkPlan, located in src/core/framework/generate.ts at lines 91-109. This function serves as the central dispatcher for all CSS generation, accepting FrameworkGenerationSettings and returning a FrameworkPlan containing both the :root CSS block and utility class mappings.

export function buildFrameworkPlan(
  settings: FrameworkGenerationSettings | null | undefined,
): FrameworkPlan {
  const preferences = resolveFrameworkPreferences(settings?.preferences)
  const colors = generateFrameworkColorPlan(settings?.colors)
  const typography = generateFrameworkTypographyPlan(settings?.typography, preferences)
  const spacing = generateFrameworkSpacingPlan(settings?.spacing, preferences)

  return {
    rootCss: composeFrameworkRootCss(colors.variableSets, [
      ...typography.variables,
      ...spacing.variables,
    ]),
    utilityClasses: {
      ...colors.utilityClasses,
      ...typography.utilityClasses,
      ...spacing.utilityClasses,
    },
  }
}

Resolving User Preferences

Before generating CSS, the system calls resolveFrameworkPreferences from src/core/framework/preferences.ts to normalize user-defined settings like light versus dark mode defaults. This ensures consistent values across both variable and utility class generation.

Token Enumeration and the Shared Plan Pattern

Instatic optimizes performance by planning each token family exactly once. The planColorTokens function in src/core/framework/colors.ts (lines 81-92) demonstrates this pattern:

function planColorTokens(settings: FrameworkColorSettings | null | undefined): ColorTokenPlan[] {
  // … sort, de‑duplicate slugs, expand variants …
}

Similar planning functions exist in typography.ts and spacing.ts. By creating a single ordered enumeration per family, both the variable-set generation and utility-class generation reuse identical data structures. This eliminates duplicated traversals and guarantees that token order, slug deduplication, and variant expansion remain synchronized between the :root definitions and utility selectors.

Generating the :root CSS Variable Block

The :root CSS is constructed by composeFrameworkRootCss in src/core/framework/generate.ts (lines 50-60):

function composeFrameworkRootCss(
  colorVariables: FrameworkColorVariableSets,
  scaleVariables: FrameworkScaleVariable[],
): string {
  return [
    formatCssVariableBlock(':root', [...colorVariables.light, ...scaleVariables]),
    formatFrameworkColorThemeCss(colorVariables),
  ]
    .filter(Boolean)
    .join('\n\n')
}

This function concatenates the light-mode variables with typography and spacing scales, then appends dark-mode overrides if present.

Dark Mode Implementation

When a dark-mode palette exists, formatFrameworkColorThemeCss adds secondary selector blocks using constants defined in src/core/framework/colors.ts: DEFAULT_THEME_OVERRIDE_SELECTOR and ALT_THEME_SELECTOR. The resulting CSS injects variables under selectors like :root.theme-alt to support theme switching.

Variable Formatting

The formatCssVariableBlock function in src/core/framework/cssVariables.ts emits the final CSS:

:root {
  --primary: hsla(...);
  --spacing-1: 0.25rem;
  …
}

Utility Class Generation

Alongside CSS variables, the framework generates locked utility classes that implement the same tokens. Each token family produces its own utility class map.

Color Utilities

In src/core/framework/colors.ts, the colorUtilityClassesFromPlan function (lines 89-102) and generateFrameworkColorUtilityClasses create classes like text-primary, bg-primary-d-1, and border-primary-l-2.

Typography and Spacing Utilities

The pattern repeats in src/core/framework/typography.ts with generateFrameworkTypographyUtilityClasses emitting classes for font-size, line-height, and font-weight. Similarly, src/core/framework/spacing.ts contains generateFrameworkSpacingUtilityClasses which generates margin and padding classes such as m-4 and p-2.

All generated utility classes are locked (generated.locked: true), preventing the publisher from rewriting them during the rendering phase.

Integration Points

Admin Canvas Rendering

The admin UI imports the generator directly in src/admin/pages/site/canvas/canvasClassCss.ts to style the live preview:

import { generateFrameworkRootCss } from '@core/framework'

const frameworkCss = generateFrameworkRootCss({
  colors: userColorSettings,
  typography: userTypographySettings,
  spacing: userSpacingSettings,
})

This ensures the canvas reflects the exact same design tokens as the final published site.

Publishing Pipeline

During page publication, the server invokes buildFrameworkPlan and injects the results into the static artifact. The rootCss content is embedded directly into the HTML:

<style>
  :root { … }
  :root.theme-alt { … }
</style>
<link rel="stylesheet" href="/_instatic/framework-utilities.css">

The utility stylesheet is serialized from the utilityClasses map by the publisher's CSS serializer in src/core/publisher/frameworkCss.ts.

Why the Two-Pass Design Matters

The architecture deliberately separates token planning from CSS emission to achieve three critical goals:

  • Performance: Token lists are traversed once per family rather than twice (once for variables and once for utilities).
  • Determinism: Shared ColorTokenPlan, typography plans, and spacing plans ensure identical slug ordering and variant IDs across both outputs, preventing mismatches between :root definitions and utility selectors.
  • Cacheability: The resulting FrameworkPlan object can be cached in the render cache and reused for subsequent renders of the same site version, avoiding recomputation.

Summary

  • Instatic's Core Framework generates CSS through the buildFrameworkPlan function in src/core/framework/generate.ts, which orchestrates the creation of both :root variables and utility classes.
  • The system uses a single-pass token planning strategy via planColorTokens, planTypographyTokens, and planSpacingTokens to ensure consistency and performance.
  • CSS custom properties are formatted by composeFrameworkRootCss and formatCssVariableBlock, with optional dark-mode support via formatFrameworkColorThemeCss.
  • Utility classes are generated as locked entities (generated.locked: true) for colors, typography, and spacing, ready for the publisher's CSS serializer.
  • The architecture serves both the admin canvas (via generateFrameworkRootCss) and the publishing pipeline (via buildFrameworkPlan), ensuring identical styling between the editor and final output.

Frequently Asked Questions

How does Instatic ensure CSS variables match utility classes?

Instatic uses a shared planning phase where planColorTokens, planTypographyTokens, and planSpacingTokens create single ordered enumerations for each token family. Both the :root variable generator and utility class generator consume these same data structures, guaranteeing identical slug ordering, variant expansion, and deduplication.

What is the purpose of locked utility classes in Instatic?

Utility classes are marked with generated.locked: true to prevent the publisher from rewriting them during the rendering phase. This ensures that the framework-generated classes remain immutable and performant in the final static output.

Where does the dark mode CSS get generated in Instatic?

Dark mode CSS is handled by formatFrameworkColorThemeCss in src/core/framework/generate.ts, which uses constants DEFAULT_THEME_OVERRIDE_SELECTOR and ALT_THEME_SELECTOR from src/core/framework/colors.ts to emit override blocks under selectors like :root.theme-alt.

Can the generated CSS be cached for performance?

Yes. The FrameworkPlan object returned by buildFrameworkPlan can be cached in the render cache and reused for subsequent renders of the same site version, avoiding the computational cost of regenerating CSS variables and utility classes on every request.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →