(
)} />
{/* Glare highlight */}
-
-
- {/* Laser shimmer sweep on hover */}
-
+ )}
- {/* Content — slight Z lift for depth */}
+ {/* Laser shimmer:仅在 hover 时才触发 CSS animation,静止状态不消耗 GPU */}
+ {!reducedMotion && (
+
+ )}
+
+ {/* Content */}
{children}
diff --git a/src/index.css b/src/index.css
index 77052a1..2bc0e59 100644
--- a/src/index.css
+++ b/src/index.css
@@ -4,18 +4,42 @@
@layer base {
:root {
- --bg-color: #050505;
- --text-primary: #f8fafc;
- --text-secondary: #94a3b8;
+ --background: 222.2 84% 4.9%;
+ --foreground: 210 40% 98%;
+ --card: 222.2 84% 4.9%;
+ --card-foreground: 210 40% 98%;
+ --popover: 222.2 84% 4.9%;
+ --popover-foreground: 210 40% 98%;
+ --primary: 217.2 91.2% 59.8%;
+ --primary-foreground: 222.2 47.4% 11.2%;
+ --secondary: 217.2 32.6% 17.5%;
+ --secondary-foreground: 210 40% 98%;
+ --muted: 217.2 32.6% 17.5%;
+ --muted-foreground: 215 20.2% 65.1%;
+ --accent: 217.2 32.6% 17.5%;
+ --accent-foreground: 210 40% 98%;
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 210 40% 98%;
+ --border: 217.2 32.6% 17.5%;
+ --input: 217.2 32.6% 17.5%;
+ --ring: 224.3 76.3% 48%;
+ --radius: 0.5rem;
+ --bg-color: hsl(var(--background));
+ --text-primary: hsl(var(--foreground));
+ --text-secondary: hsl(var(--muted-foreground));
+ }
+}
+
+@layer base {
+ * {
+ @apply border-border;
}
-
html {
scroll-behavior: smooth;
background-color: var(--bg-color);
}
-
body {
- @apply bg-background text-slate-100 font-sans antialiased selection:bg-primary/30 selection:text-white;
+ @apply bg-background text-foreground font-sans antialiased selection:bg-primary/30 selection:text-white;
min-height: 100vh;
overflow-x: hidden;
}
@@ -34,16 +58,8 @@
@apply bg-clip-text text-transparent bg-gradient-to-r from-blue-400 via-indigo-400 to-purple-400;
}
- /* Animated shimmer text */
.text-shimmer {
- background: linear-gradient(
- 90deg,
- #60a5fa 0%,
- #a78bfa 25%,
- #22d3ee 50%,
- #a78bfa 75%,
- #60a5fa 100%
- );
+ background: linear-gradient(90deg, #60a5fa 0%, #a78bfa 25%, #22d3ee 50%, #a78bfa 75%, #60a5fa 100%);
background-size: 200% auto;
-webkit-background-clip: text;
background-clip: text;
@@ -58,16 +74,12 @@
background-size: 50px 50px;
}
- /* Glow behind cards */
.glow-effect::before {
content: '';
@apply absolute inset-0 -z-10 bg-primary/20 blur-2xl rounded-full opacity-0 transition-opacity duration-300;
}
- .glow-effect:hover::before {
- @apply opacity-100;
- }
+ .glow-effect:hover::before { @apply opacity-100; }
- /* Neon text glow */
.text-glow {
text-shadow:
0 0 20px rgba(99, 130, 246, 0.5),
@@ -75,16 +87,106 @@
0 0 100px rgba(99, 130, 246, 0.1);
}
- /* Pulsing ring */
- .pulse-ring {
- position: relative;
- }
+ .pulse-ring { position: relative; }
.pulse-ring::after {
content: '';
@apply absolute inset-0 rounded-full;
border: 1px solid rgba(99, 130, 246, 0.5);
animation: pulse-expand 2s ease-out infinite;
}
+
+ /* ── Premium Glassmorphism ── */
+ .glass-premium {
+ background: linear-gradient(135deg, rgba(255,255,255,0.07) 0%, rgba(255,255,255,0.03) 100%);
+ backdrop-filter: blur(20px) saturate(180%);
+ -webkit-backdrop-filter: blur(20px) saturate(180%);
+ border: 1px solid rgba(255,255,255,0.08);
+ box-shadow:
+ 0 8px 32px 0 rgba(0,0,0,0.45),
+ inset 0 1px 0 rgba(255,255,255,0.10),
+ inset 0 -1px 0 rgba(0,0,0,0.20);
+ transition: border-color 0.3s ease, box-shadow 0.3s ease;
+ }
+ .glass-premium:hover {
+ border-color: rgba(255,255,255,0.14);
+ box-shadow:
+ 0 16px 48px 0 rgba(0,0,0,0.5),
+ inset 0 1px 0 rgba(255,255,255,0.15),
+ inset 0 -1px 0 rgba(0,0,0,0.20),
+ 0 0 0 1px rgba(99,130,246,0.12);
+ }
+
+ /* Light refraction lines (top & left edge highlight) */
+ .glass-refract {
+ position: relative;
+ overflow: hidden;
+ }
+ .glass-refract::before {
+ content: '';
+ position: absolute;
+ top: 0; left: 0; right: 0;
+ height: 1px;
+ background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.45) 35%, rgba(255,255,255,0.12) 70%, transparent 100%);
+ z-index: 2;
+ pointer-events: none;
+ }
+ .glass-refract::after {
+ content: '';
+ position: absolute;
+ top: 0; bottom: 0; left: 0;
+ width: 1px;
+ background: linear-gradient(180deg, rgba(255,255,255,0.35) 0%, rgba(255,255,255,0.05) 50%, transparent 100%);
+ z-index: 2;
+ pointer-events: none;
+ }
+
+ /* Spotlight radial glow above element */
+ .spotlight {
+ position: relative;
+ isolation: isolate;
+ }
+ .spotlight::before {
+ content: '';
+ position: absolute;
+ inset: -80px;
+ background: radial-gradient(circle at 50% -10%, rgba(99,130,246,0.18) 0%, transparent 55%);
+ z-index: -1;
+ pointer-events: none;
+ border-radius: inherit;
+ }
+
+ /* Shine sweep on hover */
+ .glass-shine {
+ position: relative;
+ overflow: hidden;
+ }
+ .glass-shine::after {
+ content: '';
+ position: absolute;
+ top: -50%; left: -75%;
+ width: 50%; height: 200%;
+ background: linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.07) 50%, rgba(255,255,255,0) 100%);
+ transform: skewX(-20deg);
+ transition: left 0.65s ease;
+ pointer-events: none;
+ z-index: 2;
+ }
+ .glass-shine:hover::after { left: 125%; }
+
+ /* Section ambient orb helper */
+ .ambient-glow {
+ position: relative;
+ }
+ .ambient-glow::before {
+ content: '';
+ position: absolute;
+ top: -200px; left: -150px;
+ width: 600px; height: 600px;
+ background: radial-gradient(circle, rgba(59,130,246,0.07) 0%, transparent 70%);
+ pointer-events: none;
+ z-index: 0;
+ border-radius: 50%;
+ }
}
/* ── Keyframes ── */
@@ -126,7 +228,6 @@
50% { transform: translateY(-10px); }
}
-/* Scan line across elements */
@keyframes scan-line {
0% { top: -2px; opacity: 0.8; }
80% { opacity: 0.6; }
diff --git a/tailwind.config.js b/tailwind.config.js
index b2e7c29..18a0af4 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -7,13 +7,47 @@ export default {
theme: {
extend: {
colors: {
- background: '#050505',
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
+ primary: {
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
+ },
+ secondary: {
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ popover: {
+ DEFAULT: "hsl(var(--popover))",
+ foreground: "hsl(var(--popover-foreground))",
+ },
+ card: {
+ DEFAULT: "hsl(var(--card))",
+ foreground: "hsl(var(--card-foreground))",
+ },
surface: '#111111',
- primary: '#3b82f6',
- secondary: '#8b5cf6',
- accent: '#06b6d4',
glow: 'rgba(59, 130, 246, 0.5)',
},
+ borderRadius: {
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
+ },
fontFamily: {
sans: ['Inter', 'system-ui', 'Avenir', 'Helvetica', 'Arial', 'sans-serif'],
},
@@ -22,6 +56,9 @@ export default {
'fade-in': 'fadeIn 0.5s ease-out forwards',
'fade-up': 'fadeUp 0.8s ease-out forwards',
'pulse-slow': 'pulse 4s cubic-bezier(0.4, 0, 0.6, 1) infinite',
+ "accordion-down": "accordion-down 0.2s ease-out",
+ "accordion-up": "accordion-up 0.2s ease-out",
+ "in": "animate-in 0.3s ease-out forwards"
},
keyframes: {
blob: {
@@ -37,6 +74,18 @@ export default {
fadeUp: {
'0%': { opacity: '0', transform: 'translateY(20px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
+ },
+ "accordion-down": {
+ from: { height: 0 },
+ to: { height: "var(--radix-accordion-content-height)" },
+ },
+ "accordion-up": {
+ from: { height: "var(--radix-accordion-content-height)" },
+ to: { height: 0 },
+ },
+ "animate-in": {
+ "0%": { opacity: 0, transform: "translateY(10px)" },
+ "100%": { opacity: 1, transform: "translateY(0)" }
}
}
},
diff --git a/vite.config.ts b/vite.config.ts
index 8b0f57b..bd66168 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -4,4 +4,36 @@ import react from '@vitejs/plugin-react'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
+ build: {
+ rollupOptions: {
+ output: {
+ // 函数形式是正确的 Rollup TS 类型
+ manualChunks(id) {
+ if (id.includes('node_modules/three')) return 'three';
+ if (id.includes('node_modules/framer-motion')) return 'motion';
+ if (id.includes('node_modules/react-dom')) return 'react-vendor';
+ if (id.includes('node_modules/react/')) return 'react-vendor';
+ },
+ },
+ },
+ // 提升 chunk 体积警告阈值(three.js 较大)
+ chunkSizeWarningLimit: 700,
+ minify: 'esbuild',
+ cssCodeSplit: true,
+ sourcemap: false,
+ },
+ server: {
+ warmup: {
+ clientFiles: [
+ './src/App.tsx',
+ './src/components/Hero.tsx',
+ './src/components/AnimatedBackground.tsx',
+ './src/components/ui/LiquidEther.tsx',
+ ],
+ },
+ },
+ // 依赖预构建:让 Vite 提前 bundle 大型 CJS 库
+ optimizeDeps: {
+ include: ['three', 'framer-motion', 'react', 'react-dom'],
+ },
})