Built with Eleventy site generator (using the v3.0 release).
- Contributing Guide - How to submit changes, code style guidelines, and deployment information
- AI Agent Notes - Context and patterns for AI assistants working on this codebase
This website is built with modern, performance-focused web technologies:
- Eleventy v3.x - A static site generator that pre-renders all content
- Node.js 24+ - JavaScript runtime (see
.nvmrcfor exact version) - Nunjucks - Templating engine for HTML generation
- Bootstrap v5.3.6 - CSS framework for responsive design and component styling
- Zero-JavaScript Output - All content is pre-rendered for maximum performance
- Markdown - Content authoring format for blog posts and pages
- Image Optimization - Automatic image processing with @11ty/eleventy-img
- WebP and AVIF format generation
- Responsive image sizing (400px, 800px, 1280px)
- Lazy loading by default
- CSS Bundling - Per-page CSS bundles via eleventy-plugin-bundle
- Syntax Highlighting - Built-in code highlighting with @11ty/eleventy-plugin-syntaxhighlight
- Navigation - Automated navigation menu with @11ty/eleventy-navigation
- RSS/Atom Feed - Automated feed generation with @11ty/eleventy-plugin-rss
- Font Awesome - Icon library integration via @11ty/font-awesome
- Netlify - Primary hosting platform (see
netlify.toml) - Vercel - Alternative deployment option (see
vercel.json) - Build command:
npm run build - Output directory:
_site
strongtownscarmel/
├── content/ # All website content
│ ├── blog/ # Blog posts (Markdown files or folders)
│ ├── index.njk # Homepage
│ ├── about.md # About page
│ ├── events.md # Events page
│ └── join.md # Join page
├── _includes/ # Template components
│ ├── layouts/ # Page layouts
│ │ ├── base.njk # Base HTML structure
│ │ ├── home.njk # Homepage template
│ │ ├── page.njk # Standard page template
│ │ └── post.njk # Blog post template
│ ├── postslist.njk # Post list component
│ └── postslist-featured.njk # Featured posts component
├── _data/ # Global data files
│ ├── metadata.js # Site metadata (title, URL, author)
│ └── eleventyDataSchema.js # Data validation schema
├── _config/ # Configuration modules
│ └── filters.js # Custom Eleventy filters
├── public/ # Static assets (copied to output)
│ ├── css/ # Stylesheets
│ └── img/ # Static images
├── eleventy.config.js # Main Eleventy configuration
├── package.json # Node.js dependencies and scripts
└── README.md # This file
- Node.js 24 or higher (use the version in
.nvmrc) - npm (comes with Node.js)
- Clone the repository:
git clone https://github.com/simpixelated/strongtownscarmel.git
cd strongtownscarmel- Install dependencies:
npm install- Start the development server:
npm startThe site will be available at http://localhost:8080 with live reload enabled.
npm start- Start development server with live reloadnpm run build- Build production site to_sitefoldernpm run debug- Run build with debug outputnpm run debugstart- Start dev server with debug outputnpm run benchmark- Run build with performance benchmarksnpm run new-post- Generate a new blog post (see below)
Blog posts live in the content/blog/ directory. You can create posts in three ways:
Use the built-in blog post generator to quickly create a new post with proper structure:
npm run new-post -- --title="Your Post Title" --tags="tag1,tag2"This will:
- Generate a slug-based folder:
content/blog/slug/ - Create an
index.mdfile with proper frontmatter - Auto-increment the folder name if it already exists
CLI Options:
--title(required) - Post title (used for frontmatter and slug generation)--tags(required) - Comma-separated list of tags--date(optional) - Publication date in YYYY-MM-DD format (defaults to today)
Example:
npm run new-post -- --title="The Autumn Greenway" --tags="transportation,bike lanes"This creates:
content/blog/the-autumn-greenway/
└── index.md
With frontmatter including the date:
---
date: 2026-02-15
title: "The Autumn Greenway"
tags:
- transportation
- bike lanes
---You can then add images and other assets to this folder.
Create a new .md file directly in content/blog/:
---
date: 2024-03-15
title: Your Post Title
tags:
- tag1
- tag2
---
Your post content here in Markdown format.Create a folder in content/blog/your-post-name/ with an index.md file:
content/blog/your-post-name/
├── index.md
├── image1.jpg
└── image2.png
This approach allows you to co-locate images with your post.
Front Matter Fields:
date(required) - Publication date in YYYY-MM-DD formattitle(required) - Post titletags(optional) - Array of tags for categorizationdraft(optional) - Set totrueto mark as draft (only visible in development)canonical(optional) - Canonical URL if content is published elsewherefeaturedimage(optional) - Path to featured imageintro(optional) - Short description/excerpt
- Create a new
.mdor.njkfile in thecontent/directory:
---
layout: layouts/page.njk
title: Your Page Title
eleventyNavigation:
key: Page Name
order: 3
---
Your page content here.- The
eleventyNavigationblock adds the page to the main navigation menukey- Display name in navigationorder- Position in navigation (lower numbers appear first)
Create a subdirectory in content/ with an index.md:
content/
└── your-section/
├── index.md
└── subpage.md
The URL structure will match the folder structure: /your-section/ and /your-section/subpage/
Templates are located in _includes/layouts/:
-
base.njk- Base HTML structure (head, meta tags, scripts)- Edit this to modify site-wide HTML structure
- Contains SEO meta tags, Open Graph tags, and social media cards
-
home.njk- Homepage layout- Extends
base.njk - Customizes the homepage structure
- Extends
-
page.njk- Standard page template- Used for About, Events, Join pages
- Simple content wrapper
-
post.njk- Blog post template- Includes post metadata, tags, and next/previous links
- Extends
base.njk
Template Syntax: Templates use Nunjucks templating language.
Images are automatically optimized during the build process:
- Add images to your content:
-
The build process automatically:
- Converts images to WebP format
- Generates multiple sizes (400px, 800px, 1280px)
- Adds lazy loading attributes
- Includes width/height to prevent layout shift
-
For background images, use the
backgroundCSSImageshortcode in templates
Global CSS is located in public/css/. The CSS is copied directly to the output folder.
For page-specific styles, use the CSS bundle feature in your template:
{% css %}
/* Your page-specific CSS here */
{% endcss %}Key configuration files:
_data/metadata.js- Site title, URL, description, author infoeleventy.config.js- Eleventy settings, plugins, and build configuration_config/filters.js- Custom template filters (date formatting, etc.)
Mark any post as a draft by adding to front matter:
---
draft: true
title: Work in Progress
---Drafts are visible during development (npm start) but excluded from production builds (npm run build).
Collections group related content. The posts collection is automatically created from any content with the posts tag.
To create a custom collection, edit eleventy.config.js:
eleventyConfig.addCollection("myCollection", function(collectionApi) {
return collectionApi.getFilteredByTag("myTag");
});- Start the development server:
npm start- Edit files in
content/,_includes/, orpublic/ - The browser automatically refreshes when files change
- View your changes at
http://localhost:8080
- Build the production site:
npm run build- Check the
_sitefolder for the generated output - Test the built site with a local server if needed
Use debug mode to see detailed build information:
npm run debug # Build with debug output
npm run debugstart # Dev server with debug outputSee CONTRIBUTING.md for guidelines on submitting changes, code style, and deployment information.
Issue: npm install fails
- Solution: Ensure you're using Node.js 24 or higher. Check with
node --version
Issue: Images not optimizing
- Solution: Clear the
_sitefolder and rebuild:rm -rf _site && npm run build
Issue: Changes not appearing
- Solution: Hard refresh your browser (Cmd+Shift+R on Mac, Ctrl+Shift+R on Windows)
- Solution: Restart the dev server
Issue: Build fails with "Cannot find module"
- Solution: Delete
node_modulesand reinstall:rm -rf node_modules && npm install
- Using Eleventy v3 with zero-JavaScript output.
- Content is exclusively pre-rendered (this is a static site).
- Can easily deploy to a subfolder without changing any content
- All URLs are decoupled from the content's location on the file system.
- Configure templates via the Eleventy Data Cascade
- Performance focused: four-hundos Lighthouse score out of the box!
- 0 Cumulative Layout Shift
- 0ms Total Blocking Time
- Local development live reload provided by Eleventy Dev Server.
- Content-driven navigation menu
- Fully automated Image optimization
- Zero-JavaScript output.
- Support for modern image formats automatically (e.g. AVIF and WebP)
- Processes images on-request during
--servefor speedy local builds. - Prefers
<img>markup if possible (single image format) but switches automatically to<picture>for multiple image formats. - Automated
<picture>syntax markup withsrcsetand optionalsizes - Includes
width/heightattributes to avoid content layout shift. - Includes
loading="lazy"for native lazy loading without JavaScript. - Includes
decoding="async" - Images can be co-located with blog post files.
- Per page CSS bundles via
eleventy-plugin-bundle. - Built-in syntax highlighter (zero-JavaScript output).
- Draft content: use
draft: trueto mark any template as a draft. Drafts are only included during--serve/--watchand are excluded from full builds. This is driven by theaddPreprocessorconfiguration API ineleventy.config.js. Schema validator will show an error if non-boolean value is set in data cascade. - Blog Posts
- Automated next/previous links
- Accessible deep links to headings
- Generated Pages
- Home, Archive, and About pages.
- Atom feed included (with easy one-line swap to use RSS or JSON
sitemap.xml- Zero-maintenance tag pages (View on the Demo)
- Content not found (404) page
content/about/index.mdis an example of a content page.content/blog/has the blog posts but really they can live in any directory. They need only thepoststag to be included in the blog posts collection.- Use the
eleventyNavigationkey (via the Eleventy Navigation plugin) in your front matter to add a template to the top level site navigation. This is in use oncontent/index.njkandcontent/about/index.md. - Content can be in any template format (blog posts needn't exclusively be markdown, for example). Configure your project's supported templates in
eleventy.config.js->templateFormats. - The
publicfolder in your input directory will be copied to the output folder (viaaddPassthroughCopyin theeleventy.config.jsfile). This means./public/css/*will live at./_site/css/*after your build completes. - This project uses three Eleventy Layouts:
_includes/layouts/base.njk: the top level HTML structure_includes/layouts/home.njk: the home page template (wrapped intobase.njk)_includes/layouts/post.njk: the blog post template (wrapped intobase.njk)_includes/postslist.njkis a Nunjucks include and is a reusable component used to display a list of all the posts.content/index.njkhas an example of how to use it.
If your site enforces a Content Security Policy (as public-facing sites should), you have a few choices (pick one):
- In
base.njk, remove<style>{% getBundle "css" %}</style>and uncomment<link rel="stylesheet" href="{% getBundleFileUrl "css" %}"> - Configure the server with the CSP directive
style-src: 'unsafe-inline'(less secure).
For AI assistants working on this codebase, see AGENTS.md for key patterns, common operations, file locations, and important configurations.