anycoder-62329bfb / index.html
Keeg42069's picture
Upload folder using huggingface_hub
6ed37a0 verified
Raw
History Blame Contribute Delete
27.7 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Generative Shape Explorer 3000</title>
<!-- FontAwesome for Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--bg-color: #0f172a;
--card-bg: #1e293b;
--primary: #3b82f6;
--primary-hover: #2563eb;
--accent: #8b5cf6;
--text-main: #f8fafc;
--text-muted: #94a3b8;
--border: #334155;
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--header-height: 70px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
background-color: var(--bg-color);
color: var(--text-main);
min-height: 100vh;
display: flex;
flex-direction: column;
overflow-x: hidden;
}
/* Header */
header {
position: sticky;
top: 0;
z-index: 100;
background: rgba(15, 23, 42, 0.85);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--border);
height: var(--header-height);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 2rem;
box-shadow: var(--shadow);
}
.brand {
display: flex;
align-items: center;
gap: 10px;
font-size: 1.25rem;
font-weight: 700;
color: var(--text-main);
}
.brand i {
color: var(--primary);
}
.anycoder-link {
font-size: 0.9rem;
color: var(--text-muted);
text-decoration: none;
transition: color 0.2s;
display: flex;
align-items: center;
gap: 6px;
background: rgba(255, 255, 255, 0.05);
padding: 6px 12px;
border-radius: 20px;
border: 1px solid var(--border);
}
.anycoder-link:hover {
color: var(--primary);
border-color: var(--primary);
background: rgba(59, 130, 246, 0.1);
}
/* Controls Section */
.controls {
padding: 2rem;
display: flex;
flex-wrap: wrap;
gap: 1rem;
align-items: center;
justify-content: center;
background: linear-gradient(180deg, rgba(15, 23, 42, 1) 0%, rgba(15, 23, 42, 0) 100%);
}
.btn {
background-color: var(--card-bg);
color: var(--text-main);
border: 1px solid var(--border);
padding: 0.75rem 1.5rem;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 8px;
font-size: 0.95rem;
}
.btn:hover {
background-color: var(--border);
transform: translateY(-1px);
}
.btn-primary {
background-color: var(--primary);
border-color: var(--primary);
color: white;
box-shadow: 0 0 15px rgba(59, 130, 246, 0.4);
}
.btn-primary:hover {
background-color: var(--primary-hover);
box-shadow: 0 0 20px rgba(59, 130, 246, 0.6);
}
.btn-danger {
color: #ef4444;
border-color: rgba(239, 68, 68, 0.3);
}
.btn-danger:hover {
background-color: rgba(239, 68, 68, 0.1);
}
/* Gallery Grid */
main {
flex: 1;
padding: 1rem 2rem 4rem 2rem;
max-width: 1600px;
margin: 0 auto;
width: 100%;
}
.gallery-stats {
margin-bottom: 1rem;
color: var(--text-muted);
font-size: 0.9rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1.5rem;
width: 100%;
}
.shape-card {
background-color: var(--card-bg);
border-radius: 12px;
overflow: hidden;
border: 1px solid var(--border);
transition: transform 0.3s ease, box-shadow 0.3s ease;
position: relative;
aspect-ratio: 1;
display: flex;
align-items: center;
justify-content: center;
}
.shape-card:hover {
transform: translateY(-5px) scale(1.02);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);
border-color: var(--primary);
z-index: 2;
}
.shape-card img {
width: 100%;
height: 100%;
object-fit: contain;
background: radial-gradient(circle at center, #263345 0%, #1e293b 100%);
}
.shape-meta {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: rgba(15, 23, 42, 0.9);
padding: 8px;
font-size: 0.75rem;
color: var(--text-muted);
transform: translateY(100%);
transition: transform 0.2s ease;
display: flex;
justify-content: space-between;
}
.shape-card:hover .shape-meta {
transform: translateY(0);
}
/* Loading Overlay */
.loader-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(15, 23, 42, 0.8);
backdrop-filter: blur(5px);
z-index: 200;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
}
.loader-overlay.active {
opacity: 1;
pointer-events: all;
}
.spinner {
width: 50px;
height: 50px;
border: 4px solid var(--border);
border-top: 4px solid var(--primary);
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 1rem;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-text {
font-size: 1.1rem;
font-weight: 600;
}
/* Toast Notification */
.toast {
position: fixed;
bottom: 2rem;
right: 2rem;
background: var(--card-bg);
border: 1px solid var(--primary);
padding: 1rem 1.5rem;
border-radius: 8px;
color: var(--text-main);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
transform: translateY(100px);
opacity: 0;
transition: all 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55);
z-index: 300;
display: flex;
align-items: center;
gap: 12px;
}
.toast.show {
transform: translateY(0);
opacity: 1;
}
.toast i {
color: #10b981;
}
/* Footer */
footer {
text-align: center;
padding: 2rem;
color: var(--text-muted);
font-size: 0.85rem;
border-top: 1px solid var(--border);
margin-top: auto;
}
/* Responsive */
@media (max-width: 768px) {
header {
padding: 0 1rem;
}
.brand span {
display: none;
}
.controls {
padding: 1rem;
flex-direction: column;
align-items: stretch;
}
.grid-container {
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
gap: 1rem;
}
}
</style>
</head>
<body>
<!-- Header -->
<header>
<div class="brand">
<i class="fa-solid fa-shapes"></i>
<span>ShapeGen 3000</span>
</div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
<i class="fa-solid fa-code"></i> Built with anycoder
</a>
</header>
<!-- Controls -->
<section class="controls">
<button class="btn btn-primary" id="generateBtn">
<i class="fa-solid fa-wand-magic-sparkles"></i> Generate 300 Images
</button>
<button class="btn btn-danger" id="clearBtn">
<i class="fa-solid fa-trash-can"></i> Clear Gallery
</button>
</section>
<!-- Main Content -->
<main>
<div class="gallery-stats">
<span id="statusText">Ready to generate.</span>
<span id="countText">Items: 0</span>
</div>
<div class="grid-container" id="gallery">
<!-- Images will be injected here -->
</div>
</main>
<!-- Footer -->
<footer>
<p>Procedural Generation using HTML5 Canvas & JavaScript</p>
</footer>
<!-- Loading Overlay -->
<div class="loader-overlay" id="loader">
<div class="spinner"></div>
<div class="loading-text" id="loadingText">Initializing...</div>
</div>
<!-- Toast Notification -->
<div class="toast" id="toast">
<i class="fa-solid fa-check-circle"></i>
<span id="toastMessage">Operation successful</span>
</div>
<script>
/**
* Shape Generator Logic
* Handles math for 2D and simulated 3D shapes
*/
const ShapeGenerator = {
canvas: document.createElement('canvas'),
ctx: null,
width: 400,
height: 400,
init() {
this.canvas.width = this.width;
this.canvas.height = this.height;
this.ctx = this.canvas.getContext('2d');
},
// Helper: Random Integer
randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
},
// Helper: Random Color (HSL for vibrancy)
randomColor() {
const h = this.randomInt(0, 360);
const s = this.randomInt(60, 100);
const l = this.randomInt(40, 70);
return `hsl(${h}, ${s}%, ${l}%)`;
},
// Helper: 3D Rotation Matrix
rotate3D(x, y, z, angleX, angleY) {
// Rotate around Y
let cosY = Math.cos(angleY);
let sinY = Math.sin(angleY);
let x1 = x * cosY - z * sinY;
let z1 = z * cosY + x * sinY;
// Rotate around X
let cosX = Math.cos(angleX);
let sinX = Math.sin(angleX);
let y2 = y * cosX - z1 * sinX;
let z2 = z1 * cosX + y * sinX;
return { x: x1, y: y2, z: z2 };
},
// Helper: Project 3D point to 2D canvas
project(x, y, z) {
const scale = 400; // Perspective scale
const distance = 4; // Camera distance
const factor = scale / (distance - z);
return {
x: x * factor + this.width / 2,
y: y * factor + this.height / 2
};
},
clear() {
this.ctx.clearRect(0, 0, this.width, this.height);
// Add a subtle background gradient
const grad = this.ctx.createRadialGradient(200, 200, 50, 200, 200, 300);
grad.addColorStop(0, '#263345');
grad.addColorStop(1, '#0f172a');
this.ctx.fillStyle = grad;
this.ctx.fillRect(0, 0, this.width, this.height);
},
generateImage(id) {
this.clear();
const type = Math.random() > 0.5 ? '3d' : '2d';
const color = this.randomColor();
const accentColor = this.randomColor();
// Randomize parameters
const params = {
angle: Math.random() * Math.PI * 2, // Rotation angle
depth: Math.random() * 0.5 + 0.5, // Depth scale
size: Math.random() * 0.5 + 0.5, // Overall size
lineWidth: Math.random() * 3 + 1,
filled: Math.random() > 0.3
};
let shapeName = "";
if (type === '2d') {
// 2D Shapes with simulated depth (extrusion)
const shapes = ['square', 'triangle', 'pentagon', 'hexagon', 'circle', 'star'];
const shape = shapes[Math.floor(Math.random() * shapes.length)];
shapeName = shape.toUpperCase();
this.draw2DShape(shape, color, params);
} else {
// 3D Shapes
const shapes = ['cube', 'pyramid', 'octahedron', 'torus'];
const shape = shapes[Math.floor(Math.random() * shapes.length)];
shapeName = shape.toUpperCase();
this.draw3DShape(shape, color, params);
}
return {
src: this.canvas.toDataURL('image/png'),
meta: `${shapeName} | Angle: ${Math.round(params.angle * 57)}° | Depth: ${params.depth.toFixed(2)}`
};
},
draw2DShape(shape, color, params) {
const cx = this.width / 2;
const cy = this.height / 2;
const size = 100 * params.size;
this.ctx.save();
this.ctx.translate(cx, cy);
this.ctx.rotate(params.angle);
this.ctx.strokeStyle = color;
this.ctx.fillStyle = color.replace(')', ', 0.2)'); // Transparent fill
this.ctx.lineWidth = params.lineWidth;
this.ctx.lineJoin = 'round';
// Simulate depth by drawing multiple layers (Extrusion effect)
const layers = Math.floor(params.depth * 10);
const offset = 4;
this.ctx.beginPath();
for(let i = 0; i < layers; i++) {
this.drawPath(shape, size - (i * offset / 2));
if (params.filled && i === 0) this.ctx.fill();
if (i < layers - 1) {
this.ctx.globalAlpha = 1 - (i / layers);
this.ctx.stroke();
this.ctx.beginPath();
}
}
this.ctx.globalAlpha = 1;
this.ctx.stroke(); // Final stroke
// Add a "center point" or highlight
this.ctx.fillStyle = '#fff';
this.ctx.beginPath();
this.ctx.arc(0, 0, 3, 0, Math.PI * 2);
this.ctx.fill();
this.ctx.restore();
},
drawPath(shape, size) {
if (shape === 'circle') {
this.ctx.arc(0, 0, size, 0, Math.PI * 2);
} else if (shape === 'square') {
this.ctx.rect(-size, -size, size * 2, size * 2);
} else if (shape === 'triangle') {
this.ctx.moveTo(0, -size);
this.ctx.lineTo(size, size);
this.ctx.lineTo(-size, size);
this.ctx.closePath();
} else if (shape === 'pentagon' || shape === 'hexagon') {
const sides = shape === 'pentagon' ? 5 : 6;
for (let i = 0; i <= sides; i++) {
const angle = (i * 2 * Math.PI) / sides - Math.PI / 2;
const x = size * Math.cos(angle);
const y = size * Math.sin(angle);
if (i === 0) this.ctx.moveTo(x, y);
else this.ctx.lineTo(x, y);
}
} else if (shape === 'star') {
const points = 5;
const outer = size;
const inner = size / 2;
for (let i = 0; i < points * 2; i++) {
const r = (i % 2 === 0) ? outer : inner;
const angle = (i * Math.PI) / points - Math.PI / 2;
const x = r * Math.cos(angle);
const y = r * Math.sin(angle);
if (i === 0) this.ctx.moveTo(x, y);
else this.ctx.lineTo(x, y);
}
this.ctx.closePath();
}
},
draw3DShape(shape, color, params) {
const vertices = [];
const edges = [];
const size = 120 * params.size;
// Define Wireframes
if (shape === 'cube') {
// 8 Vertices
for(let x=-1; x<=1; x+=2) {
for(let y=-1; y<=1; y+=2) {
for(let z=-1; z<=1; z+=2) {
vertices.push({x: x*size, y: y*size, z: z*size});
}
}
}
// 12 Edges
for(let i=0; i<8; i++) {
for(let j=i+1; j<8; j++) {
// Connect if differ by exactly 1 coordinate
const diff = Math.abs(vertices[i].x - vertices[j].x) +
Math.abs(vertices[i].y - vertices[j].y) +
Math.abs(vertices[i].z - vertices[j].z);
if(diff === size*2) edges.push([i, j]);
}
}
} else if (shape === 'pyramid') {
// 5 Vertices (Square base, point top)
const h = size * 1.5;
vertices.push({x:0, y:-h, z:0}); // Tip
vertices.push({x:-size, y:size, z:-size});
vertices.push({x:size, y:size, z:-size});
vertices.push({x:size, y:size, z:size});
vertices.push({x:-size, y:size, z:size});
edges.push([0,1], [0,2], [0,3], [0,4], [1,2], [2,3], [3,4], [4,1]);
} else if (shape === 'octahedron') {
// 6 Vertices
vertices.push({x:size, y:0, z:0});
vertices.push({x:-size, y:0, z:0});
vertices.push({x:0, y:size, z:0});
vertices.push({x:0, y:-size, z:0});
vertices.push({x:0, y:0, z:size});
vertices.push({x:0, y:0, z:-size});
// Connect all non-opposites
for(let i=0; i<6; i++){
for(let j=i+1; j<6; j++){
if (i+j !== 1 && i+j !== 5 && i+j !== 9) { // Simple logic to skip exact opposites
// Better logic: distance check
const v1 = vertices[i];
const v2 = vertices[j];
const dist = Math.sqrt((v1.x-v2.x)**2 + (v1.y-v2.y)**2 + (v1.z-v2.z)**2);
if (Math.abs(dist - size*1.414) < 1) edges.push([i,j]);
}
}
}
} else if (shape === 'torus') {
// Simulated Torus (Loops)
const rings = 3;
const segments = 16;
const R = size;
const r = size * 0.4;
// Draw 3 circles rotated around Y
for(let ring=0; ring<rings; ring++) {
const ringAngle = (ring / rings) * Math.PI * 2;
this.ctx.beginPath();
for(let i=0; i<=segments; i++) {
const theta = (i/segments) * Math.PI * 2;
// Torus parametric equation
let x = (R + r * Math.cos(theta)) * Math.cos(ringAngle);
let y = r * Math.sin(theta);
let z = (R + r * Math.cos(theta)) * Math.sin(ringAngle);
// Apply rotation
const rot = this.rotate3D(x, y, z, params.angle, params.angle * 0.5);
const proj = this.project(rot.x, rot.y, rot.z);
if(i===0) this.ctx.moveTo(proj.x, proj.y);
else this.ctx.lineTo(proj.x, proj.y);
}
this.ctx.strokeStyle = color;
this.ctx.lineWidth = params.lineWidth;
this.ctx.stroke();
}
return; // Torus handles its own drawing
}
// Transform and Draw Vertices/Edges
this.ctx.strokeStyle = color;
this.ctx.fillStyle = color;
this.ctx.lineWidth = params.lineWidth;
this.ctx.lineCap = 'round';
// Draw Edges
this.ctx.beginPath();
edges.forEach(edge => {
const v1 = this.rotate3D(vertices[edge[0]].x, vertices[edge[0]].y, vertices[edge[0]].z, params.angle, params.angle * 0.7);
const p1 = this.project(v1.x, v1.y, v1.z);
const v2 = this.rotate3D(vertices[edge[1]].x, vertices[edge[1]].y, vertices[edge[1]].z, params.angle, params.angle * 0.7);
const p2 = this.project(v2.x, v2.y, v2.z);
this.ctx.moveTo(p1.x, p1.y);
this.ctx.lineTo(p2.x, p2.y);
});
this.ctx.stroke();
// Draw Vertices (Dots) for depth perception
vertices.forEach(v => {
const rot = this.rotate3D(v.x, v.y, v.z, params.angle, params.angle * 0.7);
const proj = this.project(rot.x, rot.y, rot.z);
// Size based on Z depth (simple fog effect)
const scale = (rot.z + 300) / 400;
this.ctx.beginPath();
this.ctx.arc(proj.x, proj.y, 4 * scale, 0, Math.PI*2);
this.ctx.fill();
});
}
};
/**
* Application Logic
*/
const App = {
totalToGenerate: 300,
gallery: document.getElementById('gallery'),
loader: document.getElementById('loader'),
loadingText: document.getElementById('loadingText'),
countText: document.getElementById('countText'),
statusText: document.getElementById('statusText'),
init() {
ShapeGenerator.init();
document.getElementById('generateBtn').addEventListener('click', () => this.runGeneration());
document.getElementById('clearBtn').addEventListener('click', () => this.clearGallery());
},
async runGeneration() {
this.showLoader(true);
this.gallery.innerHTML = ''; // Clear previous
// Process in batches to keep UI responsive
const batchSize = 10;
let generated = 0;
while (generated < this.totalToGenerate) {
const batch = [];
for (let i = 0; i < batchSize && generated < this.totalToGenerate; i++) {
batch.push(generated);
generated++;
}
// Process batch
await new Promise(resolve => setTimeout(resolve, 0)); // Yield to main thread
batch.forEach(id => {
const imgData = ShapeGenerator.generateImage(id);
this.addImageToGrid(imgData, id);
});
this.updateLoader(Math.floor((generated / this.totalToGenerate) * 100), generated);
}
this.showLoader(false);
this.showToast(`Successfully generated ${this.totalToGenerate} unique shapes!`);
this.statusText.textContent = "Generation complete.";
},
addImageToGrid(data, index) {
const card = document.createElement('div');
card.className = 'shape-card';
const img = document.createElement('img');
img.src = data.src;
img.alt = `Generated shape ${index}`;
const meta = document.createElement('div');
meta.className = 'shape-meta';
meta.innerHTML = `<span>#${index + 1}</span> <span>${data.meta.split('|')[0]}</span>`;
card.appendChild(img);
card.appendChild(meta);
this.gallery.appendChild(card);
this.countText.textContent = `Items: ${this.gallery.children.length}`;
},
clearGallery() {
this.gallery.innerHTML = '';
this.countText.textContent = 'Items: 0';
this.statusText.textContent = "Gallery cleared.";
this.showToast("Gallery cleared.");
},
showLoader(show) {
if (show) {
this.loader.classList.add('active');
this.loadingText.textContent = "Generating 300 images...";
} else {
this.loader.classList.remove('active');
}
},
updateLoader(percent, count) {
this.loadingText.textContent = `Generating... ${percent}% (${count}/${this.totalToGenerate})`;
},
showToast(message) {
const toast = document.getElementById('toast');
const msgSpan = document.getElementById('toastMessage');
msgSpan.textContent = message;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
};
// Initialize App
document.addEventListener('DOMContentLoaded', () => {
App.init();
});
</script>
</body>
</html>