Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/1TSnakers/ProgressiveImageLoader/llms.txt

Use this file to discover all available pages before exploring further.

The examples below progress from the simplest possible setup to the full pattern used in the official demo. Each example is a complete, self-contained HTML file you can drop into a project directory next to progressive-image-loader.js and open directly in a browser. Read through them in order — each one introduces exactly one new concept.

Basic example

The minimal viable setup: a container element, the library script, and a three-image sequence. No optional parameters are set, so the display defaults to 600 × 600 px with a 500 ms cross-fade between quality levels.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Basic Progressive Image</title>
</head>
<body>
  <!-- Container element — can be any block-level element -->
  <div id="image-container"></div>

  <!-- Include the library before your script -->
  <script src="progressive-image-loader.js"></script>

  <script>
    new ProgressiveImageLoader({
      container: document.getElementById("image-container"),
      images: [
        "bad-image.png",   // least quality — fetched and displayed first
        "mid-image.png",   // medium quality
        "good-image.png",  // most quality — replaces all previous versions
      ]
    });
  </script>
</body>
</html>
The loader immediately kicks off requests for all three images in parallel. The first one to finish (bad-image.png, which should be the smallest file) appears right away. Each subsequent image silently replaces the previous one with a fade as it arrives, culminating in the full-quality version.
Keep your lowest-quality image under 10 KB so it arrives in the first few hundred milliseconds even on a slow connection. The whole point of progressive loading is that the user sees something quickly — a bloated first frame defeats that goal.

When you use the image_ruiner.py script to generate your image sequence, it writes a ready-made image_list.js ES module alongside the output images. You can import this module directly using a type="module" script tag, which keeps your HTML free of long hardcoded arrays. This is the exact pattern used in the official index.html demo.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Progressive Image Loader Demo</title>
</head>
<body>
  <h1>Progressive Image Loader Demo</h1>

  <div id="image-container"></div>

  <!-- The library is loaded as a classic script (no module needed) -->
  <script src="progressive-image-loader.js"></script>

  <!--
    type="module" lets us use ES module import syntax.
    The ProgressiveImageLoader class is already on window from the script above.
  -->
  <script type="module">
    import imageList from "./images/image_list.js";

    new ProgressiveImageLoader({
      container: document.getElementById("image-container"),
      images: imageList,
      width: 1250,
      fadeDuration: 500,
      disableCache: false
    });
  </script>
</body>
</html>
The imported imageList is a pre-ordered array of 9 paths — degraded_100.png first (most degraded) through degraded_000.png last (full quality) — exactly as image_ruiner.py writes it. Passing it straight to images requires no further sorting or manipulation.
Because type="module" scripts are always deferred, the ProgressiveImageLoader constructor call runs after the DOM is ready. You do not need a DOMContentLoaded listener when using this pattern.

No-cache debug mode

During development — especially while iterating on generated image sequences — the browser’s HTTP cache can show you stale files even after you rerun image_ruiner.py. Setting disableCache: true forces every image URL to include a unique timestamp query string (?t=1718000000000), bypassing the cache entirely. Pairing this with fadeDuration: 0 makes each quality upgrade snap in instantaneously, which makes it easy to watch the full loading sequence play out without waiting for fade animations.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Progressive Loader — Debug Mode</title>
</head>
<body>
  <p>No cache — instant quality switches</p>

  <div id="image-container"></div>

  <script src="progressive-image-loader.js"></script>

  <script type="module">
    import imageList from "./images/image_list.js";

    new ProgressiveImageLoader({
      container:    document.getElementById("image-container"),
      images:       imageList,
      width:        1250,
      fadeDuration: 0,     // instant swap — no cross-fade animation
      disableCache: true   // append ?t=<timestamp> to every image URL
    });
  </script>
</body>
</html>
With fadeDuration: 0 you will clearly see each quality tier replace the previous one as the network requests complete. This matches the setup used in the hosted live demo at 1tsnakers.github.io/ProgressiveImageLoader.
Leave disableCache: true only in development builds. In production every page load re-downloads the full image sequence, which can dramatically increase bandwidth consumption for your users and your hosting costs.

Smooth fade setup

For a polished production experience, set fadeDuration to a value between 300 ms and 500 ms. The library uses a CSS opacity transition on each <img> element, so the cross-fade is handled entirely by the browser’s compositor — no JavaScript timers are involved during the animation itself.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Smooth Progressive Image</title>
</head>
<body>
  <div id="image-container"></div>

  <script src="progressive-image-loader.js"></script>

  <script>
    new ProgressiveImageLoader({
      container: document.getElementById("image-container"),
      images: [
        "bad-image.png",
        "mid-image.png",
        "good-image.png",
      ],
      width:        600,
      height:       600,
      fadeDuration: 500,   // 500 ms ease-in-out cross-fade between quality levels
      disableCache: false  // rely on browser caching in production
    });
  </script>
</body>
</html>
The 500 ms fade is the library’s default value — if you omit fadeDuration entirely you get this behaviour automatically. Specify it explicitly when you want to be intentional about the animation length or when working alongside teammates who may not know the default.
The transition uses the CSS ease timing function, which starts and ends slowly with a faster middle segment. This gives the quality upgrade a natural, unobtrusive feel rather than a mechanical linear swap. The timing function is set internally by the library and cannot currently be changed through the options API.

Options quick-reference

Development config

fadeDuration: 0 + disableCache: trueInstant swaps, no cached stale images. Use while iterating on your image sequence.

Production config

fadeDuration: 500 + disableCache: falseSmooth 500 ms fades, browser caching enabled. Default behaviour — omitting both options gives you this automatically.

Module import pattern

import imageList from "./images/image_list.js"Use when your images were generated by image_ruiner.py. Keeps HTML tidy and the array is already in the correct order.

Minimal setup

Only container and images are required. Everything else has a sensible default — you can be up and running in four lines of JavaScript.

Build docs developers (and LLMs) love