Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 191 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>DNA RT - Lebendiges Mosaik</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
overflow: hidden;
background: #0a0a0a;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
touch-action: none;
}

#kunstwerk {
display: block;
width: 100vw;
height: 100vh;
cursor: crosshair;
}

.info {
position: fixed;
top: 20px;
left: 20px;
color: rgba(255, 255, 255, 0.3);
font-size: 12px;
pointer-events: none;
z-index: 10;
}
</style>
</head>
<body>
<canvas id="kunstwerk"></canvas>
<div class="info">Touch/Click to interact</div>

<script>
// Kunstwerk Configuration
const leinwand = document.getElementById('kunstwerk');
const pinsel = leinwand.getContext('2d', { alpha: false });

// Dynamische Größenanpassung
const aktualisiereDimensionen = () => {
leinwand.width = window.innerWidth;
leinwand.height = window.innerHeight;
};
aktualisiereDimensionen();

// Pixel-Mosaik Parameter
let pixelGroesse = Math.max(12, Math.min(25, Math.floor(Math.min(window.innerWidth, window.innerHeight) / 40)));
let spalten = Math.ceil(leinwand.width / pixelGroesse);
let zeilen = Math.ceil(leinwand.height / pixelGroesse);

// Organisches Farbsystem
class LebendigeZelle {
constructor(xPos, yPos) {
this.xPos = xPos;
this.yPos = yPos;
this.farbwert1 = Math.random() * 360;
this.farbwert2 = Math.random() * 360;
this.saettigung = 45 + Math.random() * 30;
this.helligkeit = 35 + Math.random() * 25;
this.atemPhase = Math.random() * Math.PI * 2;
this.atemGeschwindigkeit = 0.005 + Math.random() * 0.01;
this.pulsIntensitaet = 0;
this.zielIntensitaet = 0;
}

entwickeln(zeitstempel, interaktionsMap) {
// Organisches Atmen
this.atemPhase += this.atemGeschwindigkeit;
const atemFaktor = Math.sin(this.atemPhase) * 0.5 + 0.5;

// Farbübergang
const aktuellerFarbton = this.farbwert1 + (this.farbwert2 - this.farbwert1) * atemFaktor;

// Interaktionseffekt
const schluessel = `${this.xPos},${this.yPos}`;
if (interaktionsMap.has(schluessel)) {
this.zielIntensitaet = 1;
interaktionsMap.delete(schluessel);
} else {
this.zielIntensitaet *= 0.95;
}

this.pulsIntensitaet += (this.zielIntensitaet - this.pulsIntensitaet) * 0.1;

const finaleSaettigung = this.saettigung + this.pulsIntensitaet * 40;
const finaleHelligkeit = this.helligkeit + this.pulsIntensitaet * 30;

return `hsl(${aktuellerFarbton}, ${finaleSaettigung}%, ${finaleHelligkeit}%)`;
}
}

// Initialisierung der Zellen
let zellenGitter = [];

const initialisiereMosaik = () => {
zellenGitter = [];
for (let z = 0; z < zeilen; z++) {
for (let s = 0; s < spalten; s++) {
zellenGitter.push(new LebendigeZelle(s, z));
}
}
};

initialisiereMosaik();

// Interaktions-Tracking
const interaktionsPuffer = new Map();

const verarbeiteBeruehrung = (ereignis) => {
ereignis.preventDefault();

const beruehrungen = ereignis.touches || [ereignis];
const rect = leinwand.getBoundingClientRect();

for (let i = 0; i < beruehrungen.length; i++) {
const touch = beruehrungen[i];
const xKoordinate = (touch.clientX || touch.pageX) - rect.left;
const yKoordinate = (touch.clientY || touch.pageY) - rect.top;

const spalte = Math.floor(xKoordinate / pixelGroesse);
const zeile = Math.floor(yKoordinate / pixelGroesse);

// Wellenwirkung um Berührungspunkt
const radius = 3;
for (let dy = -radius; dy <= radius; dy++) {
for (let dx = -radius; dx <= radius; dx++) {
const distanz = Math.sqrt(dx * dx + dy * dy);
if (distanz <= radius) {
const zielSpalte = spalte + dx;
const zielZeile = zeile + dy;
if (zielSpalte >= 0 && zielSpalte < spalten && zielZeile >= 0 && zielZeile < zeilen) {
interaktionsPuffer.set(`${zielSpalte},${zielZeile}`, true);
}
}
}
}
}
};

// Event-Listener für Touch und Maus
leinwand.addEventListener('touchstart', verarbeiteBeruehrung, { passive: false });
leinwand.addEventListener('touchmove', verarbeiteBeruehrung, { passive: false });
leinwand.addEventListener('mousedown', verarbeiteBeruehrung);
leinwand.addEventListener('mousemove', (e) => {
if (e.buttons > 0) verarbeiteBeruehrung(e);
});

// Haupt-Animations-Schleife
const zeichneKunstwerk = (zeitstempel) => {
// Zeichne jede Zelle
zellenGitter.forEach(zelle => {
const farbe = zelle.entwickeln(zeitstempel, interaktionsPuffer);
pinsel.fillStyle = farbe;
pinsel.fillRect(
zelle.xPos * pixelGroesse,
zelle.yPos * pixelGroesse,
pixelGroesse,
pixelGroesse
);
});

requestAnimationFrame(zeichneKunstwerk);
};

// Größenänderung behandeln mit Debouncing
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
aktualisiereDimensionen();
pixelGroesse = Math.max(12, Math.min(25, Math.floor(Math.min(window.innerWidth, window.innerHeight) / 40)));
spalten = Math.ceil(leinwand.width / pixelGroesse);
zeilen = Math.ceil(leinwand.height / pixelGroesse);
initialisiereMosaik();
}, 250);
});

// Starte Animation
requestAnimationFrame(zeichneKunstwerk);
</script>
</body>
</html>