Setting the file. One moment.
Viewer · Algorithmic Art · anthropics/skills · Skills Docs
ContentsBack to the top of the page (opens in a new tab)
templates/ viewer.html
HTML · 599 lines · 20 KB
Let your philosophy guide the implementation.
16 The world is your oyster - be creative!
17 -->
18 < html lang = "en" >
19 < head >
20 < meta charset = "UTF-8" >
21 < meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
22 < title >Generative Art Viewer</ title >
23 < script src = "https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js" ></ script >
24 < link rel = "preconnect" href = "https://fonts.googleapis.com" >
25 < link rel = "preconnect" href = "https://fonts.gstatic.com" crossorigin >
26 < link href = "https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&family=Lora:wght@400;500&display=swap" rel = "stylesheet" >
27 < style >
28 /* Anthropic Brand Colors */
29 :root {
30 --anthropic-dark : #141413 ;
31 --anthropic-light : #faf9f5 ;
32 --anthropic-mid-gray : #b0aea5 ;
33 --anthropic-light-gray : #e8e6dc ;
34 --anthropic-orange : #d97757 ;
35 --anthropic-blue : #6a9bcc ;
36 --anthropic-green : #788c5d ;
37 }
38
39 * {
40 margin : 0 ;
41 padding : 0 ;
42 box-sizing : border-box ;
43 }
44
45 body {
46 font-family : 'Poppins' , sans-serif ;
47 background : linear-gradient ( 135 deg , var ( --anthropic-light ) 0 % , #f5f3ee 100 % );
48 min-height : 100 vh ;
49 color : var ( --anthropic-dark );
50 }
51
52 .container {
53 display : flex ;
54 min-height : 100 vh ;
55 padding : 20 px ;
56 gap : 20 px ;
57 }
58
59 /* Sidebar */
60 .sidebar {
61 width : 320 px ;
62 flex-shrink : 0 ;
63 background : rgba ( 255 , 255 , 255 , 0.95 );
64 backdrop-filter : blur ( 10 px );
65 padding : 24 px ;
66 border-radius : 12 px ;
67 box-shadow : 0 10 px 30 px rgba ( 20 , 20 , 19 , 0.1 );
68 overflow-y : auto ;
69 overflow-x : hidden ;
70 }
71
72 .sidebar h1 {
73 font-family : 'Lora' , serif ;
74 font-size : 24 px ;
75 font-weight : 500 ;
76 color : var ( --anthropic-dark );
77 margin-bottom : 8 px ;
78 }
79
80 .sidebar .subtitle {
81 color : var ( --anthropic-mid-gray );
82 font-size : 14 px ;
83 margin-bottom : 32 px ;
84 line-height : 1.4 ;
85 }
86
87 /* Control Sections */
88 .control-section {
89 margin-bottom : 32 px ;
90 }
91
92 .control-section h3 {
93 font-size : 16 px ;
94 font-weight : 600 ;
95 color : var ( --anthropic-dark );
96 margin-bottom : 16 px ;
97 display : flex ;
98 align-items : center ;
99 gap : 8 px ;
100 }
101
102 .control-section h3 ::before {
103 content : '•' ;
104 color : var ( --anthropic-orange );
105 font-weight : bold ;
106 }
107
108 /* Seed Controls */
109 .seed-input {
110 width : 100 % ;
111 background : var ( --anthropic-light );
112 padding : 12 px ;
113 border-radius : 8 px ;
114 font-family : 'Courier New' , monospace ;
115 font-size : 14 px ;
116 margin-bottom : 12 px ;
117 border : 1 px solid var ( --anthropic-light-gray );
118 text-align : center ;
119 }
120
121 .seed-input:focus {
122 outline : none ;
123 border-color : var ( --anthropic-orange );
124 box-shadow : 0 0 0 2 px rgba ( 217 , 119 , 87 , 0.1 );
125 background : white ;
126 }
127
128 .seed-controls {
129 display : grid ;
130 grid-template-columns : 1 fr 1 fr ;
131 gap : 8 px ;
132 margin-bottom : 8 px ;
133 }
134
135 .regen-button {
136 margin-bottom : 0 ;
137 }
138
139 /* Parameter Controls */
140 .control-group {
141 margin-bottom : 20 px ;
142 }
143
144 .control-group label {
145 display : block ;
146 font-size : 14 px ;
147 font-weight : 500 ;
148 color : var ( --anthropic-dark );
149 margin-bottom : 8 px ;
150 }
151
152 .slider-container {
153 display : flex ;
154 align-items : center ;
155 gap : 12 px ;
156 }
157
158 .slider-container input [ type = "range" ] {
159 flex : 1 ;
160 height : 4 px ;
161 background : var ( --anthropic-light-gray );
162 border-radius : 2 px ;
163 outline : none ;
164 -webkit-appearance : none ;
165 }
166
167 .slider-container input [ type = "range" ] ::-webkit-slider-thumb {
168 -webkit-appearance : none ;
169 width : 16 px ;
170 height : 16 px ;
171 background : var ( --anthropic-orange );
172 border-radius : 50 % ;
173 cursor : pointer ;
174 transition : all 0.2 s ease ;
175 }
176
177 .slider-container input [ type = "range" ] ::-webkit-slider-thumb:hover {
178 transform : scale ( 1.1 );
179 background : #c86641 ;
180 }
181
182 .slider-container input [ type = "range" ] ::-moz-range-thumb {
183 width : 16 px ;
184 height : 16 px ;
185 background : var ( --anthropic-orange );
186 border-radius : 50 % ;
187 border : none ;
188 cursor : pointer ;
189 transition : all 0.2 s ease ;
190 }
191
192 .value-display {
193 font-family : 'Courier New' , monospace ;
194 font-size : 12 px ;
195 color : var ( --anthropic-mid-gray );
196 min-width : 60 px ;
197 text-align : right ;
198 }
199
200 /* Color Pickers */
201 .color-group {
202 margin-bottom : 16 px ;
203 }
204
205 .color-group label {
206 display : block ;
207 font-size : 12 px ;
208 color : var ( --anthropic-mid-gray );
209 margin-bottom : 4 px ;
210 }
211
212 .color-picker-container {
213 display : flex ;
214 align-items : center ;
215 gap : 8 px ;
216 }
217
218 .color-picker-container input [ type = "color" ] {
219 width : 32 px ;
220 height : 32 px ;
221 border : none ;
222 border-radius : 6 px ;
223 cursor : pointer ;
224 background : none ;
225 padding : 0 ;
226 }
227
228 .color-value {
229 font-family : 'Courier New' , monospace ;
230 font-size : 12 px ;
231 color : var ( --anthropic-mid-gray );
232 }
233
234 /* Buttons */
235 .button {
236 background : var ( --anthropic-orange );
237 color : white ;
238 border : none ;
239 padding : 10 px 16 px ;
240 border-radius : 6 px ;
241 font-size : 14 px ;
242 font-weight : 500 ;
243 cursor : pointer ;
244 transition : all 0.2 s ease ;
245 width : 100 % ;
246 }
247
248 .button:hover {
249 background : #c86641 ;
250 transform : translateY ( -1 px );
251 }
252
253 .button:active {
254 transform : translateY ( 0 );
255 }
256
257 .button.secondary {
258 background : var ( --anthropic-blue );
259 }
260
261 .button.secondary:hover {
262 background : #5a8bb8 ;
263 }
264
265 .button.tertiary {
266 background : var ( --anthropic-green );
267 }
268
269 .button.tertiary:hover {
270 background : #6b7b52 ;
271 }
272
273 .button-row {
274 display : flex ;
275 gap : 8 px ;
276 }
277
278 .button-row .button {
279 flex : 1 ;
280 }
281
282 /* Canvas Area */
283 .canvas-area {
284 flex : 1 ;
285 display : flex ;
286 align-items : center ;
287 justify-content : center ;
288 min-width : 0 ;
289 }
290
291 #canvas-container {
292 width : 100 % ;
293 max-width : 1000 px ;
294 border-radius : 12 px ;
295 overflow : hidden ;
296 box-shadow : 0 20 px 40 px rgba ( 20 , 20 , 19 , 0.1 );
297 background : white ;
298 }
299
300 #canvas-container canvas {
301 display : block ;
302 width : 100 % !important ;
303 height : auto !important ;
304 }
305
306 /* Loading State */
307 .loading {
308 display : flex ;
309 align-items : center ;
310 justify-content : center ;
311 font-size : 18 px ;
312 color : var ( --anthropic-mid-gray );
313 }
314
315 /* Responsive - Stack on mobile */
316 @media ( max-width : 600 px ) {
317 .container {
318 flex-direction : column ;
319 }
320
321 .sidebar {
322 width : 100 % ;
323 }
324
325 .canvas-area {
326 padding : 20 px ;
327 }
328 }
329 </ style >
330 </ head >
331 < body >
332 < div class = "container" >
333 <!-- Control Sidebar -->
334 < div class = "sidebar" >
335 <!-- Headers (CUSTOMIZE THIS FOR YOUR ART) -->
336 < h1 >TITLE - EDIT</ h1 >
337 < div class = "subtitle" >SUBHEADER - EDIT</ div >
338
339 <!-- Seed Section (ALWAYS KEEP THIS) -->
340 < div class = "control-section" >
341 < h3 >Seed</ h3 >
342 < input type = "number" id = "seed-input" class = "seed-input" value = "12345" onchange = " updateSeed ()" >
343 < div class = "seed-controls" >
344 < button class = "button secondary" onclick = " previousSeed ()" >← Prev</ button >
345 < button class = "button secondary" onclick = " nextSeed ()" >Next →</ button >
346 </ div >
347 < button class = "button tertiary regen-button" onclick = " randomSeedAndUpdate ()" >↻ Random</ button >
348 </ div >
349
350 <!-- Parameters Section (CUSTOMIZE THIS FOR YOUR ART) -->
351 < div class = "control-section" >
352 < h3 >Parameters</ h3 >
353
354 <!-- Particle Count -->
355 < div class = "control-group" >
356 < label >Particle Count</ label >
357 < div class = "slider-container" >
358 < input type = "range" id = "particleCount" min = "1000" max = "10000" step = "500" value = "5000" oninput = " updateParam ('particleCount', this . value )" >
359 < span class = "value-display" id = "particleCount-value" >5000</ span >
360 </ div >
361 </ div >
362
363 <!-- Flow Speed -->
364 < div class = "control-group" >
365 < label >Flow Speed</ label >
366 < div class = "slider-container" >
367 < input type = "range" id = "flowSpeed" min = "0.1" max = "2.0" step = "0.1" value = "0.5" oninput = " updateParam ('flowSpeed', this . value )" >
368 < span class = "value-display" id = "flowSpeed-value" >0.5</ span >
369 </ div >
370 </ div >
371
372 <!-- Noise Scale -->
373 < div class = "control-group" >
374 < label >Noise Scale</ label >
375 < div class = "slider-container" >
376 < input type = "range" id = "noiseScale" min = "0.001" max = "0.02" step = "0.001" value = "0.005" oninput = " updateParam ('noiseScale', this . value )" >
377 < span class = "value-display" id = "noiseScale-value" >0.005</ span >
378 </ div >
379 </ div >
380
381 <!-- Trail Length -->
382 < div class = "control-group" >
383 < label >Trail Length</ label >
384 < div class = "slider-container" >
385 < input type = "range" id = "trailLength" min = "2" max = "20" step = "1" value = "8" oninput = " updateParam ('trailLength', this . value )" >
386 < span class = "value-display" id = "trailLength-value" >8</ span >
387 </ div >
388 </ div >
389 </ div >
390
391 <!-- Colors Section (OPTIONAL - CUSTOMIZE OR REMOVE) -->
392 < div class = "control-section" >
393 < h3 >Colors</ h3 >
394
395 <!-- Color 1 -->
396 < div class = "color-group" >
397 < label >Primary Color</ label >
398 < div class = "color-picker-container" >
399 < input type = "color" id = "color1" value = "#d97757" onchange = " updateColor ('color1', this . value )" >
400 < span class = "color-value" id = "color1-value" >#d97757</ span >
401 </ div >
402 </ div >
403
404 <!-- Color 2 -->
405 < div class = "color-group" >
406 < label >Secondary Color</ label >
407 < div class = "color-picker-container" >
408 < input type = "color" id = "color2" value = "#6a9bcc" onchange = " updateColor ('color2', this . value )" >
409 < span class = "color-value" id = "color2-value" >#6a9bcc</ span >
410 </ div >
411 </ div >
412
413 <!-- Color 3 -->
414 < div class = "color-group" >
415 < label >Accent Color</ label >
416 < div class = "color-picker-container" >
417 < input type = "color" id = "color3" value = "#788c5d" onchange = " updateColor ('color3', this . value )" >
418 < span class = "color-value" id = "color3-value" >#788c5d</ span >
419 </ div >
420 </ div >
421 </ div >
422
423 <!-- Actions Section (ALWAYS KEEP THIS) -->
424 < div class = "control-section" >
425 < h3 >Actions</ h3 >
426 < div class = "button-row" >
427 < button class = "button" onclick = " resetParameters ()" >Reset</ button >
428 </ div >
429 </ div >
430 </ div >
431
432 <!-- Main Canvas Area -->
433 < div class = "canvas-area" >
434 < div id = "canvas-container" >
435 < div class = "loading" >Initializing generative art...</ div >
436 </ div >
437 </ div >
438 </ div >
439
440 < script >
441 // ═══════════════════════════════════════════════════════════════════════
442 // GENERATIVE ART PARAMETERS - CUSTOMIZE FOR YOUR ALGORITHM
443 // ═══════════════════════════════════════════════════════════════════════
444
445 let params = {
446 seed: 12345 ,
447 particleCount: 5000 ,
448 flowSpeed: 0.5 ,
449 noiseScale: 0.005 ,
450 trailLength: 8 ,
451 colorPalette: [ '#d97757' , '#6a9bcc' , '#788c5d' ]
452 };
453
454 let defaultParams = { ... params}; // Store defaults for reset
455
456 // ═══════════════════════════════════════════════════════════════════════
457 // P5.JS GENERATIVE ART ALGORITHM - REPLACE WITH YOUR VISION
458 // ═══════════════════════════════════════════════════════════════════════
459
460 let particles = [];
461 let flowField = [];
462 let cols, rows;
463 let scl = 10 ; // Flow field resolution
464
465 function setup () {
466 let canvas = createCanvas ( 1200 , 1200 );
467 canvas. parent ( 'canvas-container' );
468
469 initializeSystem ();
470
471 // Remove loading message
472 document. querySelector ( '.loading' ).style.display = 'none' ;
473 }
474
475 function initializeSystem () {
476 // Seed the randomness for reproducibility
477 randomSeed (params.seed);
478 noiseSeed (params.seed);
479
480 // Clear particles and recreate
481 particles = [];
482
483 // Initialize particles
484 for ( let i = 0 ; i < params.particleCount; i ++ ) {
485 particles. push ( new Particle ());
486 }
487
488 // Calculate flow field dimensions
489 cols = floor (width / scl);
490 rows = floor (height / scl);
491
492 // Generate flow field
493 generateFlowField ();
494
495 // Clear background
496 background ( 250 , 249 , 245 ); // Anthropic light background
497 }
498
499 function generateFlowField () {
500 // fill this in
501 }
502
503 function draw () {
504 // fill this in
505 }
506
507 // ═══════════════════════════════════════════════════════════════════════
508 // PARTICLE SYSTEM - CUSTOMIZE FOR YOUR ALGORITHM
509 // ═══════════════════════════════════════════════════════════════════════
510
511 class Particle {
512 constructor () {
513 // fill this in
514 }
515 // fill this in
516 }
517
518 // ═══════════════════════════════════════════════════════════════════════
519 // UI CONTROL HANDLERS - CUSTOMIZE FOR YOUR PARAMETERS
520 // ═══════════════════════════════════════════════════════════════════════
521
522 function updateParam ( paramName , value ) {
523 // fill this in
524 }
525
526 function updateColor ( colorId , value ) {
527 // fill this in
528 }
529
530 // ═══════════════════════════════════════════════════════════════════════
531 // SEED CONTROL FUNCTIONS - ALWAYS KEEP THESE
532 // ═══════════════════════════════════════════════════════════════════════
533
534 function updateSeedDisplay () {
535 document. getElementById ( 'seed-input' ).value = params.seed;
536 }
537
538 function updateSeed () {
539 let input = document. getElementById ( 'seed-input' );
540 let newSeed = parseInt (input.value);
541 if (newSeed && newSeed > 0 ) {
542 params.seed = newSeed;
543 initializeSystem ();
544 } else {
545 // Reset to current seed if invalid
546 updateSeedDisplay ();
547 }
548 }
549
550 function previousSeed () {
551 params.seed = Math. max ( 1 , params.seed - 1 );
552 updateSeedDisplay ();
553 initializeSystem ();
554 }
555
556 function nextSeed () {
557 params.seed = params.seed + 1 ;
558 updateSeedDisplay ();
559 initializeSystem ();
560 }
561
562 function randomSeedAndUpdate () {
563 params.seed = Math. floor (Math. random () * 999999 ) + 1 ;
564 updateSeedDisplay ();
565 initializeSystem ();
566 }
567
568 function resetParameters () {
569 params = { ... defaultParams};
570
571 // Update UI elements
572 document. getElementById ( 'particleCount' ).value = params.particleCount;
573 document. getElementById ( 'particleCount-value' ).textContent = params.particleCount;
574 document. getElementById ( 'flowSpeed' ).value = params.flowSpeed;
575 document. getElementById ( 'flowSpeed-value' ).textContent = params.flowSpeed;
576 document. getElementById ( 'noiseScale' ).value = params.noiseScale;
577 document. getElementById ( 'noiseScale-value' ).textContent = params.noiseScale;
578 document. getElementById ( 'trailLength' ).value = params.trailLength;
579 document. getElementById ( 'trailLength-value' ).textContent = params.trailLength;
580
581 // Reset colors
582 document. getElementById ( 'color1' ).value = params.colorPalette[ 0 ];
583 document. getElementById ( 'color1-value' ).textContent = params.colorPalette[ 0 ];
584 document. getElementById ( 'color2' ).value = params.colorPalette[ 1 ];
585 document. getElementById ( 'color2-value' ).textContent = params.colorPalette[ 1 ];
586 document. getElementById ( 'color3' ).value = params.colorPalette[ 2 ];
587 document. getElementById ( 'color3-value' ).textContent = params.colorPalette[ 2 ];
588
589 updateSeedDisplay ();
590 initializeSystem ();
591 }
592
593 // Initialize UI on load
594 window. addEventListener ( 'load' , function () {
595 updateSeedDisplay ();
596 });
597 </ script >
598 </ body >
599 </ html >