Enhance Services Homepage with galaxy background animation and canvas integration
This commit is contained in:
116
index.html
116
index.html
@@ -5,8 +5,10 @@
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Services Homepage</title>
|
||||
<link rel="stylesheet" href="/styles.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="galaxy-canvas"></canvas>
|
||||
<header>
|
||||
<h1>My Services</h1>
|
||||
<p class="subtitle">Quick links to the commonly used containers on this host</p>
|
||||
@@ -32,6 +34,120 @@
|
||||
<footer>
|
||||
<small>Generated: static homepage — served by nginx in a container. Edit and rebuild to update.</small>
|
||||
</footer>
|
||||
<script>
|
||||
// Galaxy background animation with mountains
|
||||
(function initGalaxy(){
|
||||
var ww = window.innerWidth;
|
||||
var wh = window.innerHeight;
|
||||
|
||||
var renderer = new THREE.WebGLRenderer({
|
||||
antialias: true,
|
||||
canvas: document.querySelector('#galaxy-canvas'),
|
||||
alpha: false
|
||||
});
|
||||
renderer.setSize(ww, wh);
|
||||
renderer.setClearColor(0x001a2d, 1);
|
||||
|
||||
var scene = new THREE.Scene();
|
||||
scene.fog = new THREE.Fog(0x001a2d, 80, 140);
|
||||
|
||||
var camera = new THREE.PerspectiveCamera(45, ww/wh, 0.1, 200);
|
||||
camera.position.x = 70;
|
||||
camera.position.y = 30;
|
||||
camera.position.z = 5;
|
||||
camera.lookAt(new THREE.Vector3());
|
||||
|
||||
// Create galaxy particles
|
||||
var particles = [];
|
||||
for(var i = 0; i < 20000; i++){
|
||||
var particle = new Particle();
|
||||
particles.push(particle);
|
||||
scene.add(particle.object);
|
||||
}
|
||||
|
||||
function Particle(){
|
||||
var radius = Math.random() * 120 + 5;
|
||||
var height = (Math.random() - 0.5) * 10;
|
||||
var angle = Math.random() * Math.PI * 2;
|
||||
|
||||
this.object = new THREE.Object3D();
|
||||
this.object.position.y = height;
|
||||
|
||||
var geometry = new THREE.SphereGeometry(0.1, 4, 4);
|
||||
var material = new THREE.MeshBasicMaterial({
|
||||
color: 0xffffff
|
||||
});
|
||||
|
||||
var mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.position.x = radius;
|
||||
|
||||
this.object.add(mesh);
|
||||
this.object.rotation.z = angle;
|
||||
|
||||
this.update = function(){
|
||||
this.object.rotation.z += 0.0002 + (120 - radius) * 0.00002;
|
||||
};
|
||||
}
|
||||
|
||||
// Create terrain/mountains
|
||||
var terrain = new THREE.Object3D();
|
||||
var terrainGeometry = new THREE.PlaneGeometry(400, 400, 100, 100);
|
||||
|
||||
// Modify vertices to create mountain landscape
|
||||
var vertices = terrainGeometry.attributes.position.array;
|
||||
for(var i = 0; i < vertices.length; i += 3){
|
||||
var x = vertices[i];
|
||||
var y = vertices[i + 1];
|
||||
var distance = Math.sqrt(x * x + y * y);
|
||||
var height = (Math.random() - 0.5) * 12;
|
||||
height *= Math.max(0, 1 - distance / 180); // Fade height at edges
|
||||
vertices[i + 2] = height;
|
||||
}
|
||||
terrainGeometry.attributes.position.needsUpdate = true;
|
||||
terrainGeometry.computeVertexNormals();
|
||||
|
||||
var terrainMaterial = new THREE.MeshLambertMaterial({
|
||||
color: 0x0a2540,
|
||||
wireframe: true,
|
||||
transparent: true,
|
||||
opacity: 0.7
|
||||
});
|
||||
|
||||
var terrainMesh = new THREE.Mesh(terrainGeometry, terrainMaterial);
|
||||
terrainMesh.rotation.x = -Math.PI / 2;
|
||||
terrainMesh.position.y = -20;
|
||||
terrain.add(terrainMesh);
|
||||
scene.add(terrain);
|
||||
|
||||
// Add ambient light
|
||||
var ambientLight = new THREE.AmbientLight(0x4488ff, 0.4);
|
||||
scene.add(ambientLight);
|
||||
|
||||
// Add directional light for terrain
|
||||
var directionalLight = new THREE.DirectionalLight(0x88ccff, 0.6);
|
||||
directionalLight.position.set(50, 50, 50);
|
||||
scene.add(directionalLight);
|
||||
|
||||
function render(){
|
||||
requestAnimationFrame(render);
|
||||
particles.forEach(function(p){
|
||||
p.update();
|
||||
});
|
||||
terrain.rotation.z += 0.0001;
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', function(){
|
||||
ww = window.innerWidth;
|
||||
wh = window.innerHeight;
|
||||
camera.aspect = ww / wh;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(ww, wh);
|
||||
});
|
||||
|
||||
render();
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
// Fetch services.xml and render the service cards with logos.
|
||||
(async function(){
|
||||
|
||||
12
styles.css
12
styles.css
@@ -3,20 +3,22 @@
|
||||
--bg:#0f1720;--card:#0b1220;--accent:#4f46e5;--muted:#94a3b8;color-scheme: dark;
|
||||
}
|
||||
*{box-sizing:border-box}
|
||||
html,body{height:100%;margin:0;font-family:Inter,Segoe UI,Roboto,Arial,sans-serif;background:linear-gradient(180deg,#071020 0%,#0b1220 100%);color:#e6eef8}
|
||||
header{padding:24px 20px;text-align:center}
|
||||
html,body{height:100%;margin:0;font-family:Inter,Segoe UI,Roboto,Arial,sans-serif;background:#001a2d;color:#e6eef8;overflow-x:hidden}
|
||||
#galaxy-canvas{position:fixed;top:0;left:0;width:100%;height:100%;z-index:0}
|
||||
header,main,footer{position:relative;z-index:10}
|
||||
header{padding:24px 20px;text-align:center;background:rgba(0,26,45,0.7);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
|
||||
header h1{margin:0;font-size:28px}
|
||||
.subtitle{color:var(--muted);margin-top:6px}
|
||||
.search-container{margin-top:16px;max-width:400px;margin-left:auto;margin-right:auto}
|
||||
#search-input{width:100%;padding:10px 16px;border-radius:8px;border:1px solid rgba(255,255,255,0.15);background:rgba(255,255,255,0.05);color:#e6eef8;font-size:14px;outline:none;transition:all .3s ease;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
|
||||
#search-input{width:100%;padding:10px 16px;border-radius:8px;border:1px solid rgba(255,255,255,0.15);background:rgba(0,15,30,0.8);color:#e6eef8;font-size:14px;outline:none;transition:all .3s ease;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
|
||||
#search-input::placeholder{color:var(--muted)}
|
||||
#search-input:focus{border-color:rgba(79,70,229,0.5);box-shadow:0 0 0 3px rgba(79,70,229,0.2);background:rgba(255,255,255,0.08)}
|
||||
#search-input:focus{border-color:rgba(79,70,229,0.5);box-shadow:0 0 0 3px rgba(79,70,229,0.2);background:rgba(0,15,30,0.9)}
|
||||
main{max-width:1100px;margin:18px auto;padding:12px}
|
||||
.service-group{margin-bottom:32px}
|
||||
.group-header{font-size:18px;font-weight:600;color:#e6eef8;margin:0 0 12px 0;padding-bottom:8px;border-bottom:1px solid rgba(255,255,255,0.1);position:relative}
|
||||
.group-header::before{content:'';position:absolute;bottom:-1px;left:0;width:60px;height:2px;background:linear-gradient(90deg,rgba(79,70,229,0.8),rgba(139,92,246,0.5));border-radius:2px}
|
||||
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px}
|
||||
.card{display:flex;align-items:center;justify-content:center;padding:18px;border-radius:10px;background:linear-gradient(135deg, rgba(79,70,229,0.1), rgba(139,92,246,0.05), rgba(236,72,153,0.1));text-decoration:none;color:inherit;border:1px solid rgba(255,255,255,0.15);font-weight:600;transition:transform .3s ease,box-shadow .3s ease,border-color .3s ease;position:relative;overflow:hidden;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
|
||||
.card{display:flex;align-items:center;justify-content:center;padding:18px;border-radius:10px;background:linear-gradient(135deg, rgba(10,37,64,0.85), rgba(15,50,85,0.85), rgba(20,45,75,0.85));text-decoration:none;color:inherit;border:1px solid rgba(255,255,255,0.2);font-weight:600;transition:transform .3s ease,box-shadow .3s ease,border-color .3s ease;position:relative;overflow:hidden;backdrop-filter:blur(15px);-webkit-backdrop-filter:blur(15px)}
|
||||
.card::before{content:'';position:absolute;top:-50%;left:-50%;width:200%;height:200%;background:linear-gradient(45deg,transparent 30%,rgba(255,255,255,0.08) 50%,transparent 70%);transform:rotate(45deg);animation:shimmer 8s infinite linear;pointer-events:none}
|
||||
@keyframes shimmer{0%{left:-100%}100%{left:100%}}
|
||||
.card:hover::before{animation-duration:3s}
|
||||
|
||||
Reference in New Issue
Block a user