Tend your corner of the atmosphere. spores.garden turns your AT Protocol records into a personal site with unique themes. Your data never leaves your PDS. Grow something that's truly yours.
spores.garden
1/**
2 * Flower Grid Visualization Script
3 *
4 * Generates flower visualizations as PNG images.
5 *
6 * Usage:
7 * npx tsx scripts/visualize-flowers.ts <count> # Generate <count> grids of 256 flowers
8 * npx tsx scripts/visualize-flowers.ts <did> # Generate single flower from specific DID
9 */
10
11import sharp from 'sharp';
12import { generateFlowerSVGString } from '../src/utils/flower-svg';
13
14const GRID_SIZE = 16;
15const TOTAL_FLOWERS = GRID_SIZE * GRID_SIZE; // 256
16const OUTPUT_SIZE = 2000;
17const CELL_SIZE = OUTPUT_SIZE / GRID_SIZE; // 125
18const FLOWER_SIZE = 100; // viewBox size of each flower
19
20/**
21 * Generate unique seed DIDs for diverse flowers
22 */
23function generateSeeds(count: number, gridIndex: number): string[] {
24 const seeds: string[] = [];
25 const timestamp = Date.now();
26 for (let i = 0; i < count; i++) {
27 // Use varied seed patterns for maximum diversity
28 seeds.push(`did:plc:flower-grid-${gridIndex}-${i}-${timestamp}`);
29 }
30 return seeds;
31}
32
33/**
34 * Extract inner SVG content (without wrapper) from a flower SVG string
35 */
36function extractSVGContent(svgString: string): string {
37 // Match content between <svg ...> and </svg>
38 const match = svgString.match(/<svg[^>]*>([\s\S]*?)<\/svg>/i);
39 return match ? match[1].trim() : '';
40}
41
42/**
43 * Build a combined SVG with all flowers arranged in a grid
44 */
45function buildGridSVG(seeds: string[]): string {
46 const flowerGroups: string[] = [];
47
48 for (let i = 0; i < seeds.length; i++) {
49 const row = Math.floor(i / GRID_SIZE);
50 const col = i % GRID_SIZE;
51
52 // Calculate position in output coordinates
53 const x = col * CELL_SIZE + (CELL_SIZE - FLOWER_SIZE) / 2;
54 const y = row * CELL_SIZE + (CELL_SIZE - FLOWER_SIZE) / 2;
55
56 // Generate flower SVG and extract its content
57 const flowerSVG = generateFlowerSVGString(seeds[i], FLOWER_SIZE);
58 const innerContent = extractSVGContent(flowerSVG);
59
60 // Wrap in a group with translation
61 flowerGroups.push(`
62 <g transform="translate(${x}, ${y})">
63 ${innerContent}
64 </g>`);
65 }
66
67 // Build the final SVG
68 return `<?xml version="1.0" encoding="UTF-8"?>
69<svg width="${OUTPUT_SIZE}" height="${OUTPUT_SIZE}" viewBox="0 0 ${OUTPUT_SIZE} ${OUTPUT_SIZE}" xmlns="http://www.w3.org/2000/svg">
70 <rect width="100%" height="100%" fill="#f8f8f8"/>
71 ${flowerGroups.join('\n')}
72</svg>`;
73}
74
75async function generateGrid(gridIndex: number): Promise<string> {
76 // Generate unique seeds for this grid
77 const seeds = generateSeeds(TOTAL_FLOWERS, gridIndex);
78
79 // Build combined SVG
80 const gridSVG = buildGridSVG(seeds);
81
82 // Convert to PNG using sharp
83 const outputPath = `flower-grid-${gridIndex + 1}.png`;
84
85 await sharp(Buffer.from(gridSVG))
86 .resize(OUTPUT_SIZE, OUTPUT_SIZE)
87 .png()
88 .toFile(outputPath);
89
90 return outputPath;
91}
92
93async function generateSingleFlower(did: string): Promise<string> {
94 const flowerSize = 500;
95 const flowerSVG = generateFlowerSVGString(did, flowerSize);
96
97 // Create output filename from DID (sanitize for filesystem)
98 const sanitizedDid = did.replace(/:/g, '-');
99 const outputPath = `flower-${sanitizedDid}.png`;
100
101 await sharp(Buffer.from(flowerSVG))
102 .resize(flowerSize, flowerSize)
103 .png()
104 .toFile(outputPath);
105
106 return outputPath;
107}
108
109async function main() {
110 const firstArg = process.argv[2];
111
112 // Check if first argument is a DID
113 if (firstArg && firstArg.startsWith('did:')) {
114 console.log(`Generating single flower for DID: ${firstArg}...`);
115 const outputPath = await generateSingleFlower(firstArg);
116 console.log(`Saved to ${outputPath}`);
117 console.log('\nDone!');
118 return;
119 }
120
121 // Otherwise, generate grids
122 const count = parseInt(firstArg || '1', 10);
123
124 console.log(`Generating ${count} grid(s), each with ${TOTAL_FLOWERS} flowers (${GRID_SIZE}x${GRID_SIZE})...`);
125
126 for (let i = 0; i < count; i++) {
127 console.log(`\nGenerating grid ${i + 1}/${count}...`);
128 const outputPath = await generateGrid(i);
129 console.log(`Saved to ${outputPath}`);
130 }
131
132 console.log('\nDone!');
133}
134
135main().catch(console.error);