README.md raw

Responsive Image Variants

A library for generating and selecting responsive image variants per the NIP-XX Responsive Image Variants specification.

Variant Sizes

NameWidthQualityUse Case
thumb128px70%Previews, galleries
mobile-sm512px75%Small mobile portrait
mobile-lg1024px80%Large mobile, small tablets
desktop-sm1536px85%Laptops
desktop-md2048px88%Standard desktops
desktop-lg2560px90%Large/HiDPI displays
originalnative92%Full resolution (EXIF stripped)

Selection Rule

Next-Larger Selection: Pick the smallest variant >= target width.

This ensures clients only need to downscale slightly (or not at all), rather than upscaling which would cause blur.

targetWidth = containerWidth * devicePixelRatio
selectedVariant = smallest variant where variant.width >= targetWidth

Packages

TypeScript (ts/)

For browser clients (Svelte, React, etc.):

import {
  generateImageVariants,
  createResponsiveImageEvent,
  selectVariantForViewport
} from 'responsive-variants'

// Generate variants from a file
const variants = await generateImageVariants(file)

// Upload variants to Blossom...

// Create binding event (kind 1063)
const event = createResponsiveImageEvent(uploadedVariants)

// Select variant for display
const best = selectVariantForViewport(variants, containerWidth, devicePixelRatio)

Go (go/)

For relay servers:

import "git.mleku.dev/mleku/responsive-variants/go/variants"

// Generate variants
generated, err := variants.GenerateResponsiveVariants(reader)

// Select variant for viewport
best := variants.SelectVariantForViewport(variants, 1920, 1.0)

// Check if string is a blob hash
if variants.IsValidBlobHash(str) {
    // Query for binding event...
}

Binding Event Structure (Kind 1063)

{
  "kind": 1063,
  "content": "Optional caption",
  "tags": [
    ["imeta", "url https://...", "x <sha256>", "m image/jpeg", "dim 128x96", "variant thumb"],
    ["imeta", "url https://...", "x <sha256>", "m image/jpeg", "dim 512x384", "variant mobile-sm"],
    ...
    ["x", "<hash1>"],
    ["x", "<hash2>"],
    ...
  ]
}

Separate x tags enable NIP-01 tag queries to discover the binding event from any variant hash.

License

MIT