{"_id":"@dong-gri/pixel-mosaic-lazy-loader","_rev":"3-467340d330ac9717e0f14ce513d4feeb","name":"@dong-gri/pixel-mosaic-lazy-loader","dist-tags":{"latest":"1.3.4"},"versions":{"1.3.2":{"name":"@dong-gri/pixel-mosaic-lazy-loader","version":"1.3.2","keywords":["lazy-loading","image-loader","pixel-mosaic","pixelated","canvas","gif","animated-webp","apng","progressive-enhancement","web-performance","web-accessibility"],"author":{"name":"Dongri"},"license":"MIT","_id":"@dong-gri/pixel-mosaic-lazy-loader@1.3.2","maintainers":[{"name":"dong-gri","email":"official@dongri.me"}],"homepage":"https://lab.dongri.me/p/pixel-mosaic-lazy-loader","bugs":{"url":"https://github.com/catgarret/Pixel-Mosaic-Lazy-Loader/issues"},"demo":"https://git.dongri.me/example/pixel-mosaic-live/","dist":{"shasum":"67d8ce536e868be6b8fe304cdc7b766c77810ab3","tarball":"https://registry.npmjs.org/@dong-gri/pixel-mosaic-lazy-loader/-/pixel-mosaic-lazy-loader-1.3.2.tgz","fileCount":14,"integrity":"sha512-oUpgkykS1ooxkgN9XiMvjCTICVVYVAhnonFBQUf0QEYs1WUsNQW/0sfzEq5p9YdhkJYNakvhxr3K5pW7kORSXQ==","signatures":[{"sig":"MEQCIC3EsnpIFAIVY4cEEgMs05PmRZurYBVSZBQQrvjdGBLPAiB/lbZDVmLGZ0RFzEST5Uzfc69KbAJEXKBn5zSjruFFFg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":177384},"main":"./dist/pixel-mosaic.js","style":"./dist/pixel-mosaic.css","unpkg":"./dist/pixel-mosaic.js","module":"./dist/pixel-mosaic.mjs","browser":"./dist/pixel-mosaic.js","exports":{".":{"import":"./dist/pixel-mosaic.mjs","browser":"./dist/pixel-mosaic.mjs","default":"./dist/pixel-mosaic.mjs"},"./dist/*":"./dist/*","./style.css":"./dist/pixel-mosaic.css","./package.json":"./package.json"},"scripts":{"build":"node scripts/build.mjs","check":"node --check pixel-mosaic.js && node --check dist/pixel-mosaic.js && node --check dist/pixel-mosaic.mjs","pack:check":"npm pack --dry-run","prepublishOnly":"npm run build && npm run check && npm run pack:check"},"_npmUser":{"name":"dong-gri","email":"official@dongri.me"},"jsdelivr":"./dist/pixel-mosaic.js","repository":{"url":"git+https://github.com/catgarret/Pixel-Mosaic-Lazy-Loader.git","type":"git"},"_npmVersion":"11.12.1","description":"A lightweight pixel mosaic lazy loader for static and animated web images.","directories":{},"sideEffects":["./dist/pixel-mosaic.js","./dist/pixel-mosaic.css"],"_nodeVersion":"25.9.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/pixel-mosaic-lazy-loader_1.3.2_1784376796047_0.41393311643284547","host":"s3://npm-registry-packages-npm-production"}},"1.3.3":{"name":"@dong-gri/pixel-mosaic-lazy-loader","version":"1.3.3","keywords":["lazy-loading","image-loader","pixel-mosaic","pixelated","canvas","gif","animated-webp","apng","progressive-enhancement","web-performance","web-accessibility"],"author":{"name":"Dongri"},"license":"MIT","_id":"@dong-gri/pixel-mosaic-lazy-loader@1.3.3","maintainers":[{"name":"dong-gri","email":"official@dongri.me"}],"homepage":"https://lab.dongri.me/p/pixel-mosaic-lazy-loader","bugs":{"url":"https://github.com/catgarret/Pixel-Mosaic-Lazy-Loader/issues"},"demo":"https://git.dongri.me/example/pixel-mosaic-live/","dist":{"shasum":"73c2ee9f71bfce2416f5f7f5831aeb608c15d771","tarball":"https://registry.npmjs.org/@dong-gri/pixel-mosaic-lazy-loader/-/pixel-mosaic-lazy-loader-1.3.3.tgz","fileCount":14,"integrity":"sha512-AKP99zHtULeQaSqguewSPwLEloAqL1OmoTpQgLQ8XUF4lqXFss7Hpt3W4RGvLoWgqLs8QXcsttJySxDcCZB1lg==","signatures":[{"sig":"MEQCICYgNBtDRUUoLGCSnFM4YkJYh0VosZvUQUi3LsWIBnqGAiBsy4M52ri4mUF6GEJ74XJrB62VDiARHm2MBRTFHwmTPQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":177433},"main":"./dist/pixel-mosaic.js","style":"./dist/pixel-mosaic.css","unpkg":"./dist/pixel-mosaic.js","module":"./dist/pixel-mosaic.mjs","browser":"./dist/pixel-mosaic.js","exports":{".":{"import":"./dist/pixel-mosaic.mjs","browser":"./dist/pixel-mosaic.mjs","default":"./dist/pixel-mosaic.mjs"},"./dist/*":"./dist/*","./style.css":"./dist/pixel-mosaic.css","./package.json":"./package.json"},"scripts":{"build":"node scripts/build.mjs","check":"node --check pixel-mosaic.js && node --check dist/pixel-mosaic.js && node --check dist/pixel-mosaic.mjs","pack:check":"npm pack --dry-run","prepublishOnly":"npm run build && npm run check && npm run pack:check"},"_npmUser":{"name":"dong-gri","email":"official@dongri.me"},"jsdelivr":"./dist/pixel-mosaic.js","repository":{"url":"git+https://github.com/catgarret/Pixel-Mosaic-Lazy-Loader.git","type":"git"},"_npmVersion":"11.12.1","description":"A lightweight pixel mosaic lazy loader for static and animated web images.","directories":{},"sideEffects":["./dist/pixel-mosaic.js","./dist/pixel-mosaic.css"],"_nodeVersion":"25.9.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/pixel-mosaic-lazy-loader_1.3.3_1784377639029_0.7001688742704952","host":"s3://npm-registry-packages-npm-production"}},"1.3.4":{"name":"@dong-gri/pixel-mosaic-lazy-loader","version":"1.3.4","description":"A lightweight pixel mosaic lazy loader for static and animated web images.","keywords":["lazy-loading","image-loader","pixel-mosaic","pixelated","canvas","gif","animated-webp","apng","progressive-enhancement","web-performance","web-accessibility"],"license":"MIT","author":{"name":"Dongri"},"homepage":"https://lab.dongri.me/p/pixel-mosaic-lazy-loader","repository":{"type":"git","url":"git+https://github.com/catgarret/Pixel-Mosaic-Lazy-Loader.git"},"bugs":{"url":"https://github.com/catgarret/Pixel-Mosaic-Lazy-Loader/issues"},"main":"./dist/pixel-mosaic.js","module":"./dist/pixel-mosaic.mjs","browser":"./dist/pixel-mosaic.js","style":"./dist/pixel-mosaic.css","jsdelivr":"./dist/pixel-mosaic.min.js","unpkg":"./dist/pixel-mosaic.min.js","exports":{".":{"browser":"./dist/pixel-mosaic.mjs","import":"./dist/pixel-mosaic.mjs","default":"./dist/pixel-mosaic.mjs"},"./min":{"browser":"./dist/pixel-mosaic.min.mjs","import":"./dist/pixel-mosaic.min.mjs","default":"./dist/pixel-mosaic.min.mjs"},"./style.css":"./dist/pixel-mosaic.css","./style.min.css":"./dist/pixel-mosaic.min.css","./dist/*":"./dist/*","./package.json":"./package.json"},"sideEffects":["./dist/pixel-mosaic.js","./dist/pixel-mosaic.min.js","./dist/pixel-mosaic.css","./dist/pixel-mosaic.min.css"],"scripts":{"build":"node scripts/build.mjs","check":"node --check pixel-mosaic.js && node --check dist/pixel-mosaic.js && node --check dist/pixel-mosaic.min.js && node --check dist/pixel-mosaic.mjs && node --check dist/pixel-mosaic.min.mjs","pack:check":"npm pack --dry-run","prepublishOnly":"npm run build && npm run check && npm run pack:check"},"publishConfig":{"access":"public"},"demo":"https://git.dongri.me/example/pixel-mosaic-live/","devDependencies":{"clean-css":"^5.3.3","terser":"^5.49.0"},"gitHead":"802135130002227728a31cc8d5d6e862d023d6f9","_id":"@dong-gri/pixel-mosaic-lazy-loader@1.3.4","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-ZJpTGhxTq0+sK9GI/Jbfl4AINRh/kXtRARIzpNetgc+vJ4PZFE9L/5avHMMw/H5pskJh22oi5SWMRIIPkObFDw==","shasum":"22267196972be03d49d01a48e30bede938be8098","tarball":"https://registry.npmjs.org/@dong-gri/pixel-mosaic-lazy-loader/-/pixel-mosaic-lazy-loader-1.3.4.tgz","fileCount":18,"unpackedSize":2067215,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dong-gri%2fpixel-mosaic-lazy-loader@1.3.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCWgFPnh4reA9CglonmiQItqXcheFbWvFZXs/WFYi/EEAIhAJePnPctgr+La2sirhf0AtofTe3pu92o02O93M8b3eUg"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1434a809-bb2d-4bc0-bde1-48f55bc10ba7"}},"directories":{},"maintainers":[{"name":"dong-gri","email":"official@dongri.me"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pixel-mosaic-lazy-loader_1.3.4_1785597562378_0.9816454693467578"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-18T12:13:15.900Z","modified":"2026-08-01T15:19:22.991Z","1.3.2":"2026-07-18T12:13:16.222Z","1.3.3":"2026-07-18T12:27:19.164Z","1.3.4":"2026-08-01T15:19:22.665Z"},"bugs":{"url":"https://github.com/catgarret/Pixel-Mosaic-Lazy-Loader/issues"},"author":{"name":"Dongri"},"license":"MIT","homepage":"https://lab.dongri.me/p/pixel-mosaic-lazy-loader","keywords":["lazy-loading","image-loader","pixel-mosaic","pixelated","canvas","gif","animated-webp","apng","progressive-enhancement","web-performance","web-accessibility"],"repository":{"type":"git","url":"git+https://github.com/catgarret/Pixel-Mosaic-Lazy-Loader.git"},"description":"A lightweight pixel mosaic lazy loader for static and animated web images.","maintainers":[{"name":"dong-gri","email":"official@dongri.me"}],"readme":"# Pixel Mosaic Lazy Loader\n\n[![npm version](https://img.shields.io/npm/v/@dong-gri/pixel-mosaic-lazy-loader.svg)](https://www.npmjs.com/package/@dong-gri/pixel-mosaic-lazy-loader)\n[![npm downloads](https://img.shields.io/npm/dm/@dong-gri/pixel-mosaic-lazy-loader.svg)](https://www.npmjs.com/package/@dong-gri/pixel-mosaic-lazy-loader)\n[![license](https://img.shields.io/npm/l/@dong-gri/pixel-mosaic-lazy-loader.svg)](./LICENSE)\n![dependencies](https://img.shields.io/badge/dependencies-0-2ea44f)\n\n**English (default)** · [한국어](./docs/readme/README.ko.md) · [日本語](./docs/readme/README.ja.md) · [繁體中文（台灣）](./docs/readme/README.zh-TW.md) · [ไทย](./docs/readme/README.th.md) · [简体中文](./docs/readme/README.zh-CN.md) · [繁體中文](./docs/readme/README.zh-Hant.md) · [Русский](./docs/readme/README.ru.md) · [Italiano](./docs/readme/README.it.md)\n\nTurn any `<img>` into a **large-pixel → smaller-pixel → original image** reveal—without creating separate placeholder files or freezing GIF, Animated WebP, or APNG playback.\n\n![Pixel Mosaic Lazy Loader preview](./docs/readme/example.gif)\n\n[**Live Demo**](https://git.dongri.me/example/pixel-mosaic-live/) · [**npm**](https://www.npmjs.com/package/@dong-gri/pixel-mosaic-lazy-loader) · [**Blog Post**](https://lab.dongri.me/p/pixel-mosaic-lazy-loader)\n\nCurrent release: **v1.3.4**\n\n## Why Pixel Mosaic Lazy Loader?\n\n- **Zero dependencies** and no separate low-resolution placeholder assets\n- Works with static images, GIF, Animated WebP, and APNG\n- Preserves animated-image playback through direct decoding or animation-safe fallback\n- Automatically detects existing and dynamically inserted images\n- Supports global options and per-image `data-*` overrides\n- Keeps the original `<img>`, `alt` text, transparency, `border-radius`, `object-fit`, and `object-position`\n- Includes reduced-motion handling and progressive fallback for older browsers\n\n## Quick start\n\n### CDN — latest npm release\n\nThe URLs below intentionally omit a version, so they always follow the package's current npm `latest` release.\n\n> [!WARNING]\n> Publishing a new npm release updates these unversioned CDN URLs automatically. Avoid breaking changes unless you publish a new major version.\n\n```html\n<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/@dong-gri/pixel-mosaic-lazy-loader/dist/pixel-mosaic.min.css\">\n\n<img\n  data-pixel-mosaic\n  src=\"/images/example.gif\"\n  width=\"1280\"\n  height=\"720\"\n  alt=\"Animated product preview\"\n>\n\n<script src=\"https://cdn.jsdelivr.net/npm/@dong-gri/pixel-mosaic-lazy-loader/dist/pixel-mosaic.min.js\"></script>\n<script>\n  PixelMosaic.init({\n    duration: 1600,\n    startDelay: 100,\n    steps: 'auto',\n    stepCount: 8\n  });\n</script>\n```\n\n### npm\n\n```bash\nnpm install @dong-gri/pixel-mosaic-lazy-loader\n```\n\n```js\nimport PixelMosaic from '@dong-gri/pixel-mosaic-lazy-loader';\nimport '@dong-gri/pixel-mosaic-lazy-loader/style.css';\n\nconst mosaic = PixelMosaic.init({\n  duration: 1600,\n  startDelay: 100,\n  steps: 'auto',\n  stepCount: 8\n});\n```\n\n## CDN files\n\n### jsDelivr\n\n- Minified JavaScript: `https://cdn.jsdelivr.net/npm/@dong-gri/pixel-mosaic-lazy-loader/dist/pixel-mosaic.min.js`\n- Minified ES module: `https://cdn.jsdelivr.net/npm/@dong-gri/pixel-mosaic-lazy-loader/dist/pixel-mosaic.min.mjs`\n- Minified CSS: `https://cdn.jsdelivr.net/npm/@dong-gri/pixel-mosaic-lazy-loader/dist/pixel-mosaic.min.css`\n- Readable JavaScript: `https://cdn.jsdelivr.net/npm/@dong-gri/pixel-mosaic-lazy-loader/dist/pixel-mosaic.js`\n- Readable ES module: `https://cdn.jsdelivr.net/npm/@dong-gri/pixel-mosaic-lazy-loader/dist/pixel-mosaic.mjs`\n- Readable CSS: `https://cdn.jsdelivr.net/npm/@dong-gri/pixel-mosaic-lazy-loader/dist/pixel-mosaic.css`\n\n### unpkg\n\n- Minified JavaScript: `https://unpkg.com/@dong-gri/pixel-mosaic-lazy-loader/dist/pixel-mosaic.min.js`\n- Minified ES module: `https://unpkg.com/@dong-gri/pixel-mosaic-lazy-loader/dist/pixel-mosaic.min.mjs`\n- Minified CSS: `https://unpkg.com/@dong-gri/pixel-mosaic-lazy-loader/dist/pixel-mosaic.min.css`\n\n## Basic usage\n\nAdd `data-pixel-mosaic` to an image, then initialize the library.\n\n```html\n<img\n  data-pixel-mosaic\n  src=\"/images/hero.jpg\"\n  width=\"1280\"\n  height=\"720\"\n  alt=\"Product dashboard\"\n>\n```\n\n```js\nconst mosaic = PixelMosaic.init({\n  autoDetect: true,\n  autoSelector: 'main img:not([data-no-pixel-mosaic])',\n  duration: 1400,\n  startDelay: 100,\n  steps: 'auto',\n  stepCount: 8,\n  fadePortion: 0,\n  maxConcurrent: 2,\n  quality: 'auto',\n  noise: {\n    enabled: true,\n    opacity: 0.14,\n    fps: 20,\n    monochrome: true,\n    blendMode: 'soft-light'\n  }\n});\n```\n\n## Pixel steps\n\nUse `steps: 'auto'` with `stepCount` for simple settings, or provide explicit pixel sizes for advanced control.\n\n```js\nPixelMosaic.init({\n  duration: 1600,\n  steps: [64, 40, 24, 14, 8, 4, 2]\n});\n```\n\n## Per-image settings\n\nHTML data attributes override global options for a specific image.\n\n```html\n<img\n  data-pixel-mosaic\n  data-pm-duration=\"1900\"\n  data-pm-start-delay=\"700\"\n  data-pm-steps=\"auto\"\n  data-pm-step-count=\"5\"\n  data-pm-noise=\"0.16\"\n  data-pm-animated=\"true\"\n  src=\"/images/animation.webp\"\n  alt=\"Animated preview\"\n>\n```\n\n## Animated images\n\nWhen `ImageDecoder` and the codec are available, frames are decoded and pixelated directly. Otherwise, the original animation keeps playing while a Canvas mosaic is composited over it. If Canvas is unavailable, the original image remains visible through the CSS fallback.\n\n## Browser and device guidance\n\n### Minimum browser support\n\nChrome/Edge 80+, Firefox 74+, Safari 13.1+, iOS Safari 13.4+, Samsung Internet 13+, Android WebView 80+. Internet Explorer is not supported.\n\n### Recommended environment\n\nUse one of the latest two major versions of Chrome, Edge, Firefox, or Safari over HTTPS. Full frame-by-frame animated mosaic depends on `ImageDecoder`, codec availability, CORS, and the browser implementation.\n\n### Performance guidance\n\nFor conservative minimum settings, use a 2-core CPU, 2 GB RAM, images up to 1280×720, `maxConcurrent: 1`, and noise at 12 fps or less. For smoother use, a 4-core CPU, 4 GB RAM, images up to 1920×1080, `maxConcurrent: 2`, and noise at 20–24 fps are recommended. Actual load is primarily determined by pixel count, DPR, concurrent images, and noise FPS.\n\n### Progressive fallback\n\n- `ImageDecoder` available: direct frame decoding for animated mosaic\n- Canvas available: static mosaic and animation-preserving Canvas composition\n- Canvas unavailable: CSS transition fallback\n- `prefers-reduced-motion: reduce`: skip the effect and show the original immediately\n\n## Accessibility and performance\n\n- The original `<img>` and `alt` text remain in the document\n- Canvas overlays are hidden from assistive technology and do not intercept pointer events\n- Set image `width` and `height` to reduce layout shifts\n- `quality: 'auto'` considers Save-Data, device memory, CPU threads, and pointer type\n- Cross-origin animated-frame decoding requires appropriate CORS headers; playback-preserving fallback still works without them\n\n## API\n\n```js\nconst mosaic = PixelMosaic.init(options);\n\nmosaic.scan(document.querySelector('.new-content'));\nmosaic.play(document.querySelector('#hero-image'));\nmosaic.replay(document.querySelector('.gallery'));\nmosaic.destroy();\n```\n\n## Main options\n\n| Option | Default | Description |\n|---|---:|---|\n| `duration` | `1250` | Pixel transition duration in milliseconds |\n| `startDelay` | `100` | Time to hold the first mosaic state before transition |\n| `steps` | `'auto'` | Automatic steps or an array of pixel sizes |\n| `stepCount` | `8` | Number of automatically generated steps |\n| `fadePortion` | `0` | Canvas crossfade ratio; zero switches directly to the original |\n| `maxConcurrent` | `3` | Maximum images processed at once |\n| `quality` | `'auto'` | `auto`, `low`, `balanced`, or `high` |\n| `animatedMode` | `'auto'` | `auto`, `decode`, or `preserve` |\n| `respectReducedMotion` | `true` | Honor reduced-motion preferences |\n\n## Demo languages\n\nThe public demo supports Korean, English, Japanese, Traditional Chinese for Taiwan, Thai, Simplified Chinese, Traditional Chinese, Russian, and Italian. It detects the browser language, remembers the selection, and accepts `?lang=en`, `?lang=ja`, and other locale parameters.\n\n## More motion with Kineto\n\nLike this effect? Explore pixel mosaic and more web motions in [Kineto](https://kineto.dongri.me/). Tune live, copy code, and ship.\n\n## Limitations\n\n- Complex transforms, masks, or multi-layer `clip-path` combinations may not align perfectly with the Canvas overlay\n- Cross-origin Animated WebP/APNG detection and direct decoding require CORS access\n- Animated-image capabilities vary by browser, so animation-preserving fallback is always included\n\n## License\n\nMIT © [dongri.me](https://dongri.me) · Built with AI vibe-coding.\n","readmeFilename":"README.md"}