anycoder-1225bfce / index.html
HI7RAI's picture
Upload folder using huggingface_hub
51f401d verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cinematic Light & FX Engine</title>
<style>
:root {
--bg-color: #050505;
--panel-bg: rgba(20, 20, 25, 0.85);
--accent: #00f2ff;
--accent-secondary: #ff0055;
--text-main: #e0e0e0;
--font-tech: 'Segoe UI', 'Roboto', monospace;
}
* {
box-sizing: border-box;
user-select: none;
}
body {
margin: 0;
padding: 0;
background-color: var(--bg-color);
color: var(--text-main);
font-family: var(--font-tech);
overflow: hidden;
height: 100vh;
display: flex;
flex-direction: column;
}
/* Header */
header {
padding: 10px 20px;
display: flex;
justify;
align-items-content: space-between: center;
background: linear-gradient(90deg, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0) 100%);
z-index: 100;
border-bottom: 1px solid #333;
}
.brand {
font-weight: 900;
font-size: 1.2rem;
letter-spacing: 2px;
text-transform: uppercase;
background: linear-gradient(45deg, var(--accent), #fff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.coder-link {
font-size: 0.8rem;
color: #888;
text-decoration: none;
border: 1px solid #444;
padding: 4px 8px;
border-radius: 4px;
transition: all 0.3s ease;
}
.coder-link:hover {
border-color: var(--accent);
color: var(--accent);
}
/* Main Layout */
.container {
display: flex;
flex: 1;
height: calc(100vh - 50px);
}
/* Canvas Area */
.viewport {
flex: 1;
position: relative;
display: flex;
justify-content: center;
align-items: center;
background: radial-gradient(circle at center, #1a1a1a 0%, #000 100%);
overflow: hidden;
}
canvas {
box-shadow: 0 0 50px rgba(0,0,0,0.8);
border: 1px solid #333;
max-width: 100%;
max-height: 100%;
}
/* HUD Overlay */
.hud {
position: absolute;
top: 0; left: 0; width: 100%; height: 100%;
pointer-events: none;
background:
linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%),
linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06));
background-size: 100% 2px, 3px 100%;
z-index: 10;
}
.fps-counter {
position: absolute;
top: 20px;
right: 20px;
font-family: monospace;
color: var(--accent);
font-size: 1.5rem;
text-shadow: 0 0 10px var(--accent);
z-index: 20;
}
/* Controls Sidebar */
.controls {
width: 320px;
background: var(--panel-bg);
backdrop-filter: blur(10px);
border-left: 1px solid #333;
padding: 20px;
display: flex;
flex-direction: column;
gap: 20px;
overflow-y: auto;
box-shadow: -5px 0 15px rgba(0,0,0,0.5);
}
.control-group {
display: flex;
flex-direction: column;
gap: 8px;
padding-bottom: 15px;
border-bottom: 1px solid #333;
}
.control-group:last-child {
border-bottom: none;
}
label {
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 1px;
color: #888;
display: flex;
justify-content: space-between;
}
.value-display {
color: var(--accent);
font-weight: bold;
}
/* Custom Range Sliders */
input[type=range] {
-webkit-appearance: none;
width: 100%;
background: transparent;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 16px;
width: 16px;
border-radius: 50%;
background: var(--text-main);
cursor: pointer;
margin-top: -6px;
box-shadow: 0 0 10px rgba(255,255,255,0.5);
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 4px;
cursor: pointer;
background: #444;
border-radius: 2px;
}
/* Specific Slider Colors */
#fpsInput::-webkit-slider-thumb { background: var(--accent); }
#satInput::-webkit-slider-thumb { background: #ff00aa; }
#lightInput::-webkit-slider-thumb { background: #ffaa00; }
#particleInput::-webkit-slider-thumb { background: #aaff00; }
.section-title {
font-size: 0.9rem;
color: #fff;
font-weight: 600;
margin-bottom: 5px;
display: flex;
align-items: center;
gap: 10px;
}
.section-title::before {
content: '';
display: block;
width: 4px;
height: 16px;
background: var(--accent-secondary);
}
/* Responsive */
@media (max-width: 768px) {
.container {
flex-direction: column;
}
.controls {
width: 100%;
height: 40%;
border-left: none;
border-top: 1px solid #333;
}
.viewport {
height: 60%;
}
}
</style>
</head>
<body>
<header>
<div class="brand">LUMINA ENGINE <span style="font-size:0.5em; color:#666">v1.0</span></div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" class="coder-link" target="_blank">Built with anycoder</a>
</header>
<div class="container">
<div class="viewport">
<div class="hud"></div>
<div class="fps-counter">FPS: <span id="fpsVal">60</span></div>
<canvas id="mainCanvas"></canvas>
</div>
<div class="controls">
<div class="section-title">Core Settings</div>
<div class="control-group">
<label>Target FPS <span class="value-display" id="fpsVal2">60</span></label>
<input type="range" id="fpsInput" min="10" max="144" value="60">
</div>
<div class="section-title">Color Calibration</div>
<div class="control-group">
<label>Saturation <span class="value-display" id="satVal">120%</span></label>
<input type="range" id="satInput" min="0" max="300" value="120">
</div>
<div class="control-group">
<label>Brightness (Exp) <span class="value-display" id="brightVal">1.0</span></label>
<input type="range" id="brightInput" min="50" max="200" value="100">
</div>
<div class="control-group">
<label>Contrast <span class="value-display" id="contVal">100%</span></label>
<input type="range" id="contInput" min="0" max="200" value="100">
</div>
<div class="section-title">Lighting & FX</div>
<div class="control-group">
<label>Light Intensity <span class="value-display" id="lightVal">50</span></label>
<input type="range" id="lightInput" min="0" max="100" value="50">
</div>
<div class="control-group">
<label>Ray Length <span class="value-display" id="rayVal">50</span></label>
<input type="range" id="rayInput" min="0" max="100" value="50">
</div>
<div class="section-title">Particles</div>
<div class="control-group">
<label>Dust Density <span class="value-display" id="partVal">100</span></label>
<input type="range" id="particleInput" min="0" max="500" value="100">
</div>
<div class="control-group">
<label>Particle Speed <span class="value-display" id="speedVal">1.0</span></label>
<input type="range" id="speedInput" min="0" max="500" value="100">
</div>
</div>
</div>
<script>
/**
* SYSTEM CORE
* Handles Canvas setup, Resize logic, and FPS throttling.
*/
const canvas = document.getElementById('mainCanvas');
const ctx = canvas.getContext('2d', { alpha: false }); // Optimize for no transparency on canvas bg
let width, height;
function resize() {
// Maintain 16:9 aspect ratio within the viewport, but fit within container
const container = document.querySelector('.viewport');
const aspect = 16 / 9;
let w = container.clientWidth;
let h = container.clientHeight;
if (w / h > aspect) {
w = h * aspect;
} else {
h = w / aspect;
}
canvas.width = 1920; // Internal render resolution (4k ready)
canvas.height = 1080;
// Scale via CSS
canvas.style.width = `${w}px`;
canvas.style.height = `${h}px`;
// Scale Context
const scaleX = canvas.width / w;
const scaleY = canvas.height / h;
// We actually render to full 1920x1080 coordinates for sharpness,
// then CSS scales it down.
}
window.addEventListener('resize', resize);
resize();
/**
* STATE MANAGEMENT
*/
const settings = {
fps: 60,
saturation: 120,
brightness: 100, // CSS filter uses 0-300+ usually, but standard is 100%
contrast: 100,
lightIntensity: 0.5,
rayLength: 0.5,
particleCount: 100,
particleSpeed: 1.0
};
// Input Event Listeners
function bindInput(id, key, suffix = '') {
const input = document.getElementById(id);
const display = document.getElementById(id.replace('Input', 'Val') + (id.includes('Input') ? '' : 'Val'));
// Note: Simplified ID mapping logic for brevity
input.addEventListener('input', (e) => {
settings[key] = parseFloat(e.target.value);
// Update display text if exists
const disp = document.getElementById(key + 'Val') || document.getElementById(id.replace('Input', 'Val'));
if(disp) disp.innerText = settings[key] + suffix;
});
}
// Map inputs specifically
document.getElementById('fpsInput').addEventListener('input', (e) => {
settings.fps = parseFloat(e.target.value);
document.getElementById('fpsVal').innerText = settings.fps;
document.getElementById('fpsVal2').innerText = settings.fps;
});
['satInput', 'brightInput', 'contInput'].forEach(id => {
document.getElementById(id).addEventListener('input', (e) => {
const key = id.replace('Input', ''); // sat, bright, cont
const map = { satInput: 'saturation', brightInput: 'brightness', contInput: 'contrast' };
settings[map[id]] = parseFloat(e.target.value);
document.getElementById(key + 'Val').innerText = settings[map[id]] + '%';
});
});
['lightInput', 'rayInput'].forEach(id => {
document.getElementById(id).addEventListener('input', (e) => {
const key = id.replace('Input', '');
const map = { lightInput: 'lightIntensity', rayInput: 'rayLength' };
settings[map[id]] = parseFloat(e.target.value) / 100;
document.getElementById(key + 'Val').innerText = e.target.value;
});
});
document.getElementById('particleInput').addEventListener('input', (e) => {
settings.particleCount = parseInt(e.target.value);
document.getElementById('partVal').innerText = settings.particleCount;
initParticles(); // Re-init on count change
});
document.getElementById('speedInput').addEventListener('input', (e) => {
settings.particleSpeed = parseFloat(e.target.value) / 100;
document.getElementById('speedVal').innerText = settings.particleSpeed.toFixed(2);
});
/**
* SCENE OBJECTS
*/
let particles = [];
class Particle {
constructor() {
this.reset(true);
}
reset(randomX = false) {
this.x = randomX ? Math.random() * canvas.width : canvas.width + 50;
this.y = Math.random() * canvas.height;
this.z = Math.random() * 2 + 0.5; // Depth factor
this.size = Math.random() * 2;
this.speedX = (Math.random() * 5 + 2) * settings.particleSpeed;
this.opacity = Math.random() * 0.5 + 0.1;
}
update() {
// Physics: Move left
this.x -= this.speedX * (this.z * 0.5); // Parallax effect based on depth
// Volumetric Light Influence (Simulated)
// If particle is within the "light cone" (center screen), it glows
const centerX = canvas.width / 2;
const distToCenter = Math.abs(this.x - centerX);
// Reset if off screen
if (this.x < -50) {
this.reset();
}
}
draw(ctx) {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// Distance from the "Light Source"
const dx = this.x - centerX;
const dy = this.y - centerY;
const dist = Math.sqrt(dx*dx + dy*dy);
// Volumetric Ray Logic:
// Determine if particle is "caught" in the light rays
// We simulate rays as angles emanating from center
const angle = Math.atan2(dy, dx);
// A "Light Cone" moving back and forth
const time = Date.now() * 0.001;
const lightAngle = Math.sin(time) * 0.5; // Oscillate light
// Simple ray check: Is particle close to the light angle and within range?
let inLight = false;
if (dist < canvas.height * settings.rayLength) {
// Normalize angle -PI to PI
let normAngle = angle;
if(normAngle < 0) normAngle += Math.PI * 2;
// We fake the raycasting by checking if it aligns with the oscillating light
// This is computationally cheaper than real raytracing for 500 particles
const lightDir = Math.PI / 2; // Light coming from right usually in this tunnel
const deviation = Math.abs(Math.sin(angle - lightDir));
if (deviation < 0.1) { // Narrow beam
inLight = true;
}
}
// Render
ctx.beginPath();
ctx.arc(this.x, this.y, this.size * this.z, 0, Math.PI * 2);
// Color logic
if (inLight && settings.lightIntensity > 0.1) {
// Caught in ray: Bright, colored
ctx.fillStyle = `rgba(255, 255, 200, ${this.opacity})`;
ctx.shadowBlur = 10;
ctx.shadowColor = "white";
} else {
// Ambient dust
ctx.fillStyle = `rgba(100, 120, 150, ${this.opacity * 0.5})`;
ctx.shadowBlur = 0;
}
ctx.fill();
}
}
function initParticles() {
particles = [];
for(let i=0; i<settings.particleCount; i++) {
particles.push(new Particle());
}
}
/**
* MAIN RENDER LOOP
*/
let then = Date.now();
let fpsInterval = 1000 / settings.fps;
let frames = 0;
let lastFpsTime = 0;
function drawTunnel() {
// 1. Background - Dark Gradient
const grad = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
grad.addColorStop(0, '#050505');
grad.addColorStop(1, '#101015');
ctx.fillStyle = grad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 2. Grid Lines (Retro Sci-Fi Floor)
ctx.strokeStyle = `rgba(0, 242, 255, ${0.1 * settings.lightIntensity})`;
ctx.lineWidth = 2;
const time = Date.now() * 0.001;
const perspective = canvas.height / 2;
const horizon = canvas.height * 0.4;
// Vertical Lines (Converging to center)
ctx.beginPath();
for(let i = -10; i <= 10; i++) {
const x = (canvas.width / 2) + (i * 150);
// Simple perspective math
ctx.moveTo(x, horizon);
ctx.lineTo(x * 3 - (canvas.width*1.5), canvas.height);
}
ctx.stroke();
// Horizontal Lines (Moving towards camera)
const speed = (time * 100) % 100;
for(let i=0; i<20; i++) {
const y = horizon + Math.pow(i/2, 2.5) * 10 + (i < 2 ? speed : -speed);
if (y > horizon && y < canvas.height) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(canvas.width, y);
ctx.stroke();
}
}
// 3. Central Light Source (The "Sun" / Core)
const lightX = canvas.width / 2;
const lightY = horizon - 50;
// Bloom effect
ctx.globalCompositeOperation = 'lighter';
const rayGrad = ctx.createRadialGradient(lightX, lightY, 10, lightX, lightY, 400 * settings.lightIntensity + 100);
rayGrad.addColorStop(0, `rgba(255, 255, 255, 1)`);
rayGrad.addColorStop(0.1, `rgba(0, 242, 255, 0.8)`);
rayGrad.addColorStop(1, `rgba(0, 0, 0, 0)`);
ctx.fillStyle = rayGrad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'source-over';
}
function render() {
requestAnimationFrame(render);
const now = Date.now();
const elapsed = now - then;
// FPS Throttling
if (elapsed > fpsInterval) {
// Adjust for next frame (handle drift)
then = now - (elapsed % fpsInterval);
// --- PROCESSING START ---
// Clear
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 1. Draw Base Scene (The "Video")
drawTunnel();
// 2. Update & Draw Particles (Behind light core)
// Sort particles by Z to fake depth sorting isn't strictly necessary for dust,
// but good practice.
particles.forEach(p => {
p.update();
p.draw(ctx);
});
// 3. Apply Post-Processing Filters (Simulating Color Calibration)
// This affects the entire frame buffer
const f_saturate = settings.saturation;
const f_brightness = settings.brightness;
const f_contrast = settings.contrast;
ctx.filter = `saturate(${f_saturate}%) brightness(${f_brightness}%) contrast(${f_contrast}%)`;
// We redraw a transparent rect to apply the filter to the existing canvas content
// Note: standard canvas filters apply to drawings, but applying to the *result*
// requires drawing the canvas onto itself or using the filter on specific layers.
// Since we want to affect the "Video Feed", we simply apply ctx.filter
// before drawing the particles, BUT for full post-processing:
// We actually need to redraw the scene with the filter active, or use a CSS filter on the canvas element.
// Let's use the ctx.filter property which is supported in modern browsers for subsequent draws.
// Actually, to affect the "Base Layer" (Tunnel), we should set filter before drawing it.
// But we want particles to react differently?
// Let's keep it simple: Apply filter to everything.
ctx.filter = `saturate(${f_saturate}%) contrast(${f_contrast}%)`;
// Re-draw base scene with filter (expensive but accurate for "Calibration")
// Optimization: In a real engine, we'd use shaders. Here, we just rely on the filter being active
// for the final composition if we used layers.
// Given the JS limitations, we will rely on CSS filter on the <canvas> element
// for the "Brightness" (exposure) and "Contrast", while keeping internal colors rich.
// Let's do the "Video Color Calibration" math manually on the particle colors
// and rely on CSS for global exposure to save performance.
// --- PROCESSING END ---
}
}
// Start
initParticles();
render();
// Reactive CSS Filters for Performance
// We hook into the loop to update CSS variables or styles
setInterval(() => {
// Update CSS filter for brightness (Exposure) dynamically
// This mimics a hardware exposure adjustment
canvas.style.filter = `brightness(${settings.brightness}%) contrast(${settings.contrast}%) saturate(${settings.saturation}%)`;
}, 100);
</script>
</body>
</html>