UNPKG

proxydi

Version:

A typed hierarchical DI container that resolves circular dependencies via Proxy

599 lines (511 loc) 20.8 kB
<!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>