from __future__ import annotations from pathlib import Path import json import struct import zlib root = (Path(__file__).resolve().parent.parent / 'data' / 'demo_packs' / 'p5_memory_quilt') photos_dir = root / 'photos' photos_dir.mkdir(parents=True, exist_ok=True) def png_chunk(tag: bytes, data: bytes) -> bytes: return struct.pack('!I', len(data)) + tag + data + struct.pack('!I', zlib.crc32(tag + data) & 0xFFFFFFFF) def write_png(path: Path, width: int, height: int, pixels): raw = bytearray() for y in range(height): raw.append(0) for x in range(width): r, g, b, a = pixels[y * width + x] raw.extend((r, g, b, a)) compressed = zlib.compress(bytes(raw), level=9) header = b'\x89PNG\r\n\x1a\n' ihdr = struct.pack('!IIBBBBB', width, height, 8, 6, 0, 0, 0) path.write_bytes(header + png_chunk(b'IHDR', ihdr) + png_chunk(b'IDAT', compressed) + png_chunk(b'IEND', b'')) def lerp(a: int, b: int, t: float) -> int: return int(round(a * (1 - t) + b * t)) def palette_interp(c1, c2, t): return tuple(lerp(c1[i], c2[i], t) for i in range(3)) def draw_rect(pixels, w, h, x0, y0, x1, y1, color): for y in range(max(0, y0), min(h, y1)): row = y * w for x in range(max(0, x0), min(w, x1)): pixels[row + x] = (*color, 255) def draw_circle(pixels, w, h, cx, cy, r, color): r2 = r * r for y in range(max(0, cy - r), min(h, cy + r + 1)): row = y * w dy2 = (y - cy) ** 2 for x in range(max(0, cx - r), min(w, cx + r + 1)): if (x - cx) ** 2 + dy2 <= r2: pixels[row + x] = (*color, 255) def draw_line(pixels, w, h, x0, y0, x1, y1, color, thickness=1): dx = abs(x1 - x0) dy = -abs(y1 - y0) sx = 1 if x0 < x1 else -1 sy = 1 if y0 < y1 else -1 err = dx + dy x, y = x0, y0 while True: for ty in range(-thickness // 2, thickness // 2 + 1): for tx in range(-thickness // 2, thickness // 2 + 1): xx, yy = x + tx, y + ty if 0 <= xx < w and 0 <= yy < h: pixels[yy * w + xx] = (*color, 255) if x == x1 and y == y1: break e2 = 2 * err if e2 >= dy: err += dy x += sx if e2 <= dx: err += dx y += sy def make_image(name, background, accent, soft, motif): w = h = 256 pixels = [] for y in range(h): t = y / (h - 1) row_color = palette_interp(background, soft, t * 0.35) pixels.extend([(*row_color, 255)] * w) draw_rect(pixels, w, h, 0, 0, 128, 128, tuple(min(255, c + 16) for c in soft)) draw_rect(pixels, w, h, 128, 0, 256, 128, accent) draw_rect(pixels, w, h, 0, 128, 128, 256, tuple(max(0, c - 12) for c in background)) draw_rect(pixels, w, h, 128, 128, 256, 256, tuple(max(0, c - 4) for c in soft)) if motif == 'house': draw_line(pixels, w, h, 64, 122, 128, 62, (248, 240, 226), 4) draw_line(pixels, w, h, 128, 62, 192, 122, (248, 240, 226), 4) draw_rect(pixels, w, h, 88, 122, 168, 192, tuple(min(255, c + 24) for c in soft)) draw_rect(pixels, w, h, 108, 146, 148, 192, (250, 245, 238)) draw_rect(pixels, w, h, 74, 136, 96, 164, (250, 245, 238)) draw_rect(pixels, w, h, 160, 136, 182, 164, (250, 245, 238)) elif motif == 'cart': draw_rect(pixels, w, h, 60, 144, 196, 170, (92, 64, 48)) draw_rect(pixels, w, h, 82, 108, 174, 146, accent) draw_circle(pixels, w, h, 92, 176, 16, (48, 38, 32)) draw_circle(pixels, w, h, 164, 176, 16, (48, 38, 32)) draw_line(pixels, w, h, 90, 108, 72, 78, (248, 238, 221), 3) draw_line(pixels, w, h, 176, 108, 194, 78, (248, 238, 221), 3) elif motif == 'window': draw_rect(pixels, w, h, 66, 58, 190, 188, tuple(min(255, c + 32) for c in accent)) draw_rect(pixels, w, h, 78, 70, 178, 176, (250, 244, 232)) draw_line(pixels, w, h, 128, 70, 128, 176, (88, 70, 58), 4) draw_line(pixels, w, h, 78, 123, 178, 123, (88, 70, 58), 4) elif motif == 'lights': draw_line(pixels, w, h, 34, 64, 222, 64, (60, 48, 40), 3) for i, x in enumerate(range(48, 208, 24)): color = (255, 225 - i * 5, 150 + i * 8) draw_circle(pixels, w, h, x, 64 + (i % 2) * 8, 8, color) draw_rect(pixels, w, h, 58, 112, 198, 176, tuple(max(0, c - 24) for c in soft)) draw_circle(pixels, w, h, 128, 146, 26, (250, 240, 218)) elif motif == 'laundry': draw_rect(pixels, w, h, 50, 88, 206, 188, (72, 92, 116)) draw_circle(pixels, w, h, 102, 138, 26, (240, 244, 248)) draw_circle(pixels, w, h, 154, 138, 26, (240, 244, 248)) draw_line(pixels, w, h, 70, 104, 186, 104, (240, 244, 248), 2) draw_line(pixels, w, h, 70, 160, 186, 160, (240, 244, 248), 2) elif motif == 'chalk': draw_rect(pixels, w, h, 52, 80, 204, 204, tuple(max(0, c - 18) for c in background)) for i in range(4): draw_rect(pixels, w, h, 72 + i * 26, 98 + (i % 2) * 24, 92 + i * 26, 118 + (i % 2) * 24, (255, 240 - i * 18, 230 - i * 10)) draw_line(pixels, w, h, 90, 190, 166, 120, (255, 225, 140), 4) draw_line(pixels, w, h, 102, 122, 122, 102, (255, 160, 180), 3) else: raise ValueError(motif) border = (250, 244, 232) for x in range(6, w - 6, 16): draw_rect(pixels, w, h, x, 4, x + 8, 8, border) draw_rect(pixels, w, h, x, h - 8, x + 8, h - 4, border) for y in range(6, h - 6, 16): draw_rect(pixels, w, h, 4, y, 8, y + 8, border) draw_rect(pixels, w, h, w - 8, y, w - 4, y + 8, border) write_png(photos_dir / name, w, h, pixels) images = [ ('blue_house.png', (65, 94, 145), (120, 159, 196), (33, 52, 81), 'house'), ('tamale_cart.png', (171, 116, 78), (219, 163, 95), (104, 72, 52), 'cart'), ('winter_market.png', (72, 86, 110), (132, 158, 182), (38, 48, 64), 'lights'), ('kitchen_quilt.png', (145, 118, 94), (204, 168, 132), (92, 72, 58), 'window'), ('laundromat_dawn.png', (92, 106, 122), (153, 171, 186), (58, 66, 78), 'laundry'), ('chalk_hopscotch.png', (109, 146, 103), (168, 188, 136), (78, 110, 70), 'chalk'), ] for name, background, accent, soft, motif in images: make_image(name, background, accent, soft, motif) manifest = { 'pack_id': 'p5_memory_quilt', 'description': 'Synthetic neighborhood memories for the FLUX memory quilt offline demo.', 'style': 'Fabric Quilt', 'photos': [name for name, *_ in images], 'memories': [f'memory-{i:02d}' for i in range(1, 7)], 'version': 1, 'source': 'repository-authored synthetic demo pack', } memories = [ { 'id': 'memory-01', 'text': 'Every Friday the tamale cart parked outside the blue house, and neighbors waved from the porch.', 'location': 'blue house', 'season': 'summer', 'tags': ['food', 'porch', 'neighbors'], }, { 'id': 'memory-02', 'text': 'At dawn the laundromat windows glowed warm while my aunt folded towels and told the same story twice.', 'location': 'laundromat', 'season': 'spring', 'tags': ['laundry', 'family', 'dawn'], }, { 'id': 'memory-03', 'text': 'Winter market lights spilled onto the wet sidewalk, and the whole block felt quieter and kinder.', 'location': 'winter market', 'season': 'winter', 'tags': ['market', 'lights', 'winter'], }, { 'id': 'memory-04', 'text': 'On the kitchen table, a folded quilt held the smell of cedar, coffee, and Sunday conversation.', 'location': 'kitchen table', 'season': 'autumn', 'tags': ['quilt', 'kitchen', 'family'], }, { 'id': 'memory-05', 'text': 'A bus stop mural turned gold at sunset, and we counted every passing car like it was a parade.', 'location': 'bus stop', 'season': 'summer', 'tags': ['bus stop', 'mural', 'sunset'], }, { 'id': 'memory-06', 'text': 'Kids drew hopscotch chalk under the sycamore tree, then raced the shadow line before dinner.', 'location': 'sycamore tree', 'season': 'spring', 'tags': ['chalk', 'kids', 'street'], }, ] (root / 'manifest.json').write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') (root / 'memories.json').write_text(json.dumps(memories, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') print({'images': [name for name, *_ in images], 'manifest': str(root / 'manifest.json'), 'memories': str(root / 'memories.json')})