// Título: Fragmento de especulación afectiva codificada
// Autor: David_Mingorance
<!DOCTYPE html> <html lang=«es»> <head> <meta charset=«UTF-8»><title>Xenopoética</title> <style> body { margin: 0; overflow: hidden; background: #000; font: 300 1.5rem Helvetica, sans-serif; cursor: crosshair; transition: .6s; } #t { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); color: #fff; text-align: center; pointer-events: none; width: 80%; opacity: 0; transition: .5s; text-transform: uppercase; letter-spacing: 2px; } .g { animation: a .2s steps(2) infinite; } @keyframes a { 0% { clip-path: inset(20% 0 50% 0); transform: translate(-5px); } 50% { clip-path: inset(80% 0 5% 0); transform: translate(5px); } 100% { clip-path: inset(0); } } </style> </head> |
// Infección afectiva se inocula por ósmosis. Comienza lenta, sin dar cuenta, sin apenas esperarlo.
// Los síntomas no son evidentes. La predisposición baja las defensas: las torna débiles, el cuerpo y el alma se confían.
<body> <div id=«t»>Fragmento de especulación afectiva codificada</div> <script type=«module»> import * as THREE from ‘https://unpkg.com/three@0.150.0/build/three.module.js’;
const s = new THREE.Scene(), c = new THREE.PerspectiveCamera(75, innerWidth/innerHeight, 0.1, 1000), r = new THREE.WebGLRenderer({antialias: true, alpha: true}), count = 7000, m = new THREE.Vector2(), target = new THREE.Vector2(), text = document.getElementById(‘t’), orig = text.innerText; let cur = orig, clicks = 0, vis = false, hue = 180; r.setSize(innerWidth, innerHeight); document.body.appendChild(r.domElement); c.position.z = 5; |
// Extrañamiento xeno,
// Lejos de estas realidades,
// las predicciones devienen incertidumbre.
// La seguridad se transforma en un fluido sin densidad,
// etéreo, vacío, imposible de asir.
// Y sin embargo, pisa terreno firme:
// un planeta otrora nuestra única realidad.
// Pero cuando la vida evoluciona,
// tiene necesidades de expansión, de panspermia,
// es por eso que visita nuevos cuerpos celestes.
const cv = document.createElement(‘canvas’); cv.width = cv.height = 32; const ctx = cv.getContext(‘2d’); ctx.arc(16, 16, 14, 0, Math.PI * 2); ctx.fillStyle = ‘#fff’; ctx.fill(); const tex = new THREE.CanvasTexture(cv);
const geo = new THREE.BufferGeometry(), pos = new Float32Array(count * 3), vel = new Float32Array(count * 3); for(let i=0; i<count*3; i++) { pos[i] = (Math.random()-0.5)*15; vel[i] = (Math.random()-0.5)*0.01; } geo.setAttribute(‘position’, new THREE.BufferAttribute(pos, 3)); const mat = new THREE.PointsMaterial({size: 0.04, map: tex, transparent: true, opacity: 0.4, blending: THREE.AdditiveBlending, color: 0x00ffff}); const pts = new THREE.Points(geo, mat); s.add(pts);
const reset = () => { vis = false; clicks = 0; cur = orig; text.innerText = orig; text.style.opacity = 0; document.body.style.backgroundColor = «#000»; mat.color.set(0x00ffff); }; |
// Intentó abandonar sus investigaciones,
// se prometió a sí mismx que se trataba de una extravagancia fortuita,
// más no puede dejar de otear aquella zona, fuera del campo de visión,
// donde lo fantasmagórico emerge como posible.
window.onclick = () => { if(!vis) return (text.style.opacity = 1, vis = true); clicks++; hue = (hue + 40) % 360; document.body.style.backgroundColor = `hsl(${hue}, 20%, 3%)`; mat.color.setHSL(hue/360, 0.8, 0.5); text.className = ‘g’; setTimeout(() => text.className = », 200); let a = cur.split(»); for(let i=0; i<Math.ceil(a.length*0.12); i++) { let idx = Math.floor(Math.random()*a.length); if(a[idx] !== » «) a[idx] = Math.random() > 0.5 ? String.fromCharCode(33+Math.random()*20) : » «; } cur = a.join(»); text.innerText = cur; if(!cur.trim()) setTimeout(reset, 800); }; |
// Bifurcación de caminos,
// horizonte de sucesos en el agujero negro de la razón.
// La intuición es un juego de azar.
// Apostar todo significaría la destrucción.
window.onmousemove = e => { target.x = (e.clientX/innerWidth-0.5)*2; target.y = -(e.clientY/innerHeight-0.5)*2; };
function animate() { requestAnimationFrame(animate); m.lerp(target, 0.08); pts.rotation.y = m.x * 0.5; pts.rotation.x = -m.y * 0.5; const p = geo.attributes.position.array; for(let i=0; i<count*3; i+=3) { p[i] += vel[i]*(clicks+1); p[i+1] += vel[i+1]*(clicks+1); if(Math.abs(p[i]) > 12 || Math.abs(p[i+1]) > 8) { p[i] *= -0.9; p[i+1] *= -0.9; } } geo.attributes.position.needsUpdate = true; r.render(s, c); } |
// ¿Quién decide el futuro, cuando se vuelve volátil?
// Sus sistemas de medición no cotejan los registros,
// confía en la tecnología, pero sabe que no debe.
// Los filtros anímicos nublan toda interpretación aséptica.
// A su vez,
// las plataformas distorsionan lo examinado,
// trastocan las percepciones
// sin necesidad siquiera de que su traducción sea la apropiada.
animate(); window.onresize = () => { c.aspect = innerWidth/innerHeight; c.updateProjectionMatrix(); r.setSize(innerWidth, innerHeight); }; |
// Todo esto acontece mientras el mundo transcurre a su velocidad habitual,
// sin pararse a reflexionar sobre la disposición de las cosas.
// El paso del tiempo modifica nuestra existencia.
// Quién sabe si durante un instante o quizás durante una eternidad.