# Image Optimization

Image optimization with Unsplash, VSCO, and Next.js.



Image optimization with Unsplash, VSCO, and Next.js.

## System Overview [#system-overview]

* Unsplash images downloaded locally via API
* VSCO images served from local data export
* Unsplash URLs resolved to local paths at MDX parse time
* Next.js Image automatic optimization via `sharp`
* Local images compressed to max 2400px / JPEG quality 80 via build script

## Unsplash Integration [#unsplash-integration]

Images are resolved server-side in `src/lib/image/unsplash.ts`:

```typescript
import { resolveImageUrl, getAttribution } from "@/lib/image/unsplash";

const localPath = resolveImageUrl(unsplashPageUrl);
const attribution = getAttribution(unsplashPageUrl);
```

Key functions:

* `extractPhotoId()` - Extract 11-char ID from various URL formats
* `resolveImageUrl()` - Resolve to local `/images/unsplash/{id}.jpg` path
* `getAttribution()` - Get author name and UTM-tagged URL

## VSCO Integration [#vsco-integration]

VSCO images are served directly from VSCO's CDN — no local image files needed.
Metadata is in `data/vsco-export.json` (from VSCO's data export). Images use `unoptimized` to bypass Next.js image proxy, since VSCO's CDN blocks server-side requests.

## Build Process [#build-process]

```bash
# Download Unsplash images locally
bun run download:images:unsplash

# Compress oversized images in public/ (requires sharp)
node scripts/build/compress-images.mjs
```

### compress-images.mjs [#compress-imagesmjs]

Resizes all images in `public/images/` larger than 500 KB to max 2400px on the longest edge, re-encodes JPEGs with mozjpeg quality 80 and PNGs with compression level 9. Overwrites originals in-place; only writes if the result is smaller.

## Best Practices [#best-practices]

Always use the `UniversalImage` component or Next.js `Image`:

```typescript
<UniversalImage src={src} alt={alt} width={1200} height={800} priority={isHero} />
```
