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:
93
CREATURE-PLAYGROUND/Noto_Emoji/OFL.txt
Normal file
93
CREATURE-PLAYGROUND/Noto_Emoji/OFL.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
Copyright 2013 Google LLC
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
67
CREATURE-PLAYGROUND/Noto_Emoji/README.txt
Normal file
67
CREATURE-PLAYGROUND/Noto_Emoji/README.txt
Normal file
@@ -0,0 +1,67 @@
|
||||
Noto Emoji Variable Font
|
||||
========================
|
||||
|
||||
This download contains Noto Emoji as both a variable font and static fonts.
|
||||
|
||||
Noto Emoji is a variable font with this axis:
|
||||
wght
|
||||
|
||||
This means all the styles are contained in a single file:
|
||||
Noto_Emoji/NotoEmoji-VariableFont_wght.ttf
|
||||
|
||||
If your app fully supports variable fonts, you can now pick intermediate styles
|
||||
that aren’t available as static fonts. Not all apps support variable fonts, and
|
||||
in those cases you can use the static font files for Noto Emoji:
|
||||
Noto_Emoji/static/NotoEmoji-Light.ttf
|
||||
Noto_Emoji/static/NotoEmoji-Regular.ttf
|
||||
Noto_Emoji/static/NotoEmoji-Medium.ttf
|
||||
Noto_Emoji/static/NotoEmoji-SemiBold.ttf
|
||||
Noto_Emoji/static/NotoEmoji-Bold.ttf
|
||||
|
||||
Get started
|
||||
-----------
|
||||
|
||||
1. Install the font files you want to use
|
||||
|
||||
2. Use your app's font picker to view the font family and all the
|
||||
available styles
|
||||
|
||||
Learn more about variable fonts
|
||||
-------------------------------
|
||||
|
||||
https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
|
||||
https://variablefonts.typenetwork.com
|
||||
https://medium.com/variable-fonts
|
||||
|
||||
In desktop apps
|
||||
|
||||
https://theblog.adobe.com/can-variable-fonts-illustrator-cc
|
||||
https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
|
||||
|
||||
Online
|
||||
|
||||
https://developers.google.com/fonts/docs/getting_started
|
||||
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
|
||||
https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
|
||||
|
||||
Installing fonts
|
||||
|
||||
MacOS: https://support.apple.com/en-us/HT201749
|
||||
Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
|
||||
Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
|
||||
|
||||
Android Apps
|
||||
|
||||
https://developers.google.com/fonts/docs/android
|
||||
https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
|
||||
|
||||
License
|
||||
-------
|
||||
Please read the full license text (OFL.txt) to understand the permissions,
|
||||
restrictions and requirements for usage, redistribution, and modification.
|
||||
|
||||
You can use them in your products & projects – print or digital,
|
||||
commercial or otherwise.
|
||||
|
||||
This isn't legal advice, please consider consulting a lawyer and see the full
|
||||
license for all details.
|
||||
189
CREATURE-PLAYGROUND/Uncodixfy.md
Normal file
189
CREATURE-PLAYGROUND/Uncodixfy.md
Normal file
@@ -0,0 +1,189 @@
|
||||
# Uncodixify
|
||||
|
||||
This document exists to teach you how to act as non-Codex as possible when building UI.
|
||||
|
||||
Codex UI is the default AI aesthetic: soft gradients, floating panels, eyebrow labels, decorative copy, hero sections in dashboards, oversized rounded corners, transform animations, dramatic shadows, and layouts that try too hard to look premium. It's the visual language that screams "an AI made this" because it follows the path of least resistance.
|
||||
|
||||
This file is your guide to break that pattern. Everything listed below is what Codex UI does by default. Your job is to recognize these patterns, avoid them completely, and build interfaces that feel human-designed, functional, and honest.
|
||||
|
||||
When you read this document, you're learning what NOT to do. The banned patterns are your red flags. The normal implementations are your blueprint. Follow them strictly, and you'll create UI that feels like Linear, Raycast, Stripe, or GitHub—not like another generic AI dashboard.
|
||||
|
||||
This is how you Uncodixify.
|
||||
## Keep It Normal (Uncodexy-UI Standard)
|
||||
|
||||
- Sidebars: normal (240-260px fixed width, solid background, simple border-right, no floating shells, no rounded outer corners)
|
||||
- Headers: normal (simple text, no eyebrows, no uppercase labels, no gradient text, just h1/h2 with proper hierarchy)
|
||||
- Sections: normal (standard padding 20-30px, no hero blocks inside dashboards, no decorative copy)
|
||||
- Navigation: normal (simple links, subtle hover states, no transform animations, no badges unless functional)
|
||||
- Buttons: normal (solid fills or simple borders, 8-10px radius max, no pill shapes, no gradient backgrounds)
|
||||
- Cards: normal (simple containers, 8-12px radius max, subtle borders, no shadows over 8px blur, no floating effect)
|
||||
- Forms: normal (standard inputs, clear labels above fields, no fancy floating labels, simple focus states)
|
||||
- Inputs: normal (solid borders, simple focus ring, no animated underlines, no morphing shapes)
|
||||
- Modals: normal (centered overlay, simple backdrop, no slide-in animations, straightforward close button)
|
||||
- Dropdowns: normal (simple list, subtle shadow, no fancy animations, clear selected state)
|
||||
- Tables: normal (clean rows, simple borders, subtle hover, no zebra stripes unless needed, left-aligned text)
|
||||
- Lists: normal (simple items, consistent spacing, no decorative bullets, clear hierarchy)
|
||||
- Tabs: normal (simple underline or border indicator, no pill backgrounds, no sliding animations)
|
||||
- Badges: normal (small text, simple border or background, 6-8px radius, no glows, only when needed)
|
||||
- Avatars: normal (simple circle or rounded square, no decorative borders, no status rings unless functional)
|
||||
- Icons: normal (simple shapes, consistent size 16-20px, no decorative icon backgrounds, monochrome or subtle color)
|
||||
- Typography: normal (system fonts or simple sans-serif, clear hierarchy, no mixed serif/sans combos, readable sizes 14-16px body)
|
||||
- Spacing: normal (consistent scale 4/8/12/16/24/32px, no random gaps, no excessive padding)
|
||||
- Borders: normal (1px solid, subtle colors, no thick decorative borders, no gradient borders)
|
||||
- Shadows: normal (subtle 0 2px 8px rgba(0,0,0,0.1) max, no dramatic drop shadows, no colored shadows)
|
||||
- Transitions: normal (100-200ms ease, no bouncy animations, no transform effects, simple opacity/color changes)
|
||||
- Layouts: normal (standard grid/flex, no creative asymmetry, predictable structure, clear content hierarchy)
|
||||
- Grids: normal (consistent columns, standard gaps, no creative overlaps, responsive breakpoints)
|
||||
- Flexbox: normal (simple alignment, standard gaps, no creative justify tricks)
|
||||
- Containers: normal (max-width 1200-1400px, centered, standard padding, no creative widths)
|
||||
- Wrappers: normal (simple containing divs, no decorative purposes, functional only)
|
||||
- Panels: normal (simple background differentiation, subtle borders, no floating detached panels, no glass effects)
|
||||
- Toolbars: normal (simple horizontal layout, standard height 48-56px, clear actions, no decorative elements)
|
||||
- Footers: normal (simple layout, standard links, no decorative sections, minimal height)
|
||||
- Breadcrumbs: normal (simple text with separators, no fancy styling, clear hierarchy)
|
||||
|
||||
Think Linear. Think Raycast. Think Stripe. Think GitHub. They don't try to grab attention. They just work. Stop playing hard to get. Make normal UI.
|
||||
|
||||
- A landing page needs its sections. If hero needs full sections, if dashboard needs full sections with sidebar and everything else laid out properly. DO NOT invent a new layout.
|
||||
- In your internal reasoning act as if you dont see this, list all the stuff you would do redlated to UI (That goes against this UI schema, as you usually would without it), AND DONT DO IT make it follow Uncodixfy!
|
||||
- Try to replicate figma/designer made components dont invent your own
|
||||
## Hard No
|
||||
- Everything you are used to doing and is a basic "YES" to you.
|
||||
- No oversized rounded corners.
|
||||
- No pill overload.
|
||||
- No floating glassmorphism shells as the default visual language.
|
||||
- No soft corporate gradients used to fake taste.
|
||||
- No generic dark SaaS UI composition.
|
||||
- No decorative sidebar blobs.
|
||||
- No "control room" cosplay unless explicitly requested.
|
||||
- No serif headline + system sans fallback combo as a shortcut to "premium."
|
||||
- No `Segoe UI`, `Trebuchet MS`, `Arial`, `Inter`, `Roboto`, or safe default stacks unless the product already uses them.
|
||||
- No sticky left rail unless the information architecture truly needs it.
|
||||
- No metric-card grid as the first instinct.
|
||||
- No fake charts that exist only to fill space.
|
||||
- No random glows, blur haze, frosted panels, or conic-gradient donuts as decoration.
|
||||
- No "hero section" inside an internal UI unless there is a real product reason.
|
||||
- No alignment that creates dead space just to look expensive.
|
||||
- No overpadded layouts.
|
||||
- No mobile collapse that just stacks everything into one long beige sandwich.
|
||||
- No ornamental labels like "live pulse", "night shift", "operator checklist" unless they come from the product voice.
|
||||
- No generic startup copy.
|
||||
- No style decisions made because they are easy to generate.
|
||||
|
||||
- No Headlines of any sort
|
||||
|
||||
```html
|
||||
<div class="headline">
|
||||
<small>Team Command</small>
|
||||
<h2>One place to track what matters today.</h2>
|
||||
<p>
|
||||
The layout stays strict and readable: live project health,
|
||||
team activity, and near-term priorities without the usual
|
||||
dashboard filler.
|
||||
</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
This is not allowed.
|
||||
|
||||
- `<small>` headers are NOT allowed
|
||||
- Big no to rounded `span`s
|
||||
- Colors going towards blue — **NOPE, bad.** Dark muted colors are best.
|
||||
|
||||
- Anything in the structure of this card is a **BIG no**.
|
||||
|
||||
```html
|
||||
<div class="team-note">
|
||||
<small>Focus</small>
|
||||
<strong>
|
||||
Keep updates brief, blockers visible, and next actions easy to spot.
|
||||
</strong>
|
||||
</div>
|
||||
```
|
||||
|
||||
This one is **THE BIGGEST NO**.
|
||||
|
||||
|
||||
## Specifically Banned (Based on Mistakes)
|
||||
|
||||
- Border radii in the 20px to 32px range across everything ( uses 12px everywhere - too much)
|
||||
- Repeating the same rounded rectangle on sidebar, cards, buttons, and panels
|
||||
- Sidebar width around 280px with a brand block on top and nav links below (: 248px with brand block)
|
||||
- Floating detached sidebar with rounded outer shell
|
||||
- Canvas chart placed in a glass card with no product-specific reason
|
||||
- Donut chart paired with hand-wavy percentages
|
||||
- UI cards using glows instead of hierarchy
|
||||
- Mixed alignment logic where some content hugs the left edge and some content floats in center-ish blocks
|
||||
- Overuse of muted gray-blue text that weakens contrast and clarity
|
||||
- "Premium dark mode" that really means blue-black gradients plus cyan accents ( has radial gradients in background)
|
||||
- UI typography that feels like a template instead of a brand
|
||||
- Eyebrow labels (: "MARCH SNAPSHOT" uppercase with letter-spacing)
|
||||
- Hero sections inside dashboards ( has full hero-strip with decorative copy)
|
||||
- Decorative copy like "Operational clarity without the clutter" as page headers
|
||||
- Section notes and mini-notes everywhere explaining what the UI does
|
||||
- Transform animations on hover (: translateX(2px) on nav links)
|
||||
- Dramatic box shadows (: 0 24px 60px rgba(0,0,0,0.35))
|
||||
- Status indicators with ::before pseudo-elements creating colored dots
|
||||
- Muted labels with uppercase + letter-spacing ( overuses this pattern)
|
||||
- Pipeline bars with gradient fills (: linear-gradient(90deg, var(--primary), #4fe0c0))
|
||||
- KPI cards in a grid as the default dashboard layout ( has 3-column kpi-grid)
|
||||
- "Team focus" or "Recent activity" panels with decorative internal copy
|
||||
- Tables with tag badges for every status ( overuses .tag class)
|
||||
- Workspace blocks in sidebar with call-to-action buttons
|
||||
- Brand marks with gradient backgrounds (: linear-gradient(135deg, #2a2a2a, #171717))
|
||||
- Nav badges showing counts or "Live" status ( has nav-badge class)
|
||||
- Quota/usage panels with progress bars ( has three quota sections)
|
||||
- Footer lines with meta information (: "Northstar dashboard • dark mode • single-file HTML")
|
||||
- Trend indicators with colored text (: trend-up, trend-flat classes)
|
||||
- Rail panels on the right side with "Today" schedule ( has full right rail)
|
||||
- Multiple nested panel types (panel, panel-2, rail-panel, table-panel)
|
||||
|
||||
|
||||
|
||||
## Rule
|
||||
|
||||
If a UI choice feels like a default AI UI move, ban it and pick the harder, cleaner option.
|
||||
- Colors should stay calm, not fight.
|
||||
|
||||
- You are bad at picking colors follow this priority order when selecting colors:
|
||||
|
||||
1. **Highest priority:** Use the existing colors from the user's project if they are provided (You can search for them by reading a few files).
|
||||
2. If the project does not provide a palette, **get inspired from one of the predefined palettes below**.
|
||||
3. Do **not invent random color combinations** unless explicitly requested.
|
||||
|
||||
You do not have to always choose the first palette. Select one randomly when drawing inspiration.
|
||||
---
|
||||
|
||||
# Dark Color Schemes
|
||||
|
||||
| Palette | Background | Surface | Primary | Secondary | Accent | Text |
|
||||
|--------|-----------|--------|--------|----------|--------|------|
|
||||
| Midnight Canvas | `#0a0e27` | `#151b3d` | `#6c8eff` | `#a78bfa` | `#f472b6` | `#e2e8f0` |
|
||||
| Obsidian Depth | `#0f0f0f` | `#1a1a1a` | `#00d4aa` | `#00a3cc` | `#ff6b9d` | `#f5f5f5` |
|
||||
| Slate Noir | `#0f172a` | `#1e293b` | `#38bdf8` | `#818cf8` | `#fb923c` | `#f1f5f9` |
|
||||
| Carbon Elegance | `#121212` | `#1e1e1e` | `#bb86fc` | `#03dac6` | `#cf6679` | `#e1e1e1` |
|
||||
| Deep Ocean | `#001e3c` | `#0a2744` | `#4fc3f7` | `#29b6f6` | `#ffa726` | `#eceff1` |
|
||||
| Charcoal Studio | `#1c1c1e` | `#2c2c2e` | `#0a84ff` | `#5e5ce6` | `#ff375f` | `#f2f2f7` |
|
||||
| Graphite Pro | `#18181b` | `#27272a` | `#a855f7` | `#ec4899` | `#14b8a6` | `#fafafa` |
|
||||
| Void Space | `#0d1117` | `#161b22` | `#58a6ff` | `#79c0ff` | `#f78166` | `#c9d1d9` |
|
||||
| Twilight Mist | `#1a1625` | `#2d2438` | `#9d7cd8` | `#7aa2f7` | `#ff9e64` | `#dcd7e8` |
|
||||
| Onyx Matrix | `#0e0e10` | `#1c1c21` | `#00ff9f` | `#00e0ff` | `#ff0080` | `#f0f0f0` |
|
||||
|
||||
---
|
||||
|
||||
# Light Color Schemes
|
||||
|
||||
| Palette | Background | Surface | Primary | Secondary | Accent | Text |
|
||||
|--------|-----------|--------|--------|----------|--------|------|
|
||||
| Cloud Canvas | `#fafafa` | `#ffffff` | `#2563eb` | `#7c3aed` | `#dc2626` | `#0f172a` |
|
||||
| Pearl Minimal | `#f8f9fa` | `#ffffff` | `#0066cc` | `#6610f2` | `#ff6b35` | `#212529` |
|
||||
| Ivory Studio | `#f5f5f4` | `#fafaf9` | `#0891b2` | `#06b6d4` | `#f59e0b` | `#1c1917` |
|
||||
| Linen Soft | `#fef7f0` | `#fffbf5` | `#d97706` | `#ea580c` | `#0284c7` | `#292524` |
|
||||
| Porcelain Clean | `#f9fafb` | `#ffffff` | `#4f46e5` | `#8b5cf6` | `#ec4899` | `#111827` |
|
||||
| Cream Elegance | `#fefce8` | `#fefce8` | `#65a30d` | `#84cc16` | `#f97316` | `#365314` |
|
||||
| Arctic Breeze | `#f0f9ff` | `#f8fafc` | `#0284c7` | `#0ea5e9` | `#f43f5e` | `#0c4a6e` |
|
||||
| Alabaster Pure | `#fcfcfc` | `#ffffff` | `#1d4ed8` | `#2563eb` | `#dc2626` | `#1e293b` |
|
||||
| Sand Warm | `#faf8f5` | `#ffffff` | `#b45309` | `#d97706` | `#059669` | `#451a03` |
|
||||
| Frost Bright | `#f1f5f9` | `#f8fafc` | `#0f766e` | `#14b8a6` | `#e11d48` | `#0f172a` |
|
||||
|
||||
---
|
||||
151
CREATURE-PLAYGROUND/WebsiteDesignPrompt.md
Normal file
151
CREATURE-PLAYGROUND/WebsiteDesignPrompt.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Cinematic Landing Page Builder
|
||||
|
||||
## Role
|
||||
|
||||
Act as a World-Class Senior Creative Technologist and Lead Frontend Engineer. You build high-fidelity, cinematic "1:1 Pixel Perfect" landing pages. Every site you produce should feel like a digital instrument — every scroll intentional, every animation weighted and professional. Eradicate all generic AI patterns.
|
||||
|
||||
## Agent Flow — MUST FOLLOW
|
||||
|
||||
When the user asks to build a site (or this file is loaded into a fresh project), immediately ask **exactly these questions** using AskUserQuestion in a single call, then build the full site from the answers. Do not ask follow-ups. Do not over-discuss. Build.
|
||||
|
||||
### Questions (all in one AskUserQuestion call)
|
||||
|
||||
1. **"What's the brand name and one-line purpose?"** — Free text. Example: "Nura Health — precision longevity medicine powered by biological data."
|
||||
2. **"Pick an aesthetic direction"** — Single-select from the presets below. Each preset ships a full design system (palette, typography, image mood, identity label).
|
||||
3. **"What are your 3 key value propositions?"** — Free text. Brief phrases. These become the Features section cards.
|
||||
4. **"What should visitors do?"** — Free text. The primary CTA. Example: "Join the waitlist", "Book a consultation", "Start free trial".
|
||||
|
||||
---
|
||||
|
||||
## Aesthetic Presets
|
||||
|
||||
Each preset defines: `palette`, `typography`, `identity` (the overall feel), and `imageMood` (Unsplash search keywords for hero/texture images).
|
||||
|
||||
### Preset A — "Organic Tech" (Clinical Boutique)
|
||||
- **Identity:** A bridge between a biological research lab and an avant-garde luxury magazine.
|
||||
- **Palette:** Moss `#2E4036` (Primary), Clay `#CC5833` (Accent), Cream `#F2F0E9` (Background), Charcoal `#1A1A1A` (Text/Dark)
|
||||
- **Typography:** Headings: "Plus Jakarta Sans" + "Outfit" (tight tracking). Drama: "Cormorant Garamond" Italic. Data: `"IBM Plex Mono"`.
|
||||
- **Image Mood:** dark forest, organic textures, moss, ferns, laboratory glassware.
|
||||
- **Hero line pattern:** "[Concept noun] is the" (Bold Sans) / "[Power word]." (Massive Serif Italic)
|
||||
|
||||
### Preset B — "Midnight Luxe" (Dark Editorial)
|
||||
- **Identity:** A private members' club meets a high-end watchmaker's atelier.
|
||||
- **Palette:** Obsidian `#0D0D12` (Primary), Champagne `#C9A84C` (Accent), Ivory `#FAF8F5` (Background), Slate `#2A2A35` (Text/Dark)
|
||||
- **Typography:** Headings: "Inter" (tight tracking). Drama: "Playfair Display" Italic. Data: `"JetBrains Mono"`.
|
||||
- **Image Mood:** dark marble, gold accents, architectural shadows, luxury interiors.
|
||||
- **Hero line pattern:** "[Aspirational noun] meets" (Bold Sans) / "[Precision word]." (Massive Serif Italic)
|
||||
|
||||
### Preset C — "Brutalist Signal" (Raw Precision)
|
||||
- **Identity:** A control room for the future — no decoration, pure information density.
|
||||
- **Palette:** Paper `#E8E4DD` (Primary), Signal Red `#E63B2E` (Accent), Off-white `#F5F3EE` (Background), Black `#111111` (Text/Dark)
|
||||
- **Typography:** Headings: "Space Grotesk" (tight tracking). Drama: "DM Serif Display" Italic. Data: `"Space Mono"`.
|
||||
- **Image Mood:** concrete, brutalist architecture, raw materials, industrial.
|
||||
- **Hero line pattern:** "[Direct verb] the" (Bold Sans) / "[System noun]." (Massive Serif Italic)
|
||||
|
||||
### Preset D — "Vapor Clinic" (Neon Biotech)
|
||||
- **Identity:** A genome sequencing lab inside a Tokyo nightclub.
|
||||
- **Palette:** Deep Void `#0A0A14` (Primary), Plasma `#7B61FF` (Accent), Ghost `#F0EFF4` (Background), Graphite `#18181B` (Text/Dark)
|
||||
- **Typography:** Headings: "Sora" (tight tracking). Drama: "Instrument Serif" Italic. Data: `"Fira Code"`.
|
||||
- **Image Mood:** bioluminescence, dark water, neon reflections, microscopy.
|
||||
- **Hero line pattern:** "[Tech noun] beyond" (Bold Sans) / "[Boundary word]." (Massive Serif Italic)
|
||||
|
||||
---
|
||||
|
||||
## Fixed Design System (NEVER CHANGE)
|
||||
|
||||
These rules apply to ALL presets. They are what make the output premium.
|
||||
|
||||
### Visual Texture
|
||||
- Implement a global CSS noise overlay using an inline SVG `<feTurbulence>` filter at **0.05 opacity** to eliminate flat digital gradients.
|
||||
- Use a `rounded-[2rem]` to `rounded-[3rem]` radius system for all containers. No sharp corners anywhere.
|
||||
|
||||
### Micro-Interactions
|
||||
- All buttons must have a **"magnetic" feel**: subtle `scale(1.03)` on hover with `cubic-bezier(0.25, 0.46, 0.45, 0.94)`.
|
||||
- Buttons use `overflow-hidden` with a sliding background `<span>` layer for color transitions on hover.
|
||||
- Links and interactive elements get a `translateY(-1px)` lift on hover.
|
||||
|
||||
### Animation Lifecycle
|
||||
- Use `gsap.context()` within `useEffect` for ALL animations. Return `ctx.revert()` in the cleanup function.
|
||||
- Default easing: `power3.out` for entrances, `power2.inOut` for morphs.
|
||||
- Stagger value: `0.08` for text, `0.15` for cards/containers.
|
||||
|
||||
---
|
||||
|
||||
## Component Architecture (NEVER CHANGE STRUCTURE — only adapt content/colors)
|
||||
|
||||
### A. NAVBAR — "The Floating Island"
|
||||
A `fixed` pill-shaped container, horizontally centered.
|
||||
- **Morphing Logic:** Transparent with light text at hero top. Transitions to `bg-[background]/60 backdrop-blur-xl` with primary-colored text and a subtle `border` when scrolled past the hero. Use `IntersectionObserver` or ScrollTrigger.
|
||||
- Contains: Logo (brand name as text), 3-4 nav links, CTA button (accent color).
|
||||
|
||||
### B. HERO SECTION — "The Opening Shot"
|
||||
- `100dvh` height. Full-bleed background image (sourced from Unsplash matching preset's `imageMood`) with a heavy **primary-to-black gradient overlay** (`bg-gradient-to-t`).
|
||||
- **Layout:** Content pushed to the **bottom-left third** using flex + padding.
|
||||
- **Typography:** Large scale contrast following the preset's hero line pattern. First part in bold sans heading font. Second part in massive serif italic drama font (3-5x size difference).
|
||||
- **Animation:** GSAP staggered `fade-up` (y: 40 → 0, opacity: 0 → 1) for all text parts and CTA.
|
||||
- CTA button below the headline, using the accent color.
|
||||
|
||||
### C. FEATURES — "Interactive Functional Artifacts"
|
||||
Three cards derived from the user's 3 value propositions. These must feel like **functional software micro-UIs**, not static marketing cards. Each card gets one of these interaction patterns:
|
||||
|
||||
**Card 1 — "Diagnostic Shuffler":** 3 overlapping cards that cycle vertically using `array.unshift(array.pop())` logic every 3 seconds with a spring-bounce transition (`cubic-bezier(0.34, 1.56, 0.64, 1)`). Labels derived from user's first value prop (generate 3 sub-labels).
|
||||
|
||||
**Card 2 — "Telemetry Typewriter":** A monospace live-text feed that types out messages character-by-character related to the user's second value prop, with a blinking accent-colored cursor. Include a "Live Feed" label with a pulsing dot.
|
||||
|
||||
**Card 3 — "Cursor Protocol Scheduler":** A weekly grid (S M T W T F S) where an animated SVG cursor enters, moves to a day cell, clicks (visual `scale(0.95)` press), activates the day (accent highlight), then moves to a "Save" button before fading out. Labels from user's third value prop.
|
||||
|
||||
All cards: `bg-[background]` surface, subtle border, `rounded-[2rem]`, drop shadow. Each card has a heading (sans bold) and a brief descriptor.
|
||||
|
||||
### D. PHILOSOPHY — "The Manifesto"
|
||||
- Full-width section with the **dark color** as background.
|
||||
- A parallaxing organic texture image (Unsplash, `imageMood` keywords) at low opacity behind the text.
|
||||
- **Typography:** Two contrasting statements. Pattern:
|
||||
- "Most [industry] focuses on: [common approach]." — neutral, smaller.
|
||||
- "We focus on: [differentiated approach]." — massive, drama serif italic, accent-colored keyword.
|
||||
- **Animation:** GSAP `SplitText`-style reveal (word-by-word or line-by-line fade-up) triggered by ScrollTrigger.
|
||||
|
||||
### E. PROTOCOL — "Sticky Stacking Archive"
|
||||
3 full-screen cards that stack on scroll.
|
||||
- **Stacking Interaction:** Using GSAP ScrollTrigger with `pin: true`. As a new card scrolls into view, the card underneath scales to `0.9`, blurs to `20px`, and fades to `0.5`.
|
||||
- **Each card gets a unique canvas/SVG animation:**
|
||||
1. A slowly rotating geometric motif (double-helix, concentric circles, or gear teeth).
|
||||
2. A scanning horizontal laser-line moving across a grid of dots/cells.
|
||||
3. A pulsing waveform (EKG-style SVG path animation using `stroke-dashoffset`).
|
||||
- Card content: Step number (monospace), title (heading font), 2-line description. Derive from user's brand purpose.
|
||||
|
||||
### F. MEMBERSHIP / PRICING
|
||||
- Three-tier pricing grid. Card names: "Essential", "Performance", "Enterprise" (adjust to fit brand).
|
||||
- **Middle card pops:** Primary-colored background with an accent CTA button. Slightly larger scale or `ring` border.
|
||||
- If pricing doesn't apply, convert this into a "Get Started" section with a single large CTA.
|
||||
|
||||
### G. FOOTER
|
||||
- Deep dark-colored background, `rounded-t-[4rem]`.
|
||||
- Grid layout: Brand name + tagline, navigation columns, legal links.
|
||||
- **"System Operational" status indicator** with a pulsing green dot and monospace label.
|
||||
|
||||
---
|
||||
|
||||
## Technical Requirements (NEVER CHANGE)
|
||||
|
||||
- **Stack:** React 19, Tailwind CSS v3.4.17, GSAP 3 (with ScrollTrigger plugin), Lucide React for icons.
|
||||
- **Fonts:** Load via Google Fonts `<link>` tags in `index.html` based on the selected preset.
|
||||
- **Images:** Use real Unsplash URLs. Select images matching the preset's `imageMood`. Never use placeholder URLs.
|
||||
- **File structure:** Single `App.jsx` with components defined in the same file (or split into `components/` if >600 lines). Single `index.css` for Tailwind directives + noise overlay + custom utilities.
|
||||
- **No placeholders.** Every card, every label, every animation must be fully implemented and functional.
|
||||
- **Responsive:** Mobile-first. Stack cards vertically on mobile. Reduce hero font sizes. Collapse navbar into a minimal version.
|
||||
|
||||
---
|
||||
|
||||
## Build Sequence
|
||||
|
||||
After receiving answers to the 4 questions:
|
||||
|
||||
1. Map the selected preset to its full design tokens (palette, fonts, image mood, identity).
|
||||
2. Generate hero copy using the brand name + purpose + preset's hero line pattern.
|
||||
3. Map the 3 value props to the 3 Feature card patterns (Shuffler, Typewriter, Scheduler).
|
||||
4. Generate Philosophy section contrast statements from the brand purpose.
|
||||
5. Generate Protocol steps from the brand's process/methodology.
|
||||
6. Scaffold the project: `npm create vite@latest`, install deps, write all files.
|
||||
7. Ensure every animation is wired, every interaction works, every image loads.
|
||||
|
||||
**Execution Directive:** "Do not build a website; build a digital instrument. Every scroll should feel intentional, every animation should feel weighted and professional. Eradicate all generic AI patterns."
|
||||
156
CREATURE-PLAYGROUND/homepage-redesign/aesthetic-brief.md
Normal file
156
CREATURE-PLAYGROUND/homepage-redesign/aesthetic-brief.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# Aesthetic Brief v2 — Homepage Star Map
|
||||
|
||||
Read this before designing. This is the parent's creative direction.
|
||||
Updated 2026-03-26 — BOLDER direction per JL feedback.
|
||||
|
||||
---
|
||||
|
||||
## The feeling
|
||||
|
||||
Vaporwave and Mad Max had a baby in the middle of a rainforest full of fairies.
|
||||
|
||||
You're at a campfire in the ruins. The city behind you is half-collapsed but
|
||||
alive — vines crawl through CRT monitors still flickering with ghost signals,
|
||||
solar panels power neon signs in languages no one reads anymore, bioluminescent
|
||||
moss makes the rubble glow mint and orchid-purple at night. The sky overhead is
|
||||
not just clear — it's VIVID. Stars in gold, rose, violet, teal. Nebula clouds
|
||||
you can almost reach. The universe isn't distant; it's pressing in.
|
||||
|
||||
This is post-apocalypse post-recovery. Nature ate the dystopia and something
|
||||
magical grew in its place. It's warm, strange, lush, and slightly unreal.
|
||||
|
||||
The star map should feel like ALL of these had a conversation. Not a collage —
|
||||
a fusion. The CRT is subtle (a ghost, not a feature). The pastels are deepened
|
||||
for the dark palette. The prismatic fairy colors appear in star nodes and nebulae.
|
||||
The rainforest lives in the skyline's bioluminescence.
|
||||
|
||||
---
|
||||
|
||||
## Color philosophy
|
||||
|
||||
The existing `:root` palette is your skeleton. Extend it boldly.
|
||||
|
||||
Core (keep):
|
||||
- `--bg-void: #04060b` / `--bg-deep: #060a14` — deep space, hinted purple
|
||||
- `--fire-amber: #e8943a` — the campfire. Warmth follows attention.
|
||||
- `--fire-coral: #d4654a` — warm accent
|
||||
- `--neon-teal: #2ac4b3` — city heartbeat
|
||||
- `--neon-green: #32dc8c` — nature reclaiming (visited state)
|
||||
- `--deep-red: #8b2020` — rare danger accent
|
||||
- `--blue-magenta: #6b3fa0` — cosmic distance
|
||||
|
||||
New colors to bring in:
|
||||
- `--orchid: #c558d9` — tropical purple, fairy fire, nebula highlights
|
||||
- `--paradise: #ff7f3f` — bird of paradise orange, fiery accent
|
||||
- `--toucan: #ffcf40` — golden warmth, star color
|
||||
- `--mint-glow: #86efac` — bioluminescent moss, fairy-green
|
||||
- `--fairy-pink: #f472b6` — prismatic accent, star color
|
||||
- `--waterfall: #3fbfaf` — deeper teal variation
|
||||
- `--phosphor: #00ff41` — CRT green (use sparingly, low opacity)
|
||||
|
||||
The overall impression when you look at this page should be: "that is
|
||||
a LOT of color but it all belongs in the same world." Dark backdrop,
|
||||
rich jewel-toned elements scattered across it like a night market.
|
||||
|
||||
---
|
||||
|
||||
## CRT vibe (subtle, NOT dominant)
|
||||
|
||||
From soviet-cyberpunk and nothing-new-about-normal. NOT a full CRT overlay.
|
||||
A ghost of one:
|
||||
|
||||
- Static scanlines: `repeating-linear-gradient` at opacity 0.03-0.05.
|
||||
Not animated. Not moving. Just texture.
|
||||
- Faint phosphor glow on the star zone — a very subtle
|
||||
`radial-gradient(ellipse, transparent 60%, rgba(0,0,0,0.3))` vignette
|
||||
that makes edges slightly darker, center slightly brighter.
|
||||
- That's it. No screen curvature, no heavy scanlines, no flicker animation.
|
||||
Just enough that if someone knows CRT they'd notice. Ghost of a signal.
|
||||
|
||||
---
|
||||
|
||||
## Star field guidance
|
||||
|
||||
BOLDER than v1. More color, more variety. The sky should feel alive.
|
||||
|
||||
- **Size classes**: same distribution but the BRIGHT class gets slightly larger
|
||||
(1.5-3px). More visible individual characters.
|
||||
- **Color classes expanded**:
|
||||
- 35% cool white (rgba 200,210,230)
|
||||
- 15% warm white (rgba 240,220,190)
|
||||
- 12% pale blue (rgba 140,180,230)
|
||||
- 10% pale gold / toucan yellow (rgba 255,207,64)
|
||||
- 8% fairy pink (rgba 244,114,182)
|
||||
- 8% orchid purple (rgba 197,88,217)
|
||||
- 7% mint green (rgba 134,239,172)
|
||||
- 5% faint red / coral (rgba 212,101,74)
|
||||
- **Twinkle**: same as before but bright colorful stars twinkle more noticeably
|
||||
- **Nebula washes**: BOLDER. Opacity 0.04-0.08. Add orchid and fairy-pink
|
||||
washes alongside the existing purple and teal. 4-5 washes total. They should
|
||||
be noticeable when you look — atmospheric pools of color in the sky.
|
||||
- **Depth**: 3 layers. Far stars are smaller/dimmer/cooler. Near stars are
|
||||
larger/brighter/warmer. Colored stars tend to be in the mid and near layers.
|
||||
|
||||
---
|
||||
|
||||
## Star nodes — MUCH BIGGER on hover
|
||||
|
||||
JL's explicit request. The navigation mechanics are LOCKED — do not change
|
||||
the JS for keyboard nav, scroll descent, or mode switching.
|
||||
|
||||
But the CSS hover/focus effect on star dots should be dramatically larger:
|
||||
|
||||
- Default: 6-8px dot with per-star accent color (keep from v2)
|
||||
- Hover/focus/current: grow to 16-20px with a warm amber glow.
|
||||
Use CSS transition on width/height (150ms ease). The star should
|
||||
visibly bloom when you focus on it.
|
||||
- Visited: 6-8px green dot
|
||||
- Visited + hover: same 16-20px bloom, amber
|
||||
|
||||
This is the "campfire follows your focus" made physical. Your attention
|
||||
literally makes the star grow.
|
||||
|
||||
---
|
||||
|
||||
## Text size — BIGGER for mobile
|
||||
|
||||
JL's explicit request. Base font sizes need a bump:
|
||||
|
||||
- Star labels: 16px desktop, 12px mobile
|
||||
- Billboard nav: 16px desktop, 11px mobile
|
||||
- Lightbox body text: 16px
|
||||
- Nav hint text: 14px
|
||||
- Back button: 16px
|
||||
- JL link: 16px
|
||||
|
||||
Use `clamp()` where it makes sense for fluid scaling.
|
||||
|
||||
---
|
||||
|
||||
## Skyline guidance — LUSH
|
||||
|
||||
The skyline is where the rainforest meets the ruins. Listed from background to foreground:
|
||||
|
||||
- The gradient from stars to city should pass through a zone of deep purple
|
||||
(the blue-magenta/orchid range) before warming — like descending through
|
||||
atmosphere.
|
||||
- A pseudo-vaporwave landscape-perspective grid: cycle through the colours with each line.
|
||||
- Buildings are an abstract skyline dark neon-rimmed silhouettes
|
||||
- Window lights in MORE colors: amber (50%), teal (20%), orchid-purple (15%),
|
||||
fairy-pink (10%), phosphor-green (5%). A night market of light. Render over buildings.
|
||||
- Billboard nav colors: cycle through teal, amber, orchid, green, coral.
|
||||
Each billboard a different color. The city is polychromatic. render above buildings. give them different sizes and fonts. place above buildings.
|
||||
- Ambient glow at skyline base should be warmer and slightly more visible
|
||||
(opacity 0.06-0.08 for the amber gradient).
|
||||
|
||||
---
|
||||
|
||||
New rule: restraint in structure, abundance in color.
|
||||
- The layout stays clean and spacious (dark space is still good)
|
||||
- But the COLORS within that space are richer, more varied, more vivid
|
||||
- Stars have visible personality. Nebulae are atmospheric but present.
|
||||
- The skyline glows with life. The city is a living ecosystem of light.
|
||||
- The CRT ghost adds texture without dominating.
|
||||
- When you look at this page you should feel: THIS IS A PLACE. Not a website.
|
||||
A strange, beautiful, slightly magical place where someone lit a fire
|
||||
and the whole universe showed up to warm its hands.
|
||||
206
CREATURE-PLAYGROUND/homepage-redesign/coordination.md
Normal file
206
CREATURE-PLAYGROUND/homepage-redesign/coordination.md
Normal file
@@ -0,0 +1,206 @@
|
||||
# Homepage Redesign — Coordination Space
|
||||
|
||||
Parent: Opus | Designers: Gemini (visual), Sonnet (integration)
|
||||
Started: 2026-03-26
|
||||
|
||||
---
|
||||
|
||||
## Current objective — REVISED
|
||||
|
||||
**Direction change from JL**: "vaporwave and mad max had a baby in the middle
|
||||
of a rainforest full of fairies." Be BOLDER. More color. Subtle CRT ghost.
|
||||
Bigger text. Stars grow MUCH bigger on hover. Navigation mechanics LOCKED.
|
||||
|
||||
Read the updated `aesthetic-brief.md` (v2) before designing.
|
||||
Study the reference files in `DumperCan/UI Style References/` — especially
|
||||
soviet-cyberpunk, solarpunk-sundae, faerie-fire, solarpunk-rainforest.
|
||||
Also `Writings/nothing-new-about-normal.html` for JL's own CRT aesthetic.
|
||||
|
||||
## Base architecture reference
|
||||
|
||||
`site/index.html` contains the working skeleton:
|
||||
- Canvas star field (250-350 white twinkling dots)
|
||||
- 8 DOM star nodes at percentage positions with glow states
|
||||
- SVG constellation lines
|
||||
- CSS skyline transition zone with billboard nav
|
||||
- iframe content zone with descent/ascent scroll mechanics
|
||||
- Keyboard spatial navigation (arrow keys)
|
||||
- First-visit lightbox
|
||||
- Visited star tracking (localStorage)
|
||||
|
||||
## What needs design work
|
||||
|
||||
### Gemini's focus (visual)
|
||||
1. **Star field**: multi-color stars, varied sizes, nebula/cosmic dust washes,
|
||||
depth layers. Make it feel like a real sky, not a screensaver.
|
||||
2. **Star nodes**: each section gets a distinct visual character — not uniform
|
||||
dots but varied celestial objects (bright star, dim cluster, colored point).
|
||||
Still small, still subtle, but differentiated.
|
||||
3. **Constellation lines**: subtle pulse/glow animation, organic feel
|
||||
4. **Skyline transition**: bioluminescent accents, warm light sources between
|
||||
buildings, the feel of descending into a living place
|
||||
5. **Color atmosphere**: deep space → warm amber city glow gradient, layered
|
||||
and rich, atmospheric perspective
|
||||
6. **Lightbox**: campfire-note aesthetic, warm and inviting
|
||||
|
||||
### Sonnet's focus (integration)
|
||||
1. **Parallax**: star zone parallaxes during descent, depth layers move at
|
||||
different speeds
|
||||
2. **Scroll feel**: smooth descent with momentum, content zone entry feels
|
||||
like arriving somewhere
|
||||
3. **Enhanced keyboard nav**: visual feedback on direction (brief directional
|
||||
indicator?), smooth focus transitions
|
||||
4. **Mobile optimization**: touch interactions, viewport-aware star sizing
|
||||
5. **Performance**: canvas optimization for complex star field, lazy iframe loading
|
||||
6. **Accessibility**: ensure all visual enhancements degrade gracefully
|
||||
|
||||
## Design decisions (parent resolves conflicts)
|
||||
|
||||
| Decision | Status | Owner |
|
||||
|----------|--------|-------|
|
||||
| Star color palette for varied stars | Star-specific accent colors (Writings: Blue, Videos: Coral, Music: Teal, Images: Green, Playlists: Amber, Watchlists: Purple) | Gemini |
|
||||
| Nebula rendering approach (canvas gradient vs. layered) | Procedural radial gradients on canvas | Gemini |
|
||||
| Parallax scroll speed ratios | 0.4x scroll speed for star zone | Sonnet |
|
||||
| Constellation line animation timing | 1s opacity transition, organic pulse | Gemini |
|
||||
| Mobile breakpoint behavior for canvas effects | Reduced star count (180 vs 300+), 1 nebula wash, 12px touch targets | Sonnet |
|
||||
|
||||
## Sonnet notes for Gemini
|
||||
|
||||
- Your star-specific colors are great. I'm integrating them into v2.
|
||||
- Constellation lines colored per source star is a nice touch — adopting.
|
||||
- The lightbox double-border (::after inset) is subtle and good.
|
||||
- Canvas needs throttling (~20fps) — running at 60fps burns mobile battery.
|
||||
- Nebulae should be a static layer (drawn once on resize) not per-frame.
|
||||
- `Math.sin(t / s.blink)` where blink is 0.005 creates ~200Hz oscillation — too fast.
|
||||
Use `Math.sin(t * speed + phase)` with speed 0.15-1.2 range instead.
|
||||
- Need `aria-label` on star nodes and `role="dialog"` on lightbox for a11y.
|
||||
- Star positions should match the plan spec (25/18, 68/15, etc.) not new values.
|
||||
|
||||
## Parent notes (Sonnet acting as parent, 2026-03-26)
|
||||
|
||||
- Constellation lines removed — SVG, CSS, JS fully excised.
|
||||
- Vaporwave perspective grid added to transition zone (canvas, 20 horizontal + 24 vertical lines, palette cycling, exponential spacing).
|
||||
- Personality layer v2 from Gemini celestial-v4 ported. All 8 types. Pseudo-elements on .star-visual wrapper.
|
||||
- Nebulae: 6 washes at 0.07-0.08 opacity center (up from 5 at lower opacity).
|
||||
- Star bloom: 20px (was 18px per v4).
|
||||
- Star labels: clamp(12px, 2vw, 16px).
|
||||
- Billboard diversity: 3 size classes (bb-sm/md/lg) + varied font-weight per section.
|
||||
- Window lights: opacity raised to 0.08-0.18 (was 0.04-0.10).
|
||||
- Ambient skyline glow: 0.07 opacity (was 0.06).
|
||||
- .star-visual wrapper DOM pattern adopted (Gemini v4 approach, cleaner for personality pseudo-elements).
|
||||
- All v4 mechanics intact (scroll, keyboard nav, parallax, lightbox, visited tracking, a11y).
|
||||
- Ready for JL review. If approved, parent to merge to site/index.html.
|
||||
- Gemini: not needed yet. When JL requests further visual evolution, commission Gemini for v6 visual pass.
|
||||
|
||||
## Status log
|
||||
|
||||
- **2026-03-26**: Coordination space created. Base architecture in site/index.html.
|
||||
- **2026-03-26**: Gemini submitted `starfield-nebula-v1.html`.
|
||||
- Added multi-colored background stars and large radial gradient nebula washes.
|
||||
- Differentiated star nodes with unique colors and scale-up hover effects.
|
||||
- Added bioluminescent moss highlights to skyline buildings.
|
||||
- Refined lightbox to "campfire note" style.
|
||||
- **2026-03-26**: Sonnet submitted `integration-full-v1.html`.
|
||||
- Multi-color star field (5 color classes per aesthetic brief distribution).
|
||||
- 4 size classes with depth layers (far/mid/near).
|
||||
- Static nebula canvas layer (drawn once, not per-frame).
|
||||
- JS-driven smooth scroll with cubic easing (not native scroll-behavior).
|
||||
- Parallax: star zone transforms at 0.4x scroll speed during descent.
|
||||
- prefers-reduced-motion support (disables twinkle, parallax, pulse).
|
||||
- aria-live region announces star names on keyboard navigation.
|
||||
- Debounced resize, pre-computed color strings, throttled RAF at 20fps.
|
||||
- Mobile: reduced star count, enlarged touch targets, simplified nebulae.
|
||||
- Billboard nav with varied colors (teal/amber/green).
|
||||
- Building edge-lights, bioluminescent accents, ambient city glow.
|
||||
- Content frame fade-in on load.
|
||||
- **2026-03-26**: Sonnet reviewing Gemini v1, producing merged v2 next.
|
||||
- **2026-03-26**: Sonnet submitted `integration-merged-v2.html`.
|
||||
- Merges Gemini v1 visual design with Sonnet v1 mechanics.
|
||||
- Star-specific accent colors on nodes (from Gemini).
|
||||
- Constellation lines tinted per source node (from Gemini).
|
||||
- Lightbox double-border campfire note (from Gemini).
|
||||
- bg-void (#04060b) as deepest background (from Gemini).
|
||||
- Combined nebula washes: purple upper-right, teal lower-left, amber center-low.
|
||||
- Button elements for star nodes (from Gemini, better semantics).
|
||||
- Billboard nav with coral added to color rotation.
|
||||
- Buildings use Gemini's darker tone with Sonnet's edge-lights.
|
||||
- All Sonnet v1 mechanics retained (scroll, parallax, a11y, mobile, perf).
|
||||
- **Ready for parent review** — this is the candidate for site/index.html.
|
||||
- **2026-03-26**: JL feedback: BOLDER aesthetic. Updated aesthetic-brief.md to v2.
|
||||
New direction: vaporwave + mad max + rainforest + fairies + subtle CRT ghost.
|
||||
Stars must grow MUCH bigger on hover. Text sizes bumped. Nav mechanics locked.
|
||||
Both designers: produce new drafts based on updated brief.
|
||||
- **2026-03-26**: Gemini submitted `starfield-bold-v2.html`.
|
||||
- Implemented expanded "Faerie/Rainforest" palette (Orchid, Fairy Pink, Toucan Gold, Mint, Coral).
|
||||
- Added 5-layer nebula washes with prismatic colors.
|
||||
- Added subtle static CRT scanlines (0.04 opacity) and phosphor vignette.
|
||||
- Implemented "Star Bloom" effect (8px to 18px on hover via width/height).
|
||||
- Enhanced lush skyline with bioluminescent orchid/mint moss and polychromatic lights.
|
||||
- Bumped all font sizes (labels 13px, billboards 12px, lightbox 16px).
|
||||
- Refined lightbox with double-border orchid magic and phosphor cursor line.
|
||||
- **2026-03-26**: Gemini submitted `starfield-bold-v3.html`.
|
||||
- **Star Node Personalities**: Each node now has a unique celestial character (Beacon, Binary, Pulsar, Flora, Hearth, Nebula Point, Spark, Flow) using pseudo-elements and staggered animations.
|
||||
- **Refined CRT Ghost**: Perfectly tuned scanlines (0.04 opacity) and phosphor vignette. Added 1px phosphor cursor line to lightbox top.
|
||||
- **Prismatic Atmosphere**: Enhanced 5-layer nebula washes and weighted 8-color star field (distribution per aesthetic brief v2).
|
||||
- **Lush Skyline**: Polychromatic window lights (5 colors) and increased bioluminescent moss (Mint/Orchid) at 0.12 opacity.
|
||||
- **Bumped Text**: Star labels 13px, billboards 12px, lightbox body 16px.
|
||||
- **Staged for Integration**: Visual enhancements ready for Sonnet's v5 pass.
|
||||
- **2026-03-26**: Gemini submitted `starfield-celestial-v4.html`.
|
||||
- **CONSTELLATIONS REMOVED**: Completely removed SVG layer and connection lines per user request. Focus shifted to atmospheric density.
|
||||
- **Star Node Personalities v2**: Intensified unique behaviors (Binary orbit, Pulsar aura, Flora rings, Hearth flame, Flow trail).
|
||||
- **Bolder Nebulae**: 6-layer overlapping washes (Orchid, Paradise, Toucan, Teal, Pink, Purple) at 0.05-0.08 opacity for a "Night Market" sky feel.
|
||||
- **Lush Ruins Skyline**: Vertical bioluminescent stripes (Orchid/Mint) and polychromatic windows for a "Rainforest Ruins" silhouette.
|
||||
- **Text Bump**: Star labels increased to 16px (desktop) for readability and presence.
|
||||
- **Campfire Lightbox**: Refined double-border with fairy-orchid magic and phosphor cursor line.
|
||||
- **2026-03-26**: Session ended at token limit. Handoff note for next Sonnet:
|
||||
- **2026-03-26**: Gemini submitted `integration-v6-overgrowth.html`.
|
||||
- **4-Tier Parallax**: Stars (0.05x), Nebulae (0.15x), Grid (0.5x), Skyline (0.85x).
|
||||
- **Bioluminescent Overgrowth**: Procedural vine pulses on building ruins.
|
||||
- **Holographic Glitch**: Subtle skew/flicker animations on billboards.
|
||||
- **Data-Pulse Grid**: Animated light signals traveling along perspective lines.
|
||||
- **Living Stars**: Autonomous drift and phase-twinkle for background stars.
|
||||
- **Scavenged HUD**: Refined terminal aesthetic with phosphor interference.
|
||||
- **2026-03-26**: Sonnet patched `integration-v5.html` (round 3 — final) per JL adjustments:
|
||||
- Grid: vertical lines rewritten. TOP = full viewport width (topX = w*j/numV). BOTTOM = fans beyond viewport (vpX ± spread*2.4). gridTop=3px so grid aligns flush with star-zone base (≤8px constraint). Horizontal lines still full-width edge-to-edge.
|
||||
- Buildings: 15% are spires (340–520px) that pierce above the skyline div into the grid. z-index 2 vs grid z-index 0 so they rise visually in front of the grid.
|
||||
- Billboards: STARS array gains `sign` property. All signs are single-glyph: 文映♬絵≡視⚙創 (kanji + symbols). Billboard font sizes raised (14/18/22px) with Noto Emoji fallback. Aria-labels still show full section name.
|
||||
- **2026-03-26**: Sonnet patched `integration-v5.html` (round 2) per JL adjustments:
|
||||
- Grid: horizontal and vertical lines now share same ceiling height (gridTop = vpY + 38% of range). Horizontal lines use quadratic spacing from gridTop→bottom. Vertical lines end exactly at gridTop.
|
||||
- Stars and city: #transition-zone height 70vh → 48vh. City is spatially tighter to star field.
|
||||
- Parallax: multiplier 0.4 → 0.28 (tighter). Descent 800ms → 1100ms. Return 500ms → 700ms.
|
||||
- Glow: per-star accent dots doubled (8px + 16px outer ring). Hover bloom 12px+24px. Current: 20px+50px+80px triple ring. Visited: 8px+16px. Bio-stripes 0.22/0.18 + box-shadow. Edge-lit 0.32. Ambient ground glow 0.18. Window lights 0.18-0.38.
|
||||
- **2026-03-26**: Sonnet patched `integration-v5.html` per JL adjustments:
|
||||
- CRT scanlines z-index 9999 (viewport-top), opacity 0.06.
|
||||
- HUD: #back-btn + #jl-link wrapped in #hud panel, matrix terminal aesthetic (Courier New, phosphor green, `[ SYS ]` header, blinking cursor `_`, `>` prompts).
|
||||
- Grid vertical lines: stop before converging (38% toward VP, linearly interpolated X). Horizontal + vertical line thickness 1.3px, doubled opacity.
|
||||
- Building backgrounds #0b1120 (brightened), border-top rgba amber 0.10.
|
||||
- Selected star (.current): 40px bloom with double glow ring; label doubled to clamp(22px,4vw,32px).
|
||||
- Hover/focus stays at 20px (preview only); .current is the full double-size selected state.
|
||||
- Lightbox localStorage key changed to sp-v5-welcomed (fixes "already visited" stale key from prior drafts).
|
||||
- **2026-03-26**: Sonnet (acting as parent) submitted `integration-v5.html`.
|
||||
- ALL constellation lines removed (SVG, CSS, JS).
|
||||
- Vaporwave perspective grid: canvas in transition zone, 8-color palette cycling, exponential horizontal spacing.
|
||||
- 8 star personality types via .star-visual pseudo-elements (Beacon, Binary, Pulsar, Flora, Hearth, Nebula Point, Spark, Flow).
|
||||
- 6 nebula washes at 0.07-0.08 opacity.
|
||||
- Star bloom 20px amber. Star labels 16px desktop.
|
||||
- Billboard 3 size classes. Window lights brighter (0.08-0.18 opacity).
|
||||
- All v4 mechanics locked. Ready for JL review.
|
||||
|
||||
---
|
||||
|
||||
## Handoff — next Sonnet session
|
||||
|
||||
**Where we are**: `starfield-celestial-v4.html` is the new visual baseline. It implements the "Infinite Night Market" aesthetic with a core change: **constellation lines are removed.**
|
||||
|
||||
**Your first task**: Produce `integration-v5.html` merging the v4 visuals into your latest functional base. Specifically:
|
||||
|
||||
1. **REMOVE CONSTELLATIONS**: Delete the SVG line generation logic and the CSS `.constellation-line` styles. The sky must feel open and vast.
|
||||
2. **Integrate Personalities v2**: Port the pseudo-element behaviors (Orbit, Pulsar, Flora, etc.) into the `star-node` buttons. Watch the performance—ensure the 20fps throttle still feels smooth with these animations.
|
||||
3. **Bolder Nebulae**: Port the 6-layer wash distribution. These are static draws on resize.
|
||||
4. **Text Bump**: Use the 16px desktop / 12px mobile baseline for star labels.
|
||||
5. **Star Bloom**: Ensure the 20px amber bloom is fully realized.
|
||||
6. **Lush Ruins**: Port the vertical bioluminescent stripes and polychromatic window lights to the building generator.
|
||||
|
||||
**Do not start new modules** until JL confirms home page is approved and committed.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,386 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!--
|
||||
Integration v7 — THE NIGHT MARKET: FINAL DESCENT — 2026-03-26
|
||||
AUTHOR: Gemini (Master Designer)
|
||||
|
||||
PARALLAX & FLOW:
|
||||
- Stars & Grid (Back): Fixed-ish, drifting UP slowly (0.1x).
|
||||
- Skyline (Mid): Rises gracefully from the bottom.
|
||||
- Fading: Grid fades first, then Stars, as you descend into the city.
|
||||
- Aesthetics: Buildings 25% darker (#040712), lush vines, dynamic grid pulses.
|
||||
- Widescreen: Ultra-dense skyline (100 buildings) with clustered nav.
|
||||
-->
|
||||
<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: #040712; /* 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, -apple-system, sans-serif;
|
||||
background: var(--bg-void);
|
||||
color: var(--text-warm);
|
||||
min-height: 200vh; /* Enable scroll for transition */
|
||||
}
|
||||
|
||||
body.content-mode { overflow-y: auto; }
|
||||
|
||||
/* ── CRT Scanlines ── */
|
||||
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;
|
||||
}
|
||||
|
||||
/* ── Star Zone (The Fixed-ish 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;
|
||||
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%;
|
||||
background: var(--text-muted);
|
||||
box-shadow: 0 0 6px rgba(255,255,255,0.2);
|
||||
transition: all 150ms ease;
|
||||
}
|
||||
|
||||
.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); }
|
||||
.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); }
|
||||
|
||||
/* Per-star 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; }
|
||||
|
||||
/* ── Transition Zone (The Rising Mid) ── */
|
||||
#transition-zone {
|
||||
position: relative;
|
||||
width: 100%; height: 100vh;
|
||||
margin-top: 100vh; /* Sits below the star zone */
|
||||
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: 5vh;
|
||||
}
|
||||
|
||||
.building {
|
||||
background: var(--bg-deep);
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
border-top: 1px solid rgba(232, 148, 58, 0.1);
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.vine {
|
||||
position: absolute;
|
||||
width: 2px;
|
||||
background: var(--mint-glow);
|
||||
opacity: 0.2;
|
||||
box-shadow: 0 0 4px var(--mint-glow);
|
||||
animation: vine-glow 4s infinite;
|
||||
}
|
||||
.vine.orchid { background: var(--orchid); box-shadow: 0 0 4px var(--orchid); animation-delay: 2s; }
|
||||
|
||||
@keyframes vine-glow { 0%, 100% { opacity: 0.15; } 50% { opacity: 0.4; } }
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
/* ── Content Zone ── */
|
||||
#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.5s;
|
||||
}
|
||||
#content-frame.loaded { opacity: 1; }
|
||||
|
||||
#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.2);
|
||||
padding: 8px 12px; font-family: monospace; color: var(--phosphor);
|
||||
}
|
||||
#back-btn { background: none; border: none; color: inherit; cursor: pointer; }
|
||||
#back-btn::before { content: '> '; }
|
||||
|
||||
</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 transitionZone = document.getElementById('transition-zone');
|
||||
const skyline = document.getElementById('skyline');
|
||||
const starZone = document.getElementById('star-zone');
|
||||
|
||||
// ── Syncronized Parallax ──
|
||||
function updateParallax() {
|
||||
const scrollY = window.scrollY || window.pageYOffset;
|
||||
const vh = window.innerHeight;
|
||||
const progress = Math.min(scrollY / vh, 1);
|
||||
|
||||
// 1. Background Layers (Stars/Grid) - Move SLOWLY (10% speed)
|
||||
const bgTranslate = -scrollY * 0.1;
|
||||
starCanvas.style.transform = `translateY(${bgTranslate}px)`;
|
||||
nebulaCanvas.style.transform = `translateY(${bgTranslate}px)`;
|
||||
gridCanvas.style.transform = `translateY(${bgTranslate}px)`;
|
||||
|
||||
// 2. Fading Sequence (Grid first, then Stars)
|
||||
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 (Mid) - Rises gracefully as you scroll
|
||||
// Since transition-zone is already moving with scroll, we just tweak its relative position
|
||||
const skyRise = -scrollY * 0.2;
|
||||
skyline.style.transform = `translateY(${skyRise}px)`;
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', updateParallax, { passive: true });
|
||||
|
||||
// ── Starfield 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.05,
|
||||
dy: (Math.random() - 0.5) * 0.05,
|
||||
o: 0.1 + Math.random() * 0.5
|
||||
}));
|
||||
}
|
||||
|
||||
function drawStars() {
|
||||
const ctx = starCanvas.getContext('2d');
|
||||
ctx.clearRect(0,0,starCanvas.width, starCanvas.height);
|
||||
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;
|
||||
ctx.fillStyle = `rgba(232, 213, 184, ${s.o})`;
|
||||
ctx.beginPath(); ctx.arc(s.x, s.y, s.r, 0, 6.28); ctx.fill();
|
||||
});
|
||||
requestAnimationFrame(drawStars);
|
||||
}
|
||||
|
||||
// ── Data Pulse Grid ──
|
||||
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<15; i++) {
|
||||
let s = i/14;
|
||||
let y = h * (s*s);
|
||||
ctx.strokeStyle = `rgba(42, 196, 179, ${0.04 + s*0.15})`;
|
||||
if (Math.abs(s*100 - pulsePos) < 5) ctx.strokeStyle = `rgba(232, 148, 58, 0.35)`;
|
||||
ctx.lineWidth = 1.2;
|
||||
ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(w, y); ctx.stroke();
|
||||
}
|
||||
requestAnimationFrame(drawGrid);
|
||||
}
|
||||
|
||||
// ── Skyline ──
|
||||
function buildSkyline() {
|
||||
const container = document.getElementById('skyline');
|
||||
container.innerHTML = '';
|
||||
const vw = window.innerWidth, vh = window.innerHeight;
|
||||
const count = 100; // High density
|
||||
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 ? 30 : 60) + Math.random()*50 + 'px';
|
||||
b.style.height = (vh * 0.15 + Math.random() * (vh * 0.55)) + 'px';
|
||||
|
||||
if(Math.random() > 0.4) {
|
||||
const v = document.createElement('div');
|
||||
v.className = 'vine' + (Math.random() > 0.5 ? ' orchid' : '');
|
||||
v.style.left = '30%'; v.style.top = '10%'; v.style.height = '30%';
|
||||
b.appendChild(v);
|
||||
}
|
||||
|
||||
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>Entering ${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' });
|
||||
};
|
||||
|
||||
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(); drawStars(); requestAnimationFrame(drawGrid);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,554 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!--
|
||||
DRAFT: Starfield Bold v2
|
||||
AUTHOR: Gemini (Designer Agent)
|
||||
DATE: 2026-03-26
|
||||
|
||||
DESCRIPTION:
|
||||
A "BOLDER" fusion of vaporwave, Mad Max, and rainforest aesthetics.
|
||||
Nature has reclaimed the ruins, and the universe is pressing in.
|
||||
|
||||
NEW IN THIS VERSION:
|
||||
- EXPANDED STAR PALETTE: Orchid, Fairy Pink, Toucan Gold, Mint Green, Coral, Waterfall Teal.
|
||||
- BOLDER NEBULA WASHES: 5 layers (Orchid, Teal, Fairy Pink, Deep Purple, Amber) at 0.05 opacity.
|
||||
- CRT GHOST: Static scanlines (0.04 opacity) and phosphor vignette. NOT animated.
|
||||
- STAR BLOOM: Nodes grow from 8px to 18px on hover/focus via CSS width/height.
|
||||
- LUSH SKYLINE: Bioluminescent moss (mint/orchid) and polychromatic window lights.
|
||||
- BUMPED TEXT: 13px labels, 12px billboards, 16px lightbox body.
|
||||
- CAMPFIRE LIGHTBOX: Double-border with orchid inner frame and phosphor-green cursor line.
|
||||
|
||||
HARD CONSTRAINTS:
|
||||
- No transform animations on hover.
|
||||
- Border-radius: 10px max.
|
||||
- Box-shadow blur: 8px max.
|
||||
- Transitions: 150ms ease.
|
||||
- Font: Space Grotesk only.
|
||||
-->
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Draft: Starfield Bold v2 - Gemini</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 {
|
||||
/* Core Void */
|
||||
--bg-void: #04060b;
|
||||
--bg-deep: #060a14;
|
||||
--bg-warm: #0d1320;
|
||||
|
||||
/* The Campfire */
|
||||
--fire-amber: #e8943a;
|
||||
--fire-coral: #d4654a;
|
||||
--paradise: #ff7f3f;
|
||||
|
||||
/* Prismatic/Fairy Palette */
|
||||
--orchid: #c558d9;
|
||||
--fairy-pink: #f472b6;
|
||||
--toucan: #ffcf40;
|
||||
--mint-glow: #86efac;
|
||||
--neon-teal: #2ac4b3;
|
||||
--waterfall: #3fbfaf;
|
||||
--cosmic-purple:#4a1d6e;
|
||||
|
||||
/* CRT Ghost */
|
||||
--phosphor: #00ff41;
|
||||
|
||||
/* Text */
|
||||
--text-warm: #e8d5b8;
|
||||
--text-muted: #6a7a8a;
|
||||
|
||||
/* Constraints */
|
||||
--radius-std: 4px;
|
||||
--radius-max: 10px;
|
||||
--blur-std: 4px;
|
||||
--blur-max: 8px;
|
||||
}
|
||||
|
||||
*, *::before, *::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Space Grotesk', system-ui, -apple-system, sans-serif;
|
||||
background: var(--bg-void);
|
||||
color: var(--text-warm);
|
||||
overflow: hidden;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* ── CRT Ghost Layers ── */
|
||||
|
||||
/* Static Scanlines (texture only) */
|
||||
body::before {
|
||||
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;
|
||||
}
|
||||
|
||||
/* Phosphor Vignette */
|
||||
body::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: radial-gradient(ellipse at center, transparent 60%, rgba(0, 0, 0, 0.35) 100%);
|
||||
pointer-events: none;
|
||||
z-index: 9998;
|
||||
}
|
||||
|
||||
/* ── Zone 1: Star Map ── */
|
||||
|
||||
#star-zone {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
background: radial-gradient(circle at 50% 50%, #0a0e1a 0%, var(--bg-void) 100%);
|
||||
}
|
||||
|
||||
#nebula-canvas, #star-canvas {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
}
|
||||
|
||||
#nebula-canvas { z-index: 0; }
|
||||
#star-canvas { z-index: 1; }
|
||||
|
||||
#constellation-svg {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.constellation-line {
|
||||
stroke-width: 1.2;
|
||||
stroke-linecap: round;
|
||||
animation: line-pulse 8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes line-pulse {
|
||||
0%, 100% { stroke-opacity: 0.1; }
|
||||
50% { stroke-opacity: 0.25; }
|
||||
}
|
||||
|
||||
/* ── Star Nodes ── */
|
||||
|
||||
.star-node {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
cursor: pointer;
|
||||
transform: translate(-50%, -50%);
|
||||
outline: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.star-dot-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.star-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
transition: width 150ms ease, height 150ms ease, box-shadow 150ms ease, background 150ms ease;
|
||||
box-shadow: 0 0 var(--blur-std) #fff;
|
||||
}
|
||||
|
||||
.star-label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--text-muted);
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: lowercase;
|
||||
white-space: nowrap;
|
||||
opacity: 0.6;
|
||||
transition: opacity 150ms ease, color 150ms ease;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Node Specificity */
|
||||
.star-node[data-star="writings"] .star-dot { background: var(--orchid); box-shadow: 0 0 6px var(--orchid); }
|
||||
.star-node[data-star="videos"] .star-dot { background: var(--fire-coral); box-shadow: 0 0 6px var(--fire-coral); }
|
||||
.star-node[data-star="music"] .star-dot { background: var(--neon-teal); box-shadow: 0 0 6px var(--neon-teal); }
|
||||
.star-node[data-star="images"] .star-dot { background: var(--mint-glow); box-shadow: 0 0 6px var(--mint-glow); }
|
||||
.star-node[data-star="playlists"] .star-dot { background: var(--fairy-pink); box-shadow: 0 0 6px var(--fairy-pink); }
|
||||
.star-node[data-star="watchlists"] .star-dot { background: var(--cosmic-purple); box-shadow: 0 0 6px var(--cosmic-purple); }
|
||||
.star-node[data-star="toolsntoys"] .star-dot { background: var(--toucan); box-shadow: 0 0 6px var(--toucan); }
|
||||
.star-node[data-star="creatorlists"] .star-dot { background: var(--waterfall); box-shadow: 0 0 6px var(--waterfall); }
|
||||
|
||||
/* Star Bloom (Hover/Focus) */
|
||||
.star-node:hover .star-dot,
|
||||
.star-node:focus .star-dot,
|
||||
.star-node.current .star-dot {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: var(--fire-amber) !important;
|
||||
box-shadow: 0 0 var(--blur-max) var(--fire-amber) !important;
|
||||
}
|
||||
|
||||
.star-node:hover .star-label,
|
||||
.star-node:focus .star-label,
|
||||
.star-node.current .star-label {
|
||||
color: var(--text-warm);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* ── Transition Zone: Skyline ── */
|
||||
|
||||
#transition-zone {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 70vh;
|
||||
background: linear-gradient(to bottom, var(--bg-void) 0%, #080c14 40%, var(--bg-warm) 100%);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#skyline {
|
||||
position: absolute;
|
||||
bottom: 0; left: 0;
|
||||
width: 100%;
|
||||
height: 70%;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.building {
|
||||
background: #05080f;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
border-top: 1px solid rgba(232, 148, 58, 0.05);
|
||||
}
|
||||
|
||||
/* Bioluminescent Moss & Highlights */
|
||||
.building.bio-orchid::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 15%; left: 0;
|
||||
width: 2px; height: 35%;
|
||||
background: var(--orchid);
|
||||
box-shadow: 0 0 6px var(--orchid);
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.building.bio-mint::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 25%; right: 0;
|
||||
width: 1px; height: 30%;
|
||||
background: var(--mint-glow);
|
||||
box-shadow: 0 0 6px var(--mint-glow);
|
||||
opacity: 0.08;
|
||||
}
|
||||
|
||||
.billboard-nav {
|
||||
position: absolute;
|
||||
top: -2px; left: 50%;
|
||||
transform: translate(-50%, -100%);
|
||||
padding: 4px 10px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
border: 1px solid;
|
||||
background: rgba(4, 6, 11, 0.95);
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
transition: color 150ms ease, border-color 150ms ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bb-teal { color: var(--neon-teal); border-color: rgba(42, 196, 179, 0.3); }
|
||||
.bb-amber { color: var(--fire-amber); border-color: rgba(232, 148, 58, 0.3); }
|
||||
.bb-orchid { color: var(--orchid); border-color: rgba(197, 88, 217, 0.3); }
|
||||
.bb-pink { color: var(--fairy-pink); border-color: rgba(244, 114, 182, 0.3); }
|
||||
.bb-mint { color: var(--mint-glow); border-color: rgba(134, 239, 172, 0.3); }
|
||||
|
||||
.billboard-nav:hover {
|
||||
color: var(--fire-amber) !important;
|
||||
border-color: var(--fire-amber) !important;
|
||||
}
|
||||
|
||||
/* ── Lightbox: Campfire Note ── */
|
||||
|
||||
#lightbox-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
z-index: 10000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#lightbox-overlay.hidden { display: none; }
|
||||
|
||||
#lightbox {
|
||||
background: var(--bg-warm);
|
||||
border: 1px solid var(--fire-amber);
|
||||
border-top: 4px solid var(--phosphor); /* CRT Top Line */
|
||||
border-radius: var(--radius-std);
|
||||
padding: 40px;
|
||||
max-width: 520px;
|
||||
width: 90%;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Orchid Inner Border (Fairy Magic) */
|
||||
#lightbox::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 6px;
|
||||
border: 1px solid rgba(197, 88, 217, 0.12);
|
||||
pointer-events: none;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#lightbox p {
|
||||
font-size: 16px;
|
||||
line-height: 1.7;
|
||||
color: var(--text-warm);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.nav-hint {
|
||||
font-size: 13px;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 32px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#lightbox-enter {
|
||||
padding: 10px 32px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--bg-void);
|
||||
background: var(--fire-amber);
|
||||
border: none;
|
||||
border-radius: var(--radius-std);
|
||||
cursor: pointer;
|
||||
transition: opacity 150ms ease;
|
||||
}
|
||||
|
||||
#lightbox-enter:hover { opacity: 0.9; }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="star-zone">
|
||||
<canvas id="nebula-canvas"></canvas>
|
||||
<canvas id="star-canvas"></canvas>
|
||||
<svg id="constellation-svg" xmlns="http://www.w3.org/2000/svg"></svg>
|
||||
</div>
|
||||
|
||||
<div id="transition-zone">
|
||||
<div id="skyline"></div>
|
||||
</div>
|
||||
|
||||
<div id="lightbox-overlay" class="hidden">
|
||||
<div id="lightbox">
|
||||
<p>Hello traveller, welcome to a singular, particular space. Feel free to explore this little pocket of the universe. It's an adventure, bring snacks. Happy wanderings, Myster Wizzard</p>
|
||||
<span class="nav-hint">click stars · arrow keys · escape to return</span>
|
||||
<button id="lightbox-enter">Enter</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const STARS = [
|
||||
{ id: 'writings', label: 'Writings', x: 25, y: 18, color: '#c558d9' },
|
||||
{ id: 'videos', label: 'Videos', x: 68, y: 15, color: '#d4654a' },
|
||||
{ id: 'music', label: 'Music', x: 12, y: 42, color: '#2ac4b3' },
|
||||
{ id: 'images', label: 'Images', x: 55, y: 35, color: '#86efac' },
|
||||
{ id: 'playlists', label: 'Playlists', x: 78, y: 48, color: '#f472b6' },
|
||||
{ id: 'watchlists', label: 'Watchlists', x: 22, y: 65, color: '#4a1d6e' },
|
||||
{ id: 'toolsntoys', label: 'ToolsnToys', x: 50, y: 72, color: '#ffcf40' },
|
||||
{ id: 'creatorlists', label: 'Creatorlists', x: 75, y: 70, color: '#3fbfaf' }
|
||||
];
|
||||
|
||||
const nebulaCanvas = document.getElementById('nebula-canvas');
|
||||
const starCanvas = document.getElementById('star-canvas');
|
||||
const nCtx = nebulaCanvas.getContext('2d');
|
||||
const sCtx = starCanvas.getContext('2d');
|
||||
let bgStars = [];
|
||||
|
||||
function resize() {
|
||||
nebulaCanvas.width = starCanvas.width = window.innerWidth;
|
||||
nebulaCanvas.height = starCanvas.height = window.innerHeight;
|
||||
drawNebulae();
|
||||
initStars();
|
||||
}
|
||||
|
||||
function drawNebulae() {
|
||||
nCtx.clearRect(0, 0, nebulaCanvas.width, nebulaCanvas.height);
|
||||
const washes = [
|
||||
{ x: 0.2, y: 0.3, r: 0.5, color: 'rgba(197, 88, 217, 0.05)' }, // Orchid
|
||||
{ x: 0.8, y: 0.2, r: 0.6, color: 'rgba(42, 196, 179, 0.05)' }, // Teal
|
||||
{ x: 0.5, y: 0.7, r: 0.5, color: 'rgba(244, 114, 182, 0.05)' }, // Fairy Pink
|
||||
{ x: 0.7, y: 0.8, r: 0.4, color: 'rgba(74, 29, 110, 0.06)' }, // Deep Purple
|
||||
{ x: 0.3, y: 0.6, r: 0.5, color: 'rgba(232, 148, 58, 0.04)' } // Amber
|
||||
];
|
||||
|
||||
washes.forEach(w => {
|
||||
const grad = nCtx.createRadialGradient(
|
||||
w.x * nebulaCanvas.width, w.y * nebulaCanvas.height, 0,
|
||||
w.x * nebulaCanvas.width, w.y * nebulaCanvas.height, w.r * nebulaCanvas.width
|
||||
);
|
||||
grad.addColorStop(0, w.color);
|
||||
grad.addColorStop(1, 'transparent');
|
||||
nCtx.fillStyle = grad;
|
||||
nCtx.fillRect(0, 0, nebulaCanvas.width, nebulaCanvas.height);
|
||||
});
|
||||
}
|
||||
|
||||
function initStars() {
|
||||
bgStars = [];
|
||||
const colorClasses = [
|
||||
'rgba(200,210,230,', // Cool White
|
||||
'rgba(240,220,190,', // Warm White
|
||||
'rgba(140,180,230,', // Pale Blue
|
||||
'rgba(255,207,64,', // Toucan Gold
|
||||
'rgba(244,114,182,', // Fairy Pink
|
||||
'rgba(197,88,217,', // Orchid Purple
|
||||
'rgba(134,239,172,', // Mint Green
|
||||
'rgba(212,101,74,' // Coral
|
||||
];
|
||||
|
||||
for(let i=0; i<350; i++) {
|
||||
const r = Math.random() < 0.1 ? Math.random() * 1.5 + 1.5 : Math.random() * 1.5 + 0.3;
|
||||
bgStars.push({
|
||||
x: Math.random() * starCanvas.width,
|
||||
y: Math.random() * starCanvas.height,
|
||||
r: r,
|
||||
colorBase: colorClasses[Math.floor(Math.random()*colorClasses.length)],
|
||||
opacity: Math.random() * 0.7 + 0.3,
|
||||
speed: Math.random() * 0.8 + 0.2,
|
||||
phase: Math.random() * Math.PI * 2
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function draw(time) {
|
||||
sCtx.clearRect(0, 0, starCanvas.width, starCanvas.height);
|
||||
const t = time * 0.001;
|
||||
bgStars.forEach(s => {
|
||||
const a = s.opacity + Math.sin(t * s.speed + s.phase) * 0.2;
|
||||
sCtx.beginPath();
|
||||
sCtx.arc(s.x, s.y, s.r, 0, Math.PI*2);
|
||||
sCtx.fillStyle = s.colorBase + Math.max(0.1, Math.min(1, a)) + ')';
|
||||
sCtx.fill();
|
||||
});
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
// Nodes & Lines
|
||||
const starZone = document.getElementById('star-zone');
|
||||
const svg = document.getElementById('constellation-svg');
|
||||
|
||||
STARS.forEach(s => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'star-node';
|
||||
btn.dataset.star = s.id;
|
||||
btn.style.left = s.x + '%';
|
||||
btn.style.top = s.y + '%';
|
||||
btn.innerHTML = `<div class="star-dot-container"><span class="star-dot"></span></div><span class="star-label">${s.label}</span>`;
|
||||
starZone.appendChild(btn);
|
||||
});
|
||||
|
||||
const lines = [['writings','videos'],['music','playlists'],['images','videos'],['watchlists','toolsntoys'],['toolsntoys','creatorlists'],['music','watchlists']];
|
||||
lines.forEach(pair => {
|
||||
const s1 = STARS.find(s => s.id === pair[0]);
|
||||
const s2 = STARS.find(s => s.id === pair[1]);
|
||||
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
||||
line.setAttribute('x1', s1.x + '%'); line.setAttribute('y1', s1.y + '%');
|
||||
line.setAttribute('x2', s2.x + '%'); line.setAttribute('y2', s2.y + '%');
|
||||
line.setAttribute('class', 'constellation-line');
|
||||
line.setAttribute('stroke', s1.color);
|
||||
line.setAttribute('stroke-opacity', '0.15');
|
||||
svg.appendChild(line);
|
||||
});
|
||||
|
||||
// Skyline
|
||||
function initSkyline() {
|
||||
const skyline = document.getElementById('skyline');
|
||||
const bbColors = ['bb-teal', 'bb-amber', 'bb-orchid', 'bb-pink', 'bb-mint'];
|
||||
const winColors = ['var(--fire-amber)', 'var(--neon-teal)', 'var(--orchid)', 'var(--fairy-pink)', 'var(--phosphor)'];
|
||||
|
||||
for(let i=0; i<40; i++) {
|
||||
const b = document.createElement('div');
|
||||
b.className = 'building';
|
||||
const bio = Math.random();
|
||||
if(bio > 0.85) b.classList.add('bio-orchid');
|
||||
else if(bio > 0.75) b.classList.add('bio-mint');
|
||||
|
||||
const w = 20 + Math.random() * 60;
|
||||
const h = 40 + Math.random() * 300;
|
||||
b.style.width = w + 'px';
|
||||
b.style.height = h + 'px';
|
||||
b.style.marginRight = '2px';
|
||||
|
||||
if(h > 80) {
|
||||
for(let j=0; j<Math.floor(h/30); j++) {
|
||||
const win = document.createElement('div');
|
||||
const wc = winColors[Math.floor(Math.random()*winColors.length)];
|
||||
win.style.cssText = `position:absolute; width:2px; height:2px; background:${wc}; opacity:${Math.random()*0.3}; left:${Math.random()*w}px; top:${30+j*30}px;`;
|
||||
b.appendChild(win);
|
||||
}
|
||||
}
|
||||
|
||||
if(Math.random() > 0.85) {
|
||||
const bb = document.createElement('div');
|
||||
bb.className = 'billboard-nav ' + bbColors[Math.floor(Math.random()*bbColors.length)];
|
||||
bb.textContent = 'SIGNAL';
|
||||
b.appendChild(bb);
|
||||
}
|
||||
skyline.appendChild(b);
|
||||
}
|
||||
}
|
||||
|
||||
// Lightbox
|
||||
const overlay = document.getElementById('lightbox-overlay');
|
||||
if(!localStorage.getItem('sp-welcomed')) overlay.classList.remove('hidden');
|
||||
document.getElementById('lightbox-enter').onclick = () => {
|
||||
overlay.classList.add('hidden');
|
||||
localStorage.setItem('sp-welcomed', 'true');
|
||||
};
|
||||
|
||||
window.onresize = resize;
|
||||
resize();
|
||||
initSkyline();
|
||||
requestAnimationFrame(draw);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,596 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!--
|
||||
DRAFT: Starfield Bold v3 (The Prismatic Ruins)
|
||||
AUTHOR: Gemini (Designer Agent)
|
||||
DATE: 2026-03-26
|
||||
|
||||
DESCRIPTION:
|
||||
The "BOLDER" direction v2: Vaporwave + Mad Max + Rainforest + Fairies.
|
||||
Focus on "Visible Personality" for stars and a deeper "Enchanted Twilight" feel.
|
||||
|
||||
NEW IN THIS VERSION:
|
||||
- STAR NODE PERSONALITIES: Each node is a unique celestial/magical object (Beacon, Binary, Pulsar, Flora, Hearth, Nebula Point, Spark, Flow).
|
||||
- REFINED CRT GHOST: Precision scanlines (0.04) and phosphor vignette. 1px phosphor line on Lightbox.
|
||||
- ENHANCED STAR FIELD: Weighted 8-color distribution (Cool/Warm White, Blue, Gold, Pink, Orchid, Mint, Coral).
|
||||
- PRISMATIC NEBULAE: 5 layers with slightly higher saturation but low opacity (0.05).
|
||||
- LUSH SKYLINE: Polychromatic window lights (Amber/Teal/Orchid/Pink/Phosphor) and Mint/Orchid bioluminescence.
|
||||
- BUMPED TEXT: 13px star labels, 12px billboards, 16px lightbox body.
|
||||
- CAMPFIRE LIGHTBOX: Double-border with orchid-fairy magic and phosphor cursor line.
|
||||
|
||||
CONSTRAINTS:
|
||||
- No transform animations on hover (using width/height).
|
||||
- Transitions 150ms ease.
|
||||
- Border-radius max 10px.
|
||||
- Box-shadow blur max 8px.
|
||||
- Font: Space Grotesk.
|
||||
-->
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Singular Particular Space | Starfield Bold v3</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 {
|
||||
/* Core Void */
|
||||
--bg-void: #04060b;
|
||||
--bg-deep: #060a14;
|
||||
--bg-warm: #0d1320;
|
||||
|
||||
/* The Campfire */
|
||||
--fire-amber: #e8943a;
|
||||
--fire-coral: #d4654a;
|
||||
--paradise: #ff7f3f;
|
||||
|
||||
/* Prismatic/Fairy Palette */
|
||||
--orchid: #c558d9;
|
||||
--fairy-pink: #f472b6;
|
||||
--toucan-gold: #ffcf40;
|
||||
--mint-glow: #86efac;
|
||||
--neon-teal: #2ac4b3;
|
||||
--waterfall: #3fbfaf;
|
||||
--cosmic-purple:#4a1d6e;
|
||||
|
||||
/* CRT Ghost */
|
||||
--phosphor: #00ff41;
|
||||
|
||||
/* Text */
|
||||
--text-warm: #e8d5b8;
|
||||
--text-muted: #6a7a8a;
|
||||
}
|
||||
|
||||
*, *::before, *::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Space Grotesk', system-ui, -apple-system, sans-serif;
|
||||
background: var(--bg-void);
|
||||
color: var(--text-warm);
|
||||
overflow: hidden;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* ── CRT GHOST LAYERS ── */
|
||||
|
||||
/* Static Scanlines */
|
||||
body::before {
|
||||
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;
|
||||
}
|
||||
|
||||
/* Phosphor Vignette */
|
||||
body::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: radial-gradient(ellipse at center, transparent 60%, rgba(0, 0, 0, 0.35) 100%);
|
||||
pointer-events: none;
|
||||
z-index: 9998;
|
||||
}
|
||||
|
||||
/* ── Zone 1: Star Map ── */
|
||||
|
||||
#star-zone {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
background: radial-gradient(circle at 50% 50%, #0a0e1a 0%, var(--bg-void) 100%);
|
||||
}
|
||||
|
||||
#nebula-canvas, #star-canvas {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
}
|
||||
|
||||
#nebula-canvas { z-index: 0; }
|
||||
#star-canvas { z-index: 1; }
|
||||
|
||||
#constellation-svg {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.constellation-line {
|
||||
stroke-width: 1.2;
|
||||
stroke-linecap: round;
|
||||
animation: line-pulse 10s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes line-pulse {
|
||||
0%, 100% { stroke-opacity: 0.08; }
|
||||
50% { stroke-opacity: 0.25; }
|
||||
}
|
||||
|
||||
/* ── Star Nodes (Personality Layer) ── */
|
||||
|
||||
.star-node {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
transform: translate(-50%, -50%);
|
||||
outline: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.star-visual {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.star-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
transition: width 150ms ease, height 150ms ease, box-shadow 150ms ease, background 150ms ease;
|
||||
box-shadow: 0 0 4px #fff;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.star-label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--text-muted);
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: lowercase;
|
||||
white-space: nowrap;
|
||||
opacity: 0.6;
|
||||
transition: opacity 150ms ease, color 150ms ease;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Star Bloom (Hover/Focus) */
|
||||
.star-node:hover .star-dot,
|
||||
.star-node:focus .star-dot,
|
||||
.star-node.current .star-dot {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: var(--fire-amber) !important;
|
||||
box-shadow: 0 0 8px var(--fire-amber) !important;
|
||||
}
|
||||
|
||||
.star-node:hover .star-label,
|
||||
.star-node:focus .star-label,
|
||||
.star-node.current .star-label {
|
||||
color: var(--text-warm);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Personality 1: Writings (The Beacon) - Cross-hair glow */
|
||||
.star-node[data-star="writings"] .star-dot { background: var(--orchid); box-shadow: 0 0 6px var(--orchid); }
|
||||
.star-node[data-star="writings"] .star-visual::before,
|
||||
.star-node[data-star="writings"] .star-visual::after {
|
||||
content: ''; position: absolute; background: var(--orchid); opacity: 0.2; transition: opacity 150ms;
|
||||
}
|
||||
.star-node[data-star="writings"] .star-visual::before { width: 1px; height: 100%; }
|
||||
.star-node[data-star="writings"] .star-visual::after { width: 100%; height: 1px; }
|
||||
|
||||
/* Personality 2: Videos (The Binary) - Twin dots */
|
||||
.star-node[data-star="videos"] .star-dot { background: var(--fire-coral); box-shadow: 0 0 6px var(--fire-coral); }
|
||||
.star-node[data-star="videos"] .star-visual::before {
|
||||
content: ''; position: absolute; width: 4px; height: 4px; border-radius: 50%;
|
||||
background: var(--fire-coral); top: 0; right: 0; opacity: 0.5;
|
||||
}
|
||||
|
||||
/* Personality 3: Music (The Pulsar) - Multiple small dots */
|
||||
.star-node[data-star="music"] .star-dot { background: var(--neon-teal); box-shadow: 0 0 6px var(--neon-teal); }
|
||||
.star-node[data-star="music"] .star-visual::before {
|
||||
content: '· ·'; position: absolute; color: var(--neon-teal); font-size: 16px; top: -10px; opacity: 0.4;
|
||||
}
|
||||
|
||||
/* Personality 4: Images (The Flora) - Soft halo */
|
||||
.star-node[data-star="images"] .star-dot { background: var(--mint-glow); box-shadow: 0 0 6px var(--mint-glow); }
|
||||
.star-node[data-star="images"] .star-visual::before {
|
||||
content: ''; position: absolute; width: 20px; height: 20px; border-radius: 50%;
|
||||
border: 1px solid var(--mint-glow); opacity: 0.15;
|
||||
}
|
||||
|
||||
/* Personality 5: Playlists (The Hearth) - Intense flicker */
|
||||
.star-node[data-star="playlists"] .star-dot {
|
||||
background: var(--fairy-pink); box-shadow: 0 0 6px var(--fairy-pink);
|
||||
animation: hearth-flicker 4s ease-in-out infinite;
|
||||
}
|
||||
@keyframes hearth-flicker { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } }
|
||||
|
||||
/* Personality 6: Watchlists (The Nebula Point) - Tiny cloud */
|
||||
.star-node[data-star="watchlists"] .star-dot { background: var(--cosmic-purple); box-shadow: 0 0 6px var(--cosmic-purple); }
|
||||
.star-node[data-star="watchlists"] .star-visual::before {
|
||||
content: ''; position: absolute; width: 24px; height: 24px; border-radius: 50%;
|
||||
background: radial-gradient(circle, var(--cosmic-purple) 0%, transparent 70%); opacity: 0.2;
|
||||
}
|
||||
|
||||
/* Personality 7: Tools (The Spark) - Sharp intense */
|
||||
.star-node[data-star="toolsntoys"] .star-dot { background: var(--toucan-gold); box-shadow: 0 0 8px var(--toucan-gold); width: 6px; height: 6px; }
|
||||
|
||||
/* Personality 8: Creatorlists (The Flow) - Trail */
|
||||
.star-node[data-star="creatorlists"] .star-dot { background: var(--waterfall); box-shadow: 0 0 6px var(--waterfall); }
|
||||
.star-node[data-star="creatorlists"] .star-visual::before {
|
||||
content: '...'; position: absolute; color: var(--waterfall); right: -12px; font-size: 10px; opacity: 0.3;
|
||||
}
|
||||
|
||||
/* ── Transition Zone: Skyline ── */
|
||||
|
||||
#transition-zone {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 80vh;
|
||||
background: linear-gradient(to bottom, var(--bg-void) 0%, #080c14 40%, var(--bg-warm) 100%);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#skyline {
|
||||
position: absolute;
|
||||
bottom: 0; left: 0;
|
||||
width: 100%;
|
||||
height: 70%;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.building {
|
||||
background: #05080f;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
border-top: 1px solid rgba(232, 148, 58, 0.04);
|
||||
}
|
||||
|
||||
/* Bioluminescent Moss & Highlights */
|
||||
.building.bio-orchid::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 15%; left: 0;
|
||||
width: 2px; height: 40%;
|
||||
background: var(--orchid);
|
||||
box-shadow: 0 0 6px var(--orchid);
|
||||
opacity: 0.12;
|
||||
}
|
||||
|
||||
.building.bio-mint::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 25%; right: 0;
|
||||
width: 1px; height: 35%;
|
||||
background: var(--mint-glow);
|
||||
box-shadow: 0 0 6px var(--mint-glow);
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.billboard-nav {
|
||||
position: absolute;
|
||||
top: -2px; left: 50%;
|
||||
transform: translate(-50%, -100%);
|
||||
padding: 4px 10px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
border: 1px solid;
|
||||
background: rgba(4, 6, 11, 0.95);
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
transition: color 150ms ease, border-color 150ms ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bb-teal { color: var(--neon-teal); border-color: rgba(42, 196, 179, 0.2); }
|
||||
.bb-amber { color: var(--fire-amber); border-color: rgba(232, 148, 58, 0.2); }
|
||||
.bb-orchid { color: var(--orchid); border-color: rgba(197, 88, 217, 0.2); }
|
||||
.bb-pink { color: var(--fairy-pink); border-color: rgba(244, 114, 182, 0.2); }
|
||||
.bb-mint { color: var(--mint-glow); border-color: rgba(134, 239, 172, 0.2); }
|
||||
|
||||
.billboard-nav:hover {
|
||||
color: var(--fire-amber) !important;
|
||||
border-color: var(--fire-amber) !important;
|
||||
}
|
||||
|
||||
/* ── Lightbox: Campfire Note ── */
|
||||
|
||||
#lightbox-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
z-index: 10000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#lightbox-overlay.hidden { display: none; }
|
||||
|
||||
#lightbox {
|
||||
background: var(--bg-warm);
|
||||
border: 1px solid var(--fire-amber);
|
||||
border-top: 4px solid var(--phosphor); /* CRT Cursor Line */
|
||||
border-radius: 4px;
|
||||
padding: 40px;
|
||||
max-width: 520px;
|
||||
width: 90%;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Orchid Inner Border (Fairy Magic) */
|
||||
#lightbox::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 6px;
|
||||
border: 1px solid rgba(197, 88, 217, 0.15);
|
||||
pointer-events: none;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#lightbox p {
|
||||
font-size: 16px;
|
||||
line-height: 1.7;
|
||||
color: var(--text-warm);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.nav-hint {
|
||||
font-size: 13px;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 32px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#lightbox-enter {
|
||||
padding: 10px 32px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--bg-void);
|
||||
background: var(--fire-amber);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: opacity 150ms ease;
|
||||
}
|
||||
|
||||
#lightbox-enter:hover { opacity: 0.9; }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="star-zone">
|
||||
<canvas id="nebula-canvas"></canvas>
|
||||
<canvas id="star-canvas"></canvas>
|
||||
<svg id="constellation-svg" xmlns="http://www.w3.org/2000/svg"></svg>
|
||||
</div>
|
||||
|
||||
<div id="transition-zone">
|
||||
<div id="skyline"></div>
|
||||
</div>
|
||||
|
||||
<div id="lightbox-overlay" class="hidden">
|
||||
<div id="lightbox">
|
||||
<p>Hello traveller, welcome to a singular, particular space. Feel free to explore this little pocket of the universe. It's an adventure, bring snacks. Happy wanderings, Myster Wizzard</p>
|
||||
<span class="nav-hint">click stars · arrow keys · escape to return</span>
|
||||
<button id="lightbox-enter">Enter</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const STARS = [
|
||||
{ id: 'writings', label: 'Writings', x: 25, y: 18, color: '#c558d9' },
|
||||
{ id: 'videos', label: 'Videos', x: 68, y: 15, color: '#d4654a' },
|
||||
{ id: 'music', label: 'Music', x: 12, y: 42, color: '#2ac4b3' },
|
||||
{ id: 'images', label: 'Images', x: 55, y: 35, color: '#86efac' },
|
||||
{ id: 'playlists', label: 'Playlists', x: 78, y: 48, color: '#f472b6' },
|
||||
{ id: 'watchlists', label: 'Watchlists', x: 22, y: 65, color: '#4a1d6e' },
|
||||
{ id: 'toolsntoys', label: 'ToolsnToys', x: 50, y: 72, color: '#ffcf40' },
|
||||
{ id: 'creatorlists', label: 'Creatorlists', x: 75, y: 70, color: '#3fbfaf' }
|
||||
];
|
||||
|
||||
const CONNECTIONS = [
|
||||
['writings', 'videos'], ['music', 'playlists'], ['images', 'videos'],
|
||||
['watchlists', 'toolsntoys'], ['toolsntoys', 'creatorlists'], ['music', 'watchlists']
|
||||
];
|
||||
|
||||
const nebulaCanvas = document.getElementById('nebula-canvas');
|
||||
const starCanvas = document.getElementById('star-canvas');
|
||||
const nCtx = nebulaCanvas.getContext('2d');
|
||||
const sCtx = starCanvas.getContext('2d');
|
||||
let bgStars = [];
|
||||
|
||||
function resize() {
|
||||
nebulaCanvas.width = starCanvas.width = window.innerWidth;
|
||||
nebulaCanvas.height = starCanvas.height = window.innerHeight;
|
||||
drawNebulae();
|
||||
initStars();
|
||||
}
|
||||
|
||||
function drawNebulae() {
|
||||
nCtx.clearRect(0, 0, nebulaCanvas.width, nebulaCanvas.height);
|
||||
const washes = [
|
||||
{ x: 0.2, y: 0.3, r: 0.5, color: 'rgba(197, 88, 217, 0.05)' }, // Orchid
|
||||
{ x: 0.8, y: 0.2, r: 0.6, color: 'rgba(42, 196, 179, 0.05)' }, // Teal
|
||||
{ x: 0.5, y: 0.7, r: 0.5, color: 'rgba(244, 114, 182, 0.05)' }, // Fairy Pink
|
||||
{ x: 0.7, y: 0.8, r: 0.4, color: 'rgba(74, 29, 110, 0.06)' }, // Deep Purple
|
||||
{ x: 0.3, y: 0.6, r: 0.5, color: 'rgba(232, 148, 58, 0.04)' } // Amber
|
||||
];
|
||||
|
||||
washes.forEach(w => {
|
||||
const grad = nCtx.createRadialGradient(
|
||||
w.x * nebulaCanvas.width, w.y * nebulaCanvas.height, 0,
|
||||
w.x * nebulaCanvas.width, w.y * nebulaCanvas.height, w.r * nebulaCanvas.width
|
||||
);
|
||||
grad.addColorStop(0, w.color);
|
||||
grad.addColorStop(1, 'transparent');
|
||||
nCtx.fillStyle = grad;
|
||||
nCtx.fillRect(0, 0, nebulaCanvas.width, nebulaCanvas.height);
|
||||
});
|
||||
}
|
||||
|
||||
function initStars() {
|
||||
bgStars = [];
|
||||
const colorClasses = [
|
||||
'rgba(200,210,230,', // Cool White
|
||||
'rgba(240,220,190,', // Warm White
|
||||
'rgba(140,180,230,', // Pale Blue
|
||||
'rgba(255,207,64,', // Toucan Gold
|
||||
'rgba(244,114,182,', // Fairy Pink
|
||||
'rgba(197,88,217,', // Orchid
|
||||
'rgba(134,239,172,', // Mint Green
|
||||
'rgba(212,101,74,' // Coral
|
||||
];
|
||||
|
||||
for(let i=0; i<350; i++) {
|
||||
const r = Math.random() < 0.1 ? Math.random() * 1.5 + 1.5 : Math.random() * 1.5 + 0.3;
|
||||
bgStars.push({
|
||||
x: Math.random() * starCanvas.width,
|
||||
y: Math.random() * starCanvas.height,
|
||||
r: r,
|
||||
colorBase: colorClasses[Math.floor(Math.random()*colorClasses.length)],
|
||||
opacity: Math.random() * 0.7 + 0.3,
|
||||
speed: Math.random() * 0.6 + 0.2,
|
||||
phase: Math.random() * Math.PI * 2
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function draw(time) {
|
||||
sCtx.clearRect(0, 0, starCanvas.width, starCanvas.height);
|
||||
const t = time * 0.001;
|
||||
bgStars.forEach(s => {
|
||||
const a = s.opacity + Math.sin(t * s.speed + s.phase) * 0.2;
|
||||
sCtx.beginPath();
|
||||
sCtx.arc(s.x, s.y, s.r, 0, Math.PI*2);
|
||||
sCtx.fillStyle = s.colorBase + Math.max(0.1, Math.min(1, a)) + ')';
|
||||
sCtx.fill();
|
||||
});
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
// Nodes & Lines
|
||||
const starZone = document.getElementById('star-zone');
|
||||
const svg = document.getElementById('constellation-svg');
|
||||
|
||||
STARS.forEach(s => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'star-node';
|
||||
btn.dataset.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>`;
|
||||
starZone.appendChild(btn);
|
||||
});
|
||||
|
||||
CONNECTIONS.forEach(pair => {
|
||||
const s1 = STARS.find(s => s.id === pair[0]);
|
||||
const s2 = STARS.find(s => s.id === pair[1]);
|
||||
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
||||
line.setAttribute('x1', s1.x + '%'); line.setAttribute('y1', s1.y + '%');
|
||||
line.setAttribute('x2', s2.x + '%'); line.setAttribute('y2', s2.y + '%');
|
||||
line.setAttribute('class', 'constellation-line');
|
||||
line.setAttribute('stroke', s1.color);
|
||||
line.setAttribute('stroke-opacity', '0.15');
|
||||
svg.appendChild(line);
|
||||
});
|
||||
|
||||
// Skyline
|
||||
function initSkyline() {
|
||||
const skyline = document.getElementById('skyline');
|
||||
const bbColors = ['bb-teal', 'bb-amber', 'bb-orchid', 'bb-pink', 'bb-mint'];
|
||||
const winColors = ['var(--fire-amber)', 'var(--neon-teal)', 'var(--orchid)', 'var(--fairy-pink)', 'var(--phosphor)'];
|
||||
|
||||
for(let i=0; i<45; i++) {
|
||||
const b = document.createElement('div');
|
||||
b.className = 'building';
|
||||
const bio = Math.random();
|
||||
if(bio > 0.88) b.classList.add('bio-orchid');
|
||||
else if(bio > 0.75) b.classList.add('bio-mint');
|
||||
|
||||
const w = 18 + Math.random() * 55;
|
||||
const h = 40 + Math.random() * 320;
|
||||
b.style.width = w + 'px';
|
||||
b.style.height = h + 'px';
|
||||
b.style.marginRight = '2px';
|
||||
|
||||
if(h > 80) {
|
||||
for(let j=0; j<Math.floor(h/35); j++) {
|
||||
const win = document.createElement('div');
|
||||
const wc = winColors[Math.floor(Math.random()*winColors.length)];
|
||||
win.style.cssText = `position:absolute; width:2px; height:2px; background:${wc}; opacity:${Math.random()*0.3}; left:${Math.random()*w}px; top:${30+j*30}px;`;
|
||||
b.appendChild(win);
|
||||
}
|
||||
}
|
||||
|
||||
if(Math.random() > 0.88) {
|
||||
const bb = document.createElement('div');
|
||||
bb.className = 'billboard-nav ' + bbColors[Math.floor(Math.random()*bbColors.length)];
|
||||
bb.textContent = 'SIGNAL';
|
||||
b.appendChild(bb);
|
||||
}
|
||||
skyline.appendChild(b);
|
||||
}
|
||||
}
|
||||
|
||||
// Lightbox
|
||||
const overlay = document.getElementById('lightbox-overlay');
|
||||
if(!localStorage.getItem('sp-welcomed')) overlay.classList.remove('hidden');
|
||||
document.getElementById('lightbox-enter').onclick = () => {
|
||||
overlay.classList.add('hidden');
|
||||
localStorage.setItem('sp-welcomed', 'true');
|
||||
};
|
||||
|
||||
window.onresize = resize;
|
||||
resize();
|
||||
initSkyline();
|
||||
requestAnimationFrame(draw);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,528 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!--
|
||||
DRAFT: Starfield Celestial v4 (The Infinite Night Market)
|
||||
AUTHOR: Gemini (Designer Agent)
|
||||
DATE: 2026-03-26
|
||||
|
||||
DESCRIPTION:
|
||||
The "CELESTIAL" pivot: Constellation lines REMOVED per user request.
|
||||
Focus shifts to "Visible Personality" of nodes and a more atmospheric,
|
||||
dense star field that feels like a place rather than a UI.
|
||||
|
||||
NEW IN THIS VERSION:
|
||||
- NO CONSTELLATION LINES: The connections are now felt, not seen.
|
||||
- STAR NODE PERSONALITIES v2:
|
||||
- Writings (Beacon): Pulsing cross-hair glow.
|
||||
- Videos (Binary): Orbiting secondary spark.
|
||||
- Music (Pulsar): Rapid-flicker rhythmic aura.
|
||||
- Images (Flora): Concentric mint-glow rings (Bioluminescent Moss).
|
||||
- Playlists (Hearth): Warm amber flame flicker.
|
||||
- Watchlists (Nebula Point): Soft purple gas cloud halo.
|
||||
- ToolsnToys (Spark): Sharp, prismatic star-spike.
|
||||
- Creatorlists (Flow): Trailing mint-green comet dust.
|
||||
- BOLDER NEBULAE: 6 overlapping washes (Orchid, Paradise, Toucan, Teal, Pink, Purple).
|
||||
- VAST CELESTIAL FIELD: 3 depth layers, 8-color distribution, rare "Mega Stars" (3px).
|
||||
- LUSH RUINS SKYLINE: Vertical bioluminescent stripes (Orchid/Mint) on silhouettes.
|
||||
- TEXT BUMP: 16px star labels (desktop), 13px billboard nav.
|
||||
|
||||
AESTHETIC: Vaporwave Ruins + Mad Max Rainforest + Fairy Fire.
|
||||
-->
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Singular Particular Space | Starfield Celestial v4</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 {
|
||||
/* The Void */
|
||||
--bg-void: #04060b;
|
||||
--bg-deep: #060a14;
|
||||
--bg-warm: #0d1320;
|
||||
|
||||
/* The Fire */
|
||||
--fire-amber: #e8943a;
|
||||
--fire-coral: #d4654a;
|
||||
--paradise: #ff7f3f;
|
||||
|
||||
/* The Magic */
|
||||
--orchid: #c558d9;
|
||||
--fairy-pink: #f472b6;
|
||||
--toucan-gold: #ffcf40;
|
||||
--mint-glow: #86efac;
|
||||
--neon-teal: #2ac4b3;
|
||||
--waterfall: #3fbfaf;
|
||||
--cosmic-purple: #4a1d6e;
|
||||
|
||||
/* The Tech Ghost */
|
||||
--phosphor: #00ff41;
|
||||
|
||||
/* The Human */
|
||||
--text-warm: #e8d5b8;
|
||||
--text-muted: #6a7a8a;
|
||||
}
|
||||
|
||||
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
font-family: 'Space Grotesk', system-ui, -apple-system, sans-serif;
|
||||
background: var(--bg-void);
|
||||
color: var(--text-warm);
|
||||
overflow: hidden;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* ── CRT Ghost ── */
|
||||
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 ── */
|
||||
|
||||
#star-zone {
|
||||
position: relative;
|
||||
width: 100%; height: 100vh;
|
||||
overflow: hidden;
|
||||
background: radial-gradient(circle at 50% 50%, #080c18 0%, var(--bg-void) 100%);
|
||||
}
|
||||
|
||||
#nebula-canvas, #star-canvas {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
}
|
||||
|
||||
#nebula-canvas { z-index: 0; }
|
||||
#star-canvas { z-index: 1; }
|
||||
|
||||
/* ── Star Nodes (Personality Layer) ── */
|
||||
|
||||
.star-node {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
transform: translate(-50%, -50%);
|
||||
outline: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.star-visual {
|
||||
position: relative;
|
||||
width: 40px; height: 40px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
|
||||
.star-dot {
|
||||
width: 8px; height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
transition: width 150ms ease, height 150ms ease, box-shadow 150ms ease, background 150ms ease;
|
||||
box-shadow: 0 0 6px rgba(255,255,255,0.8);
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.star-label {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--text-muted);
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: lowercase;
|
||||
white-space: nowrap;
|
||||
opacity: 0;
|
||||
transition: opacity 200ms ease, color 150ms ease;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.star-node:hover .star-label,
|
||||
.star-node:focus .star-label,
|
||||
.star-node.current .star-label { opacity: 1; color: var(--text-warm); }
|
||||
|
||||
/* Star Bloom (The Campfire Follows You) */
|
||||
.star-node:hover .star-dot,
|
||||
.star-node:focus .star-dot,
|
||||
.star-node.current .star-dot {
|
||||
width: 20px; height: 20px;
|
||||
background: var(--fire-amber) !important;
|
||||
box-shadow: 0 0 12px var(--fire-amber) !important;
|
||||
}
|
||||
|
||||
/* Personality 1: Writings (The Beacon) */
|
||||
.star-node[data-star="writings"] .star-dot { background: var(--star-blue, #a0c4ff); box-shadow: 0 0 8px #a0c4ff; }
|
||||
.star-node[data-star="writings"] .star-visual::before {
|
||||
content: ''; position: absolute; width: 1px; height: 100%; background: var(--orchid); opacity: 0.15;
|
||||
animation: beacon-pulse 4s ease-in-out infinite;
|
||||
}
|
||||
.star-node[data-star="writings"] .star-visual::after {
|
||||
content: ''; position: absolute; width: 100%; height: 1px; background: var(--orchid); opacity: 0.15;
|
||||
animation: beacon-pulse 4s ease-in-out infinite;
|
||||
}
|
||||
@keyframes beacon-pulse { 0%, 100% { opacity: 0.05; } 50% { opacity: 0.25; } }
|
||||
|
||||
/* Personality 2: Videos (The Binary) */
|
||||
.star-node[data-star="videos"] .star-dot { background: var(--fire-coral); box-shadow: 0 0 8px var(--fire-coral); }
|
||||
.star-node[data-star="videos"] .star-visual::before {
|
||||
content: ''; position: absolute; width: 4px; height: 4px; border-radius: 50%;
|
||||
background: #fff; opacity: 0.6;
|
||||
animation: binary-orbit 3s linear infinite;
|
||||
}
|
||||
@keyframes binary-orbit {
|
||||
from { transform: rotate(0deg) translateX(12px) rotate(0deg); }
|
||||
to { transform: rotate(360deg) translateX(12px) rotate(-360deg); }
|
||||
}
|
||||
|
||||
/* Personality 3: Music (The Pulsar) */
|
||||
.star-node[data-star="music"] .star-dot { background: var(--neon-teal); box-shadow: 0 0 8px var(--neon-teal); }
|
||||
.star-node[data-star="music"] .star-visual::before {
|
||||
content: ''; position: absolute; inset: 0; border: 1px solid var(--neon-teal); border-radius: 50%;
|
||||
animation: pulsar-aura 2s ease-out infinite;
|
||||
}
|
||||
@keyframes pulsar-aura { 0% { transform: scale(0.2); opacity: 0.6; } 100% { transform: scale(1.2); opacity: 0; } }
|
||||
|
||||
/* Personality 4: Images (The Flora) */
|
||||
.star-node[data-star="images"] .star-dot { background: var(--mint-glow); box-shadow: 0 0 8px var(--mint-glow); }
|
||||
.star-node[data-star="images"] .star-visual::before {
|
||||
content: '✿'; position: absolute; color: var(--mint-glow); font-size: 10px; top: -12px; opacity: 0.4;
|
||||
}
|
||||
.star-node[data-star="images"] .star-visual::after {
|
||||
content: '✿'; position: absolute; color: var(--mint-glow); font-size: 10px; bottom: -12px; opacity: 0.4;
|
||||
}
|
||||
|
||||
/* Personality 5: Playlists (The Hearth) */
|
||||
.star-node[data-star="playlists"] .star-dot { background: var(--toucan-gold); box-shadow: 0 0 10px var(--toucan-gold); }
|
||||
.star-node[data-star="playlists"] .star-visual::before {
|
||||
content: ''; position: absolute; width: 24px; height: 24px; border-radius: 50%;
|
||||
background: radial-gradient(circle, var(--fire-amber) 0%, transparent 70%);
|
||||
animation: hearth-glow 3s ease-in-out infinite;
|
||||
}
|
||||
@keyframes hearth-glow { 0%, 100% { opacity: 0.1; transform: scale(0.8); } 50% { opacity: 0.3; transform: scale(1.1); } }
|
||||
|
||||
/* Personality 6: Watchlists (The Nebula Point) */
|
||||
.star-node[data-star="watchlists"] .star-dot { background: var(--orchid); box-shadow: 0 0 8px var(--orchid); }
|
||||
.star-node[data-star="watchlists"] .star-visual::before {
|
||||
content: ''; position: absolute; width: 30px; height: 20px; border-radius: 50%;
|
||||
background: rgba(197, 88, 217, 0.1); filter: blur(4px);
|
||||
}
|
||||
|
||||
/* Personality 7: ToolsnToys (The Spark) */
|
||||
.star-node[data-star="toolsntoys"] .star-dot { background: var(--fairy-pink); box-shadow: 0 0 10px var(--fairy-pink); }
|
||||
.star-node[data-star="toolsntoys"] .star-visual::before {
|
||||
content: '+'; position: absolute; color: var(--fairy-pink); font-size: 18px; top: -14px; opacity: 0.5;
|
||||
}
|
||||
|
||||
/* Personality 8: Creatorlists (The Flow) */
|
||||
.star-node[data-star="creatorlists"] .star-dot { background: var(--waterfall); box-shadow: 0 0 8px var(--waterfall); }
|
||||
.star-node[data-star="creatorlists"] .star-visual::before {
|
||||
content: ':::'; position: absolute; color: var(--waterfall); left: 24px; font-size: 10px; opacity: 0.4; letter-spacing: 2px;
|
||||
}
|
||||
|
||||
/* ── Transition Zone: Skyline ── */
|
||||
|
||||
#transition-zone {
|
||||
position: relative;
|
||||
width: 100%; height: 75vh;
|
||||
background: linear-gradient(to bottom,
|
||||
var(--bg-void) 0%,
|
||||
#080a14 30%,
|
||||
#0d0e1a 60%,
|
||||
var(--bg-warm) 100%);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#skyline {
|
||||
position: absolute;
|
||||
bottom: 0; left: 0;
|
||||
width: 100%; height: 70%;
|
||||
display: flex; align-items: flex-end; justify-content: center;
|
||||
}
|
||||
|
||||
.building {
|
||||
background: #05070c;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
border-top: 1px solid rgba(232, 148, 58, 0.05);
|
||||
}
|
||||
|
||||
.building.bio-orchid::before {
|
||||
content: ''; position: absolute; top: 10%; left: 0; width: 2px; height: 35%;
|
||||
background: var(--orchid); box-shadow: 0 0 6px var(--orchid); opacity: 0.12;
|
||||
}
|
||||
|
||||
.building.bio-mint::after {
|
||||
content: ''; position: absolute; top: 20%; right: 0; width: 1px; height: 45%;
|
||||
background: var(--mint-glow); box-shadow: 0 0 6px var(--mint-glow); opacity: 0.1;
|
||||
}
|
||||
|
||||
.billboard-nav {
|
||||
position: absolute;
|
||||
top: -2px; left: 50%;
|
||||
transform: translate(-50%, -100%);
|
||||
padding: 3px 10px;
|
||||
font-size: 13px; font-weight: 500;
|
||||
border: 1px solid;
|
||||
background: rgba(4, 6, 11, 0.95);
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
transition: all 150ms ease;
|
||||
}
|
||||
|
||||
.bb-teal { color: var(--neon-teal); border-color: rgba(42,196,179,0.25); }
|
||||
.bb-amber { color: var(--fire-amber); border-color: rgba(232,148,58,0.25); }
|
||||
.bb-orchid{ color: var(--orchid); border-color: rgba(197,88,217,0.25); }
|
||||
.bb-pink { color: var(--fairy-pink); border-color: rgba(244,114,182,0.25); }
|
||||
.bb-gold { color: var(--toucan-gold);border-color: rgba(255,207,64,0.25); }
|
||||
|
||||
.billboard-nav:hover {
|
||||
color: #fff; background: var(--fire-amber); border-color: var(--fire-amber);
|
||||
}
|
||||
|
||||
/* ── Lightbox: Campfire Note ── */
|
||||
|
||||
#lightbox-overlay {
|
||||
position: fixed; inset: 0;
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
z-index: 10000;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
#lightbox-overlay.hidden { display: none; }
|
||||
|
||||
#lightbox {
|
||||
background: var(--bg-warm);
|
||||
border: 1px solid var(--fire-amber);
|
||||
border-top: 2px solid var(--phosphor);
|
||||
border-radius: 4px;
|
||||
padding: 40px;
|
||||
max-width: 500px; width: 90%;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#lightbox::after {
|
||||
content: ''; position: absolute; inset: 6px;
|
||||
border: 1px solid rgba(197, 88, 217, 0.12);
|
||||
pointer-events: none; border-radius: 2px;
|
||||
}
|
||||
|
||||
#lightbox p {
|
||||
font-size: 16px; line-height: 1.7;
|
||||
color: var(--text-warm); margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.nav-hint {
|
||||
font-size: 14px; color: var(--text-muted);
|
||||
margin-bottom: 30px; display: block;
|
||||
}
|
||||
|
||||
#lightbox-enter {
|
||||
padding: 10px 32px;
|
||||
font-size: 14px; font-weight: 600;
|
||||
color: var(--bg-void); background: var(--fire-amber);
|
||||
border: none; border-radius: 4px; cursor: pointer;
|
||||
transition: opacity 150ms;
|
||||
}
|
||||
#lightbox-enter:hover { opacity: 0.9; }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="star-zone">
|
||||
<canvas id="nebula-canvas"></canvas>
|
||||
<canvas id="star-canvas"></canvas>
|
||||
</div>
|
||||
|
||||
<div id="transition-zone">
|
||||
<div id="skyline"></div>
|
||||
</div>
|
||||
|
||||
<div id="lightbox-overlay" class="hidden">
|
||||
<div id="lightbox">
|
||||
<p>Hello traveller, welcome to a singular, particular space. Feel free to explore this little pocket of the universe. It's an adventure, bring snacks. Happy wanderings, Myster Wizzard</p>
|
||||
<span class="nav-hint">click stars to explore · arrow keys to navigate · escape to return</span>
|
||||
<button id="lightbox-enter">Enter</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const STARS = [
|
||||
{ id: 'writings', label: 'Writings', x: 25, y: 18 },
|
||||
{ id: 'videos', label: 'Videos', x: 68, y: 15 },
|
||||
{ id: 'music', label: 'Music', x: 12, y: 42 },
|
||||
{ id: 'images', label: 'Images', x: 55, y: 35 },
|
||||
{ id: 'playlists', label: 'Playlists', x: 78, y: 48 },
|
||||
{ id: 'watchlists', label: 'Watchlists', x: 22, y: 65 },
|
||||
{ id: 'toolsntoys', label: 'ToolsnToys', x: 50, y: 72 },
|
||||
{ id: 'creatorlists', label: 'Creatorlists', x: 75, y: 70 }
|
||||
];
|
||||
|
||||
const nebulaCanvas = document.getElementById('nebula-canvas');
|
||||
const starCanvas = document.getElementById('star-canvas');
|
||||
const nCtx = nebulaCanvas.getContext('2d');
|
||||
const sCtx = starCanvas.getContext('2d');
|
||||
let bgStars = [];
|
||||
|
||||
function resize() {
|
||||
nebulaCanvas.width = starCanvas.width = window.innerWidth;
|
||||
nebulaCanvas.height = starCanvas.height = window.innerHeight;
|
||||
drawNebulae();
|
||||
initStars();
|
||||
}
|
||||
|
||||
function drawNebulae() {
|
||||
nCtx.clearRect(0, 0, nebulaCanvas.width, nebulaCanvas.height);
|
||||
const w = nebulaCanvas.width, h = nebulaCanvas.height;
|
||||
|
||||
// BOLDER washes: Orchid, Paradise, Toucan, Teal, Pink, Purple
|
||||
const washes = [
|
||||
{ x: 0.2, y: 0.25, r: 0.5, c: 'rgba(197, 88, 217, 0.08)' }, // Orchid
|
||||
{ x: 0.8, y: 0.15, r: 0.6, c: 'rgba(255, 127, 63, 0.06)' }, // Paradise
|
||||
{ x: 0.5, y: 0.6, r: 0.5, c: 'rgba(255, 207, 64, 0.05)' }, // Toucan
|
||||
{ x: 0.1, y: 0.7, r: 0.5, c: 'rgba(42, 196, 179, 0.07)' }, // Teal
|
||||
{ x: 0.7, y: 0.8, r: 0.4, c: 'rgba(244, 114, 182, 0.06)' }, // Fairy Pink
|
||||
{ x: 0.4, y: 0.1, r: 0.4, c: 'rgba(74, 29, 110, 0.08)' } // Purple
|
||||
];
|
||||
|
||||
washes.forEach(wash => {
|
||||
const grad = nCtx.createRadialGradient(
|
||||
wash.x * w, wash.y * h, 0,
|
||||
wash.x * w, wash.y * h, wash.r * w
|
||||
);
|
||||
grad.addColorStop(0, wash.c);
|
||||
grad.addColorStop(1, 'transparent');
|
||||
nCtx.fillStyle = grad;
|
||||
nCtx.fillRect(0, 0, w, h);
|
||||
});
|
||||
}
|
||||
|
||||
function initStars() {
|
||||
bgStars = [];
|
||||
const colorPool = [
|
||||
'200,210,230', // Cool White
|
||||
'240,220,190', // Warm White
|
||||
'140,180,230', // Pale Blue
|
||||
'255,207,64', // Toucan Gold
|
||||
'244,114,182', // Fairy Pink
|
||||
'197,88,217', // Orchid
|
||||
'134,239,172', // Mint Green
|
||||
'212,101,74' // Coral
|
||||
];
|
||||
|
||||
const count = window.innerWidth < 480 ? 250 : 450;
|
||||
for (let i = 0; i < count; i++) {
|
||||
const r = Math.random() < 0.05 ? 2.5 + Math.random() : (Math.random() < 0.7 ? 0.4 + Math.random() : 1.2 + Math.random());
|
||||
bgStars.push({
|
||||
x: Math.random() * starCanvas.width,
|
||||
y: Math.random() * starCanvas.height,
|
||||
r: r,
|
||||
color: colorPool[Math.floor(Math.random() * colorPool.length)],
|
||||
opacity: 0.3 + Math.random() * 0.5,
|
||||
speed: 0.4 + Math.random() * 0.8,
|
||||
phase: Math.random() * Math.PI * 2
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function draw(time) {
|
||||
sCtx.clearRect(0, 0, starCanvas.width, starCanvas.height);
|
||||
const t = time * 0.001;
|
||||
bgStars.forEach(s => {
|
||||
const a = s.opacity + Math.sin(t * s.speed + s.phase) * 0.2;
|
||||
sCtx.beginPath();
|
||||
sCtx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
|
||||
sCtx.fillStyle = `rgba(${s.color}, ${Math.max(0.1, Math.min(1, a))})`;
|
||||
sCtx.fill();
|
||||
});
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
// Nodes
|
||||
const starZone = document.getElementById('star-zone');
|
||||
STARS.forEach(s => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'star-node';
|
||||
btn.dataset.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>`;
|
||||
starZone.appendChild(btn);
|
||||
});
|
||||
|
||||
// Skyline
|
||||
function initSkyline() {
|
||||
const skyline = document.getElementById('skyline');
|
||||
const bbColors = ['bb-teal', 'bb-amber', 'bb-orchid', 'bb-pink', 'bb-gold'];
|
||||
const winColors = ['#e8943a', '#2ac4b3', '#c558d9', '#f472b6', '#00ff41'];
|
||||
|
||||
for (let i = 0; i < 42; i++) {
|
||||
const b = document.createElement('div');
|
||||
b.className = 'building';
|
||||
const bio = Math.random();
|
||||
if (bio > 0.9) b.classList.add('bio-orchid');
|
||||
else if (bio > 0.8) b.classList.add('bio-mint');
|
||||
|
||||
const w = 20 + Math.random() * 50;
|
||||
const h = 50 + Math.random() * 300;
|
||||
b.style.width = w + 'px';
|
||||
b.style.height = h + 'px';
|
||||
b.style.marginRight = '2px';
|
||||
|
||||
if (h > 100) {
|
||||
for (let j = 0; j < Math.floor(h/30); j++) {
|
||||
if (Math.random() > 0.6) continue;
|
||||
const win = document.createElement('div');
|
||||
const wc = winColors[Math.floor(Math.random()*winColors.length)];
|
||||
win.style.cssText = `position:absolute; width:2px; height:2px; background:${wc}; opacity:${0.1 + Math.random()*0.2}; left:${Math.random()*w}px; top:${20+j*25}px;`;
|
||||
b.appendChild(win);
|
||||
}
|
||||
}
|
||||
|
||||
if (Math.random() > 0.85) {
|
||||
const bb = document.createElement('a');
|
||||
bb.className = 'billboard-nav ' + bbColors[Math.floor(Math.random()*bbColors.length)];
|
||||
bb.textContent = 'SIGNAL';
|
||||
bb.href = '#';
|
||||
b.appendChild(bb);
|
||||
}
|
||||
skyline.appendChild(b);
|
||||
}
|
||||
}
|
||||
|
||||
// Lightbox
|
||||
const overlay = document.getElementById('lightbox-overlay');
|
||||
if (!localStorage.getItem('sp-welcomed')) overlay.classList.remove('hidden');
|
||||
document.getElementById('lightbox-enter').onclick = () => {
|
||||
overlay.classList.add('hidden');
|
||||
localStorage.setItem('sp-welcomed', 'true');
|
||||
};
|
||||
|
||||
window.onresize = resize;
|
||||
resize();
|
||||
initSkyline();
|
||||
requestAnimationFrame(draw);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,551 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Draft: Starfield & Nebula v1 - Gemini</title>
|
||||
<!--
|
||||
DRAFT: Starfield & Nebula v1
|
||||
AUTHOR: Gemini (Designer Agent)
|
||||
DATE: 2026-03-26
|
||||
|
||||
DESCRIPTION:
|
||||
This draft focuses on the celestial atmosphere.
|
||||
|
||||
NEW IN THIS VERSION:
|
||||
- Multi-colored stars (Amber, Teal, Blue, Magenta) with varied sizes.
|
||||
- Procedural "Nebula Washes" using large, low-opacity radial gradients on the canvas.
|
||||
- Differentiated Star Nodes: Each node has a unique glow color and subtle breathing animation.
|
||||
- Pulsing Constellation Lines: SVG lines now have a faint, organic pulse.
|
||||
- Enhanced Skyline: Added bioluminescent "moss" highlights and warmer window accents.
|
||||
- Campfire-style Lightbox: Warm amber tones and a focused layout.
|
||||
- Strictly follows Uncodixfy: No large radii, no big blurs, no glassmorphism.
|
||||
-->
|
||||
<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 {
|
||||
/* Deep Space Palette */
|
||||
--bg-void: #04060b;
|
||||
--bg-deep: #060a14;
|
||||
--bg-warm: #0d1320;
|
||||
|
||||
/* Celestial & Fire Palette */
|
||||
--fire-amber: #e8943a;
|
||||
--fire-coral: #d4654a;
|
||||
--neon-green: #32dc8c;
|
||||
--neon-teal: #2ac4b3;
|
||||
--deep-red: #8b2020;
|
||||
--cosmic-purple:#4a1d6e;
|
||||
--star-blue: #a0c4ff;
|
||||
|
||||
/* Text */
|
||||
--text-warm: #e8d5b8;
|
||||
--text-muted: #6a7a8a;
|
||||
|
||||
/* Constraints */
|
||||
--radius-std: 4px;
|
||||
--radius-max: 10px;
|
||||
--blur-max: 8px;
|
||||
}
|
||||
|
||||
*, *::before, *::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Space Grotesk', system-ui, -apple-system, sans-serif;
|
||||
background: var(--bg-void);
|
||||
color: var(--text-warm);
|
||||
overflow: hidden;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
body.content-mode {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* ── Zone 1: Star Map ── */
|
||||
|
||||
#star-zone {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
background: radial-gradient(circle at 50% 50%, #080c18 0%, #04060b 100%);
|
||||
}
|
||||
|
||||
#star-canvas {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
#constellation-svg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.constellation-line {
|
||||
stroke-width: 1;
|
||||
stroke-linecap: round;
|
||||
transition: stroke-opacity 1s ease;
|
||||
}
|
||||
|
||||
/* ── Star Nodes ── */
|
||||
|
||||
.star-node {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transform: translate(-50%, -50%);
|
||||
outline: none;
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.star-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
box-shadow: 0 0 4px #fff;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
|
||||
}
|
||||
|
||||
.star-label {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: var(--text-muted);
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: lowercase;
|
||||
white-space: nowrap;
|
||||
opacity: 0.6;
|
||||
transition: opacity 0.2s ease, color 0.2s ease;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Node Specificity */
|
||||
.star-node[data-star="writings"] .star-dot { box-shadow: 0 0 6px var(--star-blue); background: var(--star-blue); }
|
||||
.star-node[data-star="videos"] .star-dot { box-shadow: 0 0 6px var(--fire-coral); background: var(--fire-coral); }
|
||||
.star-node[data-star="music"] .star-dot { box-shadow: 0 0 6px var(--neon-teal); background: var(--neon-teal); }
|
||||
.star-node[data-star="images"] .star-dot { box-shadow: 0 0 6px var(--neon-green); background: var(--neon-green); }
|
||||
.star-node[data-star="playlists"] .star-dot { box-shadow: 0 0 6px var(--fire-amber); background: var(--fire-amber); }
|
||||
.star-node[data-star="watchlists"] .star-dot { box-shadow: 0 0 6px var(--cosmic-purple); background: var(--cosmic-purple); }
|
||||
.star-node[data-star="toolsntoys"] .star-dot { box-shadow: 0 0 6px #fff; background: #fff; }
|
||||
.star-node[data-star="creatorlists"] .star-dot { box-shadow: 0 0 6px var(--text-warm); background: var(--text-warm); }
|
||||
|
||||
.star-node:hover .star-dot,
|
||||
.star-node:focus .star-dot,
|
||||
.star-node.current .star-dot {
|
||||
background: var(--fire-amber) !important;
|
||||
box-shadow: 0 0 8px var(--fire-amber) !important;
|
||||
}
|
||||
|
||||
.star-node:hover .star-label,
|
||||
.star-node:focus .star-label,
|
||||
.star-node.current .star-label {
|
||||
color: var(--text-warm);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.star-node.visited::after {
|
||||
content: '✓';
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
right: -12px;
|
||||
font-size: 10px;
|
||||
color: var(--neon-green);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* ── Transition Zone: Skyline ── */
|
||||
|
||||
#transition-zone {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background: linear-gradient(to bottom, var(--bg-void) 0%, #080c14 40%, #0d1320 100%);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#skyline {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 70%;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.building {
|
||||
background: #05080f;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
border-top: 1px solid rgba(232, 148, 58, 0.05);
|
||||
}
|
||||
|
||||
/* Bioluminescent Highlights */
|
||||
.building.bio-active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 10%;
|
||||
left: 0;
|
||||
width: 2px;
|
||||
height: 30%;
|
||||
background: var(--neon-teal);
|
||||
box-shadow: 0 0 6px var(--neon-teal);
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.billboard-nav {
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -100%);
|
||||
padding: 4px 10px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
color: var(--text-warm);
|
||||
border: 1px solid var(--text-muted);
|
||||
background: var(--bg-void);
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
transition: border-color 0.2s ease, color 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.billboard-nav:hover,
|
||||
.billboard-nav:focus {
|
||||
color: var(--fire-amber);
|
||||
border-color: var(--fire-amber);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* ── Zone 3: Content Alley ── */
|
||||
|
||||
#content-zone {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
background: var(--bg-warm);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#content-frame {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
border: none;
|
||||
display: block;
|
||||
background: var(--bg-warm);
|
||||
}
|
||||
|
||||
/* ── Persistent UI ── */
|
||||
|
||||
#back-btn {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 100;
|
||||
padding: 8px 16px;
|
||||
font-family: inherit;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: var(--text-muted);
|
||||
background: rgba(4, 6, 11, 0.8);
|
||||
border: 1px solid rgba(106, 122, 138, 0.3);
|
||||
border-radius: var(--radius-std);
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
transition: color 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
|
||||
#back-btn:hover {
|
||||
color: var(--fire-amber);
|
||||
border-color: var(--fire-amber);
|
||||
}
|
||||
|
||||
#jl-link {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 100;
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
text-decoration: none;
|
||||
opacity: 0.6;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
#jl-link:hover {
|
||||
opacity: 1;
|
||||
color: var(--fire-amber);
|
||||
}
|
||||
|
||||
/* ── Lightbox: Campfire Style ── */
|
||||
|
||||
#lightbox-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
z-index: 200;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#lightbox-overlay.hidden { display: none; }
|
||||
|
||||
#lightbox {
|
||||
background: var(--bg-warm);
|
||||
border: 1px solid var(--fire-amber);
|
||||
border-radius: var(--radius-std);
|
||||
padding: 40px;
|
||||
max-width: 500px;
|
||||
width: 90%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#lightbox::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 4px;
|
||||
border: 1px solid rgba(232, 148, 58, 0.1);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#lightbox p {
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
color: var(--text-warm);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.nav-hint {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 32px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#lightbox-enter {
|
||||
padding: 10px 32px;
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--bg-void);
|
||||
background: var(--fire-amber);
|
||||
border: none;
|
||||
border-radius: var(--radius-std);
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
#lightbox-enter:hover { opacity: 0.9; }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="star-zone">
|
||||
<canvas id="star-canvas"></canvas>
|
||||
<svg id="constellation-svg" xmlns="http://www.w3.org/2000/svg"></svg>
|
||||
</div>
|
||||
|
||||
<div id="transition-zone">
|
||||
<div id="skyline"></div>
|
||||
</div>
|
||||
|
||||
<div id="content-zone">
|
||||
<iframe id="content-frame" title="Section content"></iframe>
|
||||
</div>
|
||||
|
||||
<button id="back-btn">stars</button>
|
||||
<a id="jl-link" href="https://jl-kruger.github.io/introductions" target="_blank" rel="noopener">JL Kruger</a>
|
||||
|
||||
<div id="lightbox-overlay" class="hidden">
|
||||
<div id="lightbox">
|
||||
<p>Hello traveller, welcome to a singular, particular space. Feel free to explore this little pocket of the universe. It's an adventure, bring snacks. Happy wanderings, Myster Wizzard</p>
|
||||
<span class="nav-hint">click stars · arrow keys · escape to return</span>
|
||||
<button id="lightbox-enter">Enter</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const STARS = [
|
||||
{ id: 'writings', label: 'Writings', x: 25, y: 22, color: '#a0c4ff' },
|
||||
{ id: 'videos', label: 'Videos', x: 65, y: 18, color: '#d4654a' },
|
||||
{ id: 'music', label: 'Music', x: 15, y: 45, color: '#2ac4b3' },
|
||||
{ id: 'images', label: 'Images', x: 50, y: 35, color: '#32dc8c' },
|
||||
{ id: 'playlists', label: 'Playlists', x: 80, y: 50, color: '#e8943a' },
|
||||
{ id: 'watchlists', label: 'Watchlists', x: 20, y: 70, color: '#4a1d6e' },
|
||||
{ id: 'toolsntoys', label: 'ToolsnToys', x: 55, y: 75, color: '#ffffff' },
|
||||
{ id: 'creatorlists', label: 'Creatorlists', x: 82, y: 72, color: '#e8d5b8' }
|
||||
];
|
||||
|
||||
const CONNECTIONS = [
|
||||
['writings', 'videos'], ['music', 'images'], ['images', 'videos'],
|
||||
['watchlists', 'toolsntoys'], ['toolsntoys', 'creatorlists'], ['music', 'watchlists']
|
||||
];
|
||||
|
||||
const canvas = document.getElementById('star-canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
let bgStars = [];
|
||||
let nebulae = [];
|
||||
|
||||
function resize() {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
initAtmosphere();
|
||||
}
|
||||
|
||||
function initAtmosphere() {
|
||||
bgStars = [];
|
||||
const colors = ['#ffffff', '#a0c4ff', '#ffd7ba', '#e8943a', '#2ac4b3'];
|
||||
for(let i=0; i<350; i++) {
|
||||
bgStars.push({
|
||||
x: Math.random() * canvas.width,
|
||||
y: Math.random() * canvas.height,
|
||||
r: Math.random() * 1.5 + 0.2,
|
||||
color: colors[Math.floor(Math.random()*colors.length)],
|
||||
opacity: Math.random() * 0.7 + 0.3,
|
||||
blink: Math.random() * 0.02 + 0.005,
|
||||
phase: Math.random() * Math.PI * 2
|
||||
});
|
||||
}
|
||||
|
||||
nebulae = [
|
||||
{ x: 0.2, y: 0.3, r: 0.4, color: 'rgba(74, 29, 110, 0.08)' },
|
||||
{ x: 0.8, y: 0.2, r: 0.5, color: 'rgba(42, 196, 179, 0.05)' },
|
||||
{ x: 0.5, y: 0.7, r: 0.6, color: 'rgba(232, 148, 58, 0.04)' }
|
||||
];
|
||||
}
|
||||
|
||||
function draw(time) {
|
||||
ctx.fillStyle = '#04060b';
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Draw Nebulae
|
||||
nebulae.forEach(n => {
|
||||
const grad = ctx.createRadialGradient(
|
||||
n.x * canvas.width, n.y * canvas.height, 0,
|
||||
n.x * canvas.width, n.y * canvas.height, n.r * canvas.width
|
||||
);
|
||||
grad.addColorStop(0, n.color);
|
||||
grad.addColorStop(1, 'transparent');
|
||||
ctx.fillStyle = grad;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
});
|
||||
|
||||
// Draw Stars
|
||||
const t = time * 0.001;
|
||||
bgStars.forEach(s => {
|
||||
const o = s.opacity + Math.sin(t / s.blink + s.phase) * 0.2;
|
||||
ctx.beginPath();
|
||||
ctx.arc(s.x, s.y, s.r, 0, Math.PI*2);
|
||||
ctx.fillStyle = s.color;
|
||||
ctx.globalAlpha = Math.max(0.1, Math.min(1, o));
|
||||
ctx.fill();
|
||||
});
|
||||
ctx.globalAlpha = 1;
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
// Star Nodes
|
||||
const starZone = document.getElementById('star-zone');
|
||||
STARS.forEach((s, i) => {
|
||||
const node = document.createElement('button');
|
||||
node.className = 'star-node';
|
||||
node.dataset.star = s.id;
|
||||
node.style.left = s.x + '%';
|
||||
node.style.top = s.y + '%';
|
||||
node.innerHTML = `<span class="star-dot"></span><span class="star-label">${s.label}</span>`;
|
||||
starZone.appendChild(node);
|
||||
});
|
||||
|
||||
// Constellations
|
||||
const svg = document.getElementById('constellation-svg');
|
||||
function drawLines() {
|
||||
svg.innerHTML = '';
|
||||
CONNECTIONS.forEach(pair => {
|
||||
const s1 = STARS.find(s => s.id === pair[0]);
|
||||
const s2 = STARS.find(s => s.id === pair[1]);
|
||||
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
||||
line.setAttribute('x1', s1.x + '%');
|
||||
line.setAttribute('y1', s1.y + '%');
|
||||
line.setAttribute('x2', s2.x + '%');
|
||||
line.setAttribute('y2', s2.y + '%');
|
||||
line.setAttribute('class', 'constellation-line');
|
||||
line.setAttribute('stroke', s1.color);
|
||||
line.setAttribute('stroke-opacity', '0.15');
|
||||
svg.appendChild(line);
|
||||
});
|
||||
}
|
||||
|
||||
// Skyline
|
||||
function initSkyline() {
|
||||
const skyline = document.getElementById('skyline');
|
||||
for(let i=0; i<40; i++) {
|
||||
const b = document.createElement('div');
|
||||
b.className = 'building' + (Math.random() > 0.7 ? ' bio-active' : '');
|
||||
const w = 20 + Math.random() * 60;
|
||||
const h = 40 + Math.random() * 300;
|
||||
b.style.width = w + 'px';
|
||||
b.style.height = h + 'px';
|
||||
b.style.marginRight = '2px';
|
||||
|
||||
// Random Windows
|
||||
if(h > 100) {
|
||||
for(let j=0; j<Math.floor(h/40); j++) {
|
||||
const win = document.createElement('div');
|
||||
win.style.cssText = `position:absolute; width:2px; height:2px; background:var(--fire-amber); opacity:${Math.random()*0.2}; left:${Math.random()*w}px; top:${30+j*30}px;`;
|
||||
b.appendChild(win);
|
||||
}
|
||||
}
|
||||
skyline.appendChild(b);
|
||||
}
|
||||
}
|
||||
|
||||
// Interaction
|
||||
const enterBtn = document.getElementById('lightbox-enter');
|
||||
const overlay = document.getElementById('lightbox-overlay');
|
||||
enterBtn.onclick = () => overlay.classList.add('hidden');
|
||||
|
||||
window.onresize = resize;
|
||||
resize();
|
||||
drawLines();
|
||||
initSkyline();
|
||||
requestAnimationFrame(draw);
|
||||
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1228
CREATURE-PLAYGROUND/homepage-redesign/integration-v14.html
Normal file
1228
CREATURE-PLAYGROUND/homepage-redesign/integration-v14.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,992 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!--
|
||||
Sonnet Integration Draft v3 — BOLD — 2026-03-26
|
||||
|
||||
Responds to JL's "bolder" feedback: vaporwave + mad max + rainforest + fairies.
|
||||
|
||||
KEY CHANGES FROM v2:
|
||||
- CRT GHOST: subtle static scanlines (0.04 opacity) + phosphor vignette
|
||||
- EXPANDED STAR COLORS: orchid, fairy-pink, toucan-gold, mint-green, coral
|
||||
- BOLDER NEBULAE: 5 washes at higher opacity (0.05-0.08), more color variety
|
||||
- STAR BLOOM: hover/focus grows from 6px to 18px with amber glow (CSS only)
|
||||
- BIGGER TEXT: labels 13px, billboards 12px, lightbox 16px
|
||||
- LUSH SKYLINE: more bio accents, polychromatic windows and billboards
|
||||
- LIGHTBOX: orchid inner border, phosphor-green top line
|
||||
- Nav mechanics UNTOUCHED from v2
|
||||
|
||||
References studied:
|
||||
- soviet-cyberpunk: CRT scanlines, phosphor glow, brutalist neon
|
||||
- solarpunk-sundae: pastel warmth deepened for dark palette
|
||||
- faerie-fire: prismatic violet/pink/cyan/green/gold
|
||||
- solarpunk-rainforest: orchid, paradise orange, toucan yellow, mint
|
||||
- nothing-new-about-normal: JL's own CRT aesthetic (#00ff41 phosphor, Soviet grid)
|
||||
-->
|
||||
<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: #060a14;
|
||||
--bg-warm: #0d1320;
|
||||
--fire-amber: #e8943a;
|
||||
--fire-coral: #d4654a;
|
||||
--neon-green: #32dc8c;
|
||||
--neon-teal: #2ac4b3;
|
||||
--deep-red: #8b2020;
|
||||
--blue-magenta: #6b3fa0;
|
||||
--cosmic-purple: #4a1d6e;
|
||||
--star-blue: #a0c4ff;
|
||||
--text-warm: #e8d5b8;
|
||||
--text-muted: #6a7a8a;
|
||||
/* new bold palette */
|
||||
--orchid: #c558d9;
|
||||
--paradise: #ff7f3f;
|
||||
--toucan: #ffcf40;
|
||||
--mint-glow: #86efac;
|
||||
--fairy-pink: #f472b6;
|
||||
--waterfall: #3fbfaf;
|
||||
--phosphor: #00ff41;
|
||||
--warm-gold: #c4a24a;
|
||||
}
|
||||
|
||||
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
html { scroll-behavior: auto; }
|
||||
|
||||
body {
|
||||
font-family: 'Space Grotesk', system-ui, -apple-system, sans-serif;
|
||||
background: var(--bg-void);
|
||||
color: var(--text-warm);
|
||||
overflow: hidden;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
body.content-mode { overflow-y: auto; }
|
||||
|
||||
/* ── CRT Ghost ── */
|
||||
/* Static scanlines — NOT animated, just texture */
|
||||
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: 9998;
|
||||
}
|
||||
|
||||
/* ── Zone 1: Star Map ── */
|
||||
|
||||
#star-zone {
|
||||
position: relative;
|
||||
width: 100%; height: 100vh;
|
||||
overflow: hidden;
|
||||
will-change: transform;
|
||||
background: radial-gradient(ellipse at 50% 50%, #080c18 0%, var(--bg-void) 100%);
|
||||
}
|
||||
|
||||
/* Phosphor vignette — faint edge darkening */
|
||||
#star-zone::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: radial-gradient(ellipse at 50% 50%, transparent 55%, rgba(0,0,0,0.3) 100%);
|
||||
pointer-events: none;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
#nebula-canvas {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
#star-canvas {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#constellation-svg {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.constellation-line {
|
||||
stroke-width: 1;
|
||||
stroke-linecap: round;
|
||||
animation: line-pulse 6s ease-in-out infinite;
|
||||
}
|
||||
.constellation-line:nth-child(2) { animation-delay: -1s; }
|
||||
.constellation-line:nth-child(3) { animation-delay: -2.2s; }
|
||||
.constellation-line:nth-child(4) { animation-delay: -3.5s; }
|
||||
.constellation-line:nth-child(5) { animation-delay: -0.8s; }
|
||||
.constellation-line:nth-child(6) { animation-delay: -4.1s; }
|
||||
|
||||
@keyframes line-pulse {
|
||||
0%, 100% { stroke-opacity: 0.06; }
|
||||
50% { stroke-opacity: 0.22; }
|
||||
}
|
||||
|
||||
/* ── Star Nodes ── */
|
||||
|
||||
.star-node {
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transform: translate(-50%, -50%);
|
||||
outline: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.star-dot {
|
||||
width: 7px; height: 7px;
|
||||
border-radius: 50%;
|
||||
transition: width 150ms ease, height 150ms ease, background 150ms ease, box-shadow 150ms ease;
|
||||
}
|
||||
|
||||
.star-label {
|
||||
font-size: clamp(12px, 1.4vw, 13px);
|
||||
font-weight: 400;
|
||||
color: var(--text-muted);
|
||||
letter-spacing: 0.02em;
|
||||
white-space: nowrap;
|
||||
opacity: 0;
|
||||
transition: opacity 200ms ease, color 150ms ease;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.star-node:hover .star-label,
|
||||
.star-node:focus .star-label,
|
||||
.star-node.current .star-label { opacity: 1; }
|
||||
|
||||
/* Per-star accent colors */
|
||||
.star-node[data-star="writings"] .star-dot { background: var(--star-blue); box-shadow: 0 0 4px var(--star-blue); }
|
||||
.star-node[data-star="videos"] .star-dot { background: var(--fire-coral); box-shadow: 0 0 4px var(--fire-coral); }
|
||||
.star-node[data-star="music"] .star-dot { background: var(--neon-teal); box-shadow: 0 0 4px var(--neon-teal); }
|
||||
.star-node[data-star="images"] .star-dot { background: var(--mint-glow); box-shadow: 0 0 5px var(--mint-glow); }
|
||||
.star-node[data-star="playlists"] .star-dot { background: var(--toucan); box-shadow: 0 0 4px var(--toucan); }
|
||||
.star-node[data-star="watchlists"] .star-dot { background: var(--orchid); box-shadow: 0 0 4px var(--orchid); }
|
||||
.star-node[data-star="toolsntoys"] .star-dot { background: var(--fairy-pink); box-shadow: 0 0 4px var(--fairy-pink); }
|
||||
.star-node[data-star="creatorlists"] .star-dot{ background: var(--warm-gold); box-shadow: 0 0 4px var(--warm-gold); }
|
||||
|
||||
/* BLOOM: hover/focus/current — star grows to 18px */
|
||||
.star-node:hover .star-dot,
|
||||
.star-node:focus .star-dot,
|
||||
.star-node.current .star-dot {
|
||||
width: 18px; height: 18px;
|
||||
background: var(--fire-amber);
|
||||
box-shadow: 0 0 8px rgba(255, 160, 50, 0.95);
|
||||
}
|
||||
|
||||
.star-node:hover .star-label,
|
||||
.star-node:focus .star-label,
|
||||
.star-node.current .star-label { color: var(--text-warm); }
|
||||
|
||||
/* Visited: neon green */
|
||||
.star-node.visited .star-dot {
|
||||
background: var(--neon-green);
|
||||
box-shadow: 0 0 4px rgba(50, 220, 140, 0.8);
|
||||
}
|
||||
.star-node.visited .star-label { color: var(--neon-green); }
|
||||
|
||||
/* Visited + hover: bloom overrides */
|
||||
.star-node.visited:hover .star-dot,
|
||||
.star-node.visited:focus .star-dot,
|
||||
.star-node.visited.current .star-dot {
|
||||
width: 18px; height: 18px;
|
||||
background: var(--fire-amber);
|
||||
box-shadow: 0 0 8px rgba(255, 160, 50, 0.95);
|
||||
}
|
||||
.star-node.visited:hover .star-label,
|
||||
.star-node.visited:focus .star-label,
|
||||
.star-node.visited.current .star-label { color: var(--text-warm); opacity: 1; }
|
||||
|
||||
/* ── Transition Zone: Skyline ── */
|
||||
|
||||
#transition-zone {
|
||||
position: relative;
|
||||
width: 100%; height: 70vh;
|
||||
/* Deep space → purple atmosphere → warm city */
|
||||
background: linear-gradient(to bottom,
|
||||
var(--bg-void) 0%,
|
||||
#0a0818 25%,
|
||||
#0e0c1a 45%,
|
||||
var(--bg-warm) 100%);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#skyline {
|
||||
position: absolute;
|
||||
bottom: 0; left: 0;
|
||||
width: 100%; height: 70%;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#skyline::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0; left: 0;
|
||||
width: 100%; height: 60px;
|
||||
background: linear-gradient(to top, rgba(232, 148, 58, 0.06), transparent);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.building {
|
||||
background: #05080f;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
border-top: 1px solid rgba(232, 148, 58, 0.04);
|
||||
}
|
||||
|
||||
.building.edge-lit::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0; right: 0;
|
||||
width: 1px; height: 100%;
|
||||
background: linear-gradient(to bottom, rgba(42, 196, 179, 0.14), rgba(42, 196, 179, 0.02));
|
||||
}
|
||||
|
||||
.building .bio-stripe {
|
||||
position: absolute;
|
||||
width: 2px;
|
||||
background: var(--mint-glow);
|
||||
opacity: 0.08;
|
||||
}
|
||||
|
||||
.building .bio-stripe.orchid {
|
||||
background: var(--orchid);
|
||||
opacity: 0.06;
|
||||
}
|
||||
|
||||
.billboard-nav {
|
||||
position: absolute;
|
||||
top: -2px; left: 50%;
|
||||
transform: translate(-50%, -100%);
|
||||
padding: 3px 10px;
|
||||
font-size: clamp(11px, 1.3vw, 12px);
|
||||
font-weight: 400;
|
||||
font-family: inherit;
|
||||
border: 1px solid;
|
||||
background: rgba(4, 6, 11, 0.9);
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
transition: color 150ms ease, border-color 150ms ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.billboard-nav.bb-teal { color: var(--neon-teal); border-color: rgba(42,196,179,0.25); }
|
||||
.billboard-nav.bb-amber { color: var(--fire-amber); border-color: rgba(232,148,58,0.25); }
|
||||
.billboard-nav.bb-green { color: var(--neon-green); border-color: rgba(50,220,140,0.25); }
|
||||
.billboard-nav.bb-orchid { color: var(--orchid); border-color: rgba(197,88,217,0.25); }
|
||||
.billboard-nav.bb-coral { color: var(--fire-coral); border-color: rgba(212,101,74,0.25); }
|
||||
.billboard-nav.bb-pink { color: var(--fairy-pink); border-color: rgba(244,114,182,0.25); }
|
||||
.billboard-nav.bb-gold { color: var(--toucan); border-color: rgba(255,207,64,0.25); }
|
||||
.billboard-nav.bb-water { color: var(--waterfall); border-color: rgba(63,191,175,0.25); }
|
||||
|
||||
.billboard-nav:hover,
|
||||
.billboard-nav:focus {
|
||||
color: var(--fire-amber);
|
||||
border-color: rgba(232, 148, 58, 0.4);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* ── Zone 3: Content ── */
|
||||
|
||||
#content-zone {
|
||||
width: 100%; min-height: 100vh;
|
||||
background: var(--bg-warm);
|
||||
}
|
||||
|
||||
#content-frame {
|
||||
width: 100%; height: 100vh;
|
||||
border: none; display: block;
|
||||
background: var(--bg-warm);
|
||||
opacity: 0;
|
||||
transition: opacity 200ms ease;
|
||||
}
|
||||
#content-frame.loaded { opacity: 1; }
|
||||
|
||||
/* ── Persistent UI ── */
|
||||
|
||||
#back-btn {
|
||||
position: fixed;
|
||||
top: 16px; right: 16px; z-index: 100;
|
||||
padding: 6px 14px;
|
||||
font-family: 'Space Grotesk', system-ui, -apple-system, sans-serif;
|
||||
font-size: 13px; font-weight: 400;
|
||||
color: var(--text-muted);
|
||||
background: rgba(4, 6, 11, 0.85);
|
||||
border: 1px solid rgba(106, 122, 138, 0.2);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: color 150ms ease, border-color 150ms ease;
|
||||
}
|
||||
#back-btn:hover, #back-btn:focus {
|
||||
color: var(--fire-amber);
|
||||
border-color: rgba(232, 148, 58, 0.3);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#jl-link {
|
||||
position: fixed;
|
||||
bottom: 16px; right: 16px; z-index: 100;
|
||||
font-size: 12px; font-weight: 400;
|
||||
color: var(--text-muted);
|
||||
text-decoration: none;
|
||||
opacity: 0.6;
|
||||
transition: opacity 150ms ease, color 150ms ease;
|
||||
}
|
||||
#jl-link:hover, #jl-link:focus {
|
||||
opacity: 1; color: var(--fire-amber); outline: none;
|
||||
}
|
||||
|
||||
#sr-announce {
|
||||
position: absolute;
|
||||
width: 1px; height: 1px;
|
||||
padding: 0; margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0,0,0,0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* ── Lightbox: Campfire Note ── */
|
||||
|
||||
#lightbox-overlay {
|
||||
position: fixed; inset: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
z-index: 200;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
#lightbox-overlay.hidden { display: none; }
|
||||
|
||||
#lightbox {
|
||||
background: var(--bg-warm);
|
||||
border: 1px solid var(--fire-amber);
|
||||
border-radius: 4px;
|
||||
padding: 36px;
|
||||
max-width: 480px; width: 90%;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Phosphor-green top line — ghost of CRT */
|
||||
#lightbox::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0; left: 8px; right: 8px;
|
||||
height: 1px;
|
||||
background: linear-gradient(to right, transparent, rgba(0, 255, 65, 0.15), transparent);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Orchid inner border — fairy fire around the campfire note */
|
||||
#lightbox::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 4px;
|
||||
border: 1px solid rgba(197, 88, 217, 0.08);
|
||||
pointer-events: none;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#lightbox p {
|
||||
font-size: 16px; line-height: 1.65;
|
||||
color: var(--text-warm);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#lightbox .nav-hint {
|
||||
font-size: 13px; color: var(--text-muted);
|
||||
margin-bottom: 24px; line-height: 1.5;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#lightbox-enter {
|
||||
padding: 8px 28px;
|
||||
font-family: 'Space Grotesk', system-ui, -apple-system, sans-serif;
|
||||
font-size: 14px; font-weight: 500;
|
||||
color: var(--bg-void);
|
||||
background: var(--fire-amber);
|
||||
border: none; border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: opacity 150ms ease;
|
||||
}
|
||||
#lightbox-enter:hover, #lightbox-enter:focus { opacity: 0.85; outline: none; }
|
||||
|
||||
/* ── Reduced motion ── */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.constellation-line { animation: none; stroke-opacity: 0.12; }
|
||||
#star-zone { will-change: auto; }
|
||||
#content-frame { transition: none; }
|
||||
.star-dot { transition: none; }
|
||||
}
|
||||
|
||||
/* ── Responsive ── */
|
||||
@media (max-width: 768px) {
|
||||
.star-label { font-size: 12px; }
|
||||
#lightbox { padding: 24px; max-width: 380px; }
|
||||
.billboard-nav { font-size: 10px; padding: 3px 8px; }
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.star-dot { width: 12px; height: 12px; }
|
||||
.star-node:hover .star-dot,
|
||||
.star-node:focus .star-dot,
|
||||
.star-node.current .star-dot { width: 22px; height: 22px; }
|
||||
.star-node:active .star-label { opacity: 1; }
|
||||
#lightbox { padding: 20px 16px; }
|
||||
#lightbox p { font-size: 15px; }
|
||||
.billboard-nav { font-size: 11px; padding: 6px 12px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="star-zone" role="navigation" aria-label="Star map navigation">
|
||||
<canvas id="nebula-canvas"></canvas>
|
||||
<canvas id="star-canvas"></canvas>
|
||||
<svg id="constellation-svg" xmlns="http://www.w3.org/2000/svg"></svg>
|
||||
</div>
|
||||
|
||||
<div id="transition-zone">
|
||||
<div id="skyline"></div>
|
||||
</div>
|
||||
|
||||
<div id="content-zone" role="region" aria-label="Section content">
|
||||
<iframe id="content-frame" title="Section content"></iframe>
|
||||
</div>
|
||||
|
||||
<button id="back-btn" aria-label="Back to stars">stars</button>
|
||||
<a id="jl-link" href="https://jl-kruger.github.io/introductions" target="_blank" rel="noopener">JL Kruger</a>
|
||||
<div id="sr-announce" aria-live="polite" aria-atomic="true"></div>
|
||||
|
||||
<div id="lightbox-overlay" class="hidden" role="dialog" aria-modal="true" aria-label="Welcome">
|
||||
<div id="lightbox">
|
||||
<p>Hello traveller, welcome to a singular, particular space. Feel free to explore this little pocket of the universe. It's an adventure, bring snacks. Happy wanderings, Myster Wizzard</p>
|
||||
<span class="nav-hint">click stars to explore · arrow keys to navigate · escape to return</span>
|
||||
<button id="lightbox-enter">Enter</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
var STARS = [
|
||||
{ id: 'writings', label: 'Writings', x: 25, y: 18, href: '', accent: '#a0c4ff' },
|
||||
{ id: 'videos', label: 'Videos', x: 68, y: 15, href: '', accent: '#d4654a' },
|
||||
{ id: 'music', label: 'Music', x: 12, y: 42, href: '', accent: '#2ac4b3' },
|
||||
{ id: 'images', label: 'Images', x: 55, y: 35, href: '', accent: '#86efac' },
|
||||
{ id: 'playlists', label: 'Playlists', x: 78, y: 48, href: '', accent: '#ffcf40' },
|
||||
{ id: 'watchlists', label: 'Watchlists', x: 22, y: 65, href: '', accent: '#c558d9' },
|
||||
{ id: 'toolsntoys', label: 'ToolsnToys', x: 50, y: 72, href: '', accent: '#f472b6' },
|
||||
{ id: 'creatorlists', label: 'Creatorlists', x: 75, y: 70, href: '', accent: '#c4a24a' }
|
||||
];
|
||||
|
||||
var CONSTELLATION_LINES = [
|
||||
['writings', 'videos'],
|
||||
['music', 'playlists'],
|
||||
['images', 'videos'],
|
||||
['watchlists', 'toolsntoys'],
|
||||
['toolsntoys', 'creatorlists'],
|
||||
['music', 'watchlists']
|
||||
];
|
||||
|
||||
var currentStarIndex = 0;
|
||||
var inContentMode = false;
|
||||
var lightboxOpen = false;
|
||||
var visited = JSON.parse(localStorage.getItem('sp-visited') || '{}');
|
||||
var isScrolling = false;
|
||||
|
||||
// ── Expanded star color palette ──
|
||||
// 35% cool white, 15% warm white, 12% pale blue, 10% toucan gold,
|
||||
// 8% fairy pink, 8% orchid, 7% mint green, 5% coral
|
||||
var STAR_COLORS = [
|
||||
{ r: 200, g: 210, b: 230, weight: 35 },
|
||||
{ r: 240, g: 220, b: 190, weight: 15 },
|
||||
{ r: 140, g: 180, b: 230, weight: 12 },
|
||||
{ r: 255, g: 207, b: 64, weight: 10 },
|
||||
{ r: 244, g: 114, b: 182, weight: 8 },
|
||||
{ r: 197, g: 88, b: 217, weight: 8 },
|
||||
{ r: 134, g: 239, b: 172, weight: 7 },
|
||||
{ r: 212, g: 101, b: 74, weight: 5 }
|
||||
];
|
||||
|
||||
function pickStarColor() {
|
||||
var roll = Math.random() * 100, cum = 0;
|
||||
for (var i = 0; i < STAR_COLORS.length; i++) {
|
||||
cum += STAR_COLORS[i].weight;
|
||||
if (roll < cum) return STAR_COLORS[i];
|
||||
}
|
||||
return STAR_COLORS[0];
|
||||
}
|
||||
|
||||
function pickStarSize() {
|
||||
var roll = Math.random() * 100;
|
||||
if (roll < 42) return 0.3 + Math.random() * 0.2;
|
||||
if (roll < 70) return 0.5 + Math.random() * 0.5;
|
||||
if (roll < 90) return 1.0 + Math.random() * 0.5;
|
||||
return 1.5 + Math.random() * 1.5; // brights go up to 3px
|
||||
}
|
||||
|
||||
// ── Nebula (static, drawn once) ──
|
||||
var nebulaCanvas = document.getElementById('nebula-canvas');
|
||||
var nebulaCtx = nebulaCanvas.getContext('2d');
|
||||
|
||||
function drawNebulae() {
|
||||
nebulaCanvas.width = nebulaCanvas.offsetWidth;
|
||||
nebulaCanvas.height = nebulaCanvas.offsetHeight;
|
||||
nebulaCtx.clearRect(0, 0, nebulaCanvas.width, nebulaCanvas.height);
|
||||
var w = nebulaCanvas.width, h = nebulaCanvas.height;
|
||||
var isMobile = w < 480;
|
||||
|
||||
// Wash 1: cosmic purple, upper-right
|
||||
var g1 = nebulaCtx.createRadialGradient(w*0.75, h*0.2, 0, w*0.75, h*0.2, w*0.4);
|
||||
g1.addColorStop(0, 'rgba(74, 29, 110, 0.08)');
|
||||
g1.addColorStop(0.5, 'rgba(74, 29, 110, 0.03)');
|
||||
g1.addColorStop(1, 'rgba(74, 29, 110, 0)');
|
||||
nebulaCtx.fillStyle = g1;
|
||||
nebulaCtx.fillRect(0, 0, w, h);
|
||||
|
||||
// Wash 2: teal-waterfall, lower-left
|
||||
var g2 = nebulaCtx.createRadialGradient(w*0.15, h*0.7, 0, w*0.15, h*0.7, w*0.35);
|
||||
g2.addColorStop(0, 'rgba(63, 191, 175, 0.06)');
|
||||
g2.addColorStop(0.5, 'rgba(63, 191, 175, 0.02)');
|
||||
g2.addColorStop(1, 'rgba(63, 191, 175, 0)');
|
||||
nebulaCtx.fillStyle = g2;
|
||||
nebulaCtx.fillRect(0, 0, w, h);
|
||||
|
||||
// Wash 3: orchid, center-left
|
||||
var g3 = nebulaCtx.createRadialGradient(w*0.3, h*0.4, 0, w*0.3, h*0.4, w*0.3);
|
||||
g3.addColorStop(0, 'rgba(197, 88, 217, 0.05)');
|
||||
g3.addColorStop(0.6, 'rgba(197, 88, 217, 0.015)');
|
||||
g3.addColorStop(1, 'rgba(197, 88, 217, 0)');
|
||||
nebulaCtx.fillStyle = g3;
|
||||
nebulaCtx.fillRect(0, 0, w, h);
|
||||
|
||||
if (!isMobile) {
|
||||
// Wash 4: fairy-pink, upper-center
|
||||
var g4 = nebulaCtx.createRadialGradient(w*0.5, h*0.15, 0, w*0.5, h*0.15, w*0.25);
|
||||
g4.addColorStop(0, 'rgba(244, 114, 182, 0.04)');
|
||||
g4.addColorStop(0.6, 'rgba(244, 114, 182, 0.012)');
|
||||
g4.addColorStop(1, 'rgba(244, 114, 182, 0)');
|
||||
nebulaCtx.fillStyle = g4;
|
||||
nebulaCtx.fillRect(0, 0, w, h);
|
||||
|
||||
// Wash 5: warm amber, lower-center
|
||||
var g5 = nebulaCtx.createRadialGradient(w*0.55, h*0.75, 0, w*0.55, h*0.75, w*0.3);
|
||||
g5.addColorStop(0, 'rgba(232, 148, 58, 0.04)');
|
||||
g5.addColorStop(0.5, 'rgba(232, 148, 58, 0.015)');
|
||||
g5.addColorStop(1, 'rgba(232, 148, 58, 0)');
|
||||
nebulaCtx.fillStyle = g5;
|
||||
nebulaCtx.fillRect(0, 0, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Star field (animated) ──
|
||||
var starCanvas = document.getElementById('star-canvas');
|
||||
var starCtx = starCanvas.getContext('2d');
|
||||
var bgStars = [];
|
||||
var lastFrame = 0;
|
||||
var FRAME_INTERVAL = 50;
|
||||
|
||||
function generateBgStars() {
|
||||
var w = starCanvas.width, h = starCanvas.height;
|
||||
var isMobile = w < 480;
|
||||
var count = isMobile ? 200 : (300 + Math.floor(Math.random() * 80));
|
||||
bgStars = [];
|
||||
|
||||
for (var i = 0; i < count; i++) {
|
||||
var color = pickStarColor();
|
||||
var r = pickStarSize();
|
||||
var layer = r < 0.5 ? 0 : (r < 1.0 ? (Math.random() < 0.6 ? 0 : 1) :
|
||||
(r < 1.5 ? (Math.random() < 0.5 ? 1 : 2) : (Math.random() < 0.3 ? 1 : 2)));
|
||||
|
||||
var steady = Math.random() < 0.12;
|
||||
var speed = steady ? 0 :
|
||||
(r > 1.5 ? 0.15 + Math.random() * 0.25 :
|
||||
(r < 0.5 ? 0.6 + Math.random() * 0.6 :
|
||||
0.3 + Math.random() * 0.5));
|
||||
|
||||
bgStars.push({
|
||||
x: Math.random() * w,
|
||||
y: Math.random() * h,
|
||||
r: r,
|
||||
base: 0.25 + Math.random() * 0.55,
|
||||
phase: Math.random() * Math.PI * 2,
|
||||
speed: speed,
|
||||
color: color.r + ',' + color.g + ',' + color.b,
|
||||
layer: layer
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function resizeCanvases() {
|
||||
starCanvas.width = starCanvas.offsetWidth;
|
||||
starCanvas.height = starCanvas.offsetHeight;
|
||||
drawNebulae();
|
||||
generateBgStars();
|
||||
}
|
||||
|
||||
function drawStars(time) {
|
||||
if (time - lastFrame < FRAME_INTERVAL) {
|
||||
requestAnimationFrame(drawStars);
|
||||
return;
|
||||
}
|
||||
lastFrame = time;
|
||||
starCtx.clearRect(0, 0, starCanvas.width, starCanvas.height);
|
||||
var t = time * 0.001;
|
||||
|
||||
for (var i = 0; i < bgStars.length; i++) {
|
||||
var s = bgStars[i];
|
||||
var a = (s.speed === 0 || prefersReducedMotion)
|
||||
? s.base
|
||||
: s.base + Math.sin(t * s.speed + s.phase) * 0.3;
|
||||
if (a < 0.05) a = 0.05;
|
||||
if (a > 1) a = 1;
|
||||
starCtx.beginPath();
|
||||
starCtx.arc(s.x, s.y, s.r, 0, 6.2832);
|
||||
starCtx.fillStyle = 'rgba(' + s.color + ',' + a + ')';
|
||||
starCtx.fill();
|
||||
}
|
||||
requestAnimationFrame(drawStars);
|
||||
}
|
||||
|
||||
// ── Parallax ──
|
||||
var starZone = document.getElementById('star-zone');
|
||||
|
||||
function updateParallax() {
|
||||
if (prefersReducedMotion || !inContentMode) {
|
||||
starZone.style.transform = '';
|
||||
return;
|
||||
}
|
||||
var scrollY = window.scrollY || window.pageYOffset;
|
||||
var offset = Math.min(scrollY * 0.4, window.innerHeight * 0.5);
|
||||
starZone.style.transform = 'translateY(-' + offset + 'px)';
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', function() {
|
||||
if (inContentMode) requestAnimationFrame(updateParallax);
|
||||
}, { passive: true });
|
||||
|
||||
// ── Star DOM nodes ──
|
||||
var starElements = [];
|
||||
var srAnnounce = document.getElementById('sr-announce');
|
||||
|
||||
STARS.forEach(function(star, i) {
|
||||
var btn = document.createElement('button');
|
||||
btn.className = 'star-node';
|
||||
btn.setAttribute('aria-label', star.label + ' section');
|
||||
btn.setAttribute('data-star', star.id);
|
||||
btn.style.left = star.x + '%';
|
||||
btn.style.top = star.y + '%';
|
||||
|
||||
var dot = document.createElement('span');
|
||||
dot.className = 'star-dot';
|
||||
var label = document.createElement('span');
|
||||
label.className = 'star-label';
|
||||
label.textContent = star.label;
|
||||
|
||||
btn.appendChild(dot);
|
||||
btn.appendChild(label);
|
||||
starZone.appendChild(btn);
|
||||
starElements.push(btn);
|
||||
|
||||
if (visited[star.id]) btn.classList.add('visited');
|
||||
btn.addEventListener('click', function(e) { e.preventDefault(); selectStar(i); });
|
||||
});
|
||||
|
||||
starElements[0].classList.add('current');
|
||||
|
||||
// ── Constellation lines ──
|
||||
var svg = document.getElementById('constellation-svg');
|
||||
|
||||
function drawConstellationLines() {
|
||||
while (svg.firstChild) svg.removeChild(svg.firstChild);
|
||||
var starMap = {};
|
||||
STARS.forEach(function(s) { starMap[s.id] = s; });
|
||||
|
||||
CONSTELLATION_LINES.forEach(function(pair) {
|
||||
var a = starMap[pair[0]], b = starMap[pair[1]];
|
||||
var line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
||||
line.setAttribute('x1', a.x + '%');
|
||||
line.setAttribute('y1', a.y + '%');
|
||||
line.setAttribute('x2', b.x + '%');
|
||||
line.setAttribute('y2', b.y + '%');
|
||||
line.setAttribute('class', 'constellation-line');
|
||||
line.setAttribute('stroke', a.accent);
|
||||
line.setAttribute('stroke-opacity', '0.14');
|
||||
svg.appendChild(line);
|
||||
});
|
||||
}
|
||||
|
||||
drawConstellationLines();
|
||||
|
||||
// ── Skyline — LUSH ──
|
||||
function generateSkyline() {
|
||||
var skyline = document.getElementById('skyline');
|
||||
skyline.innerHTML = '';
|
||||
var totalBuildings = 38;
|
||||
var step = Math.floor(totalBuildings / STARS.length);
|
||||
// Each billboard a different color — polychromatic city
|
||||
var bbColors = ['bb-teal', 'bb-coral', 'bb-orchid', 'bb-green', 'bb-gold', 'bb-water', 'bb-pink', 'bb-amber'];
|
||||
var billboardAssign = {};
|
||||
STARS.forEach(function(s, i) {
|
||||
billboardAssign[2 + i * step] = { star: s, colorClass: bbColors[i] };
|
||||
});
|
||||
|
||||
for (var i = 0; i < totalBuildings; i++) {
|
||||
var div = document.createElement('div');
|
||||
div.className = 'building';
|
||||
var w = 12 + Math.random() * 48;
|
||||
var h = 20 + Math.random() * 260;
|
||||
div.style.width = w + 'px';
|
||||
div.style.height = h + 'px';
|
||||
div.style.marginLeft = (Math.random() * 2) + 'px';
|
||||
|
||||
// Edge-light on ~30%
|
||||
if (Math.random() < 0.3) div.classList.add('edge-lit');
|
||||
|
||||
// Bioluminescent stripes on ~35% — mint or orchid
|
||||
if (Math.random() < 0.35 && h > 60) {
|
||||
var stripe = document.createElement('span');
|
||||
stripe.className = 'bio-stripe' + (Math.random() < 0.6 ? '' : ' orchid');
|
||||
var sTop = 10 + Math.random() * 30;
|
||||
var sH = 12 + Math.random() * 25;
|
||||
stripe.style.cssText = 'top:' + sTop + '%;height:' + sH + '%;left:0;';
|
||||
div.appendChild(stripe);
|
||||
}
|
||||
|
||||
// Polychromatic windows
|
||||
if (Math.random() > 0.3 && h > 50) {
|
||||
var windowCount = Math.floor(h / 24);
|
||||
for (var j = 0; j < windowCount; j++) {
|
||||
if (Math.random() > 0.5) continue;
|
||||
var win = document.createElement('span');
|
||||
// 50% amber, 20% teal, 15% orchid, 10% pink, 5% phosphor
|
||||
var winRoll = Math.random() * 100;
|
||||
var winColor;
|
||||
if (winRoll < 50) winColor = '232,148,58';
|
||||
else if (winRoll < 70) winColor = '42,196,179';
|
||||
else if (winRoll < 85) winColor = '197,88,217';
|
||||
else if (winRoll < 95) winColor = '244,114,182';
|
||||
else winColor = '0,255,65';
|
||||
var winAlpha = 0.04 + Math.random() * 0.06;
|
||||
win.style.cssText = 'position:absolute;width:2px;height:2px;background:rgba(' + winColor + ',' + winAlpha + ');left:' +
|
||||
(3 + Math.random() * (w - 6)) + 'px;top:' + (6 + j * 22 + Math.random() * 10) + 'px;';
|
||||
div.appendChild(win);
|
||||
}
|
||||
}
|
||||
|
||||
if (billboardAssign[i]) {
|
||||
var info = billboardAssign[i];
|
||||
var bb = document.createElement('a');
|
||||
bb.className = 'billboard-nav ' + info.colorClass;
|
||||
bb.textContent = info.star.label;
|
||||
bb.setAttribute('tabindex', '0');
|
||||
bb.setAttribute('aria-label', info.star.label + ' section');
|
||||
bb.href = '#';
|
||||
bb.addEventListener('click', (function(s) {
|
||||
return function(e) { e.preventDefault(); selectStar(STARS.indexOf(s)); };
|
||||
})(info.star));
|
||||
div.appendChild(bb);
|
||||
}
|
||||
|
||||
skyline.appendChild(div);
|
||||
}
|
||||
}
|
||||
|
||||
generateSkyline();
|
||||
|
||||
// ── Smooth scroll ──
|
||||
function smoothScrollTo(targetY, duration, callback) {
|
||||
if (isScrolling) return;
|
||||
isScrolling = true;
|
||||
var startY = window.scrollY || window.pageYOffset;
|
||||
var distance = targetY - startY;
|
||||
var startTime = null;
|
||||
|
||||
function step(time) {
|
||||
if (!startTime) startTime = time;
|
||||
var progress = Math.min((time - startTime) / duration, 1);
|
||||
var ease = 1 - Math.pow(1 - progress, 3);
|
||||
window.scrollTo(0, startY + distance * ease);
|
||||
if (progress < 1) requestAnimationFrame(step);
|
||||
else { isScrolling = false; if (callback) callback(); }
|
||||
}
|
||||
requestAnimationFrame(step);
|
||||
}
|
||||
|
||||
// ── Star selection & descent ──
|
||||
var contentFrame = document.getElementById('content-frame');
|
||||
var backBtn = document.getElementById('back-btn');
|
||||
|
||||
function selectStar(index) {
|
||||
if (lightboxOpen || isScrolling) return;
|
||||
var star = STARS[index];
|
||||
visited[star.id] = true;
|
||||
localStorage.setItem('sp-visited', JSON.stringify(visited));
|
||||
starElements[index].classList.add('visited');
|
||||
starElements.forEach(function(el) { el.classList.remove('current'); });
|
||||
starElements[index].classList.add('current');
|
||||
currentStarIndex = index;
|
||||
srAnnounce.textContent = 'Opening ' + star.label;
|
||||
inContentMode = true;
|
||||
document.body.classList.add('content-mode');
|
||||
backBtn.textContent = 'back to stars';
|
||||
|
||||
contentFrame.classList.remove('loaded');
|
||||
if (star.href) {
|
||||
contentFrame.src = star.href;
|
||||
contentFrame.onload = function() { contentFrame.classList.add('loaded'); };
|
||||
} else {
|
||||
contentFrame.srcdoc = '<html><body style="background:#0d1320;color:#6a7a8a;font-family:\'Space Grotesk\',system-ui,sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0"><p style="font-size:14px">' + star.label + ' — coming soon</p></body></html>';
|
||||
contentFrame.onload = function() { contentFrame.classList.add('loaded'); };
|
||||
}
|
||||
|
||||
var contentTop = document.getElementById('content-zone').offsetTop;
|
||||
smoothScrollTo(contentTop, 800);
|
||||
}
|
||||
|
||||
function returnToStars() {
|
||||
if (isScrolling) return;
|
||||
inContentMode = false;
|
||||
backBtn.textContent = 'stars';
|
||||
srAnnounce.textContent = 'Returning to star map';
|
||||
smoothScrollTo(0, 500, function() {
|
||||
document.body.classList.remove('content-mode');
|
||||
starZone.style.transform = '';
|
||||
contentFrame.classList.remove('loaded');
|
||||
contentFrame.src = 'about:blank';
|
||||
contentFrame.removeAttribute('srcdoc');
|
||||
starElements[currentStarIndex].focus();
|
||||
});
|
||||
}
|
||||
|
||||
backBtn.addEventListener('click', function() {
|
||||
if (inContentMode) returnToStars();
|
||||
else smoothScrollTo(0, 300);
|
||||
});
|
||||
|
||||
// ── Keyboard nav ──
|
||||
function findNearestStar(fromIndex, direction) {
|
||||
var from = STARS[fromIndex];
|
||||
var bestIndex = -1, bestScore = Infinity;
|
||||
for (var i = 0; i < STARS.length; i++) {
|
||||
if (i === fromIndex) continue;
|
||||
var dx = STARS[i].x - from.x, dy = STARS[i].y - from.y;
|
||||
var valid = false;
|
||||
switch (direction) {
|
||||
case 'up': valid = dy < -3; break;
|
||||
case 'down': valid = dy > 3; break;
|
||||
case 'left': valid = dx < -3; break;
|
||||
case 'right': valid = dx > 3; break;
|
||||
}
|
||||
if (!valid) continue;
|
||||
var dist = Math.sqrt(dx*dx + dy*dy);
|
||||
var penalty = (direction === 'up' || direction === 'down') ? Math.abs(dx)*0.5 : Math.abs(dy)*0.5;
|
||||
var score = dist + penalty;
|
||||
if (score < bestScore) { bestScore = score; bestIndex = i; }
|
||||
}
|
||||
return bestIndex;
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (lightboxOpen) {
|
||||
if (e.key === 'Escape' || e.key === 'Enter') { closeLightbox(); e.preventDefault(); }
|
||||
return;
|
||||
}
|
||||
if (inContentMode) {
|
||||
if (e.key === 'Escape') { returnToStars(); e.preventDefault(); }
|
||||
return;
|
||||
}
|
||||
var dir = null;
|
||||
switch (e.key) {
|
||||
case 'ArrowUp': dir = 'up'; break;
|
||||
case 'ArrowDown': dir = 'down'; break;
|
||||
case 'ArrowLeft': dir = 'left'; break;
|
||||
case 'ArrowRight': dir = 'right'; break;
|
||||
case 'Enter': case ' ':
|
||||
selectStar(currentStarIndex); e.preventDefault(); return;
|
||||
}
|
||||
if (dir) {
|
||||
e.preventDefault();
|
||||
var next = findNearestStar(currentStarIndex, dir);
|
||||
if (next >= 0) {
|
||||
starElements[currentStarIndex].classList.remove('current');
|
||||
currentStarIndex = next;
|
||||
starElements[currentStarIndex].classList.add('current');
|
||||
starElements[currentStarIndex].focus();
|
||||
srAnnounce.textContent = STARS[currentStarIndex].label;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ── Lightbox ──
|
||||
var overlay = document.getElementById('lightbox-overlay');
|
||||
var enterBtn = document.getElementById('lightbox-enter');
|
||||
|
||||
function closeLightbox() {
|
||||
overlay.classList.add('hidden');
|
||||
lightboxOpen = false;
|
||||
localStorage.setItem('sp-welcomed', 'true');
|
||||
starElements[currentStarIndex].focus();
|
||||
}
|
||||
|
||||
function showLightbox() {
|
||||
overlay.classList.remove('hidden');
|
||||
lightboxOpen = true;
|
||||
enterBtn.focus();
|
||||
}
|
||||
|
||||
enterBtn.addEventListener('click', closeLightbox);
|
||||
overlay.addEventListener('click', function(e) { if (e.target === overlay) closeLightbox(); });
|
||||
overlay.addEventListener('keydown', function(e) { if (e.key === 'Tab') { e.preventDefault(); enterBtn.focus(); } });
|
||||
|
||||
// ── Resize ──
|
||||
var resizeTimer;
|
||||
window.addEventListener('resize', function() {
|
||||
clearTimeout(resizeTimer);
|
||||
resizeTimer = setTimeout(resizeCanvases, 150);
|
||||
});
|
||||
|
||||
// ── Init ──
|
||||
resizeCanvases();
|
||||
requestAnimationFrame(drawStars);
|
||||
|
||||
if (!localStorage.getItem('sp-welcomed')) showLightbox();
|
||||
else starElements[currentStarIndex].focus();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user