Intro_Game / index.html
eaglelandsonce's picture
Update index.html
83ac4b3 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GPT-4 Emergence Quiz - Hyper-Enhanced</title>
<style>
body {
margin: 0;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: #000; /* Darker background for bloom */
color: #fff;
}
canvas {
display: block;
}
#ui-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none; /* Let clicks pass through to the canvas */
}
#questionBox, #feedback {
pointer-events: auto; /* Allow interaction with these elements */
}
#questionBox {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0,0,0,0.75);
padding: 15px 30px;
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.2);
max-width: 85%;
text-align: center;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.5);
backdrop-filter: blur(8px);
}
#questionBox h3 { margin-top: 0; color: #4fc3f7; }
#questionBox ul { list-style: none; padding: 0; text-align: left; display: inline-block; }
#questionBox li { margin-bottom: 8px; font-size: 1.1em; }
#questionBox b {
display: inline-block;
width: 25px;
text-shadow: 0 0 5px currentColor;
}
#feedback {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0,0,0,0.75);
padding: 10px 20px;
border-radius: 8px;
font-size: 1.2em;
font-weight: bold;
border: 1px solid rgba(255, 255, 255, 0.2);
}
</style>
</head>
<body>
<div id="ui-container">
<div id="questionBox"></div>
<div id="feedback"></div>
</div>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.157.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.157.0/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
// --- Quiz Data ---
const questions = [
{ text: "GPT-4 breaks down a complex problem into multiple reasoning paths...", options: ["Tree-of-Thought (ToT)", "ReAct Prompting", "Reflexive Dialogue", "Implicit Memory Simulation"], correct: 0 },
{ text: "GPT-4 responds by alternating between thinking and acting...", options: ["Tree-of-Thought (ToT)", "ReAct Prompting", "Reflexive Dialogue", "Implicit Memory Simulation"], correct: 1 },
{ text: "GPT-4 engages in a back-and-forth with itself to refine responses.", options: ["Tree-of-Thought (ToT)", "ReAct Prompting", "Reflexive Dialogue", "Implicit Memory Simulation"], correct: 2 },
{ text: "GPT-4 'remembers' prior interactions naturally without explicit repeats.", options: ["Tree-of-Thought (ToT)", "ReAct Prompting", "Reflexive Dialogue", "Implicit Memory Simulation"], correct: 3 }
];
let currentQuestionIndex = 0;
let isTransitioning = false;
// --- UI & Audio ---
const questionBox = document.getElementById('questionBox');
const feedbackBox = document.getElementById('feedback');
const audio = {
hover: new Audio('https://cdn.pixabay.com/audio/2022/11/21/audio_a721674937.mp3'),
click: new Audio('https://cdn.pixabay.com/audio/2022/03/15/audio_73ed20145c.mp3'),
correct: new Audio('https://cdn.pixabay.com/audio/2022/01/21/audio_816633f81d.mp3'),
wrong: new Audio('https://cdn.pixabay.com/audio/2021/08/04/audio_c89b3f4f71.mp3')
};
Object.values(audio).forEach(a => a.volume = 0.5);
// --- Three.js Setup ---
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100);
// *** MODIFIED: Camera is lower and closer ***
camera.position.set(0, 1.5, 7.5);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ReinhardToneMapping;
document.body.appendChild(renderer.domElement);
// --- Post-Processing (Bloom Effect) ---
const renderScene = new RenderPass(scene, camera);
const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.2, 0.4, 0.85);
const composer = new EffectComposer(renderer);
composer.addPass(renderScene);
composer.addPass(bloomPass);
// --- Lighting ---
scene.add(new THREE.AmbientLight(0xffffff, 0.3));
const dirLight = new THREE.DirectionalLight(0xffffff, 1.5);
dirLight.position.set(5, 5, 5);
dirLight.castShadow = true;
dirLight.shadow.mapSize.width = 1024;
dirLight.shadow.mapSize.height = 1024;
scene.add(dirLight);
// --- Helper to create letter textures ---
function createLetterTexture(letter, textColor, boxColor) {
const canvas = document.createElement('canvas');
canvas.width = 256;
canvas.height = 256;
const context = canvas.getContext('2d');
context.fillStyle = `#${boxColor.getHexString()}`;
context.fillRect(0, 0, 256, 256);
context.font = 'bold 180px Arial';
context.fillStyle = textColor;
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText(letter, 128, 128);
return new THREE.CanvasTexture(canvas);
}
// --- Objects ---
const cubes = [];
const geometry = new THREE.BoxGeometry(1.2, 1.2, 1.2);
const colors = [0x66bb6a, 0xffca28, 0x42a5f5, 0xab47bc];
const CUBE_BASE_Y = 0.7; // *** ADDED: A constant for the base height ***
for (let i = 0; i < 4; i++) {
const color = new THREE.Color(colors[i]);
const letter = String.fromCharCode(65 + i);
const letterTexture = createLetterTexture(letter, 'rgba(255,255,255,0.9)', color);
const materials = [
new THREE.MeshStandardMaterial({ color: color }),
new THREE.MeshStandardMaterial({ color: color }),
new THREE.MeshStandardMaterial({ color: color }),
new THREE.MeshStandardMaterial({ color: color }),
new THREE.MeshStandardMaterial({ map: letterTexture, color: color }),
new THREE.MeshStandardMaterial({ color: color })
];
const cube = new THREE.Mesh(geometry, materials);
// *** MODIFIED: Set a lower Y position ***
cube.position.set((i - 1.5) * 2.8, CUBE_BASE_Y, 0);
cube.userData.id = i;
cube.userData.baseColor = color;
cube.userData.spin = 0;
cube.castShadow = true;
scene.add(cube);
cubes.push(cube);
}
const plane = new THREE.Mesh(
new THREE.PlaneGeometry(30, 30),
new THREE.MeshStandardMaterial({ color: 0x111111, side: THREE.DoubleSide })
);
plane.rotation.x = -Math.PI / 2;
plane.receiveShadow = true;
scene.add(plane);
let activeParticles = [];
// --- Interactivity ---
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
let INTERSECTED;
function onPointerMove(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
function onClick() {
if (isTransitioning || !INTERSECTED) return;
audio.click.currentTime = 0;
audio.click.play();
checkAnswer(INTERSECTED.userData.id);
}
window.addEventListener('pointermove', onPointerMove);
window.addEventListener('click', onClick);
// --- Game Logic ---
function loadQuestion() {
isTransitioning = false;
if (currentQuestionIndex >= questions.length) {
questionBox.innerHTML = `<h2>Quiz Complete!</h2>`;
feedbackBox.innerHTML = 'Excellent work!';
cubes.forEach((cube, i) => setTimeout(() => cube.visible = false, i * 100));
return;
}
const q = questions[currentQuestionIndex];
questionBox.innerHTML = `<h3>Question ${currentQuestionIndex + 1}:</h3><p>${q.text}</p><ul>${
q.options.map((opt, i) => `<li style="color:#${colors[i].toString(16)}"><b style="color:#${colors[i].toString(16)}">${String.fromCharCode(65 + i)}:</b> ${opt}</li>`).join('')
}</ul>`;
feedbackBox.innerHTML = '<p>Select the correct concept</p>';
}
function checkAnswer(selectedIndex) {
isTransitioning = true;
const q = questions[currentQuestionIndex];
const correct = q.correct === selectedIndex;
feedbackBox.innerHTML = correct
? `<p style="color: #8BC34A;">Correct!</p>`
: `<p style="color: #E57373;">Incorrect. The answer was ${String.fromCharCode(65 + q.correct)}.</p>`;
const sound = correct ? audio.correct : audio.wrong;
sound.currentTime = 0;
sound.play();
const cube = cubes[selectedIndex];
cube.userData.spin += Math.PI * 2;
createParticleEffect(cube.position, correct ? 0x8BC34A : 0xE57373);
currentQuestionIndex++;
setTimeout(loadQuestion, 2500);
}
function createParticleEffect(position, color) {
const particleCount = 200;
const particles = new THREE.BufferGeometry();
const posArray = new Float32Array(particleCount * 3);
const velArray = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount * 3; i+=3) {
posArray[i] = position.x;
posArray[i+1] = position.y;
posArray[i+2] = position.z;
velArray[i] = (Math.random() - 0.5) * 4;
velArray[i+1] = (Math.random() - 0.5) * 4 + 2;
velArray[i+2] = (Math.random() - 0.5) * 4;
}
particles.setAttribute('position', new THREE.BufferAttribute(posArray, 3));
const material = new THREE.PointsMaterial({ size: 0.1, color: color, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false });
const particleSystem = new THREE.Points(particles, material);
particleSystem.userData.velocities = velArray;
particleSystem.userData.lifetime = 0;
scene.add(particleSystem);
activeParticles.push(particleSystem);
}
loadQuestion();
// --- Render Loop ---
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const elapsedTime = clock.getElapsedTime();
const deltaTime = clock.getDelta();
// *** MODIFIED: Replaced orbit with a subtle dolly zoom ***
camera.position.z = 7.5 + Math.sin(elapsedTime * 0.2) * 0.5;
camera.lookAt(0, 0, 0);
cubes.forEach(cube => {
if (cube.userData.spin > 0) {
const spinAmount = Math.min(cube.userData.spin, deltaTime * 15);
cube.rotation.y += spinAmount;
cube.userData.spin -= spinAmount;
} else {
cube.rotation.y += deltaTime * 0.3;
}
// *** MODIFIED: Use the new base Y position for bobbing animation ***
cube.position.y = CUBE_BASE_Y + Math.sin(elapsedTime * 1.5 + cube.userData.id * 2) * 0.15;
});
// Particle animation
activeParticles.forEach((system, index) => {
const positions = system.geometry.attributes.position;
const velocities = system.userData.velocities;
system.userData.lifetime += deltaTime;
for (let i = 0; i < positions.count; i++) {
velocities[i*3+1] -= 9.8 * deltaTime * 0.2;
positions.array[i*3] += velocities[i*3] * deltaTime;
positions.array[i*3+1] += velocities[i*3+1] * deltaTime;
positions.array[i*3+2] += velocities[i*3+2] * deltaTime;
}
positions.needsUpdate = true;
system.material.opacity = Math.max(0, 1.0 - system.userData.lifetime / 1.5);
if (system.userData.lifetime > 1.5) {
scene.remove(system);
system.geometry.dispose();
system.material.dispose();
activeParticles.splice(index, 1);
}
});
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(cubes);
if (intersects.length > 0 && !isTransitioning) {
if (INTERSECTED != intersects[0].object) {
if (INTERSECTED) INTERSECTED.scale.set(1, 1, 1);
INTERSECTED = intersects[0].object;
INTERSECTED.scale.set(1.1, 1.1, 1.1);
audio.hover.currentTime = 0;
audio.hover.play();
}
} else {
if (INTERSECTED) INTERSECTED.scale.set(1, 1, 1);
INTERSECTED = null;
}
composer.render();
}
animate();
// --- Resize Handler ---
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
composer.setSize(window.innerWidth, window.innerHeight);
});
</script>
</body>
</html>