# How the Theme System Works in the Web-Video-Presentation Skill

> Explore how the web-video-presentation skill's theme system uses a file-based architecture to separate theme metadata and design tokens for automatic discovery and runtime CSS injection.

- Repository: [ConardLi/garden-skills](https://github.com/ConardLi/garden-skills)
- Tags: internals
- Published: 2026-08-30

---

**The web-video-presentation skill uses a declarative, file-based architecture that separates theme metadata ([`theme.json`](https://github.com/ConardLi/garden-skills/blob/main/theme.json)) from design tokens ([`tokens.css`](https://github.com/ConardLi/garden-skills/blob/main/tokens.css)), enabling automatic discovery and runtime CSS injection without requiring code changes.**

The web-video-presentation skill in the **ConardLi/garden-skills** repository implements a lightweight theming system that allows designers to create fully-styled video presentations by supplying just two declarative files. This architecture leverages CSS custom properties and TypeScript interfaces to ensure type-safe, runtime theme switching driven by mood-based motion configurations.

## Theme System Architecture

The theme system adopts a strict separation of concerns between identity metadata and visual styling. Each theme resides in its own directory under `skills/web-video-presentation/themes/<theme-id>/` and must provide exactly two files to be recognized by the loader.

### Metadata Layer: [`theme.json`](https://github.com/ConardLi/garden-skills/blob/main/theme.json)

The [`theme.json`](https://github.com/ConardLi/garden-skills/blob/main/theme.json) file defines the theme's identity and semantic characteristics. It declares a unique `id`, human-readable `name` and `nameZh` fields for internationalization, a descriptive text block, and strategic metadata that drives UI behavior.

Key fields include:
- **`mood`**: An array of tags (e.g., `"cinematic"`, `"light"`, `"professional"`) that downstream animation utilities consume to adjust motion timing
- **`bestFor`**: Usage hints describing optimal scenarios for the theme
- **`preview`**: A color palette object (`shell`, `surface`, `text`, `accent`) used by the theme picker UI to render swatches

Located at [`skills/web-video-presentation/themes/warm-keynote/theme.json`](https://github.com/ConardLi/garden-skills/blob/main/skills/web-video-presentation/themes/warm-keynote/theme.json), this file serves as the contract between the designer's intent and the runtime system.

### Design Tokens Layer: [`tokens.css`](https://github.com/ConardLi/garden-skills/blob/main/tokens.css)

The [`tokens.css`](https://github.com/ConardLi/garden-skills/blob/main/tokens.css) file declares CSS custom properties that the presentation UI consumes uniformly. All components reference these variables, ensuring that swapping a theme instantly updates colors, typography, motion timing, shadows, and grid patterns without modifying component code.

Variables defined in [`tokens.css`](https://github.com/ConardLi/garden-skills/blob/main/tokens.css) include:
- `--accent`, `--surface`, `--text`: Core color tokens
- `--font-display-en`, `--font-body`: Typography stacks
- `--dur-base`, `--dur-slow`, `--dur-cinematic`: Motion timing variables
- `--shadow-elevation-*`: Depth and shadow values

## Type Safety and the Theme Interface

To ensure runtime reliability, the system defines a strict TypeScript interface in [`skills/web-video-presentation/templates/src/registry/types.ts`](https://github.com/ConardLi/garden-skills/blob/main/skills/web-video-presentation/templates/src/registry/types.ts):

```typescript
export interface Theme {
  id: string;
  name: string;
  nameZh: string;
  description: string;
  descriptionZh: string;
  mood: string[];
  bestFor: string[];
  preview: { 
    shell: string; 
    surface: string; 
    text: string; 
    accent: string 
  };
}

```

This `Theme` type enforces the shape of [`theme.json`](https://github.com/ConardLi/garden-skills/blob/main/theme.json) files, enabling compile-time checking when the loader fetches metadata. The interface supports bilingual content through the `nameZh` and `descriptionZh` fields, facilitating internationalized presentation UIs.

## Theme Discovery and Build Process

The system automatically discovers available themes during the build phase through [`skills/web-video-presentation/scripts/scaffold.sh`](https://github.com/ConardLi/garden-skills/blob/main/skills/web-video-presentation/scripts/scaffold.sh). This shell script performs the following operations:

1. Loops over every folder under `skills/web-video-presentation/themes/*`
2. Validates the presence of [`theme.json`](https://github.com/ConardLi/garden-skills/blob/main/theme.json) and [`tokens.css`](https://github.com/ConardLi/garden-skills/blob/main/tokens.css)
3. Reads each [`theme.json`](https://github.com/ConardLi/garden-skills/blob/main/theme.json) to extract metadata
4. Compiles a master [`themes.json`](https://github.com/ConardLi/garden-skills/blob/main/themes.json) catalog that the UI queries at runtime

This build-time generation ensures the presentation UI always has an accurate, up-to-date list of available themes without manual registration.

## Runtime Loading and Injection

At application startup, the runtime loads the selected theme's assets. The entry point at [`skills/web-video-presentation/templates/src/main.tsx`](https://github.com/ConardLi/garden-skills/blob/main/skills/web-video-presentation/templates/src/main.tsx) coordinates this injection process:

```typescript
// src/main.tsx
import { useEffect } from 'react';
import type { Theme } from './registry/types';

export function applyTheme(themeId: string) {
  // Resolve the CSS file using Vite's import.meta.glob
  const cssModules = import.meta.glob('../themes/*/tokens.css', { eager: true });
  const cssPath = Object.keys(cssModules).find(p => p.includes(`/${themeId}/`));
  
  if (cssPath) {
    const link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = cssPath;
    document.head.appendChild(link);
  }
}

// Usage within a React component
function ThemePicker({ themes }: { themes: Theme[] }) {
  const [selected, setSelected] = useState<string>(themes[0].id);
  useEffect(() => applyTheme(selected), [selected]);
  // ...
}

```

The JSON metadata is fetched separately to populate the theme-picker UI:

```typescript
export async function loadThemeMeta(id: string): Promise<Theme> {
  const resp = await fetch(`/themes/${id}/theme.json`);
  return resp.json();
}

```

## Mood-Driven Motion and Animation

Components consume the `mood` array from [`theme.json`](https://github.com/ConardLi/garden-skills/blob/main/theme.json) to adjust animation characteristics dynamically. The `mood` tags directly map to CSS timing variables defined in [`tokens.css`](https://github.com/ConardLi/garden-skills/blob/main/tokens.css), creating a semantic link between visual style and motion behavior.

For example, a theme with `"cinematic"` in its `mood` array will utilize longer duration values (`--dur-cinematic`), while a `"light"` or `"playful"` mood triggers faster spring settings (`--dur-base`). The `Stage` component and animation helpers reference these variables to maintain consistent visual feel:

```tsx
// src/components/Stage.tsx
export const Stage = () => (
  <section
    style={{
      backgroundColor: 'var(--surface)',
      color: 'var(--text)',
      padding: 'var(--stage-pad-y) var(--stage-pad-x)',
    }}
  >
    {/* Content renders with theme-derived values */}
  </section>
);

```

## Creating a Custom Theme

To add a new theme to the web-video-presentation skill:

1. Create a new directory under `skills/web-video-presentation/themes/<your-theme-id>/`
2. Add a [`theme.json`](https://github.com/ConardLi/garden-skills/blob/main/theme.json) file conforming to the `Theme` interface, specifying `id`, `mood` tags, and `preview` colors
3. Add a [`tokens.css`](https://github.com/ConardLi/garden-skills/blob/main/tokens.css) file defining all required CSS custom properties (`--accent`, `--font-*`, `--dur-*`)
4. Run the build process to execute [`scaffold.sh`](https://github.com/ConardLi/garden-skills/blob/main/scaffold.sh), which automatically registers the new theme in the catalog

No modifications to the TypeScript source code are required, as the loader dynamically resolves themes based on directory structure and file presence.

## Summary

- The web-video-presentation skill uses a **two-file system**: [`theme.json`](https://github.com/ConardLi/garden-skills/blob/main/theme.json) for metadata and [`tokens.css`](https://github.com/ConardLi/garden-skills/blob/main/tokens.css) for design tokens
- **[`scaffold.sh`](https://github.com/ConardLi/garden-skills/blob/main/scaffold.sh)** automatically discovers themes and generates a runtime catalog during the build process
- The **`Theme`** interface in [`types.ts`](https://github.com/ConardLi/garden-skills/blob/main/types.ts) provides type safety for JSON metadata, including internationalization support
- **CSS custom properties** enable instant visual updates without component recompilation
- **`mood` tags** in theme metadata drive animation timing through semantic variable mapping
- New themes require only directory creation and file placement, with zero code changes needed

## Frequently Asked Questions

### What files are required to create a new theme in web-video-presentation?

You must provide exactly two files in a new directory under `skills/web-video-presentation/themes/<theme-id>/`: a [`theme.json`](https://github.com/ConardLi/garden-skills/blob/main/theme.json) containing metadata (id, name, mood, preview colors) and a [`tokens.css`](https://github.com/ConardLi/garden-skills/blob/main/tokens.css) declaring CSS custom properties. The [`scaffold.sh`](https://github.com/ConardLi/garden-skills/blob/main/scaffold.sh) script automatically detects these files during the build process.

### How does the theme system handle animation timing and motion?

The system reads the `mood` array from [`theme.json`](https://github.com/ConardLi/garden-skills/blob/main/theme.json) (e.g., `"cinematic"`, `"light"`) and maps these tags to CSS timing variables like `--dur-base` and `--dur-cinematic` defined in [`tokens.css`](https://github.com/ConardLi/garden-skills/blob/main/tokens.css). Components reference these variables to adjust animation durations and easing curves dynamically.

### Where is the theme catalog generated during the build process?

The [`scaffold.sh`](https://github.com/ConardLi/garden-skills/blob/main/scaffold.sh) script located at [`skills/web-video-presentation/scripts/scaffold.sh`](https://github.com/ConardLi/garden-skills/blob/main/skills/web-video-presentation/scripts/scaffold.sh) iterates through the `themes/` directory, validates each theme's files, and compiles a [`themes.json`](https://github.com/ConardLi/garden-skills/blob/main/themes.json) catalog. This catalog is consumed by the UI to populate the theme picker without hardcoding theme lists.

### Can themes support internationalization?

Yes. The `Theme` interface in [`types.ts`](https://github.com/ConardLi/garden-skills/blob/main/types.ts) explicitly includes `nameZh` and `descriptionZh` fields. When creating a theme, you can provide bilingual content in [`theme.json`](https://github.com/ConardLi/garden-skills/blob/main/theme.json), and the presentation UI can render the appropriate language based on user preferences.