Initial commit — Singular Particular Space v1
Homepage (site/index.html): integration-v14 promoted, Writings section integrated with 33 pieces clustered by type (stories/essays/miscellany), Writings welcome lightbox, content frame at 98% opacity. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,417 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!--
|
||||
Integration v7 — THE NIGHT MARKET: MERGED MASTERY — 2026-03-26
|
||||
AUTHOR: Gemini (Master Designer) & Sonnet (Full-stack Integration)
|
||||
|
||||
THE MOTION FLOW:
|
||||
- Stars & Grid (Locked Back): Recede UP slowly (0.1x relative speed).
|
||||
- Sequence Fading: Grid fades by 40% scroll, Stars by 85% scroll.
|
||||
- Skyline Ascent: Rises quickly (0.7x relative speed) into the sky.
|
||||
- 8px Gap Constraint: Grid pinned to star-zone base; flush alignment.
|
||||
|
||||
THE AESTHETIC (Vaporwave Mad Max Rainforest):
|
||||
- 25% Darker Buildings (#050810).
|
||||
- Procedural Bioluminescent Overgrowth (Mint/Orchid).
|
||||
- Holographic Glitch Glyphs (文映♬絵≡視⚙創).
|
||||
- Scavenged Matrix HUD ([ SYSTEM ] header, phosphor green).
|
||||
- CRT Ghost (0.04 opacity).
|
||||
|
||||
THE MECHANICS:
|
||||
- Smooth cubic descent/ascent.
|
||||
- Keyboard spatial navigation (arrow keys).
|
||||
- Visited star tracking (localStorage).
|
||||
- Throttled 20fps RAF for performance.
|
||||
-->
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Singular Particular Space</title>
|
||||
<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=Noto+Emoji&family=Space+Grotesk:wght@300;400;500;600&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg-void: #04060b;
|
||||
--bg-deep: #050810; /* 25% Darker */
|
||||
--bg-warm: #0d1320;
|
||||
--fire-amber: #e8943a;
|
||||
--fire-coral: #d4654a;
|
||||
--neon-green: #32dc8c;
|
||||
--neon-teal: #2ac4b3;
|
||||
--orchid: #c558d9;
|
||||
--mint-glow: #86efac;
|
||||
--fairy-pink: #f472b6;
|
||||
--phosphor: #00ff41;
|
||||
--text-warm: #e8d5b8;
|
||||
--text-muted: #6a7a8a;
|
||||
}
|
||||
|
||||
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
html { scroll-behavior: auto; overflow-x: hidden; }
|
||||
|
||||
body {
|
||||
font-family: 'Space Grotesk', system-ui, sans-serif;
|
||||
background: var(--bg-void);
|
||||
color: var(--text-warm);
|
||||
min-height: 200vh;
|
||||
}
|
||||
body.content-mode { overflow-y: auto; }
|
||||
|
||||
/* ── CRT Scanline Overlay ── */
|
||||
body::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0, 0, 0, 0.04) 2px, rgba(0, 0, 0, 0.04) 4px);
|
||||
pointer-events: none;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
/* ── Zone 1: Star Map (The Receding Back) ── */
|
||||
#star-zone {
|
||||
position: fixed;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100vh;
|
||||
z-index: 1;
|
||||
background: radial-gradient(ellipse at 50% 40%, #090d1c 0%, var(--bg-void) 100%);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
#nebula-canvas, #star-canvas, #grid-canvas {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
#grid-canvas {
|
||||
height: 45vh;
|
||||
top: auto; bottom: 0; /* Flush with bottom */
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* ── Star Nodes ── */
|
||||
.star-node {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
transform: translate(-50%, -50%);
|
||||
background: none; border: none; outline: none;
|
||||
}
|
||||
|
||||
.star-visual {
|
||||
position: relative;
|
||||
width: 40px; height: 40px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
|
||||
.star-dot {
|
||||
width: 7px; height: 7px;
|
||||
border-radius: 50%;
|
||||
transition: all 150ms ease;
|
||||
box-shadow: 0 0 6px rgba(255,255,255,0.15);
|
||||
}
|
||||
|
||||
.star-label {
|
||||
font-size: clamp(12px, 2vw, 16px);
|
||||
color: var(--text-muted);
|
||||
opacity: 0;
|
||||
transition: all 200ms ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.star-node:hover .star-label, .star-node.current .star-label { opacity: 1; color: var(--text-warm); }
|
||||
|
||||
/* Personality Colors */
|
||||
.star-node[data-star="writings"] .star-dot { background: #a0c4ff; }
|
||||
.star-node[data-star="videos"] .star-dot { background: #d4654a; }
|
||||
.star-node[data-star="music"] .star-dot { background: #2ac4b3; }
|
||||
.star-node[data-star="images"] .star-dot { background: #86efac; }
|
||||
.star-node[data-star="playlists"] .star-dot { background: #ffcf40; }
|
||||
.star-node[data-star="watchlists"] .star-dot { background: #c558d9; }
|
||||
.star-node[data-star="toolsntoys"] .star-dot { background: #f472b6; }
|
||||
.star-node[data-star="creatorlists"] .star-dot { background: #c4a24a; }
|
||||
|
||||
/* Bloom Effect */
|
||||
.star-node:hover .star-dot { width: 20px; height: 20px; background: var(--fire-amber) !important; box-shadow: 0 0 12px var(--fire-amber); }
|
||||
.star-node.current .star-dot { width: 40px; height: 40px; background: var(--fire-amber) !important; box-shadow: 0 0 20px var(--fire-amber); }
|
||||
|
||||
/* ── Zone 2: Transition (The Rising Skyline) ── */
|
||||
#transition-zone {
|
||||
position: relative;
|
||||
width: 100%; height: 100vh;
|
||||
margin-top: 100vh;
|
||||
z-index: 5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#skyline {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
padding-bottom: 2vh;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.building {
|
||||
background: var(--bg-deep);
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
border-top: 1px solid rgba(232, 148, 58, 0.12);
|
||||
margin: 0 1px;
|
||||
}
|
||||
|
||||
.vine {
|
||||
position: absolute;
|
||||
width: 2px;
|
||||
background: var(--mint-glow);
|
||||
opacity: 0.2;
|
||||
box-shadow: 0 0 4px var(--mint-glow);
|
||||
animation: vine-breathe 4s infinite;
|
||||
}
|
||||
.vine.orchid { background: var(--orchid); box-shadow: 0 0 4px var(--orchid); animation-delay: 2s; }
|
||||
|
||||
@keyframes vine-breathe { 0%, 100% { opacity: 0.15; height: 30%; } 50% { opacity: 0.4; height: 45%; } }
|
||||
|
||||
.billboard-nav {
|
||||
position: absolute;
|
||||
top: -2px; left: 50%;
|
||||
transform: translate(-50%, -100%);
|
||||
background: rgba(4, 6, 11, 0.95);
|
||||
border: 1px solid var(--neon-teal);
|
||||
color: var(--neon-teal);
|
||||
padding: 4px 10px;
|
||||
font-size: 18px;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
pointer-events: auto;
|
||||
z-index: 10;
|
||||
animation: glitch 12s infinite;
|
||||
}
|
||||
|
||||
@keyframes glitch {
|
||||
0%, 94%, 100% { transform: translate(-50%, -100%) skew(0deg); }
|
||||
95% { transform: translate(-52%, -101%) skew(4deg); color: var(--fire-coral); }
|
||||
97% { transform: translate(-48%, -99%) skew(-3deg); color: var(--orchid); }
|
||||
}
|
||||
|
||||
/* ── Zone 3: Content ── */
|
||||
#content-zone {
|
||||
position: relative;
|
||||
width: 100%; min-height: 100vh;
|
||||
background: var(--bg-warm);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
#content-frame {
|
||||
width: 100%; height: 100vh;
|
||||
border: none; background: var(--bg-warm);
|
||||
opacity: 0; transition: opacity 0.4s;
|
||||
}
|
||||
#content-frame.loaded { opacity: 1; }
|
||||
|
||||
/* ── HUD ── */
|
||||
#hud {
|
||||
position: fixed; top: 15px; right: 15px; z-index: 100;
|
||||
background: rgba(4, 6, 11, 0.9); border: 1px solid rgba(0, 255, 65, 0.15);
|
||||
padding: 10px 14px; font-family: monospace;
|
||||
}
|
||||
#hud::before { content: '[ SYSTEM ]'; font-size: 8px; color: rgba(0,255,65,0.4); display: block; margin-bottom: 4px; }
|
||||
#back-btn { background: none; border: none; color: var(--phosphor); cursor: pointer; font-size: 12px; }
|
||||
#back-btn::before { content: '> '; }
|
||||
#back-btn::after { content: '_'; animation: cursor-blink 1s step-end infinite; }
|
||||
@keyframes cursor-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="star-zone">
|
||||
<canvas id="nebula-canvas"></canvas>
|
||||
<canvas id="star-canvas"></canvas>
|
||||
<canvas id="grid-canvas"></canvas>
|
||||
</div>
|
||||
|
||||
<div id="transition-zone">
|
||||
<div id="skyline"></div>
|
||||
</div>
|
||||
|
||||
<div id="content-zone">
|
||||
<iframe id="content-frame"></iframe>
|
||||
</div>
|
||||
|
||||
<div id="hud">
|
||||
<button id="back-btn">STARS</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const STARS = [
|
||||
{ id: 'writings', label: 'Writings', sign: '文', x: 25, y: 18 },
|
||||
{ id: 'videos', label: 'Videos', sign: '映', x: 68, y: 15 },
|
||||
{ id: 'music', label: 'Music', sign: '♬', x: 12, y: 42 },
|
||||
{ id: 'images', label: 'Images', sign: '絵', x: 55, y: 35 },
|
||||
{ id: 'playlists', label: 'Playlists', sign: '≡', x: 78, y: 48 },
|
||||
{ id: 'watchlists', label: 'Watchlists', sign: '視', x: 22, y: 65 },
|
||||
{ id: 'toolsntoys', label: 'ToolsnToys', sign: '⚙', x: 50, y: 72 },
|
||||
{ id: 'creatorlists', label: 'Creatorlists', sign: '創', x: 75, y: 70 }
|
||||
];
|
||||
|
||||
const starCanvas = document.getElementById('star-canvas');
|
||||
const nebulaCanvas = document.getElementById('nebula-canvas');
|
||||
const gridCanvas = document.getElementById('grid-canvas');
|
||||
const skyline = document.getElementById('skyline');
|
||||
const starZone = document.getElementById('star-zone');
|
||||
|
||||
// ── Parallax & Fading Logic ──
|
||||
function updateParallax() {
|
||||
const scrollY = window.scrollY || window.pageYOffset;
|
||||
const vh = window.innerHeight;
|
||||
const progress = Math.min(scrollY / vh, 1);
|
||||
|
||||
// 1. Receding Background (Slow Drift UP)
|
||||
const bgTranslate = -scrollY * 0.1;
|
||||
starCanvas.style.transform = `translateY(${bgTranslate}px)`;
|
||||
nebulaCanvas.style.transform = `translateY(${bgTranslate}px)`;
|
||||
gridCanvas.style.transform = `translateY(${bgTranslate}px)`;
|
||||
|
||||
// 2. Sequential Fading
|
||||
gridCanvas.style.opacity = Math.max(0, 1 - progress * 2.5); // Fades out by 40% scroll
|
||||
starCanvas.style.opacity = Math.max(0, 1 - progress * 1.2); // Fades out by 85% scroll
|
||||
nebulaCanvas.style.opacity = Math.max(0, 1 - progress * 1.5);
|
||||
|
||||
// 3. Skyline Ascent (Quickly Rising into Frame)
|
||||
const skyTranslate = -scrollY * 0.35;
|
||||
skyline.style.transform = `translateY(${skyTranslate}px)`;
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', updateParallax, { passive: true });
|
||||
|
||||
// ── Starfield (Animated Drift) ──
|
||||
let bgStars = [];
|
||||
function initStars() {
|
||||
const w = window.innerWidth, h = window.innerHeight;
|
||||
starCanvas.width = w; starCanvas.height = h;
|
||||
bgStars = Array.from({length: 300}, () => ({
|
||||
x: Math.random() * w, y: Math.random() * h,
|
||||
r: Math.random() * 2,
|
||||
dx: (Math.random() - 0.5) * 0.06,
|
||||
dy: (Math.random() - 0.5) * 0.06,
|
||||
o: 0.15 + Math.random() * 0.5,
|
||||
phase: Math.random() * Math.PI * 2
|
||||
}));
|
||||
}
|
||||
|
||||
function drawStars(time) {
|
||||
const ctx = starCanvas.getContext('2d');
|
||||
ctx.clearRect(0,0,starCanvas.width, starCanvas.height);
|
||||
const t = time * 0.001;
|
||||
bgStars.forEach(s => {
|
||||
s.x += s.dx; s.y += s.dy;
|
||||
if (s.x < 0) s.x = starCanvas.width; if (s.x > starCanvas.width) s.x = 0;
|
||||
if (s.y < 0) s.y = starCanvas.height; if (s.y > starCanvas.height) s.y = 0;
|
||||
const alpha = s.o + Math.sin(t + s.phase) * 0.15;
|
||||
ctx.fillStyle = `rgba(232, 213, 184, ${alpha})`;
|
||||
ctx.beginPath(); ctx.arc(s.x, s.y, s.r, 0, 6.28); ctx.fill();
|
||||
});
|
||||
requestAnimationFrame(drawStars);
|
||||
}
|
||||
|
||||
// ── Perspective Grid (Data Pulses) ──
|
||||
function drawGrid(time) {
|
||||
const ctx = gridCanvas.getContext('2d');
|
||||
const w = gridCanvas.width = gridCanvas.offsetWidth;
|
||||
const h = gridCanvas.height = gridCanvas.offsetHeight;
|
||||
ctx.clearRect(0,0,w,h);
|
||||
const pulsePos = (time * 0.05) % 100;
|
||||
|
||||
for(let i=0; i<18; i++) {
|
||||
let s = i/17;
|
||||
let y = h * (s*s);
|
||||
ctx.strokeStyle = `rgba(42, 196, 179, ${0.05 + s*0.2})`;
|
||||
if (Math.abs(s*100 - pulsePos) < 4) ctx.strokeStyle = `rgba(232, 148, 58, 0.4)`;
|
||||
ctx.lineWidth = 1.3;
|
||||
ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(w, y); ctx.stroke();
|
||||
}
|
||||
requestAnimationFrame(drawGrid);
|
||||
}
|
||||
|
||||
// ── Skyline (Massive Density) ──
|
||||
function buildSkyline() {
|
||||
const container = document.getElementById('skyline');
|
||||
container.innerHTML = '';
|
||||
const vw = window.innerWidth, vh = window.innerHeight;
|
||||
const count = 100;
|
||||
const clusterStart = Math.floor(count/2) - 4;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const b = document.createElement('div');
|
||||
b.className = 'building';
|
||||
b.style.width = (vw < 768 ? 40 : 80) + Math.random()*50 + 'px';
|
||||
b.style.height = (vh * 0.1 + Math.random() * (vh * 0.6)) + 'px';
|
||||
|
||||
if(Math.random() > 0.35) {
|
||||
const v = document.createElement('div');
|
||||
v.className = 'vine' + (Math.random() > 0.55 ? ' orchid' : '');
|
||||
v.style.left = '35%'; v.style.top = '12%';
|
||||
b.appendChild(v);
|
||||
}
|
||||
|
||||
// Brighter Windows
|
||||
if (Math.random() > 0.2 && b.style.height.replace('px','') > 60) {
|
||||
const win = document.createElement('span');
|
||||
win.style.cssText = `position:absolute;width:2px;height:2px;background:rgba(232,148,58,0.3);left:4px;top:10px;box-shadow:0 0 4px rgba(232,148,58,0.2);`;
|
||||
b.appendChild(win);
|
||||
}
|
||||
|
||||
if (i >= clusterStart && i < clusterStart + 8) {
|
||||
const star = STARS[i - clusterStart];
|
||||
const link = document.createElement('a');
|
||||
link.className = 'billboard-nav';
|
||||
link.textContent = star.sign;
|
||||
link.href = '#';
|
||||
link.onclick = (e) => { e.preventDefault(); selectStar(STARS.indexOf(star)); };
|
||||
b.appendChild(link);
|
||||
}
|
||||
container.appendChild(b);
|
||||
}
|
||||
}
|
||||
|
||||
function selectStar(idx) {
|
||||
const frame = document.getElementById('content-frame');
|
||||
frame.classList.remove('loaded');
|
||||
frame.srcdoc = `<html><body style="background:#0d1320;color:#e8d5b8;font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;">
|
||||
<p>Opening ${STARS[idx].label}...</p></body></html>`;
|
||||
setTimeout(() => frame.classList.add('loaded'), 500);
|
||||
window.scrollTo({ top: document.getElementById('content-zone').offsetTop, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
document.getElementById('back-btn').onclick = () => window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
|
||||
// Init Star Nodes
|
||||
STARS.forEach((s, i) => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'star-node';
|
||||
btn.setAttribute('data-star', s.id);
|
||||
btn.style.left = s.x + '%'; btn.style.top = s.y + '%';
|
||||
btn.innerHTML = `<div class="star-visual"><span class="star-dot"></span></div><span class="star-label">${s.label}</span>`;
|
||||
btn.onclick = () => selectStar(i);
|
||||
starZone.appendChild(btn);
|
||||
});
|
||||
|
||||
window.addEventListener('resize', () => { initStars(); buildSkyline(); });
|
||||
initStars(); buildSkyline(); requestAnimationFrame(drawStars); requestAnimationFrame(drawGrid);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user