Complete guide to Speedwell's intelligent image processing system.
Speedwell includes an automated image processing system that handles optimization, responsive variants, and metadata extraction.
public/originals/ (any folder structure)npm run images_data/_meta.json.images FileThe .images file in your project root controls image processing. This file is required for npm run images to work.
Current configuration:
{"sizes": {"small": 300,"medium": 700,"large": 1400,"full": 2200},"quality": 90}
Sizes are based on the longest side of the image:
"small": 300 - Maximum 300px on longest side"medium": 700 - Maximum 700px on longest side"large": 1400 - Maximum 1400px on longest side"full": 2200 - Maximum 2200px on longest sideExamples:
Aspect ratios are always preserved.
quality - JPEG/WebP quality (1-100){"sizes": {"thumbnail": 150,"small": 300,"medium": 700,"large": 1400,"xlarge": 1920,"full": 2200},"quality": 85}
Add or remove size breakpoints as needed for your design.
public/originals/)public/originals/
├── hero-image.jpg
├── portfolio/
│ ├── project-1.jpg
│ └── project-2.jpg
└── team/
├── john-doe.jpg
└── jane-smith.jpg
Best practices:
public/images/)After running npm run images, the structure is mirrored:
public/images/
├── hero-image-small.jpg
├── hero-image-small.webp
├── hero-image-medium.jpg
├── hero-image-medium.webp
├── hero-image-large.jpg
├── hero-image-large.webp
├── hero-image-full.jpg
├── hero-image-full.webp
└── portfolio/
├── project-1-small.jpg
├── project-1-small.webp
├── project-1-medium.jpg
└── ...
The system automatically makes filenames URL-friendly:
Before:
My Project Photo (2024).JPG
Team Photo - John & Jane.jpg
Logo Final Version.png
After:
my-project-photo-2024.jpg
team-photo-john-jane.jpg
logo-final-version.png
Rules:
_data/_meta.json)Generated metadata for each image:
{"portfolio/project-1.jpg": {"width": 2400,"height": 1600,"orientation": "landscape","aspectRatio": 1.5,"sizes": {"small": { "width": 300, "height": 200 },"medium": { "width": 700, "height": 467 },"large": { "width": 1400, "height": 933 },"full": { "width": 2200, "height": 1467 }},"exif": {"gps": { "latitude": 32.7767, "longitude": -96.797 },"orientation": 1,"dateTime": "2024:12:03 10:30:00"}}}
import { getImage } from '@/utils/image'const image = getImage('portfolio/project-1.jpg')<imgsrc={image.src}srcSet={image.srcset}alt="Project 1"width={image.width}height={image.height}/>
<imgsrc="/images/project-small.jpg"srcSet="/images/project-small.webp 300w,/images/project-medium.webp 700w,/images/project-large.webp 1400w,/images/project-full.webp 2200w"sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"alt="Project"loading="lazy"/>
const image = getImage('portfolio/project-1.jpg')<div className={image.orientation === 'portrait' ? 'col-span-1' : 'col-span-2'}><img src={image.src} alt="Project" /></div>
Modern browsers get WebP versions automatically:
The system generates both formats. Use <picture> element for explicit control:
<picture><sourcesrcSet="/images/hero-large.webp"type="image/webp"/><imgsrc="/images/hero-large.jpg"alt="Hero"/></picture>
npm run images before deployingloading="lazy" attributeCheck:
.images file exists in project rootpublic/originals/npm install to ensure Sharp is installedquality value in .imagesAdd specific sizes for different use cases:
{"sizes": {"thumbnail": 150,"card": 400,"hero": 1920,"fullscreen": 2560},"quality": 90}
Process specific folders:
public/originals/folder-name/npm run images