body {
margin: 0;
font-family: system-ui, sans-serif;
background: linear-gradient(135deg, #1e1e2f, #2c2c44);
color: white;
display: flex;
flex-direction: column;
align-items: center;
}
h1 {
margin: 14px 0;
font-size: 1.4rem;
}
.view {
width: 90%;
max-width: 420px;
aspect-ratio: 3 / 4;
border-radius: 16px;
overflow: hidden;
background: black;
box-shadow: 0 10px 30px rgba(0,0,0,.4);
}
canvas {
width: 100%;
height: 100%;
display: block;
}
.controls {
margin: 14px 0;
display: flex;
gap: 10px;
flex-wrap: wrap;
justify-content: center;
}
button, select {
background: #4a4a7a;
color: white;
border: none;
padding: 10px 14px;
border-radius: 10px;
cursor: pointer;
}
Simulador de Daltonismo
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const video = document.createElement("video");
video.playsInline = true;
video.muted = true;
let stream;
let facingMode = "environment";
let mode = "normal";
const matrices = {
normal: [
1,0,0,
0,1,0,
0,0,1
],
protanopia: [
0.152, 1.053, -0.205,
0.115, 0.786, 0.099,
-0.004, -0.048, 1.052
],
deuteranopia: [
0.367, 0.861, -0.228,
0.280, 0.673, 0.047,
-0.012, 0.043, 0.969
],
tritanopia: [
1.255, -0.076, -0.179,
-0.078, 0.931, 0.148,
0.005, 0.691, 0.304
]
};
async function startCamera() {
if (stream) stream.getTracks().forEach(t => t.stop());
stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: { ideal: facingMode } },
audio: false
});
video.srcObject = stream;
await video.play();
// IMPORTANTE: tamaño real del canvas = tamaño visual
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
requestAnimationFrame(draw);
}
function draw() {
const vw = video.videoWidth;
const vh = video.videoHeight;
const cw = canvas.width;
const ch = canvas.height;
// Escalado tipo object-fit: cover
const scale = Math.max(cw / vw, ch / vh);
const sw = vw * scale;
const sh = vh * scale;
const dx = (cw - sw) / 2;
const dy = (ch - sh) / 2;
ctx.drawImage(video, dx, dy, sw, sh);
if (mode !== "normal") {
const img = ctx.getImageData(0, 0, cw, ch);
const d = img.data;
const m = matrices[mode];
for (let i = 0; i < d.length; i += 4) {
const r = d[i];
const g = d[i + 1];
const b = d[i + 2];
d[i] = r*m[0] + g*m[1] + b*m[2];
d[i + 1] = r*m[3] + g*m[4] + b*m[5];
d[i + 2] = r*m[6] + g*m[7] + b*m[8];
}
ctx.putImageData(img, 0, 0);
}
requestAnimationFrame(draw);
}
document.getElementById("startBtn").onclick = startCamera;
document.getElementById("switchBtn").onclick = () => {
facingMode = facingMode === "user" ? "environment" : "user";
startCamera();
};
document.getElementById("filter").onchange = e => {
mode = e.target.value;
};