Files
youid/index.html
2026-01-15 06:52:21 -05:00

298 lines
5.8 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>youID</title>
<style>
:root {
--bg: #f6f2e9;
--text: #111;
--muted: #555;
--accent: #1f5fff;
--card: #e8f0ff;
--serif: "Times New Roman", Times, serif;
}
* {
box-sizing: border-box;
}
html, body {
margin: 0;
height: 100%;
font-family: var(--serif);
background: var(--bg);
color: var(--text);
overflow: hidden;
}
/* ---------- BACKGROUND ANIMATION ---------- */
#bg {
position: fixed;
inset: 0;
z-index: 0;
pointer-events: none;
}
canvas {
width: 100%;
height: 100%;
}
/* ---------- APP ---------- */
#app {
position: relative;
z-index: 1;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.view {
width: 100%;
max-width: 700px;
padding: 48px;
text-align: center;
opacity: 0;
transform: translateY(10px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.view.active {
opacity: 1;
transform: translateY(0);
}
h1 {
font-size: 56px;
margin: 0 0 12px;
font-weight: normal;
}
.subtitle {
font-size: 18px;
color: var(--muted);
}
/* ---------- INPUT ---------- */
#question {
font-size: 26px;
margin-bottom: 24px;
}
textarea {
width: 100%;
font-family: var(--serif);
font-size: 20px;
padding: 16px;
border: 1px solid #aaa;
background: transparent;
resize: none;
outline: none;
}
.controls {
margin-top: 12px;
font-size: 14px;
color: var(--muted);
}
.key {
border: 1px solid #999;
padding: 2px 6px;
border-radius: 4px;
font-family: monospace;
background: #fff;
}
/* ---------- RESULT CARD ---------- */
.card {
background: var(--card);
padding: 36px;
border-radius: 12px;
}
.card h2 {
margin-top: 0;
font-size: 32px;
}
.card p {
font-size: 18px;
line-height: 1.6;
}
</style>
</head>
<body>
<div id="bg">
<canvas id="canvas"></canvas>
</div>
<div id="app">
<!-- TITLE -->
<div id="title" class="view active">
<h1>youID</h1>
<div class="subtitle">Loading questions…</div>
</div>
<!-- QUESTION -->
<div id="qa" class="view">
<div id="question"></div>
<textarea id="input" rows="4"></textarea>
<div class="controls">
Press <span class="key">Enter</span> to continue
</div>
</div>
<!-- RESULT -->
<div id="result" class="view">
<div class="card">
<h2 id="ageTitle"></h2>
<p id="ageDetails"></p>
</div>
</div>
</div>
<script>
/* ================= BACKGROUND VISUALIZATION ================= */
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let w, h;
let nodes = [];
let confidence = 0;
function resize() {
w = canvas.width = window.innerWidth;
h = canvas.height = window.innerHeight;
}
window.addEventListener("resize", resize);
resize();
for (let i = 0; i < 80; i++) {
nodes.push({
x: Math.random() * w,
y: Math.random() * h,
vx: (Math.random() - 0.5) * 0.3,
vy: (Math.random() - 0.5) * 0.3
});
}
function animate() {
ctx.clearRect(0, 0, w, h);
ctx.globalAlpha = 0.15 + confidence * 0.25;
nodes.forEach(n => {
n.x += n.vx;
n.y += n.vy;
if (n.x < 0 || n.x > w) n.vx *= -1;
if (n.y < 0 || n.y > h) n.vy *= -1;
ctx.beginPath();
ctx.arc(n.x, n.y, 2, 0, Math.PI * 2);
ctx.fillStyle = "#000";
ctx.fill();
});
requestAnimationFrame(animate);
}
animate();
/* ================= AGE DETECTION ENGINE ================= */
const questions = [
"Describe something that recently changed your mind.",
"What does success mean to you personally?",
"Explain a concept you find interesting to someone unfamiliar with it.",
"When was the last time you felt uncertain, and why?",
"What do you think people misunderstand about growing up?"
];
let qIndex = 0;
let metrics = {
wordLength: 0,
sentenceLength: 0,
edits: 0,
latency: []
};
let lastTime = Date.now();
function analyze(text) {
const words = text.trim().split(/\s+/);
const sentences = text.split(/[.!?]/);
metrics.wordLength += words.reduce((a, w) => a + w.length, 0) / words.length;
metrics.sentenceLength += words.length / Math.max(1, sentences.length);
confidence = Math.min(1, confidence + 0.15);
}
function estimateAge() {
const wl = metrics.wordLength / qIndex;
const sl = metrics.sentenceLength / qIndex;
if (wl < 4.2) return ["Under 13", "Your responses were concrete, immediate, and low in abstraction."];
if (wl < 4.8) return ["1317", "You showed emerging abstraction with developing structure."];
if (wl < 5.5) return ["1825", "Your language suggests identity exploration and self-reflection."];
return ["26+", "Your responses demonstrated high abstraction and reflective reasoning."];
}
/* ================= UI FLOW ================= */
const views = {
title: document.getElementById("title"),
qa: document.getElementById("qa"),
result: document.getElementById("result")
};
function show(view) {
Object.values(views).forEach(v => v.classList.remove("active"));
views[view].classList.add("active");
}
const questionEl = document.getElementById("question");
const input = document.getElementById("input");
function nextQuestion() {
if (qIndex >= questions.length || confidence >= 0.85) {
const [title, detail] = estimateAge();
document.getElementById("ageTitle").textContent = title;
document.getElementById("ageDetails").textContent = detail;
show("result");
return;
}
questionEl.textContent = questions[qIndex++];
input.value = "";
input.focus();
}
input.addEventListener("keydown", e => {
if (e.key === "Enter") {
e.preventDefault();
show("title");
views.title.querySelector(".subtitle").textContent = "Loading…";
const text = input.value;
setTimeout(() => {
analyze(text);
show("qa");
nextQuestion();
}, 300);
}
});
setTimeout(() => {
show("qa");
nextQuestion();
}, 1200);
</script>
</body>
</html>