Contributing Templates
This guide shows you how to add a new template to the Statue static site generator.
Before You Start
- Read CONTRIBUTING.md for general contribution guidelines
- Understand SvelteKit routing basics
- Review existing templates in
templates/directory - Know how Statue's content system works (see content/docs/routing.md)
Step-by-Step: Adding a New Template
1. Plan Your Template
Decide what makes your template unique:
- Purpose: What type of site is this for? (portfolio, documentation, landing page, etc.)
- Structure: What pages/routes will it include?
- Content: What example content will demonstrate the template?
- Audience: Who is this template for?
Examples:
- Blog template: Minimal, content-focused, for writers
- Portfolio template: Project showcase, for designers/developers
- Docs template: Documentation-focused, for technical writers
2. Create the Template Directory
Create the directory structure:
mkdir -p templates/your-template/src/routes
mkdir -p templates/your-template/content
Your template must have:
src/routes/- Route files that define page layoutscontent/- Example markdown contentsite.config.js- Default configuration for this template
Optional:
static/- Custom assets (favicon, images)
3. Create Route Files
Create the essential routes:
Required: Content Page Route
Create templates/your-template/src/routes/[...slug]/+page.svelte:
<script>
import { ContentHeader, ContentBody } from '$lib';
export let data;
$: content = data.content;
</script>
<svelte:head>
<title>{content.metadata.title}</title>
</svelte:head>
<ContentHeader
title={content.metadata.title}
description={content.metadata.description}
/>
<ContentBody content={content.content} />
Create templates/your-template/src/routes/[...slug]/+page.server.js:
import { getContentBySlug } from '$lib/cms/content-processor';
export const prerender = true;
export async function load({ params }) {
const slug = params.slug || 'index';
const content = await getContentBySlug(slug);
return { content };
}
Required: Directory Listing Route
Create templates/your-template/src/routes/[directory]/+page.svelte:
<script>
import { DirectoryHeader, DirectoryContent } from '$lib';
export let data;
</script>
<svelte:head>
<title>{data.currentDirectory.title}</title>
</svelte:head>
<DirectoryHeader
title={data.currentDirectory.title}
description={data.currentDirectory.description}
/>
<DirectoryContent content={data.directoryContent} />
Create templates/your-template/src/routes/[directory]/+page.server.js:
import { getDirectoryContent } from '$lib/cms/content-processor';
export const prerender = true;
export async function load({ params }) {
const directory = params.directory;
const content = await getDirectoryContent(directory);
return content;
}
Required: Homepage
Create templates/your-template/src/routes/+page.svelte:
<script>
// Your homepage design
import { Hero, Categories } from '$lib';
</script>
<svelte:head>
<title>Home</title>
</svelte:head>
<!-- Customize your homepage layout -->
<Hero
title="Your Template Title"
subtitle="Brief description of what this template is for"
/>
<!-- Add other components as needed -->
Optional: Layout File
Create templates/your-template/src/routes/+layout.svelte:
<script>
import { NavigationBar, Footer } from '$lib';
import '$lib/index.css';
</script>
<div class="min-h-screen bg-[var(--color-background)] text-[var(--color-foreground)]">
<NavigationBar />
<main class="max-w-6xl mx-auto px-4 py-8">
<slot />
</main>
<Footer
copyrightText="Your Template © 2024"
/>
</div>
Why: +layout.svelte wraps all pages with common elements like navigation and footer.
Important: Use $lib imports in your template files - they will be automatically transformed to statue-ssg imports when users initialize the template.
4. Add Example Content
Create example markdown files that showcase your template:
Create templates/your-template/content/blog/example-post.md:
---
title: Example Blog Post
description: This is an example post for your template
date: 2024-01-01
---
# Welcome to Your Template
This is example content that shows users how the template works.
Add more example content to demonstrate features.
Best practices:
- Create 2-3 example posts per content directory
- Use realistic content that demonstrates the template's strengths
- Include all frontmatter fields the template supports
- Show different content types (if applicable)
5. Create Template Configuration
Create templates/your-template/site.config.js:
export default {
site: {
name: 'My Template Site',
description: 'A brief description for this template',
url: 'https://example.com',
author: 'Template Author'
},
contact: {
email: '[email protected]',
address: {}
},
social: {
github: 'https://github.com/username',
twitter: 'https://twitter.com/username'
},
legal: {
doNotSell: {}
}
};
Why: This provides sensible defaults for users who initialize with your template. They'll customize it later.
6. Test Your Template Locally
Load your template into the workspace:
npm run template:load your-template --force
Start the dev server:
npm run dev
Test checklist:
- Homepage renders correctly
- Individual content pages work (
/blog/example-post) - Directory listing pages work (
/blog) - Navigation works correctly
- All components render properly
- Responsive on mobile, tablet, desktop
- Works with different themes
- No console errors or warnings
When done testing, restore the default template:
git checkout src/routes content site.config.js
7. Document Your Template
Update content/docs/templates.md:
Add a section describing your template:
### Your Template Name
Brief description of what this template is for and who should use it.
**Initialize:**
\`\`\`bash
npx statue init --template your-template
\`\`\`
**Includes:**
- List key features
- Notable pages or layouts
- Special functionality
**Best for:** Target audience and use cases
Update this guide's "Examples" section if your template demonstrates a new pattern.
8. Create a README (Optional)
Create templates/your-template/README.md:
# Your Template Name
Description of the template, its purpose, and key features.
## Features
- Feature 1
- Feature 2
- Feature 3
## Customization
Brief notes on how users might customize this template.
## Example Sites
List any example sites using this template (if available).
9. Submit Your PR
Before submitting:
- Template loads without errors
- All routes use
export const prerender = true - Example content is meaningful and realistic
- Documented in content/docs/templates.md
- Works with all built-in themes
- No hardcoded colors (uses theme variables)
- Responsive design
- No console errors/warnings
- Tested with
npm run build
PR Title:
feat: add [template-name] template
PR Description:
## New Template: Your Template Name
Brief description of what this template is for and who will use it.
### Key Features
- Feature 1
- Feature 2
- Feature 3
### Example Usage
\`\`\`bash
npx statue init --template your-template
\`\`\`
### Testing Done
- [x] Tested locally with dev server
- [x] Tested build process
- [x] Tested with multiple themes
- [x] Responsive design verified
- [x] Documentation updated
Template Guidelines
Required Patterns
1. Use Prerendering
Every +page.server.js must include:
export const prerender = true;
Why: Statue generates static sites. Without this, the template won't work.
2. Use Theme Variables
Never hardcode colors:
<!-- ✅ Good -->
<div class="bg-[var(--color-card)] text-[var(--color-foreground)]">
<!-- ❌ Bad -->
<div class="bg-gray-900 text-white">
Why: Templates must work with all themes.
3. Use $lib Imports
Import components from $lib, not statue-ssg:
<!-- ✅ Good (in template files) -->
import { Hero, Categories } from '$lib';
<!-- ❌ Bad -->
import { Hero, Categories } from 'statue-ssg';
Why: The init script automatically transforms $lib to statue-ssg when users initialize.
4. Responsive Design
All templates must be responsive:
<!-- ✅ Good -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<!-- ❌ Bad -->
<div style="width: 1200px;">
5. Meaningful Example Content
Provide realistic example content:
<!-- ✅ Good -->
# Getting Started with Web Development
Learn the fundamentals of building modern websites...
<!-- ❌ Bad -->
# Test Post
Lorem ipsum dolor sit amet...
Why: Example content helps users understand how to use the template.
Template Structure Best Practices
Keep it simple:
- Don't over-engineer
- Focus on the template's core purpose
- Fewer routes are better than too many
Make it flexible:
- Use Statue components where possible
- Allow easy customization
- Don't lock users into specific content structures
Show, don't tell:
- Demonstrate features with example content
- Include comments in route files
- Make patterns obvious
Common Pitfalls
❌ Don't: Complex Custom Components
Templates should use Statue's built-in components. If you need custom components, consider contributing them to the main component library instead.
✅ Do: Use Built-in Components
import { Hero, Categories, ContentBody } from '$lib';
❌ Don't: Template-Specific Configuration
Don't add new configuration fields that only your template uses.
✅ Do: Use Standard Config
Use fields from the standard site.config.js schema.
❌ Don't: Hardcoded Content
Don't hardcode site name, URLs, etc. in templates.
✅ Do: Use Template Variables
<h1>Statue SSG</h1>
<a href="https://mplode.dev">Visit Site</a>
Template Management Commands
For template development:
# List available templates
npm run template:list
# Load a template into workspace for testing
npm run template:load blog --force
# Save current workspace as a template
npm run template:save my-template
# Restore default template
git checkout src/routes content site.config.js
Why these exist: Templates are tested by loading them into the main project workspace.
Automated PR Script
Want to skip the manual PR process?
Use the automated PR script from the root of your Statue site:
# From your Statue site's root directory
# Just the template (routes, content, config, static)
./path/to/statue/scripts/autopr.sh template portfolio
# Template + ALL custom components and themes (complete bundle)
./path/to/statue/scripts/autopr.sh all portfolio
Template Mode
What it does:
- Looks for
src/routes/,content/,site.config.js,static/in current directory - Forks the statue repository (if needed)
- Creates a new branch
- Copies all template files to
templates/portfolio/ - Commits and pushes the changes
- Opens a pull request automatically
All Mode (Template + Custom Components + Themes)
What it does:
- Everything from template mode, PLUS:
- Bundles
src/lib/index.ts(component exports) →templates/portfolio/src/lib/index.ts - Bundles
src/lib/index.css(styles/theme imports) →templates/portfolio/src/lib/index.css - Bundles all custom components from
src/lib/components/→templates/portfolio/src/lib/components/ - Bundles all custom themes from
src/lib/themes/→templates/portfolio/src/lib/themes/ - Preserves directory structure (e.g.,
src/lib/components/forms/Input.sveltekeeps its path)
When to use all mode:
- You've built a complete Statue site with custom components and themes
- You want to contribute the entire package as a template
- Your custom components/themes are specific to this template
When to use template mode:
- Your site only uses built-in Statue components
- Your custom components should be contributed separately (not template-specific)
Requirements:
- GitHub CLI (
gh) installed and authenticated - Run from the root of your Statue site
- Must have
src/routes/directory (required) - Optionally includes
content/,site.config.js,static/ - For
allmode: Automatically includes anysrc/lib/components/andsrc/lib/themes/
Note: You'll still need to add documentation manually after the PR is created. The script just handles the git workflow.
Converting Existing Sites to Templates
Have a Statue site you want to contribute as a template?
The process is straightforward:
Identify the key files:
src/routes/- Your route filescontent/- Your example contentsite.config.js- Your config (sanitize personal info first!)
Copy to template directory:
mkdir -p templates/your-template/src cp -r src/routes templates/your-template/src/ cp -r content templates/your-template/ cp site.config.js templates/your-template/Clean up the content:
- Replace personal info with placeholders
- Use generic example content
- Ensure all imports use
$lib(notstatue-ssg)
Test it:
npm run template:load your-template --force npm run devSubmit a PR following the guidelines above
Questions?
- Check existing templates in
templates/for patterns - Read CONTRIBUTING.md for PR process
- Ask in Discord
- Ask in GitHub Discussions