import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) import numpy as np from PIL import Image, ImageDraw, ImageFont import particri def create_checkerboard(w: int, h: int, grid_size: int = 16) -> Image.Image: """Creates a transparent checkerboard background like Photoshop.""" img = Image.new("RGBA", (w, h), (200, 200, 200, 255)) draw = ImageDraw.Draw(img) for y in range(0, h, grid_size): for x in range(0, w, grid_size): if (x // grid_size + y // grid_size) % 2 == 0: draw.rectangle([x, y, x + grid_size, y + grid_size], fill=(240, 240, 240, 255)) return img def main(): print("Synthesizing Complete Multi-Panel Reference Replica...") out_dir = Path(__file__).resolve().parent.parent / "output" out_dir.mkdir(exist_ok=True) panel_w, panel_h = 480, 270 scale = panel_w / 1920.0 # 0.25 scale factor # 1. Panel 1: Light Streaks e1 = particri.Presets.light_streaks(width=panel_w, height=panel_h, density=0.8, seed=303) e1.warmup(1.5) p1_rgba = e1.render(bloom=True, bloom_intensity=0.8, bloom_radius=5) img1 = Image.new("RGBA", (panel_w, panel_h), (2, 8, 12, 255)) img1.paste(Image.fromarray(p1_rgba), mask=Image.fromarray(p1_rgba).split()[3]) # 2. Panel 2: Golden Sparkles on Checkerboard e2 = particri.ParticleEngine(max_particles=10000, width=panel_w, height=panel_h) e2.add_curl_noise(seed=42, strength=25.0, frequency=0.005, speed=0.15) e2.add_brownian(10.0, seed=43) # Bokeh e2.add_emitter( shape=particri.EmitterShape.Box, position=(panel_w * 0.5, panel_h * 0.5), size=(panel_w, panel_h), rate=40.0, speed_range=(3.0, 10.0), size_start_range=(5.0, 12.0), size_end_range=(1.0, 4.0), color_start=(1.0, 0.85, 0.38, 0.85), color_end=(1.0, 0.65, 0.15, 0.0), particle_shape=particri.ParticleShape.Bokeh, seed=50, ) # Stars e2.add_emitter( shape=particri.EmitterShape.Box, position=(panel_w * 0.5, panel_h * 0.5), size=(panel_w, panel_h), rate=35.0, speed_range=(4.0, 15.0), size_start_range=(10.0, 24.0), size_end_range=(0.0, 3.0), color_start=(1.0, 0.95, 0.75, 1.0), color_end=(1.0, 0.55, 0.1, 0.0), particle_shape=particri.ParticleShape.Star4, twinkle_speed_range=(4.0, 14.0), seed=60, ) e2.warmup(1.5) p2_rgba = e2.render(bloom=True, bloom_intensity=0.7, bloom_radius=5) img2 = create_checkerboard(panel_w, panel_h, grid_size=12) img2.paste(Image.fromarray(p2_rgba), mask=Image.fromarray(p2_rgba).split()[3]) # 3. Panel 3: Starburst Cluster on Checkerboard e3 = particri.ParticleEngine(max_particles=10000, width=panel_w, height=panel_h) e3.add_drag(0.3) e3.add_curl_noise(seed=101, strength=20.0, frequency=0.006, speed=0.2) # Concentrated center starburst e3.add_emitter( shape=particri.EmitterShape.Circle, position=(panel_w * 0.5, panel_h * 0.5), size=(35.0, 35.0), rate=90.0, speed_range=(5.0, 35.0), size_start_range=(8.0, 18.0), size_end_range=(0.0, 2.0), color_start=(1.0, 0.98, 0.88, 1.0), color_end=(1.0, 0.65, 0.2, 0.0), particle_shape=particri.ParticleShape.Star8, twinkle_speed_range=(6.0, 20.0), radial_velocity=True, seed=110, ) # Outer sparkles e3.add_emitter( shape=particri.EmitterShape.Circle, position=(panel_w * 0.5, panel_h * 0.5), size=(70.0, 70.0), rate=70.0, speed_range=(5.0, 20.0), size_start_range=(5.0, 12.0), size_end_range=(0.0, 2.0), color_start=(1.0, 0.88, 0.45, 1.0), color_end=(1.0, 0.5, 0.1, 0.0), particle_shape=particri.ParticleShape.Star4, twinkle_speed_range=(4.0, 14.0), radial_velocity=True, seed=120, ) e3.warmup(1.5) p3_rgba = e3.render(bloom=True, bloom_intensity=0.75, bloom_radius=5) img3 = create_checkerboard(panel_w, panel_h, grid_size=12) img3.paste(Image.fromarray(p3_rgba), mask=Image.fromarray(p3_rgba).split()[3]) # 4. Panel 4: Cosmic Nebula e4 = particri.Presets.cosmic_nebula(width=panel_w, height=panel_h, density=0.8, seed=202) e4.warmup(2.0) p4_rgba = e4.render(bloom=True, bloom_intensity=0.8, bloom_radius=5) img4 = Image.new("RGBA", (panel_w, panel_h), (4, 2, 10, 255)) img4.paste(Image.fromarray(p4_rgba), mask=Image.fromarray(p4_rgba).split()[3]) # Stitch top row: 4 panels spacing = 8 top_w = panel_w * 4 + spacing * 3 top_h = panel_h # Bottom banner: Glitter field e_bot = particri.Presets.glitter_field(width=top_w, height=120, density=1.5, seed=404) e_bot.warmup(1.5) bot_rgba = e_bot.render(bloom=True, bloom_intensity=0.8, bloom_radius=6) img_bot = Image.new("RGBA", (top_w, 120), (14, 10, 8, 255)) img_bot.paste(Image.fromarray(bot_rgba), mask=Image.fromarray(bot_rgba).split()[3]) # Canvas total_w = top_w + 32 total_h = top_h + 120 + spacing + 32 canvas = Image.new("RGBA", (total_w, total_h), (25, 27, 34, 255)) # Paste top 4 panels canvas.paste(img1, (16, 16)) canvas.paste(img2, (16 + panel_w + spacing, 16)) canvas.paste(img3, (16 + (panel_w + spacing) * 2, 16)) canvas.paste(img4, (16 + (panel_w + spacing) * 3, 16)) # Paste bottom banner canvas.paste(img_bot, (16, 16 + panel_h + spacing)) showcase_path = out_dir / "reference_replica_showcase.png" canvas.save(str(showcase_path)) print(f"Saved complete reference replica showcase to: {showcase_path}") if __name__ == "__main__": main()