Files
Leonxlnx 6d8c96d1db Major update: synth styles, gradient sets, export dialogs, glass UI, docs
- Synth styles: blend any two renderers with five mix operations into
  brand-new generated looks, savable to localStorage as style chips
- Share codes bumped to v2 (synth fields), v1 codes still decode
- Gradient set generator: 4-12 seed variations with preview grid and
  ZIP batch download via a dependency-free store-only ZIP writer
- Export buttons now open dialogs with live preview and settings
- UI redesign: glassy translucent surfaces, rounder geometry, staggered
  intro animation, hover micro-interactions, refined scrollbars
- Docs page, generated favicon/touch icons and OG image, meta tags
- Skip chromatic aberration during synth blends to keep the D3D shader
  linker under its inlining limit

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-10 16:13:52 +02:00

92 lines
2.8 KiB
JavaScript

/* Minimal store-only (no compression) ZIP writer for batch PNG export. */
var ZipWriter = (function () {
var CRC_TABLE = (function () {
var t = new Uint32Array(256);
for (var n = 0; n < 256; n++) {
var c = n;
for (var k = 0; k < 8; k++) c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
t[n] = c >>> 0;
}
return t;
})();
function crc32(buf) {
var c = 0xFFFFFFFF;
for (var i = 0; i < buf.length; i++) {
c = CRC_TABLE[(c ^ buf[i]) & 0xFF] ^ (c >>> 8);
}
return (c ^ 0xFFFFFFFF) >>> 0;
}
function dosDateTime() {
var d = new Date();
var time = (d.getHours() << 11) | (d.getMinutes() << 5) | (d.getSeconds() >> 1);
var date = ((d.getFullYear() - 1980) << 9) | ((d.getMonth() + 1) << 5) | d.getDate();
return { time: time, date: date };
}
/* entries: [{ name: string, data: Uint8Array }] -> Blob */
function build(entries) {
var parts = [];
var central = [];
var offset = 0;
var dt = dosDateTime();
entries.forEach(function (e) {
var nameBytes = new TextEncoder().encode(e.name);
var crc = crc32(e.data);
var local = new Uint8Array(30 + nameBytes.length);
var v = new DataView(local.buffer);
v.setUint32(0, 0x04034b50, true);
v.setUint16(4, 20, true); // version needed
v.setUint16(6, 0x0800, true); // utf8 flag
v.setUint16(8, 0, true); // store
v.setUint16(10, dt.time, true);
v.setUint16(12, dt.date, true);
v.setUint32(14, crc, true);
v.setUint32(18, e.data.length, true);
v.setUint32(22, e.data.length, true);
v.setUint16(26, nameBytes.length, true);
v.setUint16(28, 0, true);
local.set(nameBytes, 30);
parts.push(local, e.data);
var cd = new Uint8Array(46 + nameBytes.length);
var c = new DataView(cd.buffer);
c.setUint32(0, 0x02014b50, true);
c.setUint16(4, 20, true);
c.setUint16(6, 20, true);
c.setUint16(8, 0x0800, true);
c.setUint16(10, 0, true);
c.setUint16(12, dt.time, true);
c.setUint16(14, dt.date, true);
c.setUint32(16, crc, true);
c.setUint32(20, e.data.length, true);
c.setUint32(24, e.data.length, true);
c.setUint16(28, nameBytes.length, true);
c.setUint32(42, offset, true);
cd.set(nameBytes, 46);
central.push(cd);
offset += local.length + e.data.length;
});
var cdSize = 0;
central.forEach(function (c) { cdSize += c.length; });
var end = new Uint8Array(22);
var ev = new DataView(end.buffer);
ev.setUint32(0, 0x06054b50, true);
ev.setUint16(8, entries.length, true);
ev.setUint16(10, entries.length, true);
ev.setUint32(12, cdSize, true);
ev.setUint32(16, offset, true);
return new Blob(parts.concat(central, [end]), { type: "application/zip" });
}
return { build: build };
})();