smithery.ai

generate-astro-gallery

Generate Astro page files from an existing gallery manifest. Internal step of /gallery workflow - use directly only to regenerate from completed manifests.

First seen Apr 22, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Declared agents claude-code

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 7,182 B
  • docs SUMMARY.md 185 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Generate Astro Gallery

Generates Astro gallery files from a completed manifest. This is typically the final step of /gallery workflow.

Prerequisites

  • Manifest file at src/data/gallery-manifests/{folder}.json with all blocks populated
  • Images already in src/assets/images/photos/{folder}/

Usage

/generate-astro-gallery {manifest.json}

Example: /generate-astro-gallery src/data/gallery-manifests/cabo-2025.json

Workflow

1. Read Manifest & Validate

  1. Read the manifest file
  2. Read ~/.claude/skills/review-image-batch/references/layout-guide.md to understand component constraints
  3. Run validation/normalization to fix common agent errors
{
  "gallery": "cabo-2025",
  "title": "CABO 2025",
  "slug": "cabo",
  "year": "2025",
  "images": [...],
  "blocks": [...]
}

Manifest Validation (REQUIRED)

Before generating, run the validation script to fix common agent errors:

bun scripts/validate-gallery-manifest.ts src/data/gallery-manifests/{folder}.json

This script automatically fixes:

  • type → layout
  • Image indices → filenames
  • note → notes

And validates layout values are valid component names.

2. Generate Data File

Create src/data/{folder}.ts:

import type { Chapter } from "../consts";

export const title = "{TITLE}";
export const chapters: Chapter[] = [];

For multi-chapter galleries:

export const chapters: Chapter[] = [
  { name: "CH I", href: "/" },
  { name: "CH II", href: "part2" },
];

3. Generate Page File

Create src/pages/photographing/{slug}/index.astro:

---
import BaseLayout from "../../../layouts/BaseLayout.astro";
import {
  FullBleedImage,
  WideImage,
  TwoUpLayout,
  ThreeUpLayout,
  FourUpGrid,
  SplitLayout,
  OffsetImage,
  InsetImage,
  Spacer
} from "../../../components/photos";
import { title, chapters } from "../../../data/{folder}";
import { getPageTitle } from "../../../lib/navigation";

const pageTitle = getPageTitle(title, Astro.url.pathname, chapters);

// Image imports - one per image in manifest
import img001 from "../../../assets/images/photos/{folder}/DSCF1234.jpeg";
import img002 from "../../../assets/images/photos/{folder}/DSCF1235.jpeg";
// ...
---

<BaseLayout title={pageTitle} navTitle={title} chapters={chapters}>
  <!-- Layout blocks from manifest -->
</BaseLayout>

4. Update Gallery Index

Add entry to src/pages/photographing/~/index.astro:

<a href="/photographing/{slug}/">{TITLE}</a>

Layout Component Mapping

Manifest Layout Astro Component Image Count Props
FullBleed <FullBleedImage> 1 priority
WideImage <WideImage> 1 priority
TwoUp <TwoUpLayout> 2 —
ThreeUp <ThreeUpLayout> 3 —
FourUp <FourUpGrid> 4 —
SplitLayout <SplitLayout> 2 ratio
OffsetImage <OffsetImage> 1 align, size, priority
InsetImage <InsetImage> 1 priority
Spacer <Spacer> 0 size (small/medium/large/xl)
Chapter (structural) 0 name, slug - splits into pages

Component Props Reference

<!-- Single image layouts -->
<FullBleedImage src={img} alt="description" priority={true} />
<WideImage src={img} alt="description" />

<!-- Whitespace components -->
<OffsetImage src={img} alt="description" align="left" size="medium" />
<OffsetImage src={img} alt="description" align="right" size="small" priority={true} />
<InsetImage src={img} alt="description" />
<InsetImage src={img} alt="description" priority={true} />
<Spacer size="medium" />

<!-- Multi-image layouts -->
<TwoUpLayout images={[
  { src: img1, alt: "description 1" },
  { src: img2, alt: "description 2" },
]} />

<ThreeUpLayout images={[
  { src: img1, alt: "description 1" },
  { src: img2, alt: "description 2" },
  { src: img3, alt: "description 3" },
]} />

<FourUpGrid images={[
  { src: img1, alt: "description 1" },
  { src: img2, alt: "description 2" },
  { src: img3, alt: "description 3" },
  { src: img4, alt: "description 4" },
]} />

<SplitLayout
  images={[
    { src: img1, alt: "description 1" },
    { src: img2, alt: "description 2" },
  ]}
  ratio="2/3"
/>

Handling Block Props

When a block has props in the manifest, pass them to the component:

Manifest:

{
  "layout": "OffsetImage",
  "images": ["portrait.jpeg"],
  "props": { "align": "left", "size": "small" }
}

Generated:

<OffsetImage src={portrait} alt="..." align="left" size="small" />

Import Naming Convention

Generate semantic import names from block notes:

  • Block notes: "sunset hero shot over the bay"
  • Import name: sunsetHero or baySunset

Or use sequential naming: img001, img002, etc.

First Image Priority

Add priority={true} to the first <FullBleedImage> or <WideImage> to preload above-the-fold content.

Composability

This skill is used by:

  • /gallery - Final step after batch review is complete
  • Can be used standalone to regenerate pages from existing manifests

Multi-Chapter Galleries

When manifest contains Chapter blocks, generate multiple pages instead of one.

Detection

const chapters = manifest.blocks.filter(b => b.layout === "Chapter");
const hasChapters = chapters.length > 0;

Processing

  1. Parse chapters from blocks:
const chapterData = chapters.map(c => ({
  name: c.props.name,
  slug: c.props.slug,
  href: c.props.slug === "/" ? "/" : c.props.slug
}));
  1. Split blocks by chapter:
// Group blocks between Chapter markers
const chapterBlocks = [];
let current = [];
for (const block of manifest.blocks) {
  if (block.layout === "Chapter") {
    if (current.length) chapterBlocks.push(current);
    current = [];
  } else {
    current.push(block);
  }
}
if (current.length) chapterBlocks.push(current);
  1. Generate data file with chapters:
export const chapters: Chapter[] = [
  { name: "Celestún", href: "/" },
  { name: "Uxmal", href: "uxmal" },
  { name: "Haciendas", href: "haciendas" },
];
  1. Generate one .astro file per chapter:
Chapter Slug Generated File
/ index.astro
uxmal uxmal.astro
haciendas haciendas.astro

Each page imports only the images used in that chapter.

Chapter Page Template

Same as single-page, but only includes blocks for that chapter:

---
// ... imports ...
import { title, chapters } from "../../../data/{folder}";

// Only images for THIS chapter
import img001 from "...";
import img002 from "...";
---

<BaseLayout title={pageTitle} navTitle={title} chapters={chapters}>
  <!-- Only blocks for this chapter -->
</BaseLayout>

First Image Per Chapter

Add priority={true} to the first FullBleed/WideImage in each chapter page.