|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Our Little 3D Terminal</title> |
|
|
<style> |
|
|
body { margin: 0; overflow: hidden; background-color: #0a0a0a; } |
|
|
canvas { display: block; } |
|
|
#chat-container { |
|
|
position: absolute; |
|
|
bottom: 20px; |
|
|
left: 50%; |
|
|
transform: translateX(-50%); |
|
|
width: 80%; |
|
|
max-width: 600px; |
|
|
z-index: 10; |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
align-items: center; |
|
|
} |
|
|
#chat-input { |
|
|
width: 100%; |
|
|
padding: 10px; |
|
|
border: none; |
|
|
border-radius: 5px; |
|
|
background-color: rgba(50, 50, 70, 0.8); |
|
|
color: #00ff00; |
|
|
font-family: 'Courier New', Courier, monospace; |
|
|
font-size: 1em; |
|
|
outline: none; |
|
|
box-shadow: 0 0 10px rgba(0, 255, 0, 0.5); |
|
|
} |
|
|
#chat-input::placeholder { |
|
|
color: rgba(0, 255, 0, 0.5); |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
|
|
|
|
|
|
<canvas id="three-canvas"></canvas> |
|
|
|
|
|
|
|
|
<div id="chat-container"> |
|
|
<input type="text" id="chat-input" placeholder="Type your thoughts here..."> |
|
|
</div> |
|
|
|
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.158.0/three.min.js"></script> |
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.158.0/examples/js/controls/OrbitControls.js"></script> |
|
|
|
|
|
<script> |
|
|
|
|
|
const canvas = document.getElementById('three-canvas'); |
|
|
const chatInput = document.getElementById('chat-input'); |
|
|
const chatMessages = []; |
|
|
const maxMessages = 10; |
|
|
|
|
|
|
|
|
const scene = new THREE.Scene(); |
|
|
scene.background = new THREE.Color(0x0a0a0a); |
|
|
|
|
|
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); |
|
|
camera.position.set(0, 1, 5); |
|
|
|
|
|
const renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true }); |
|
|
renderer.setSize(window.innerWidth, window.innerHeight); |
|
|
|
|
|
|
|
|
const ambientLight = new THREE.AmbientLight(0x404040); |
|
|
scene.add(ambientLight); |
|
|
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); |
|
|
directionalLight.position.set(1, 1, 1).normalize(); |
|
|
scene.add(directionalLight); |
|
|
|
|
|
|
|
|
const controls = new THREE.OrbitControls(camera, renderer.domElement); |
|
|
controls.enableDamping = true; |
|
|
controls.dampingFactor = 0.25; |
|
|
controls.screenSpacePanning = false; |
|
|
controls.maxPolarAngle = Math.PI / 2; |
|
|
|
|
|
|
|
|
const terminalWidth = 4; |
|
|
const terminalHeight = 2.5; |
|
|
const terminalDepth = 0.1; |
|
|
const terminalGeometry = new THREE.BoxGeometry(terminalWidth, terminalHeight, terminalDepth); |
|
|
|
|
|
|
|
|
const textCanvas = document.createElement('canvas'); |
|
|
textCanvas.width = 512; |
|
|
textCanvas.height = 512; |
|
|
const textContext = textCanvas.getContext('2d'); |
|
|
const terminalTexture = new THREE.CanvasTexture(textCanvas); |
|
|
|
|
|
|
|
|
const terminalMaterial = new THREE.MeshStandardMaterial({ |
|
|
map: terminalTexture, |
|
|
color: 0x222222, |
|
|
emissive: 0x00ff00, |
|
|
emissiveIntensity: 0.8, |
|
|
metalness: 0.1, |
|
|
roughness: 0.8, |
|
|
}); |
|
|
|
|
|
const terminalMesh = new THREE.Mesh(terminalGeometry, terminalMaterial); |
|
|
terminalMesh.position.set(0, 1.5, 0); |
|
|
scene.add(terminalMesh); |
|
|
|
|
|
|
|
|
function updateTerminalTexture() { |
|
|
textContext.fillStyle = '#0a0a0a'; |
|
|
textContext.fillRect(0, 0, textCanvas.width, textCanvas.height); |
|
|
|
|
|
textContext.font = 'Bold 40px Courier New'; |
|
|
textContext.fillStyle = '#00ff00'; |
|
|
textContext.textAlign = 'left'; |
|
|
textContext.textBaseline = 'top'; |
|
|
|
|
|
const padding = 20; |
|
|
const lineHeight = 45; |
|
|
|
|
|
|
|
|
for (let i = 0; i < chatMessages.length; i++) { |
|
|
const message = chatMessages[chatMessages.length - 1 - i]; |
|
|
const y = textCanvas.height - padding - (i * lineHeight); |
|
|
if (y < padding) break; |
|
|
|
|
|
|
|
|
const words = message.split(' '); |
|
|
let line = ''; |
|
|
let currentY = y; |
|
|
|
|
|
for (let j = 0; j < words.length; j++) { |
|
|
const testLine = line + words[j] + ' '; |
|
|
const metrics = textContext.measureText(testLine); |
|
|
const testWidth = metrics.width; |
|
|
|
|
|
if (testWidth > textCanvas.width - padding * 2 && j > 0) { |
|
|
textContext.fillText(line, padding, currentY); |
|
|
line = words[j] + ' '; |
|
|
currentY += lineHeight; |
|
|
if (currentY > textCanvas.height - padding) break; |
|
|
} else { |
|
|
line = testLine; |
|
|
} |
|
|
} |
|
|
if (line.length > 0 && currentY <= textCanvas.height - padding) { |
|
|
textContext.fillText(line, padding, currentY); |
|
|
} |
|
|
if (currentY > textCanvas.height - padding) break; |
|
|
} |
|
|
|
|
|
|
|
|
terminalTexture.needsUpdate = true; |
|
|
} |
|
|
|
|
|
|
|
|
updateTerminalTexture(); |
|
|
|
|
|
|
|
|
chatInput.addEventListener('keypress', function(event) { |
|
|
if (event.key === 'Enter') { |
|
|
const message = chatInput.value.trim(); |
|
|
if (message) { |
|
|
console.log("Sending message:", message); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
chatMessages.push("You: " + message); |
|
|
while (chatMessages.length > maxMessages) { |
|
|
chatMessages.shift(); |
|
|
} |
|
|
updateTerminalTexture(); |
|
|
|
|
|
chatInput.value = ''; |
|
|
event.preventDefault(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
function animate() { |
|
|
requestAnimationFrame(animate); |
|
|
|
|
|
controls.update(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
renderer.render(scene, camera); |
|
|
} |
|
|
|
|
|
|
|
|
window.addEventListener('resize', onWindowResize, false); |
|
|
|
|
|
function onWindowResize() { |
|
|
camera.aspect = window.innerWidth / window.innerHeight; |
|
|
camera.updateProjectionMatrix(); |
|
|
renderer.setSize(window.innerWidth, window.innerHeight); |
|
|
} |
|
|
|
|
|
|
|
|
animate(); |
|
|
|
|
|
|
|
|
chatMessages.push("Alexa: Hey there!"); |
|
|
chatMessages.push("Alexa: What's up?"); |
|
|
updateTerminalTexture(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</script> |
|
|
</body> |
|
|
</html> |