flux.vision, tobias.raayoni-last.com and randogoth.com. They were one site until October 2026, serving four audiences from a single dated list, which is the only format that can hold unrelated things at once. flux.vision is recovered from the Wayback Machine, where it had sat since being deleted in 2021: 90 articles, closed and maintained rather than updated. tobias.raayoni-last.com is the professional record, 97 articles back to 1999. randogoth.com is the technical work, 41 articles across six areas, served as an ANSI bulletin board. History starts here deliberately. The development history, the 266-row inventory that records why each article went where it did, the Wayback pipelines, the pruned articles, the source archives and the full-size images are kept beside the repo rather than in it, so a clone is the web presence and not the argument that produced it. REFACTOR.md is gitignored for the same reason. See README.md for where that material lives, and keep it: the sort is not reproducible from these three directories alone. Each site documents itself in its own README, including the traps that cost time and look like nothing when you get them wrong.
61 lines
2.1 KiB
JavaScript
61 lines
2.1 KiB
JavaScript
/* Tile loading, after the 2004-2019 site.
|
|
*
|
|
* The original showed animated static (void.gif, 79 frames at 40ms) in each
|
|
* tile until jquery.lazyload fetched the real image on scroll. On a 2014
|
|
* connection fetching 231 library images, that static was visible for a good
|
|
* while. Served locally it is gone in a few milliseconds and the effect is
|
|
* lost entirely, so the hold is made deliberate rather than left to latency:
|
|
* the noise runs for at least HOLD_MS whatever the connection does.
|
|
*
|
|
* Loading also starts only once a tile is genuinely near the viewport, and
|
|
* each tile takes a small stagger, so a screen of them resolves in a ripple
|
|
* rather than all snapping at once.
|
|
*/
|
|
(function () {
|
|
"use strict";
|
|
|
|
var HOLD_MS = 320; /* minimum time the static is on screen */
|
|
var STAGGER = 35; /* ms between neighbouring tiles resolving */
|
|
var MARGIN = "80px";
|
|
|
|
var tiles = document.querySelectorAll(".art-preview.lazy[data-src]");
|
|
if (!tiles.length) return;
|
|
var queued = 0, lastAt = 0;
|
|
|
|
function reveal(el, src) {
|
|
el.style.setProperty("--src", "url('" + src + "')");
|
|
el.classList.add("loaded");
|
|
}
|
|
|
|
function load(el) {
|
|
var src = el.getAttribute("data-src");
|
|
if (!src || el.dataset.done) return;
|
|
el.dataset.done = "1";
|
|
|
|
var now = Date.now();
|
|
var slot = Math.max(now, lastAt + STAGGER);
|
|
lastAt = slot;
|
|
var floor = slot - now + HOLD_MS; /* earliest this tile may resolve */
|
|
var began = now, ready = false, elapsed = 0;
|
|
|
|
var img = new Image();
|
|
img.onload = function () {
|
|
ready = true;
|
|
elapsed = Date.now() - began;
|
|
setTimeout(function () { reveal(el, src); }, Math.max(0, floor - elapsed));
|
|
};
|
|
img.onerror = function () { el.classList.add("empty"); };
|
|
img.src = src;
|
|
}
|
|
|
|
if (!("IntersectionObserver" in window)) {
|
|
Array.prototype.forEach.call(tiles, load);
|
|
return;
|
|
}
|
|
var io = new IntersectionObserver(function (entries) {
|
|
entries.forEach(function (e) {
|
|
if (e.isIntersecting) { load(e.target); io.unobserve(e.target); }
|
|
});
|
|
}, { rootMargin: MARGIN });
|
|
Array.prototype.forEach.call(tiles, function (t) { io.observe(t); });
|
|
})();
|