1+ import React , { useMemo } from 'react' ;
2+ import ReactDOMServer from 'react-dom/server' ;
3+ import { DownloadSimple } from '@phosphor-icons/react' ;
4+
5+ const GenerativeArt = ( ) => {
6+ const art = useMemo ( ( ) => {
7+ const SVG_SIZE = 500 ;
8+ const NUM_SHAPES = 25 ;
9+ const shapes = [ ] ;
10+
11+ const colors = [ '#FBBF24' , '#A7F3D0' , '#F87171' , '#60A5FA' , '#A78BFA' ] ;
12+
13+ for ( let i = 0 ; i < NUM_SHAPES ; i ++ ) {
14+ const x = Math . random ( ) * SVG_SIZE ;
15+ const y = Math . random ( ) * SVG_SIZE ;
16+ const width = 10 + Math . random ( ) * 150 ;
17+ const height = 10 + Math . random ( ) * 150 ;
18+ const fill = colors [ Math . floor ( Math . random ( ) * colors . length ) ] ;
19+ const rotation = Math . random ( ) * 360 ;
20+ const opacity = 0.5 + Math . random ( ) * 0.5 ;
21+
22+ shapes . push (
23+ < rect
24+ key = { i }
25+ x = { x }
26+ y = { y }
27+ width = { width }
28+ height = { height }
29+ fill = { fill }
30+ opacity = { opacity }
31+ transform = { `rotate(${ rotation } ${ x + width / 2 } ${ y + height / 2 } )` }
32+ />
33+ ) ;
34+ }
35+
36+ return (
37+ < svg width = "100%" height = "100%" viewBox = { `0 0 ${ SVG_SIZE } ${ SVG_SIZE } ` } xmlns = "http://www.w3.org/2000/svg" >
38+ < defs >
39+ < clipPath id = "art-board" >
40+ < rect width = { SVG_SIZE } height = { SVG_SIZE } />
41+ </ clipPath >
42+ </ defs >
43+ < rect width = { SVG_SIZE } height = { SVG_SIZE } fill = "#1F2937" />
44+ < g clipPath = "url(#art-board)" >
45+ { shapes }
46+ </ g >
47+ </ svg >
48+ ) ;
49+ } , [ ] ) ;
50+
51+ const handleDownload = ( ) => {
52+ const svgString = ReactDOMServer . renderToString ( art ) ;
53+ const blob = new Blob ( [ svgString ] , { type : 'image/svg+xml' } ) ;
54+ const url = URL . createObjectURL ( blob ) ;
55+ const link = document . createElement ( 'a' ) ;
56+ link . href = url ;
57+ link . download = 'generative-art.svg' ;
58+ document . body . appendChild ( link ) ;
59+ link . click ( ) ;
60+ document . body . removeChild ( link ) ;
61+ URL . revokeObjectURL ( url ) ;
62+ } ;
63+
64+ return (
65+ < div >
66+ < div style = { { width : '100%' , height : '60vh' , border : '1px solid #374151' , borderRadius : '8px' , overflow : 'hidden' } } >
67+ { art }
68+ </ div >
69+ < div className = "flex justify-center mt-4" >
70+ < button
71+ onClick = { handleDownload }
72+ className = "flex items-center gap-2 text-lg font-arvo font-normal px-6 py-2 rounded-md border transition-colors duration-300 ease-in-out border-green-700 bg-green-800/50 text-white hover:bg-green-700/50"
73+ >
74+ < DownloadSimple size = { 24 } />
75+ Download SVG
76+ </ button >
77+ </ div >
78+ </ div >
79+ ) ;
80+ } ;
81+
82+ export default GenerativeArt ;
0 commit comments