@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio(interacciones avanzadas, personalización dinámica, <canvas>, WebGL, etc.).
@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansioLa API de Canvas proporciona un área de dibujo en la web. Con el contexto 2D, permite gráficos y animaciones con JavaScript.
Para 3D, usa WebGL, que aprovecha la GPU para
renderizado avanzado
@carmenansio@carmenansio<canvas id="myCanvas"></canvas>const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(50, 50, 100, 100); 
// Dibuja un cuadrado azul
@carmenansio@carmenansioWebGL permite el renderizado de gráficos 3D directamente en el navegador utilizando la GPU. Se usa frecuentemente en juegos y visualizaciones avanzadas.
@carmenansio@carmenansio<canvas id="myCanvas"></canvas>const canvas = document.getElementById('myCanvas');
const gl = canvas.getContext('webgl'); // Se obtiene el contexto WebGL
// Configura el color de fondo y limpia el canvas
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);@carmenansio@carmenansio@carmenansio@carmenansio// Crear la escena
const scene = new THREE.Scene();
// Crear la cámara (perspectiva)
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// Crear el renderizador WebGL
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Crear un cubo
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// Posicionar la cámara
camera.position.z = 5;
// Animación
function animate() {
    requestAnimationFrame(animate);
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);
}
animate();@carmenansio// configuración three.js
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
	75,
	window.innerWidth / window.innerHeight,
	0.1,
	1000
);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById("container").appendChild(renderer.domElement);
// configuración cubo de Rubik
const rubikCube = new THREE.Group();
scene.add(rubikCube);
const cubieSize = 0.9;
@carmenansio// configurar Tweakpane
const pane = new Tweakpane.Pane();
const params = {
	rotationSpeedX: 0.01,
	rotationSpeedY: 0.01,
	rotationSpeedZ: 0.01
};
pane.addInput(params, "rotationSpeedX", { min: 0, max: 0.1, step: 0.01 });
pane.addInput(params, "rotationSpeedY", { min: 0, max: 0.1, step: 0.01 });
pane.addInput(params, "rotationSpeedZ", { min: 0, max: 0.1, step: 0.01 });
pane.addButton({ title: "Reset Cube" }).on("click", () => {
	rubikCube.rotation.set(0, 0, 0);
});@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansioNuestros ojos capturan unos 150 snapshots por segundo y el cerebro los procesa como un flujo continuo, interpolando los cambios entre cada imagen para generar la ilusión de movimiento.
@carmenansio@carmenansio@carmenansio@carmenansioEjecuta código sincronizado con los frames renderizados para animaciones fluidas y eficientes.
@carmenansio// Mal ejemplo: muchas actualizaciones directas
for (let i = 0; i < 1000; i++) {
  element.style.width = i + "px";
}
// Buen ejemplo: uso de batch
let width = 0;
requestAnimationFrame(function update() {
  element.style.width = width + "px";
  if (width < 1000) {
    width++;
    requestAnimationFrame(update);
  }
});@carmenansio@carmenansio@carmenansio@carmenansio@carmenansioconst canvas = document.getElementById("fluid");
const gl = canvas.getContext("webgl2");
// Obtiene el elemento canvas y crea un contexto WebGL2
// WebGL2 es la API moderna para gráficos 3D en el navegador@carmenansio@carmenansioin vec2 position;
void main() {
    gl_Position = vec4(position, 0.0, 1.0);
}
// Es muy simple
// Solo posiciona los vértices en la pantalla
// Crea un cuadrado que cubre toda la pantalla@carmenansio@carmenansiouniform vec2 resolution;
uniform float time;
uniform vec2 mouse;
// Los uniforms son variables que podemos controlar desde JavaScript
// resolution: tamaño de la pantalla
// time: tiempo transcurrido
// mouse: posición del cursor@carmenansio@carmenansiovec3 palette(float t) {
    vec3 a = vec3(0.5, 0.5, 0.5);
    vec3 b = vec3(0.5, 0.5, 0.5);
    vec3 c = vec3(1.0, 1.0, 1.0);
    vec3 d = vec3(0.263, 0.416, 0.557);
    return a + b * cos(6.28318 * (c * t + d));
}
// Genera colores suaves que cambian con el tiempo
// Usa funciones trigonométricas para crear transiciones suaves@carmenansio@carmenansiofor(float i = 0.0; i < 4.0; i++) {
    uv = fract(uv * 1.5) - 0.5;
    float d = length(uv) * exp(-length(uv0));
    vec3 col = palette(length(uv0) + i*.4 + time*.4);
    d = sin(d*8. + time)/8.;
    d = abs(d);
    d = pow(0.01 / d, 1.2);
    finalColor += col * d;
}
// Crea el efecto fluido principal
// Cada iteración añade una capa al efecto
// Usa matemáticas para crear patrones orgánicos@carmenansio@carmenansiofunction updateMouse(x, y) {
    const rect = canvas.getBoundingClientRect();
    mouseX = (x - rect.left) * window.devicePixelRatio;
    mouseY = canvas.height - (y - rect.top) * window.devicePixelRatio;
}
// Actualiza la posición del mouse
// Considera la densidad de píxeles del dispositivo
// Invierte el eje Y para coincidir con las coordenadas de WebGL@carmenansio@carmenansiofunction render() {
    const time = (Date.now() - startTime) * 0.001;
    gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
    gl.uniform1f(timeLocation, time);
    gl.uniform2f(mouseLocation, mouseX, mouseY);
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
    requestAnimationFrame(render);
}
// Actualiza los uniforms cada frame
// Dibuja la escena
// Usa requestAnimationFrame para mantener una animación suave@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio<canvas id="canvas"></canvas>@carmenansioconst canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");@carmenansio// Tamaño del canvas
function resize() {
	canvas.width = window.innerWidth;
	canvas.height = window.innerHeight;
}
resize();
window.addEventListener("resize", resize);@carmenansio// Configuración del texto
const text = "JSConf";
ctx.font = "bold 120px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";@carmenansio// Pixeles para el texto
function getTextPixels() {
	ctx.fillStyle = "#fff";
	ctx.fillText(text, canvas.width / 2, canvas.height / 2);
	return ctx.getImageData(0, 0, canvas.width, canvas.height);
}@carmenansio// Clase Particula
class Particle {
	constructor(x, y) {
		this.originX = x;
		this.originY = y;
		this.reset();
	}
// ...@carmenansio// Generamos un array con 1000 partículas inicializadas con la clase Particle.
const particles = Array.from({ length: 1000 }, () => new Particle());@carmenansio// Genera las partículas del texto en pixeles
let particles = [];
function createParticles() {
	particles = [];
	const pixels = getTextPixels();
	const data = pixels.data;
	for (let y = 0; y < canvas.height; y += 4) {
		for (let x = 0; x < canvas.width; x += 4) {
			const index = (y * canvas.width + x) * 4;
			if (data[index] > 128) {
				particles.push(new Particle(x, y));
			}
		}
	}
}@carmenansio// Interacción del mouse
let mouse = { x: canvas.width / 2, y: canvas.height / 2 };
canvas.addEventListener("mousemove", (e) => {
	mouse.x = e.clientX;
	mouse.y = e.clientY;
});@carmenansio// Animación loop
function animate() {
	ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
	ctx.fillRect(0, 0, canvas.width, canvas.height);
	particles.forEach((particle) => {
		particle.update(mouse);
		particle.draw();
	});
	requestAnimationFrame(animate);
}@carmenansio// !important
requestAnimationFrame(animate);@carmenansio// Inicializar
createParticles();
animate();@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio
    preload()
setup()@carmenansiolet img;
let particles = [];
let dispersalSpeed = 2;
function preload() {
    img = loadImage("https://picsum.photos/800/600"); // Imagen externa con Picsum
}
function setup() {
    createCanvas(windowWidth, windowHeight);
    imageMode(CENTER);
    resetParticles();
}@carmenansiofunction resetParticles() {
    particles = [];
    let imgWidth = width * 0.8;
    let imgHeight = (img.height / img.width) * imgWidth;
    
    for (let x = 0; x < img.width; x += 5) {
        for (let y = 0; y < img.height; y += 5) {
            let c = img.get(x, y); // Obtiene el color del píxel
            let screenX = map(x, 0, img.width, width / 2 - imgWidth / 2, width / 2 + imgWidth / 2);
            let screenY = map(y, 0, img.height, height / 2 - imgHeight / 2, height / 2 + imgHeight / 2);
            
            particles.push({
                x: screenX,
                y: screenY,
                targetX: screenX,
                targetY: screenY,
                color: c,
                velocityX: random(-1, 1) * dispersalSpeed,
                velocityY: random(-1, 1) * dispersalSpeed,
            });
        }
    }
}@carmenansiofunction draw() {
    background(0);
    if (displayImage) {
        particles.forEach(p => {
            fill(p.color);
            noStroke();
            ellipse(p.x, p.y, 5, 5);
            
            // Actualización de posición para el efecto de explosión
            p.x += p.velocityX;
            p.y += p.velocityY;
        });
    }
}@carmenansiofunction keyPressed() {
    if (key === ' ') { // Barra espaciadora para iniciar la explosión
        explosionStarted = true;
    }
}@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio@carmenansio