ornstein-saber-eval / canvas_three_scene.html
KyleHessling1's picture
Initial eval upload: thinking-on full bench, tool-calling, report
ed47c9c verified
Raw
History Blame Contribute Delete
12.1 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Crystal Formation</title>
<style>
body { margin: 0; overflow: hidden; background: #000; }
canvas { display: block; }
</style>
</head>
<body>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.160.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
// Scene setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, 15);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild(renderer.domElement);
// Post-processing
const composer = new EffectComposer(renderer);
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
0.4, 0.4, 0.85
);
composer.addPass(bloomPass);
// Chromatic aberration shader
const chromaticAberrationShader = {
uniforms: {
tDiffuse: { value: null },
uIntensity: { value: 0.003 }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D tDiffuse;
uniform float uIntensity;
varying vec2 vUv;
void main() {
vec2 center = vUv - 0.5;
float dist = length(center);
vec2 direction = normalize(center);
float aberration = uIntensity * dist;
vec2 redUv = vUv + direction * aberration;
vec2 blueUv = vUv - direction * aberration;
float r = texture2D(tDiffuse, redUv).r;
float g = texture2D(tDiffuse, vUv).g;
float b = texture2D(tDiffuse, blueUv).b;
gl_FragColor = vec4(r, g, b, 1.0);
}
`
};
const chromaticAberrationPass = new ShaderPass(chromaticAberrationShader);
composer.addPass(chromaticAberrationPass);
// Fog
scene.fog = new THREE.FogExp2(0x1a1a2e, 0.02);
// Create gradient sky
const skyGeometry = new THREE.SphereGeometry(100, 32, 32);
const skyMaterial = new THREE.ShaderMaterial({
uniforms: {
topColor: { value: new THREE.Color(0x1a1a2e) },
bottomColor: { value: new THREE.Color(0x2d3748) },
offset: { value: 20 },
exponent: { value: 0.4 }
},
vertexShader: `
varying vec3 vWorldPosition;
void main() {
vec4 worldPosition = modelMatrix * vec4(position, 1.0);
vWorldPosition = worldPosition.xyz;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform vec3 topColor;
uniform vec3 bottomColor;
uniform float offset;
uniform float exponent;
varying vec3 vWorldPosition;
void main() {
float h = normalize(vWorldPosition + offset).y;
gl_FragColor = vec4(mix(bottomColor, topColor, max(pow(max(h, 0.0), exponent), 0.0)), 1.0);
}
`,
side: THREE.BackSide
});
const sky = new THREE.Mesh(skyGeometry, skyMaterial);
scene.add(sky);
// Lighting
const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambientLight);
const keyLight = new THREE.DirectionalLight(0xffffff, 1);
keyLight.position.set(5, 10, 5);
keyLight.castShadow = true;
keyLight.shadow.mapSize.width = 1024;
keyLight.shadow.mapSize.height = 1024;
keyLight.shadow.camera.near = 0.5;
keyLight.shadow.camera.far = 50;
keyLight.shadow.camera.left = -10;
keyLight.shadow.camera.right = 10;
keyLight.shadow.camera.top = 10;
keyLight.shadow.camera.bottom = -10;
scene.add(keyLight);
const rimLight = new THREE.DirectionalLight(0x00ffff, 0.8);
rimLight.position.set(-5, 5, -5);
scene.add(rimLight);
const fillLight = new THREE.DirectionalLight(0xff00ff, 0.6);
fillLight.position.set(5, 3, -5);
scene.add(fillLight);
// Crystal material
const crystalMaterial = new THREE.MeshPhysicalMaterial({
color: 0xffffff,
metalness: 0.0,
roughness: 0.1,
transmission: 0.9,
thickness: 0.5,
ior: 1.5,
clearcoat: 1.0,
clearcoatRoughness: 0.1,
envMapIntensity: 1.0,
side: THREE.DoubleSide
});
// Create crystals
const crystals = [];
for (let i = 0; i < 15; i++) {
const geometry = new THREE.IcosahedronGeometry(Math.random() * 0.8 + 0.2, 0);
const crystal = new THREE.Mesh(geometry, crystalMaterial);
crystal.position.set(
(Math.random() - 0.5) * 8,
Math.random() * 6 + 2,
(Math.random() - 0.5) * 8
);
crystal.rotation.set(
Math.random() * Math.PI,
Math.random() * Math.PI,
Math.random() * Math.PI
);
crystal.userData = {
rotationSpeed: {
x: (Math.random() - 0.5) * 0.01,
y: (Math.random() - 0.5) * 0.01,
z: (Math.random() - 0.5) * 0.01
},
floatSpeed: Math.random() * 0.5 + 0.2,
floatOffset: Math.random() * Math.PI * 2
};
crystal.castShadow = true;
crystal.receiveShadow = true;
scene.add(crystal);
crystals.push(crystal);
}
// Grid plane
const gridHelper = new THREE.GridHelper(100, 50, 0x444444, 0x222222);
gridHelper.position.y = -1;
gridHelper.material.opacity = 0.3;
gridHelper.material.transparent = true;
scene.add(gridHelper);
// Satellite crystal
const satelliteGeometry = new THREE.IcosahedronGeometry(0.5, 0);
const satellite = new THREE.Mesh(satelliteGeometry, crystalMaterial);
satellite.castShadow = true;
scene.add(satellite);
// Particle trail
const particleCount = 100;
const particles = new THREE.BufferGeometry();
const positions = new Float32Array(particleCount * 3);
const opacities = new Float32Array(particleCount);
particles.setAttribute('position', new THREE.BufferAttribute(positions, 3));
particles.setAttribute('opacity', new THREE.BufferAttribute(opacities, 1));
const particleMaterial = new THREE.PointsMaterial({
color: 0x00ffff,
size: 0.1,
transparent: true,
opacity: 0.6,
blending: THREE.AdditiveBlending
});
const particleSystem = new THREE.Points(particles, particleMaterial);
scene.add(particleSystem);
// Mouse parallax
let mouseX = 0, mouseY = 0;
const targetMouseX = 0, targetMouseY = 0;
document.addEventListener('mousemove', (event) => {
targetMouseX = (event.clientX / window.innerWidth) * 2 - 1;
targetMouseY = -(event.clientY / window.innerHeight) * 2 + 1;
});
// Animation
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const time = clock.getElapsedTime();
// Smooth mouse parallax
mouseX += (targetMouseX - mouseX) * 0.05;
mouseY += (targetMouseY - mouseY) * 0.05;
camera.position.x += (mouseX * 2 - camera.position.x) * 0.05;
camera.position.y += (5 + mouseY * 2 - camera.position.y) * 0.05;
camera.lookAt(0, 2, 0);
// Animate crystals
crystals.forEach(crystal => {
crystal.rotation.x += crystal.userData.rotationSpeed.x;
crystal.rotation.y += crystal.userData.rotationSpeed.y;
crystal.rotation.z += crystal.userData.rotationSpeed.z;
crystal.position.y += Math.sin(time * crystal.userData.floatSpeed + crystal.userData.floatOffset) * 0.002;
});
// Animate satellite
const orbitRadius = 10;
const orbitSpeed = 0.5;
satellite.position.x = Math.cos(time * orbitSpeed) * orbitRadius;
satellite.position.z = Math.sin(time * orbitSpeed) * orbitRadius;
satellite.position.y = 5 + Math.sin(time * 0.3) * 2;
satellite.rotation.x += 0.01;
satellite.rotation.y += 0.02;
// Update particle trail
const positions = particles.attributes.position.array;
const opacities = particles.attributes.opacity.array;
for (let i = 0; i < particleCount; i++) {
const t = i / particleCount;
const trailIndex = Math.floor(t * 20) % 20;
const trailTime = time - trailIndex * 0.1;
const trailRadius = orbitRadius;
positions[i * 3] = Math.cos(trailTime * orbitSpeed) * trailRadius;
positions[i * 3 + 1] = 5 + Math.sin(trailTime * 0.3) * 2;
positions[i * 3 + 2] = Math.sin(trailTime * orbitSpeed) * trailRadius;
opacities[i] = (1 - t) * 0.6;
}
particles.attributes.position.needsUpdate = true;
particles.attributes.opacity.needsUpdate = true;
composer.render();
}
// Handle resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
composer.setSize(window.innerWidth, window.innerHeight);
});
animate();
</script>
</body>
</html>