| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599 |
- <!DOCTYPE html>
- <!--
- THIS IS A TEMPLATE THAT SHOULD BE USED EVERY TIME AND MODIFIED.
- WHAT TO KEEP:
- ✓ Overall structure (header, sidebar, main content)
- ✓ Anthropic branding (colors, fonts, layout)
- ✓ Seed navigation section (always include this)
- ✓ Self-contained artifact (everything inline)
- WHAT TO CREATIVELY EDIT:
- ✗ The p5.js algorithm (implement YOUR vision)
- ✗ The parameters (define what YOUR art needs)
- ✗ The UI controls (match YOUR parameters)
- Let your philosophy guide the implementation.
- The world is your oyster - be creative!
- -->
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Generative Art Viewer</title>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>
- <link rel="preconnect" href="https://fonts.googleapis.com">
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
- <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&family=Lora:wght@400;500&display=swap" rel="stylesheet">
- <style>
- /* Anthropic Brand Colors */
- :root {
- --anthropic-dark: #141413;
- --anthropic-light: #faf9f5;
- --anthropic-mid-gray: #b0aea5;
- --anthropic-light-gray: #e8e6dc;
- --anthropic-orange: #d97757;
- --anthropic-blue: #6a9bcc;
- --anthropic-green: #788c5d;
- }
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
- body {
- font-family: 'Poppins', sans-serif;
- background: linear-gradient(135deg, var(--anthropic-light) 0%, #f5f3ee 100%);
- min-height: 100vh;
- color: var(--anthropic-dark);
- }
- .container {
- display: flex;
- min-height: 100vh;
- padding: 20px;
- gap: 20px;
- }
- /* Sidebar */
- .sidebar {
- width: 320px;
- flex-shrink: 0;
- background: rgba(255, 255, 255, 0.95);
- backdrop-filter: blur(10px);
- padding: 24px;
- border-radius: 12px;
- box-shadow: 0 10px 30px rgba(20, 20, 19, 0.1);
- overflow-y: auto;
- overflow-x: hidden;
- }
- .sidebar h1 {
- font-family: 'Lora', serif;
- font-size: 24px;
- font-weight: 500;
- color: var(--anthropic-dark);
- margin-bottom: 8px;
- }
- .sidebar .subtitle {
- color: var(--anthropic-mid-gray);
- font-size: 14px;
- margin-bottom: 32px;
- line-height: 1.4;
- }
- /* Control Sections */
- .control-section {
- margin-bottom: 32px;
- }
- .control-section h3 {
- font-size: 16px;
- font-weight: 600;
- color: var(--anthropic-dark);
- margin-bottom: 16px;
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .control-section h3::before {
- content: '•';
- color: var(--anthropic-orange);
- font-weight: bold;
- }
- /* Seed Controls */
- .seed-input {
- width: 100%;
- background: var(--anthropic-light);
- padding: 12px;
- border-radius: 8px;
- font-family: 'Courier New', monospace;
- font-size: 14px;
- margin-bottom: 12px;
- border: 1px solid var(--anthropic-light-gray);
- text-align: center;
- }
- .seed-input:focus {
- outline: none;
- border-color: var(--anthropic-orange);
- box-shadow: 0 0 0 2px rgba(217, 119, 87, 0.1);
- background: white;
- }
- .seed-controls {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 8px;
- margin-bottom: 8px;
- }
- .regen-button {
- margin-bottom: 0;
- }
- /* Parameter Controls */
- .control-group {
- margin-bottom: 20px;
- }
- .control-group label {
- display: block;
- font-size: 14px;
- font-weight: 500;
- color: var(--anthropic-dark);
- margin-bottom: 8px;
- }
- .slider-container {
- display: flex;
- align-items: center;
- gap: 12px;
- }
- .slider-container input[type="range"] {
- flex: 1;
- height: 4px;
- background: var(--anthropic-light-gray);
- border-radius: 2px;
- outline: none;
- -webkit-appearance: none;
- }
- .slider-container input[type="range"]::-webkit-slider-thumb {
- -webkit-appearance: none;
- width: 16px;
- height: 16px;
- background: var(--anthropic-orange);
- border-radius: 50%;
- cursor: pointer;
- transition: all 0.2s ease;
- }
- .slider-container input[type="range"]::-webkit-slider-thumb:hover {
- transform: scale(1.1);
- background: #c86641;
- }
- .slider-container input[type="range"]::-moz-range-thumb {
- width: 16px;
- height: 16px;
- background: var(--anthropic-orange);
- border-radius: 50%;
- border: none;
- cursor: pointer;
- transition: all 0.2s ease;
- }
- .value-display {
- font-family: 'Courier New', monospace;
- font-size: 12px;
- color: var(--anthropic-mid-gray);
- min-width: 60px;
- text-align: right;
- }
- /* Color Pickers */
- .color-group {
- margin-bottom: 16px;
- }
- .color-group label {
- display: block;
- font-size: 12px;
- color: var(--anthropic-mid-gray);
- margin-bottom: 4px;
- }
- .color-picker-container {
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .color-picker-container input[type="color"] {
- width: 32px;
- height: 32px;
- border: none;
- border-radius: 6px;
- cursor: pointer;
- background: none;
- padding: 0;
- }
- .color-value {
- font-family: 'Courier New', monospace;
- font-size: 12px;
- color: var(--anthropic-mid-gray);
- }
- /* Buttons */
- .button {
- background: var(--anthropic-orange);
- color: white;
- border: none;
- padding: 10px 16px;
- border-radius: 6px;
- font-size: 14px;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.2s ease;
- width: 100%;
- }
- .button:hover {
- background: #c86641;
- transform: translateY(-1px);
- }
- .button:active {
- transform: translateY(0);
- }
- .button.secondary {
- background: var(--anthropic-blue);
- }
- .button.secondary:hover {
- background: #5a8bb8;
- }
- .button.tertiary {
- background: var(--anthropic-green);
- }
- .button.tertiary:hover {
- background: #6b7b52;
- }
- .button-row {
- display: flex;
- gap: 8px;
- }
- .button-row .button {
- flex: 1;
- }
- /* Canvas Area */
- .canvas-area {
- flex: 1;
- display: flex;
- align-items: center;
- justify-content: center;
- min-width: 0;
- }
- #canvas-container {
- width: 100%;
- max-width: 1000px;
- border-radius: 12px;
- overflow: hidden;
- box-shadow: 0 20px 40px rgba(20, 20, 19, 0.1);
- background: white;
- }
- #canvas-container canvas {
- display: block;
- width: 100% !important;
- height: auto !important;
- }
- /* Loading State */
- .loading {
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 18px;
- color: var(--anthropic-mid-gray);
- }
- /* Responsive - Stack on mobile */
- @media (max-width: 600px) {
- .container {
- flex-direction: column;
- }
- .sidebar {
- width: 100%;
- }
- .canvas-area {
- padding: 20px;
- }
- }
- </style>
- </head>
- <body>
- <div class="container">
- <!-- Control Sidebar -->
- <div class="sidebar">
- <!-- Headers (CUSTOMIZE THIS FOR YOUR ART) -->
- <h1>TITLE - EDIT</h1>
- <div class="subtitle">SUBHEADER - EDIT</div>
- <!-- Seed Section (ALWAYS KEEP THIS) -->
- <div class="control-section">
- <h3>Seed</h3>
- <input type="number" id="seed-input" class="seed-input" value="12345" onchange="updateSeed()">
- <div class="seed-controls">
- <button class="button secondary" onclick="previousSeed()">← Prev</button>
- <button class="button secondary" onclick="nextSeed()">Next →</button>
- </div>
- <button class="button tertiary regen-button" onclick="randomSeedAndUpdate()">↻ Random</button>
- </div>
- <!-- Parameters Section (CUSTOMIZE THIS FOR YOUR ART) -->
- <div class="control-section">
- <h3>Parameters</h3>
-
- <!-- Particle Count -->
- <div class="control-group">
- <label>Particle Count</label>
- <div class="slider-container">
- <input type="range" id="particleCount" min="1000" max="10000" step="500" value="5000" oninput="updateParam('particleCount', this.value)">
- <span class="value-display" id="particleCount-value">5000</span>
- </div>
- </div>
- <!-- Flow Speed -->
- <div class="control-group">
- <label>Flow Speed</label>
- <div class="slider-container">
- <input type="range" id="flowSpeed" min="0.1" max="2.0" step="0.1" value="0.5" oninput="updateParam('flowSpeed', this.value)">
- <span class="value-display" id="flowSpeed-value">0.5</span>
- </div>
- </div>
- <!-- Noise Scale -->
- <div class="control-group">
- <label>Noise Scale</label>
- <div class="slider-container">
- <input type="range" id="noiseScale" min="0.001" max="0.02" step="0.001" value="0.005" oninput="updateParam('noiseScale', this.value)">
- <span class="value-display" id="noiseScale-value">0.005</span>
- </div>
- </div>
- <!-- Trail Length -->
- <div class="control-group">
- <label>Trail Length</label>
- <div class="slider-container">
- <input type="range" id="trailLength" min="2" max="20" step="1" value="8" oninput="updateParam('trailLength', this.value)">
- <span class="value-display" id="trailLength-value">8</span>
- </div>
- </div>
- </div>
- <!-- Colors Section (OPTIONAL - CUSTOMIZE OR REMOVE) -->
- <div class="control-section">
- <h3>Colors</h3>
-
- <!-- Color 1 -->
- <div class="color-group">
- <label>Primary Color</label>
- <div class="color-picker-container">
- <input type="color" id="color1" value="#d97757" onchange="updateColor('color1', this.value)">
- <span class="color-value" id="color1-value">#d97757</span>
- </div>
- </div>
- <!-- Color 2 -->
- <div class="color-group">
- <label>Secondary Color</label>
- <div class="color-picker-container">
- <input type="color" id="color2" value="#6a9bcc" onchange="updateColor('color2', this.value)">
- <span class="color-value" id="color2-value">#6a9bcc</span>
- </div>
- </div>
- <!-- Color 3 -->
- <div class="color-group">
- <label>Accent Color</label>
- <div class="color-picker-container">
- <input type="color" id="color3" value="#788c5d" onchange="updateColor('color3', this.value)">
- <span class="color-value" id="color3-value">#788c5d</span>
- </div>
- </div>
- </div>
- <!-- Actions Section (ALWAYS KEEP THIS) -->
- <div class="control-section">
- <h3>Actions</h3>
- <div class="button-row">
- <button class="button" onclick="resetParameters()">Reset</button>
- </div>
- </div>
- </div>
- <!-- Main Canvas Area -->
- <div class="canvas-area">
- <div id="canvas-container">
- <div class="loading">Initializing generative art...</div>
- </div>
- </div>
- </div>
- <script>
- // ═══════════════════════════════════════════════════════════════════════
- // GENERATIVE ART PARAMETERS - CUSTOMIZE FOR YOUR ALGORITHM
- // ═══════════════════════════════════════════════════════════════════════
- let params = {
- seed: 12345,
- particleCount: 5000,
- flowSpeed: 0.5,
- noiseScale: 0.005,
- trailLength: 8,
- colorPalette: ['#d97757', '#6a9bcc', '#788c5d']
- };
- let defaultParams = {...params}; // Store defaults for reset
- // ═══════════════════════════════════════════════════════════════════════
- // P5.JS GENERATIVE ART ALGORITHM - REPLACE WITH YOUR VISION
- // ═══════════════════════════════════════════════════════════════════════
- let particles = [];
- let flowField = [];
- let cols, rows;
- let scl = 10; // Flow field resolution
- function setup() {
- let canvas = createCanvas(1200, 1200);
- canvas.parent('canvas-container');
-
- initializeSystem();
-
- // Remove loading message
- document.querySelector('.loading').style.display = 'none';
- }
- function initializeSystem() {
- // Seed the randomness for reproducibility
- randomSeed(params.seed);
- noiseSeed(params.seed);
- // Clear particles and recreate
- particles = [];
-
- // Initialize particles
- for (let i = 0; i < params.particleCount; i++) {
- particles.push(new Particle());
- }
- // Calculate flow field dimensions
- cols = floor(width / scl);
- rows = floor(height / scl);
-
- // Generate flow field
- generateFlowField();
- // Clear background
- background(250, 249, 245); // Anthropic light background
- }
- function generateFlowField() {
- // fill this in
- }
- function draw() {
- // fill this in
- }
- // ═══════════════════════════════════════════════════════════════════════
- // PARTICLE SYSTEM - CUSTOMIZE FOR YOUR ALGORITHM
- // ═══════════════════════════════════════════════════════════════════════
- class Particle {
- constructor() {
- // fill this in
- }
- // fill this in
- }
- // ═══════════════════════════════════════════════════════════════════════
- // UI CONTROL HANDLERS - CUSTOMIZE FOR YOUR PARAMETERS
- // ═══════════════════════════════════════════════════════════════════════
- function updateParam(paramName, value) {
- // fill this in
- }
- function updateColor(colorId, value) {
- // fill this in
- }
- // ═══════════════════════════════════════════════════════════════════════
- // SEED CONTROL FUNCTIONS - ALWAYS KEEP THESE
- // ═══════════════════════════════════════════════════════════════════════
- function updateSeedDisplay() {
- document.getElementById('seed-input').value = params.seed;
- }
- function updateSeed() {
- let input = document.getElementById('seed-input');
- let newSeed = parseInt(input.value);
- if (newSeed && newSeed > 0) {
- params.seed = newSeed;
- initializeSystem();
- } else {
- // Reset to current seed if invalid
- updateSeedDisplay();
- }
- }
- function previousSeed() {
- params.seed = Math.max(1, params.seed - 1);
- updateSeedDisplay();
- initializeSystem();
- }
- function nextSeed() {
- params.seed = params.seed + 1;
- updateSeedDisplay();
- initializeSystem();
- }
- function randomSeedAndUpdate() {
- params.seed = Math.floor(Math.random() * 999999) + 1;
- updateSeedDisplay();
- initializeSystem();
- }
- function resetParameters() {
- params = {...defaultParams};
-
- // Update UI elements
- document.getElementById('particleCount').value = params.particleCount;
- document.getElementById('particleCount-value').textContent = params.particleCount;
- document.getElementById('flowSpeed').value = params.flowSpeed;
- document.getElementById('flowSpeed-value').textContent = params.flowSpeed;
- document.getElementById('noiseScale').value = params.noiseScale;
- document.getElementById('noiseScale-value').textContent = params.noiseScale;
- document.getElementById('trailLength').value = params.trailLength;
- document.getElementById('trailLength-value').textContent = params.trailLength;
-
- // Reset colors
- document.getElementById('color1').value = params.colorPalette[0];
- document.getElementById('color1-value').textContent = params.colorPalette[0];
- document.getElementById('color2').value = params.colorPalette[1];
- document.getElementById('color2-value').textContent = params.colorPalette[1];
- document.getElementById('color3').value = params.colorPalette[2];
- document.getElementById('color3-value').textContent = params.colorPalette[2];
-
- updateSeedDisplay();
- initializeSystem();
- }
- // Initialize UI on load
- window.addEventListener('load', function() {
- updateSeedDisplay();
- });
- </script>
- </body>
- </html>
|