mirror of
https://github.com/System-End/My-website.git
synced 2026-04-19 23:22:50 +00:00
added custom cursor, secrets :3
This commit is contained in:
parent
ad802f60a9
commit
9dcdfabfdd
13 changed files with 259 additions and 174 deletions
|
|
@ -4,7 +4,6 @@ import Navbar from "@/components/Navbar";
|
|||
import AboutPage from "@/pages/AboutPage";
|
||||
import ProjectsPage from "@/pages/ProjectsPage";
|
||||
import APCSPPage from "@/pages/APCSPPage";
|
||||
import ParallaxPage from "@/pages/ParallaxPage";
|
||||
import FoxGame from "@/games/fox-adventure/components/FoxGame";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
|
|
@ -39,7 +38,6 @@ const App = () => {
|
|||
return (
|
||||
<Router>
|
||||
<div className={`min-h-screen bg-background-primary ${isGameActive ? 'game-active' : ''}`}>
|
||||
{/* Background Logo */}
|
||||
<div className="fixed inset-0 z-behind pointer-events-none">
|
||||
<div className="absolute inset-0">
|
||||
<img
|
||||
|
|
@ -50,7 +48,6 @@ const App = () => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Content */}
|
||||
<div className="relative">
|
||||
<Navbar />
|
||||
<main className="content-wrapper section-spacing">
|
||||
|
|
@ -58,7 +55,6 @@ const App = () => {
|
|||
<Route path="/" element={<AboutPage />} />
|
||||
<Route path="/projects" element={<ProjectsPage />} />
|
||||
<Route path="/apcsp" element={<APCSPPage />} />
|
||||
{/* <Route path="/parallax" element={<ParallaxPage />} /> */}
|
||||
<Route path="*" element={
|
||||
<div className="flex flex-col items-center justify-center min-h-[60vh] space-y-4">
|
||||
<h1 className="text-4xl font-bold text-glow">404: Page Not Found</h1>
|
||||
|
|
@ -69,7 +65,6 @@ const App = () => {
|
|||
</main>
|
||||
</div>
|
||||
|
||||
{/* Fox Game Overlay */}
|
||||
{isGameActive && <FoxGame />}
|
||||
</div>
|
||||
</Router>
|
||||
|
|
|
|||
21
src/assets/cursors/default.svg
Normal file
21
src/assets/cursors/default.svg
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
||||
<!-- Fox head shape -->
|
||||
<path d="M16 2 L24 10 L24 24 L8 24 L8 10 Z"
|
||||
fill="#ff9466"
|
||||
stroke="#240046"
|
||||
stroke-width="1.5"/>
|
||||
<!-- Ears -->
|
||||
<path d="M8 10 L2 2 L8 8"
|
||||
fill="#ff9466"
|
||||
stroke="#240046"
|
||||
stroke-width="1.5"/>
|
||||
<path d="M24 10 L30 2 L24 8"
|
||||
fill="#ff9466"
|
||||
stroke="#240046"
|
||||
stroke-width="1.5"/>
|
||||
<!-- Eyes -->
|
||||
<circle cx="12" cy="14" r="2" fill="#240046"/>
|
||||
<circle cx="20" cy="14" r="2" fill="#240046"/>
|
||||
<!-- Nose -->
|
||||
<circle cx="16" cy="18" r="1.5" fill="#240046"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 658 B |
5
src/assets/cursors/paw.svg
Normal file
5
src/assets/cursors/paw.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<path fill="#ffc6e5" stroke="#ff9466" stroke-width="2" d="M12,4 C14,4 15,6 15,8 C15,10 14,12 12,12 C10,12 9,10 9,8 C9,6 10,4 12,4 Z"/>
|
||||
<path fill="#ffc6e5" stroke="#ff9466" stroke-width="2" d="M20,4 C22,4 23,6 23,8 C23,10 22,12 20,12 C18,12 17,10 17,8 C17,6 18,4 20,4 Z"/>
|
||||
<path fill="#ffc6e5" stroke="#ff9466" stroke-width="2" d="M16,8 C20,8 23,12 23,16 C23,20 20,24 16,24 C12,24 9,20 9,16 C9,12 12,8 16,8 Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 515 B |
26
src/assets/cursors/tail-loading.svg
Normal file
26
src/assets/cursors/tail-loading.svg
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
||||
<!-- Tail base -->
|
||||
<path d="M4 16 Q8 8 16 8 Q24 8 28 16 Q24 24 16 24 Q8 24 4 16"
|
||||
fill="#ff9466"
|
||||
stroke="#240046"
|
||||
stroke-width="1.5">
|
||||
<animateTransform
|
||||
attributeName="transform"
|
||||
type="rotate"
|
||||
from="0 16 16"
|
||||
to="360 16 16"
|
||||
dur="1s"
|
||||
repeatCount="indefinite"/>
|
||||
</path>
|
||||
<!-- Tail tip -->
|
||||
<circle cx="16" cy="16" r="4"
|
||||
fill="#ffc6e5"
|
||||
stroke="#240046"
|
||||
stroke-width="1.5">
|
||||
<animate
|
||||
attributeName="r"
|
||||
values="4;5;4"
|
||||
dur="1s"
|
||||
repeatCount="indefinite"/>
|
||||
</circle>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 683 B |
|
|
@ -1,8 +1,7 @@
|
|||
import React, { useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { Monitor, Power, Lock } from 'lucide-react';
|
||||
|
||||
const VNCViewer = () => {
|
||||
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
|
||||
const toggleFullscreen = () => {
|
||||
|
|
@ -10,10 +9,8 @@ const VNCViewer = () => {
|
|||
if (iframe) {
|
||||
if (!document.fullscreenElement) {
|
||||
iframe.requestFullscreen();
|
||||
setIsFullscreen(true);
|
||||
} else {
|
||||
document.exitFullscreen();
|
||||
setIsFullscreen(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -21,7 +18,6 @@ const VNCViewer = () => {
|
|||
return (
|
||||
<div className="min-h-screen w-full flex items-center justify-center p-4">
|
||||
<div className="w-full max-w-6xl bg-background-primary/80 backdrop-blur-sm rounded-xl shadow-xl border border-accent-primary/20 overflow-hidden transition-all duration-300 hover:border-accent-neon/40 hover:shadow-accent-primary/20">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b border-accent-primary/20">
|
||||
<div className="flex items-center gap-3">
|
||||
<Monitor className="text-accent-primary" size={24} />
|
||||
|
|
@ -49,7 +45,6 @@ const VNCViewer = () => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* VNC Viewer */}
|
||||
<div className="aspect-video w-full bg-black/50 relative">
|
||||
{isConnected ? (
|
||||
<iframe
|
||||
|
|
@ -66,7 +61,6 @@ const VNCViewer = () => {
|
|||
)}
|
||||
</div>
|
||||
|
||||
{/* Status Bar */}
|
||||
<div className="p-2 border-t border-accent-primary/20 flex justify-between items-center text-sm text-text-primary/60">
|
||||
<span>Status: {isConnected ? 'Connected' : 'Disconnected'}</span>
|
||||
<span>Press ESC to exit fullscreen</span>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// src/games/fox-adventure/components/GameOverlay.tsx
|
||||
import React from 'react';
|
||||
import { Play, RotateCcw } from 'lucide-react';
|
||||
import useGameStore from '../state/gameStore';
|
||||
import { Play, Pause, RotateCcw } from 'lucide-react';
|
||||
|
||||
export const GameOverlay: React.FC = () => {
|
||||
const { gameStatus, score, startNewGame, resumeGame } = useGameStore();
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export const useGameLoop = () => {
|
|||
|
||||
if (gameStore.gameStatus === 'PLAYING') {
|
||||
// Update entities
|
||||
gameStore.updateEnemies();
|
||||
gameStore.updateEnemies(deltaTime);
|
||||
|
||||
// Spawn collectibles
|
||||
spawnCollectible();
|
||||
|
|
@ -75,4 +75,5 @@ export const useGameLoop = () => {
|
|||
}
|
||||
};
|
||||
}, []);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,62 +1,5 @@
|
|||
import { create } from 'zustand';
|
||||
|
||||
interface Position {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
interface PowerUp {
|
||||
id: string;
|
||||
type: 'SPEED' | 'SHIELD' | 'MAGNET';
|
||||
duration: number;
|
||||
position: Position;
|
||||
}
|
||||
|
||||
interface Collectible {
|
||||
id: string;
|
||||
type: 'STAR' | 'GEM' | 'KEY';
|
||||
value: number;
|
||||
position: Position;
|
||||
}
|
||||
|
||||
interface Enemy {
|
||||
id: string;
|
||||
type: 'WOLF' | 'OWL' | 'HUNTER';
|
||||
position: Position;
|
||||
direction: Position;
|
||||
speed: number;
|
||||
}
|
||||
|
||||
interface PlayerState {
|
||||
position: Position;
|
||||
health: number;
|
||||
speed: number;
|
||||
powerUps: PowerUp[];
|
||||
isInvincible: boolean;
|
||||
hasKey: boolean;
|
||||
}
|
||||
|
||||
interface GameState {
|
||||
player: PlayerState;
|
||||
enemies: Enemy[];
|
||||
collectibles: Collectible[];
|
||||
powerUps: PowerUp[];
|
||||
score: number;
|
||||
level: number;
|
||||
gameStatus: 'MENU' | 'PLAYING' | 'PAUSED' | 'GAME_OVER';
|
||||
highScores: number[];
|
||||
timePlayed: number;
|
||||
|
||||
// Actions
|
||||
movePlayer: (direction: Position) => void;
|
||||
updateEnemies: () => void;
|
||||
collectItem: (itemId: string) => void;
|
||||
takeDamage: (amount: number) => void;
|
||||
activatePowerUp: (powerUpId: string) => void;
|
||||
startNewGame: () => void;
|
||||
pauseGame: () => void;
|
||||
resumeGame: () => void;
|
||||
}
|
||||
import type { GameState, Position } from '@/types/game';
|
||||
|
||||
const useGameStore = create<GameState>((set, get) => ({
|
||||
player: {
|
||||
|
|
@ -76,7 +19,7 @@ const useGameStore = create<GameState>((set, get) => ({
|
|||
highScores: [],
|
||||
timePlayed: 0,
|
||||
|
||||
movePlayer: (direction) => {
|
||||
movePlayer: (direction: Position) => {
|
||||
const { player } = get();
|
||||
set({
|
||||
player: {
|
||||
|
|
@ -112,8 +55,8 @@ const useGameStore = create<GameState>((set, get) => ({
|
|||
set({ enemies: updatedEnemies });
|
||||
},
|
||||
|
||||
collectItem: (itemId) => {
|
||||
const { collectibles, score, player } = get();
|
||||
collectItem: (itemId: string) => {
|
||||
const { collectibles, score } = get();
|
||||
const item = collectibles.find(c => c.id === itemId);
|
||||
if (!item) return;
|
||||
|
||||
|
|
@ -123,7 +66,7 @@ const useGameStore = create<GameState>((set, get) => ({
|
|||
});
|
||||
},
|
||||
|
||||
takeDamage: (amount) => {
|
||||
takeDamage: (amount: number) => {
|
||||
const { player, gameStatus } = get();
|
||||
if (player.isInvincible) return;
|
||||
|
||||
|
|
@ -137,7 +80,7 @@ const useGameStore = create<GameState>((set, get) => ({
|
|||
});
|
||||
},
|
||||
|
||||
activatePowerUp: (powerUpId) => {
|
||||
activatePowerUp: (powerUpId: string) => {
|
||||
const { player, powerUps } = get();
|
||||
const powerUp = powerUps.find(p => p.id === powerUpId);
|
||||
if (!powerUp) return;
|
||||
|
|
@ -150,7 +93,6 @@ const useGameStore = create<GameState>((set, get) => ({
|
|||
powerUps: powerUps.filter(p => p.id !== powerUpId)
|
||||
});
|
||||
|
||||
// Reset power-up after duration
|
||||
setTimeout(() => {
|
||||
const currentPlayer = get().player;
|
||||
set({
|
||||
|
|
|
|||
|
|
@ -1,40 +1,104 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background-primary: #1a0b2e;
|
||||
--background-secondary: #2f1c54;
|
||||
--accent-primary: #9d4edd;
|
||||
--accent-neon: #b249f8;
|
||||
--text-glow: #e0aaff;
|
||||
--text-primary: #ffffff;
|
||||
--dark-accent: #240046;
|
||||
--fox-pink: #ffc6e5;
|
||||
--fox-pink-glow: #ffadd6;
|
||||
--fox-orange: #ff9466;
|
||||
--fox-white: #fff5f9;
|
||||
:root {
|
||||
--background-primary: #1a0b2e;
|
||||
--background-secondary: #2f1c54;
|
||||
--accent-primary: #9d4edd;
|
||||
--accent-neon: #b249f8;
|
||||
--text-glow: #e0aaff;
|
||||
--text-primary: #ffffff;
|
||||
--dark-accent: #240046;
|
||||
--fox-pink: #ffc6e5;
|
||||
--fox-pink-glow: #ffadd6;
|
||||
--fox-orange: #ff9466;
|
||||
--fox-white: #fff5f9;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--background-primary);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
body {
|
||||
@apply
|
||||
font-family: "Inter", sans-serif
|
||||
bg-background-primary text-text-primary;;
|
||||
|
||||
@layer utilities {
|
||||
.text-glow {
|
||||
text-shadow: 0 0 10px var(--text-glow);
|
||||
}
|
||||
|
||||
.section-spacing > * + * {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.card-spacing > * + * {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.element-spacing > * + * {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
/* Global spacing */
|
||||
.content-wrapper {
|
||||
@apply
|
||||
gap-3 px-4 py-2 my-1
|
||||
items-center rounded-lg
|
||||
transition-all hover:bg-accent-primary/10 hover:text-accent-neon
|
||||
flex
|
||||
hover:bg-accent-primary/10 hover:text-accent-neon;
|
||||
}
|
||||
.nav-link.active {
|
||||
@apply
|
||||
p-8 mb-8
|
||||
rounded-xl
|
||||
transition-all hover:border-accent-neon/40 hover:shadow-lg hover:shadow-accent-primary/10
|
||||
relative
|
||||
bg-gradient-card border border-accent-primary/20 hover:border-accent-neon/40 hover:shadow-lg hover:shadow-accent-primary/10;
|
||||
}
|
||||
.text-glow {
|
||||
|
||||
@layer components {
|
||||
.content-wrapper {
|
||||
max-width: 80rem;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 2rem 1rem;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
transition-property: all;
|
||||
transition-duration: 200ms;
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
background-color: rgba(157, 78, 221, 0.1);
|
||||
color: var(--accent-neon);
|
||||
}
|
||||
|
||||
.nav-link.active {
|
||||
background-color: rgba(157, 78, 221, 0.2);
|
||||
color: var(--accent-neon);
|
||||
}
|
||||
|
||||
.fox-card {
|
||||
position: relative;
|
||||
border-radius: 0.75rem;
|
||||
padding: 2rem;
|
||||
transition-property: all;
|
||||
transition-duration: 300ms;
|
||||
border: 1px solid rgba(157, 78, 221, 0.2);
|
||||
background: linear-gradient(135deg, rgba(47, 28, 84, 0.3) 0%, rgba(157, 78, 221, 0.1) 100%);
|
||||
}
|
||||
|
||||
.fox-card:hover {
|
||||
border-color: rgba(178, 73, 248, 0.4);
|
||||
box-shadow: 0 0 10px rgba(157, 78, 221, 0.1);
|
||||
}
|
||||
|
||||
.content-grid {
|
||||
display: grid;
|
||||
gap: 2rem;
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.content-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.content-grid {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
/* Default cursor for all elements */
|
||||
* {
|
||||
cursor: url('@/assets/cursors/default.svg') 16 16, auto;
|
||||
cursor: url('@/assets/cursors/default.svg') 16 16, auto;
|
||||
}
|
||||
|
||||
/* Interactive elements cursor */
|
||||
a,
|
||||
button,
|
||||
|
|
@ -11,36 +12,36 @@ input[type="button"],
|
|||
select,
|
||||
.interactive,
|
||||
.nav-link {
|
||||
cursor: url('@/assets/cursors/paw.svg') 16 16, pointer;
|
||||
cursor: url('@/assets/cursors/paw.svg') 16 16, pointer;
|
||||
}
|
||||
|
||||
/* Loading state cursor */
|
||||
.loading,
|
||||
:disabled,
|
||||
[aria-busy="true"] {
|
||||
cursor: url('@/assets/cursors/tail-loading.svg') 16 16, progress;
|
||||
cursor: url('@/assets/cursors/tail-loading.svg') 16 16, progress;
|
||||
}
|
||||
|
||||
/* Hover effects for interactive elements */
|
||||
a:hover,
|
||||
button:hover,
|
||||
[role="button"]:hover,
|
||||
.nav-link:hover {
|
||||
/* Add a subtle glow effect on hover */
|
||||
filter: drop-shadow(0 0 4px var(--fox-pink-glow));
|
||||
transition: filter 0.3s ease;
|
||||
filter: drop-shadow(0 0 4px var(--fox-pink-glow));
|
||||
transition: filter 0.3s ease;
|
||||
}
|
||||
|
||||
/* Custom cursor regions */
|
||||
.text-select {
|
||||
cursor: text;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.resize {
|
||||
cursor: nw-resize;
|
||||
}
|
||||
/* Ensure cursors work with transform effects */
|
||||
* {
|
||||
cursor-position: fixed;
|
||||
cursor: nw-resize;
|
||||
}
|
||||
|
||||
/* Prevent cursor inheritance in certain cases */
|
||||
iframe,
|
||||
canvas {
|
||||
cursor: inherit;
|
||||
cursor: inherit;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,44 @@
|
|||
@layer utilities {
|
||||
.animated-bg {
|
||||
@apply
|
||||
overflow-hidden; } { content: ''
|
||||
.animated-bg::before
|
||||
relative
|
||||
bg-gradient-primary .animated-bg::before;
|
||||
@apply
|
||||
inset-0 opacity-50; animation: gradientShift 15s ease infinite
|
||||
absolute
|
||||
bg-gradient-primary;
|
||||
.animated-bg {
|
||||
@apply overflow-hidden;
|
||||
}
|
||||
|
||||
.animated-bg::before {
|
||||
content: '';
|
||||
@apply absolute inset-0 opacity-50;
|
||||
@apply bg-gradient-primary;
|
||||
animation: gradientShift 15s ease infinite;
|
||||
}
|
||||
|
||||
.fox-ear {
|
||||
position: absolute;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background: var(--fox-pink);
|
||||
opacity: 0.1;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.fox-ear-left {
|
||||
top: -15px;
|
||||
left: -15px;
|
||||
transform: rotate(45deg);
|
||||
border-radius: 0 0 0 15px;
|
||||
}
|
||||
|
||||
.fox-ear-right {
|
||||
top: -15px;
|
||||
right: -15px;
|
||||
transform: rotate(-45deg);
|
||||
border-radius: 0 0 15px 0;
|
||||
}
|
||||
}
|
||||
.fox-ear {
|
||||
|
||||
@keyframes gradientShift {
|
||||
0%, 100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +1,32 @@
|
|||
export interface Position {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface PowerUp {
|
||||
id: string;
|
||||
type: 'SPEED' | 'SHIELD' | 'MAGNET';
|
||||
duration: number;
|
||||
position: { x: number; y: number };
|
||||
position: Position;
|
||||
}
|
||||
|
||||
export interface Collectible {
|
||||
id: string;
|
||||
type: 'STAR' | 'GEM' | 'KEY';
|
||||
value: number;
|
||||
position: { x: number; y: number };
|
||||
position: Position;
|
||||
}
|
||||
|
||||
export interface Enemy {
|
||||
id: string;
|
||||
type: 'WOLF' | 'OWL' | 'HUNTER';
|
||||
position: { x: number; y: number };
|
||||
direction: { x: number; y: number };
|
||||
position: Position;
|
||||
direction: Position;
|
||||
speed: number;
|
||||
}
|
||||
|
||||
export interface PlayerState {
|
||||
position: { x: number; y: number };
|
||||
position: Position;
|
||||
health: number;
|
||||
speed: number;
|
||||
powerUps: PowerUp[];
|
||||
|
|
@ -39,4 +44,14 @@ export interface GameState {
|
|||
gameStatus: 'MENU' | 'PLAYING' | 'PAUSED' | 'GAME_OVER';
|
||||
highScores: number[];
|
||||
timePlayed: number;
|
||||
}
|
||||
|
||||
// Actions
|
||||
movePlayer: (direction: Position) => void;
|
||||
updateEnemies: (deltaTime?: number) => void;
|
||||
collectItem: (itemId: string) => void;
|
||||
takeDamage: (amount: number) => void;
|
||||
activatePowerUp: (powerUpId: string) => void;
|
||||
startNewGame: () => void;
|
||||
pauseGame: () => void;
|
||||
resumeGame: () => void;
|
||||
}
|
||||
|
|
@ -19,40 +19,31 @@ export default {
|
|||
'fox-orange': '#ff9466',
|
||||
'fox-white': '#fff5f9',
|
||||
},
|
||||
animation: {
|
||||
'bounce-slow': 'bounce 3s linear infinite',
|
||||
'glow': 'glow 2s ease-in-out infinite',
|
||||
'float': 'float 3s ease-in-out infinite',
|
||||
'spin-slow': 'spin 3s linear infinite',
|
||||
'wag': 'wag 1s ease-in-out infinite',
|
||||
'score-popup': 'scorePopup 0.5s ease-out forwards',
|
||||
'particle-fade': 'particleFade 1s ease-out forwards',
|
||||
'menu-enter': 'menuEnter 0.3s ease-out forwards',
|
||||
'menu-exit': 'menuExit 0.3s ease-in forwards',
|
||||
'player-idle': 'playerIdle 2s ease-in-out infinite',
|
||||
'player-hit': 'playerHit 0.5s ease-in-out',
|
||||
},
|
||||
keyframes: {
|
||||
glow: {
|
||||
'0%, 100%': { filter: 'drop-shadow(0 0 2px var(--accent-neon))' },
|
||||
'50%': { filter: 'drop-shadow(0 0 8px var(--accent-neon))' },
|
||||
},
|
||||
float: {
|
||||
'0%, 100%': { transform: 'translateY(0)' },
|
||||
'50%': { transform: 'translateY(-10px)' },
|
||||
},
|
||||
wag: {
|
||||
'0%, 100%': { transform: 'rotate(-10deg)' },
|
||||
'50%': { transform: 'rotate(10deg)' },
|
||||
},
|
||||
},
|
||||
backgroundImage: {
|
||||
'gradient-game': 'linear-gradient(135deg, var(--background-primary) 0%, var(--background-secondary) 100%)',
|
||||
'gradient-card': 'linear-gradient(135deg, rgba(47, 28, 84, 0.3) 0%, rgba(157, 78, 221, 0.1) 100%)',
|
||||
},
|
||||
backdropFilter: {
|
||||
'game': 'blur(8px)',
|
||||
transitionProperty: {
|
||||
'all': 'all',
|
||||
},
|
||||
boxShadow: {
|
||||
'accent': '0 0 10px var(--accent-primary)',
|
||||
},
|
||||
opacity: {
|
||||
'10': '0.1',
|
||||
'20': '0.2',
|
||||
'40': '0.4',
|
||||
}
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
safelist: [
|
||||
'bg-accent-primary/10',
|
||||
'bg-accent-primary/20',
|
||||
'border-accent-primary/20',
|
||||
'border-accent-neon/40',
|
||||
'shadow-accent-primary/10',
|
||||
'hover:bg-accent-primary/10',
|
||||
'hover:border-accent-neon/40',
|
||||
'hover:shadow-accent-primary/10'
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue