Refactor: Remove teal; strict monochrome 16-point demo

This commit is contained in:
2026-02-16 19:45:43 -08:00
parent 2c98766f44
commit c9b8312a26

View File

@@ -3,19 +3,23 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sune Logo Animation </title> <title>Sune Logo ✺</title>
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<style> <style>
:root { :root {
--sune-primary: #ffffff; --sune-primary: #ffffff;
--sune-bg: #000000; --sune-bg: #000000;
--miku-teal: #39c5bb;
} }
body { body {
background-color: var(--sune-bg); background-color: var(--sune-bg);
color: var(--sune-primary); color: var(--sune-primary);
transition: background-color 0.5s ease, color 0.5s ease; transition: background-color 0.4s ease, color 0.4s ease;
margin: 0;
display: flex;
align-items: center;
justify-center: center;
height: 100vh;
} }
.inverted { .inverted {
@@ -23,7 +27,6 @@
--sune-bg: #ffffff; --sune-bg: #ffffff;
} }
/* The Core Animation Keyframes */
@keyframes sune-spin { @keyframes sune-spin {
from { transform: rotate(0deg); } from { transform: rotate(0deg); }
to { transform: rotate(360deg); } to { transform: rotate(360deg); }
@@ -31,17 +34,17 @@
@keyframes sune-pulse { @keyframes sune-pulse {
0%, 100% { transform: scale(1); opacity: 1; } 0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(0.85); opacity: 0.4; } 50% { transform: scale(0.8); opacity: 0.3; }
} }
@keyframes sune-breathe { @keyframes sune-breathe {
0%, 100% { transform: scale(1); } 0%, 100% { transform: scale(1); }
50% { transform: scale(1.1); } 50% { transform: scale(1.08); }
} }
.sune-main-group { .sune-main-group {
transform-origin: center; transform-origin: center;
animation: sune-spin 12s linear infinite; animation: sune-spin 16s linear infinite;
} }
.is-generating .sune-main-group { .is-generating .sune-main-group {
@@ -50,71 +53,69 @@
.sune-spike { .sune-spike {
transform-origin: center; transform-origin: center;
transition: fill 0.3s ease; fill: currentColor;
} }
/* Staggered animation for 16 spikes */ /* Staggered pulse for the 16 spikes */
.is-generating .sune-spike { .is-generating .sune-spike {
animation: sune-pulse 2s ease-in-out infinite; animation: sune-pulse 2s ease-in-out infinite;
} }
/* Generate delays for 16 points via CSS (Multiples of 4 logic) */ /* 16 spikes, staggered by 1/16th of the duration */
.sune-spike:nth-child(4n) { color: var(--miku-teal); } .sune-spike:nth-child(1) { animation-delay: 0.000s; }
.sune-spike:nth-child(2) { animation-delay: 0.125s; }
.sune-spike:nth-child(1) { animation-delay: 0.0s; } .sune-spike:nth-child(3) { animation-delay: 0.250s; }
.sune-spike:nth-child(2) { animation-delay: 0.1s; } .sune-spike:nth-child(4) { animation-delay: 0.375s; }
.sune-spike:nth-child(3) { animation-delay: 0.2s; } .sune-spike:nth-child(5) { animation-delay: 0.500s; }
.sune-spike:nth-child(4) { animation-delay: 0.3s; } .sune-spike:nth-child(6) { animation-delay: 0.625s; }
.sune-spike:nth-child(5) { animation-delay: 0.4s; } .sune-spike:nth-child(7) { animation-delay: 0.750s; }
.sune-spike:nth-child(6) { animation-delay: 0.5s; } .sune-spike:nth-child(8) { animation-delay: 0.875s; }
.sune-spike:nth-child(7) { animation-delay: 0.6s; } .sune-spike:nth-child(9) { animation-delay: 1.000s; }
.sune-spike:nth-child(8) { animation-delay: 0.7s; } .sune-spike:nth-child(10) { animation-delay: 1.125s; }
.sune-spike:nth-child(9) { animation-delay: 0.8s; } .sune-spike:nth-child(11) { animation-delay: 1.250s; }
.sune-spike:nth-child(10) { animation-delay: 0.9s; } .sune-spike:nth-child(12) { animation-delay: 1.375s; }
.sune-spike:nth-child(11) { animation-delay: 1.0s; } .sune-spike:nth-child(13) { animation-delay: 1.500s; }
.sune-spike:nth-child(12) { animation-delay: 1.1s; } .sune-spike:nth-child(14) { animation-delay: 1.625s; }
.sune-spike:nth-child(13) { animation-delay: 1.2s; } .sune-spike:nth-child(15) { animation-delay: 1.750s; }
.sune-spike:nth-child(14) { animation-delay: 1.3s; } .sune-spike:nth-child(16) { animation-delay: 1.875s; }
.sune-spike:nth-child(15) { animation-delay: 1.4s; }
.sune-spike:nth-child(16) { animation-delay: 1.5s; }
.logo-container { .logo-container {
transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); transition: transform 0.6s cubic-bezier(0.2, 1, 0.2, 1);
animation: sune-breathe 8s ease-in-out infinite;
} }
.logo-container:active { .is-generating.logo-container {
transform: scale(0.9); animation: none;
} }
</style> </style>
</head> </head>
<body class="h-screen flex flex-col items-center justify-center overflow-hidden"> <body class="flex flex-col items-center justify-center">
<div id="logoWrapper" class="logo-container cursor-pointer p-20" onclick="toggleState()"> <div id="logoWrapper" class="logo-container cursor-pointer p-10" onclick="toggleState()">
<svg id="suneLogo" width="300" height="300" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> <svg id="suneLogo" width="400" height="400" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<g class="sune-main-group" id="spikeGroup"> <g class="sune-main-group" id="spikeGroup"></g>
<!-- Spikes will be generated here -->
</g>
</svg> </svg>
</div> </div>
<div class="fixed bottom-10 flex flex-col items-center gap-4"> <div class="fixed bottom-12 flex flex-col items-center gap-6">
<h1 class="text-2xl font-light tracking-widest uppercase opacity-50">Sune ✺ 16</h1>
<div class="flex gap-4"> <div class="flex gap-4">
<button onclick="toggleInvert()" class="px-4 py-2 border border-current rounded-full text-xs hover:bg-current hover:text-black transition">Invert Color</button> <button onclick="toggleInvert()" class="w-10 h-10 rounded-full border border-current flex items-center justify-center hover:bg-current hover:text-[var(--sune-bg)] transition-all" title="Invert Colors">
<button onclick="toggleState()" class="px-4 py-2 border border-current rounded-full text-xs hover:bg-current hover:text-black transition">Toggle "Generating"</button> <div class="w-4 h-4 rounded-full bg-current"></div>
</button>
<button id="stateBtn" onclick="toggleState()" class="px-6 py-2 rounded-full border border-current text-[10px] uppercase tracking-[0.2em] hover:bg-current hover:text-[var(--sune-bg)] transition-all">
Idle
</button>
</div> </div>
<p class="text-[10px] opacity-30 font-mono">Click logo to expand/collapse</p>
</div> </div>
<script> <script>
const spikeGroup = document.getElementById('spikeGroup'); const spikeGroup = document.getElementById('spikeGroup');
const points = 16; const points = 16;
const outerRadius = 45; const outerRadius = 48;
const innerRadius = 15; const innerRadius = 14;
const centerX = 50; const centerX = 50;
const centerY = 50; const centerY = 50;
// Procedural generation of the 16-point star
function generateSune() { function generateSune() {
let html = ''; let html = '';
for (let i = 0; i < points; i++) { for (let i = 0; i < points; i++) {
@@ -122,7 +123,6 @@
const nextAngle = ((i + 1) * 2 * Math.PI) / points; const nextAngle = ((i + 1) * 2 * Math.PI) / points;
const midAngle = angle + (Math.PI / points); const midAngle = angle + (Math.PI / points);
// Calculate coordinates
const x1 = centerX + innerRadius * Math.cos(angle); const x1 = centerX + innerRadius * Math.cos(angle);
const y1 = centerY + innerRadius * Math.sin(angle); const y1 = centerY + innerRadius * Math.sin(angle);
@@ -132,8 +132,7 @@
const x2 = centerX + innerRadius * Math.cos(nextAngle); const x2 = centerX + innerRadius * Math.cos(nextAngle);
const y2 = centerY + innerRadius * Math.sin(nextAngle); const y2 = centerY + innerRadius * Math.sin(nextAngle);
// Create a single spike path html += `<path class="sune-spike" d="M ${centerX} ${centerY} L ${x1} ${y1} L ${xPeak} ${yPeak} L ${x2} ${y2} Z" />`;
html += `<path class="sune-spike" d="M ${centerX} ${centerY} L ${x1} ${y1} L ${xPeak} ${yPeak} L ${x2} ${y2} Z" fill="currentColor" />`;
} }
spikeGroup.innerHTML = html; spikeGroup.innerHTML = html;
} }
@@ -144,10 +143,10 @@
function toggleState() { function toggleState() {
const wrapper = document.getElementById('logoWrapper'); const wrapper = document.getElementById('logoWrapper');
wrapper.classList.toggle('is-generating'); const btn = document.getElementById('stateBtn');
const isGen = wrapper.classList.toggle('is-generating');
// Haptic feedback simulation btn.innerText = isGen ? 'Generating' : 'Idle';
if ('vibrate' in navigator) navigator.vibrate(10); if ('vibrate' in navigator) navigator.vibrate(isGen ? [10, 30, 10] : 10);
} }
generateSune(); generateSune();