This commit is contained in:
2026-06-18 13:03:19 +08:00
3 changed files with 230 additions and 0 deletions
+58
View File
@@ -9,6 +9,7 @@
"version": "0.0.0",
"dependencies": {
"@ant-design/icons": "^6.2.5",
"@types/three": "^0.184.1",
"antd": "^6.3.7",
"dayjs": "^1.11.20",
"plyr-react": "^6.0.0",
@@ -16,6 +17,7 @@
"react": "^19.2.5",
"react-dom": "^19.2.5",
"react-router-dom": "^7.15.0",
"three": "^0.184.0",
"uuid": "^14.0.0",
"zustand": "^5.0.13"
},
@@ -392,6 +394,12 @@
"node": ">=6.9.0"
}
},
"node_modules/@dimforge/rapier3d-compat": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz",
"integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==",
"license": "Apache-2.0"
},
"node_modules/@emnapi/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
@@ -1726,6 +1734,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/@tweenjs/tween.js": {
"version": "23.1.3",
"resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz",
"integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==",
"license": "MIT"
},
"node_modules/@tybys/wasm-util": {
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
@@ -1788,6 +1802,32 @@
"@types/react": "^19.2.0"
}
},
"node_modules/@types/stats.js": {
"version": "0.17.4",
"resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz",
"integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==",
"license": "MIT"
},
"node_modules/@types/three": {
"version": "0.184.1",
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.184.1.tgz",
"integrity": "sha512-6q4VdiqVsrTRqmk62/BnlcAvIrnDM0zf2ZDVKI5kZiniWrSaOHaQzmbp+BNzoggc/8tgW412pL//wZIxu2PPTA==",
"license": "MIT",
"dependencies": {
"@dimforge/rapier3d-compat": "~0.12.0",
"@tweenjs/tween.js": "~23.1.3",
"@types/stats.js": "*",
"@types/webxr": ">=0.5.17",
"fflate": "~0.8.2",
"meshoptimizer": "~1.1.1"
}
},
"node_modules/@types/webxr": {
"version": "0.5.24",
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz",
"integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==",
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.2.tgz",
@@ -2858,6 +2898,12 @@
}
}
},
"node_modules/fflate": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz",
"integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==",
"license": "MIT"
},
"node_modules/file-entry-cache": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -3543,6 +3589,12 @@
"node": ">= 8"
}
},
"node_modules/meshoptimizer": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.1.1.tgz",
"integrity": "sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g==",
"license": "MIT"
},
"node_modules/micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
@@ -4424,6 +4476,12 @@
"node": ">=0.8"
}
},
"node_modules/three": {
"version": "0.184.0",
"resolved": "https://registry.npmjs.org/three/-/three-0.184.0.tgz",
"integrity": "sha512-wtTRjG92pM5eUg/KuUnHsqSAlPM296brTOcLgMRqEeylYTh/CdtvKUvCyyCQTzFuStieWxvZb8mVTMvdPyUpxg==",
"license": "MIT"
},
"node_modules/throttle-debounce": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz",
+2
View File
@@ -11,6 +11,7 @@
},
"dependencies": {
"@ant-design/icons": "^6.2.5",
"@types/three": "^0.184.1",
"antd": "^6.3.7",
"dayjs": "^1.11.20",
"plyr-react": "^6.0.0",
@@ -18,6 +19,7 @@
"react": "^19.2.5",
"react-dom": "^19.2.5",
"react-router-dom": "^7.15.0",
"three": "^0.184.0",
"uuid": "^14.0.0",
"zustand": "^5.0.13"
},
+170
View File
@@ -0,0 +1,170 @@
const fs = require('fs');
const content = `import { useEffect, useRef } from 'react';
import * as THREE from 'three';
const GalaxyBackground = () => {
const containerRef = useRef(null);
const animationIdRef = useRef(0);
useEffect(() => {
if (!containerRef.current) return;
const width = containerRef.current.clientWidth;
const height = containerRef.current.clientHeight;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
camera.position.z = 50;
const canvas = containerRef.current.querySelector('canvas');
if (!canvas) return;
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true,
alpha: true,
});
renderer.setSize(width, height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
const particleCount = 5000;
const positions = new Float32Array(particleCount * 3);
const colors = new Float32Array(particleCount * 3);
const sizes = new Float32Array(particleCount);
const phases = new Float32Array(particleCount);
const color1 = new THREE.Color(0x6366f1);
const color2 = new THREE.Color(0x8b5cf6);
const color3 = new THREE.Color(0xec4899);
for (let i = 0; i < particleCount; i++) {
const i3 = i * 3;
const radius = 2 + Math.random() * 25;
const theta = Math.random() * Math.PI * 2;
const phi = Math.acos(2 * Math.random() - 1);
positions[i3] = radius * Math.sin(phi) * Math.cos(theta);
positions[i3 + 1] = radius * Math.sin(phi) * Math.sin(theta);
positions[i3 + 2] = radius * Math.cos(phi);
const colorMix = Math.random();
let color;
if (colorMix < 0.33) {
color = color1;
} else if (colorMix < 0.66) {
color = color2;
} else {
color = color3;
}
colors[i3] = color.r;
colors[i3 + 1] = color.g;
colors[i3 + 2] = color.b;
sizes[i] = 0.02 + Math.random() * 0.08;
phases[i] = Math.random() * Math.PI * 2;
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));
geometry.setAttribute('phase', new THREE.BufferAttribute(phases, 1));
const shaderMaterial = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0 },
uPixelRatio: { value: renderer.getPixelRatio() },
uSize: { value: 40 },
},
vertexShader: "attribute float size; attribute float phase; varying vec3 vColor; uniform float uTime; uniform float uPixelRatio; uniform float uSize; void main() { vColor = color; float spiralOffset = phase + uTime * 0.1; float spiralRadius = length(position.xy) * 0.02; float x = position.x + cos(spiralOffset) * spiralRadius; float y = position.y + sin(spiralOffset) * spiralRadius; float z = position.z + sin(uTime * 0.05 + phase) * 0.5; vec4 mvPosition = modelViewMatrix * vec4(x, y, z, 1.0); gl_PointSize = size * uSize * (300.0 / -mvPosition.z) * uPixelRatio; gl_Position = projectionMatrix * mvPosition; }",
fragmentShader: "varying vec3 vColor; uniform float uTime; void main() { vec2 center = gl_PointCoord - vec2(0.5); float dist = length(center); if (dist > 0.5) discard; float gradient = 1.0 - smoothstep(0.0, 0.5, dist); float glow = 1.0 - smoothstep(0.15, 0.5, dist); vec3 finalColor = vColor * gradient; float alpha = glow * (0.7 + sin(uTime * 2.0 + gl_FragCoord.x * 0.05) * 0.3); gl_FragColor = vec4(finalColor, alpha); }",
transparent: true,
opacity: 0.9,
depthWrite: false,
blending: THREE.AdditiveBlending,
vertexColors: true,
});
const particles = new THREE.Points(geometry, shaderMaterial);
scene.add(particles);
const centerGlowGeometry = new THREE.SphereGeometry(8, 32, 32);
const centerGlowMaterial = new THREE.MeshBasicMaterial({
color: 0x6366f1,
transparent: true,
opacity: 0.08,
});
const centerGlow = new THREE.Mesh(centerGlowGeometry, centerGlowMaterial);
scene.add(centerGlow);
const animate = () => {
animationIdRef.current = requestAnimationFrame(animate);
const time = performance.now() * 0.001;
if (shaderMaterial.uniforms.uTime) {
shaderMaterial.uniforms.uTime.value = time;
}
particles.rotation.y += 0.0003;
particles.rotation.x += 0.0001;
centerGlow.rotation.y -= 0.0002;
const pulse = 0.08 + Math.sin(time * 1.5) * 0.03;
centerGlow.scale.setScalar(pulse);
renderer.render(scene, camera);
};
animate();
const handleResize = () => {
const newWidth = containerRef.current?.clientWidth || width;
const newHeight = containerRef.current?.clientHeight || height;
camera.aspect = newWidth / newHeight;
camera.updateProjectionMatrix();
renderer.setSize(newWidth, newHeight);
shaderMaterial.uniforms.uPixelRatio.value = renderer.getPixelRatio();
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
cancelAnimationFrame(animationIdRef.current);
geometry.dispose();
shaderMaterial.dispose();
renderer.dispose();
centerGlowGeometry.dispose();
centerGlowMaterial.dispose();
};
}, []);
return (
<div
ref={containerRef}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
zIndex: 0,
overflow: 'hidden',
}}
>
<canvas style={{ display: 'block' }} />
</div>
);
};
export default GalaxyBackground;
`;
fs.writeFileSync('d:/ÃñÖÚÆÕ¿µ/video_item/video-gen-app/src/components/GalaxyBackground.tsx', content);
console.log('File written successfully');