lokiai / index.html
ParthSadaria's picture
Update index.html
a0b3c15 verified
raw
history blame
16.6 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Loki.AI - Access Premium AI Models Free</title>
<!-- Favicon (Optional but recommended) -->
<link rel="icon" href="favicon.ico" type="image/x-icon">
<!-- Google Fonts: DM Sans (Bold 700, Regular 400) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&display=swap" rel="stylesheet">
<style>
:root {
--bg-color: #050505;
--text-color: #e0e0e0;
--text-color-muted: #777;
--accent-color: #00ffff; /* Cyan */
--glow-color: rgba(0, 255, 255, 0.15);
--hover-bg: rgba(0, 255, 255, 0.1);
--border-color: rgba(255, 255, 255, 0.1);
--font-main: 'DM Sans', sans-serif;
--transition-speed: 0.3s;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: 16px;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-main);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
position: relative;
overflow: hidden;
cursor: none; /* Hide default cursor */
perspective: 1000px;
}
/* Subtle Animated Background Gradient */
body::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: radial-gradient(circle at 30% 70%, rgba(0, 50, 50, 0.3), transparent 50%),
radial-gradient(circle at 70% 30%, rgba(50, 0, 50, 0.2), transparent 50%);
opacity: 0;
animation: fadeInBg 3s ease-out forwards, pulseBg 15s infinite ease-in-out alternate;
z-index: 0;
}
@keyframes fadeInBg {
to { opacity: 1; }
}
@keyframes pulseBg {
0% { transform: scale(1); opacity: 0.5; }
100% { transform: scale(1.1); opacity: 0.8; }
}
.container {
position: relative;
z-index: 2;
padding: 2rem;
max-width: 900px;
width: 90%;
animation: slideInUp 1s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.5s forwards;
opacity: 0;
transform: translateY(30px);
}
@keyframes slideInUp {
to {
opacity: 1;
transform: translateY(0);
}
}
h1 {
font-size: clamp(3rem, 10vw, 6rem);
font-weight: 700;
letter-spacing: -0.05em;
margin-bottom: 0.2rem;
color: var(--text-color);
text-shadow: 0 0 15px rgba(255, 255, 255, 0.1);
transition: color var(--transition-speed) ease, text-shadow var(--transition-speed) ease;
}
.subtitle {
font-size: clamp(0.9rem, 2.5vw, 1.2rem);
font-weight: 400;
color: var(--text-color-muted);
margin-bottom: 2.5rem;
letter-spacing: 0.05em;
transition: color var(--transition-speed) ease;
}
.models-section {
margin-bottom: 3rem;
opacity: 0;
animation: fadeIn 1s ease 1s forwards;
}
.models-section h2 {
font-size: clamp(1rem, 3vw, 1.3rem);
font-weight: 700;
color: var(--accent-color);
margin-bottom: 1.5rem;
text-transform: uppercase;
letter-spacing: 0.1em;
text-shadow: 0 0 10px var(--glow-color);
}
.models-grid {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 0.8rem;
}
.model-badge {
display: inline-block;
background-color: rgba(255, 255, 255, 0.05);
color: var(--text-color-muted);
font-size: clamp(0.75rem, 2vw, 0.9rem);
font-weight: 400;
padding: 0.5em 1em;
border-radius: 15px;
border: 1px solid var(--border-color);
transition: all var(--transition-speed) cubic-bezier(0.25, 0.46, 0.45, 0.94);
transform: scale(1);
}
.model-badge:hover {
background-color: var(--hover-bg);
color: var(--accent-color);
border-color: var(--accent-color);
transform: scale(1.05) translateY(-2px);
box-shadow: 0 4px 15px rgba(0, 255, 255, 0.2);
}
.playgrounds-section {
opacity: 0;
animation: fadeIn 1s ease 1.2s forwards;
display: flex;
flex-direction: column; /* Stack links vertically on mobile */
align-items: center;
gap: 1rem;
}
@media (min-width: 600px) {
.playgrounds-section {
flex-direction: row; /* Side-by-side on larger screens */
justify-content: center;
gap: 1.5rem;
}
}
.playground-link {
display: inline-block;
color: var(--text-color);
text-decoration: none;
font-size: clamp(0.9rem, 2.5vw, 1.1rem);
font-weight: 700;
padding: 0.8em 1.8em;
border: 2px solid var(--border-color);
border-radius: 5px;
position: relative;
overflow: hidden;
transition: all var(--transition-speed) ease;
z-index: 1;
}
.playground-link::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: var(--accent-color);
transition: left var(--transition-speed) ease;
z-index: -1;
}
.playground-link:hover {
color: var(--bg-color);
border-color: var(--accent-color);
transform: translateY(-3px);
box-shadow: 0 5px 20px rgba(0, 255, 255, 0.3);
}
.playground-link:hover::before {
left: 0;
}
.playground-link span {
display: inline-block;
transition: transform 0.2s ease;
}
.playground-link:hover span {
transform: translateX(3px);
}
/* --- Mouse Effects --- */
.glow {
position: fixed;
/* Position set by JS */
left: 0;
top: 0;
width: 800px;
height: 800px;
background: radial-gradient(circle at center, var(--glow-color) 0%, rgba(0, 0, 0, 0) 60%);
border-radius: 50%; /* Ensure it's circular for centering */
pointer-events: none;
opacity: 0;
transition: opacity 0.4s ease; /* Only transition opacity */
/* transform: translate(-50%, -50%); NO - JS handles transform */
z-index: 1;
filter: blur(10px);
will-change: transform, opacity; /* Optimize animation */
}
body:hover .glow {
opacity: 1;
}
.cursor {
position: fixed;
/* Position set by JS */
left: 0;
top: 0;
width: 25px;
height: 25px;
border: 2px solid var(--accent-color);
border-radius: 50%;
pointer-events: none;
transition: background-color 0.2s ease, border-color 0.2s ease, border-width 0.2s ease, width 0.2s ease, height 0.2s ease; /* Smooth style changes, transform handled by JS loop */
/* transform: translate(-50%, -50%); NO - JS handles transform */
z-index: 9999;
mix-blend-mode: difference;
background-color: transparent;
will-change: transform; /* Optimize animation */
}
/* Cursor interaction states (applied via JS) */
.cursor.hover-link {
/* Scale handled by JS */
background-color: var(--accent-color);
border-color: transparent;
}
.cursor.hover-text {
/* Scale handled by JS */
border-width: 4px;
border-color: rgba(255,255,255, 0.5);
}
.cursor.clicking {
/* Scale handled by JS */
background-color: rgba(255,255,255,0.3);
}
@keyframes fadeIn {
to { opacity: 1; }
}
/* Responsive adjustments */
@media (max-width: 768px) {
h1 {
letter-spacing: -0.03em;
}
.container {
padding: 1.5rem;
}
.models-grid {
gap: 0.6rem;
}
.playgrounds-section {
gap: 0.8rem;
}
.playground-link {
padding: 0.7em 1.5em;
}
/* Reduce glow size on smaller screens */
.glow {
width: 500px;
height: 500px;
}
}
</style>
</head>
<body>
<!-- Mouse Effect Elements -->
<div class="cursor"></div>
<div class="glow"></div>
<!-- Main Content -->
<div class="container">
<h1>Loki.AI</h1>
<p class="subtitle">By Parth Sadaria</p>
<div class="models-section">
<h2>Free Access To Premium Models</h2>
<div class="models-grid">
<!-- Updated Model List -->
<span class="model-badge">GPT-4o</span>
<span class="model-badge">GPT-4o-mini</span>
<span class="model-badge">OpenAI o1</span>
<span class="model-badge">OpenAI o3-mini</span>
<span class="model-badge">GPT-4.5</span>
<span class="model-badge">Claude 3.7 Sonnet</span>
<span class="model-badge">Gemini 1.5 Pro</span>
<span class="model-badge">Gemini 1.5 Flash</span>
<span class="model-badge">And More Top Models...</span>
</div>
</div>
<div class="playgrounds-section">
<a href="https://parthsadaria-lokiai.hf.space/playground" class="playground-link" target="_blank" rel="noopener noreferrer">
<span>AI Playground</span>
</a>
<a href="https://parthsadaria-lokiai.hf.space/image-playground" class="playground-link" target="_blank" rel="noopener noreferrer">
<span>Image Playground</span>
</a>
</div>
</div>
<script>
const cursor = document.querySelector('.cursor');
const glow = document.querySelector('.glow');
const hoverables = document.querySelectorAll('a, .model-badge');
const textElements = document.querySelectorAll('h1, p, h2, .model-badge'); // Include badges for text hover
let mouseX = 0;
let mouseY = 0;
let cursorX = 0;
let cursorY = 0;
let glowX = 0;
let glowY = 0;
// Adjust speed for desired smoothness (lower = smoother, more 'lag')
const cursorSpeed = 0.15;
const glowSpeed = 0.1;
// Store current scale factor for smooth transitions
let currentCursorScale = 1;
const baseCursorScale = 1;
const hoverLinkCursorScale = 1.5;
const hoverTextCursorScale = 0.7;
const clickCursorScale = 0.6;
// Pre-calculate half-widths/heights ONCE (assuming they don't change)
// Note: If elements resize dynamically, might need recalculation
let cursorHalfWidth = cursor.offsetWidth / 2;
let cursorHalfHeight = cursor.offsetHeight / 2;
let glowHalfWidth = glow.offsetWidth / 2;
let glowHalfHeight = glow.offsetHeight / 2;
// Recalculate on resize just in case
window.addEventListener('resize', () => {
cursorHalfWidth = cursor.offsetWidth / 2;
cursorHalfHeight = cursor.offsetHeight / 2;
glowHalfWidth = glow.offsetWidth / 2;
glowHalfHeight = glow.offsetHeight / 2;
});
function animate() {
// Lerp for smooth following
cursorX += (mouseX - cursorX) * cursorSpeed;
cursorY += (mouseY - cursorY) * cursorSpeed;
glowX += (mouseX - glowX) * glowSpeed;
glowY += (mouseY - glowY) * glowSpeed;
// Apply transform for positioning and scaling
// Calculate the top-left position needed to center the element
const cursorTranslateX = cursorX - cursorHalfWidth;
const cursorTranslateY = cursorY - cursorHalfHeight;
const glowTranslateX = glowX - glowHalfWidth;
const glowTranslateY = glowY - glowHalfHeight;
cursor.style.transform = `translate(${cursorTranslateX}px, ${cursorTranslateY}px) scale(${currentCursorScale})`;
glow.style.transform = `translate(${glowTranslateX}px, ${glowTranslateY}px)`; // Glow doesn't scale dynamically here
requestAnimationFrame(animate);
}
document.addEventListener('mousemove', (e) => {
mouseX = e.clientX;
mouseY = e.clientY;
});
// Start the animation loop
animate();
function updateCursorState() {
let targetScale = baseCursorScale;
let isHoveringLink = false;
let isHoveringText = false;
// Check hover states directly (more robust than relying on mouseenter/leave timing with lerp)
hoverables.forEach(el => {
const rect = el.getBoundingClientRect();
if (mouseX >= rect.left && mouseX <= rect.right && mouseY >= rect.top && mouseY <= rect.bottom) {
isHoveringLink = true;
}
});
textElements.forEach(el => {
// Avoid text hover if already hovering a link defined in hoverables
if (!isHoveringLink) {
const rect = el.getBoundingClientRect();
if (mouseX >= rect.left && mouseX <= rect.right && mouseY >= rect.top && mouseY <= rect.bottom) {
isHoveringText = true;
}
}
});
// Apply styles and target scale based on state
cursor.classList.toggle('hover-link', isHoveringLink);
cursor.classList.toggle('hover-text', isHoveringText && !isHoveringLink); // Only text hover if not link hover
if (isHoveringLink) {
targetScale = hoverLinkCursorScale;
} else if (isHoveringText) {
targetScale = hoverTextCursorScale;
}
// Handle clicking state separately
if (cursor.classList.contains('clicking')) {
// Optionally combine scales or prioritize click scale
targetScale = clickCursorScale; // Click scale overrides others
}
// Smoothly transition scale (optional, can also rely on CSS transition if preferred)
// currentCursorScale += (targetScale - currentCursorScale) * 0.2; // Lerp scale
// Simpler: Just set the target scale and let JS/CSS handle visual update
currentCursorScale = targetScale;
}
// Update state on mouse move for accuracy
document.addEventListener('mousemove', updateCursorState);
// Add/Remove clicking class
document.addEventListener('mousedown', () => {
cursor.classList.add('clicking');
updateCursorState(); // Re-evaluate state immediately on click
});
document.addEventListener('mouseup', () => {
cursor.classList.remove('clicking');
updateCursorState(); // Re-evaluate state immediately on release
});
// Initial state check in case mouse enters window over an element
updateCursorState();
</script>
</body>
</html>