Skip to content

Commit 8bcbf38

Browse files
committed
feat(theme): add Mist — a hypnagogic fog design language
Fourth fezcodex theme built on the threshold between waking and sleep: fog paper, eucalyptus ink, drift-blue glows, Instrument Serif display, lowercase IBM Plex Mono whispers, fading horizon rules, veil-glass surfaces, and blur-dissolve motion. - mist brand library (Orb, Veil, Horizon, Strip, Chapter, Spec, Colophon) - full page suite in mist-views + MistBlogPage, chrome (sidebar/navbar/ footer), search, command palette, side panel, modals, contact, toasts - theme registration, dispatchers, design selection card, settings switchers in all four themes - Syntax companion gets a fog-wisp form (fixes stale framer scaleX carrying over from the default sprite) - Banner gets a mist veil variant; fezmist launch banner added and terracotta banner deactivated; timeline entry added - Toast reads theme reactively via LocalStorageManager write events (fixes wrong-theme toasts on first visit with ?fezTheme=...) - bump to v0.27.3, kernel codename Mistwright
1 parent 2adb4d9 commit 8bcbf38

66 files changed

Lines changed: 8452 additions & 23 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package-lock.json

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "fezcodex",
3-
"version": "0.26.2",
3+
"version": "0.27.3",
44
"private": true,
55
"homepage": "https://fezcode.com",
66
"dependencies": {

public/banner.piml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@
175175
(from) 2026-04-22T00:00:00Z
176176
(to) 2026-08-31T23:59:59Z
177177
(text) FEZTERRACOTTA IS ONLINE: A WEIGHTED CODEX OF BONE PAPER AND TERRA INK. ENABLE VIA SETTINGS OR COMMAND PALETTE.
178-
(isActive) true
178+
(isActive) false
179179
(link) https://fezcode.com/settings?fezTheme=terracotta&fezBlogMode=terracotta#fezcodex-theme
180180
(linkText) Enable Terracotta
181181

@@ -189,3 +189,13 @@
189189
(link) https://fezcode.com/urban-rogue/
190190
(linkText) Play Urban Rogue
191191

192+
> (banner)
193+
(id) fezmist-launch
194+
(type) info
195+
(from) 2026-06-09T00:00:00Z
196+
(to) 2026-09-30T23:59:59Z
197+
(text) FEZMIST IS ONLINE: A CODEX HALF-REMEMBERED — FOG PAPER, EUCALYPTUS INK, HORIZONS THAT FADE. ENABLE VIA SETTINGS OR COMMAND PALETTE.
198+
(isActive) true
199+
(link) https://fezcode.com/settings?fezTheme=mist#fezcodex-theme
200+
(linkText) Enable Mist
201+

public/site-config.piml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
(config)
22
(kernel)
3-
(codename) Bonewright
3+
(codename) Mistwright
4+
# (codename) StoneSet
5+
# (codename) Bonewright
46
# codename roadmap — bump on a major design / identity shift
57
# v0.24.x Stone_Set
68
# v0.25.x Loadbearing
79
# v0.26.x Chisel_Mark
10+
# v0.27.x Mistwright
811

912
(hero)
1013
(title) Fezcodex

public/timeline/timeline.piml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
(timeline)
2+
> (item)
3+
(date) 2026-06-10
4+
(title) Fezmist: The Hypnagogic Codex
5+
(description) Deployed 'Mist', a fourth design language built on hypnagogia — the threshold between waking and sleep. Fog paper, eucalyptus ink, drift-blue glows, Instrument Serif display and lowercase IBM Plex Mono whispers. Every page rebuilt as a drift: fading horizon rules, veil-glass surfaces, blur-dissolve motion, a breathing orb mark, and theme-aware Search, Command Palette, Side Panel, Toasts, Modals — plus a fog-wisp form for Syntax. Kernel codename bumped to Mistwright (v0.27.x).
6+
(type) feature
7+
(icon) CloudIcon
8+
(link) /settings#fezcodex-theme
9+
210
> (item)
311
(date) 2026-04-23
412
(title) Vite + Vike Migration: Replacing CRA and react-snap

src/components/Banner.jsx

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const Banner = () => {
1919
const { fezcodexTheme } = useVisualSettings() || {};
2020
const isLuxe = fezcodexTheme === 'luxe';
2121
const isTerracotta = fezcodexTheme === 'terracotta';
22+
const isMist = fezcodexTheme === 'mist';
2223

2324
useEffect(() => {
2425
const fetchBanner = async () => {
@@ -266,6 +267,81 @@ const Banner = () => {
266267
);
267268
}
268269

270+
/* ============================================================
271+
* MIST BANNER — a veil strip surfacing from the fog
272+
* ============================================================ */
273+
if (isMist) {
274+
const typePalette = (() => {
275+
switch (bannerType) {
276+
case 'error':
277+
return { accent: '#A87E7E', kicker: 'signal · lost' };
278+
case 'warning':
279+
return { accent: '#A89B7E', kicker: 'caveat · gentle' };
280+
case 'info':
281+
default:
282+
return { accent: '#5F837B', kicker: 'drift · notice' };
283+
}
284+
})();
285+
286+
return (
287+
<AnimatePresence>
288+
{isVisible && (
289+
<motion.div
290+
initial={{ height: 0, opacity: 0 }}
291+
animate={{ height: 'auto', opacity: 1 }}
292+
exit={{ height: 0, opacity: 0 }}
293+
className="relative z-[100] bg-[#EEF2F1]/90 backdrop-blur-md selection:bg-[#8FA8BC]/30"
294+
>
295+
{/* bottom edge — a horizon, never a hard rule */}
296+
<span
297+
aria-hidden="true"
298+
className="absolute bottom-0 left-0 right-0 h-px"
299+
style={{
300+
background: `linear-gradient(90deg, transparent, ${typePalette.accent}80, transparent)`,
301+
}}
302+
/>
303+
<div className="max-w-[1800px] mx-auto px-5 md:px-12 py-3 flex items-start md:items-center gap-4 md:gap-6">
304+
<div className="flex items-center gap-3 shrink-0 pt-0.5 md:pt-0">
305+
<span
306+
aria-hidden="true"
307+
className="inline-block w-[7px] h-[7px] rounded-full"
308+
style={{
309+
background: `radial-gradient(circle at 40% 35%, #FFFFFF 0%, ${typePalette.accent} 100%)`,
310+
boxShadow: `0 0 8px 2px ${typePalette.accent}55`,
311+
}}
312+
/>
313+
<span
314+
className="font-ibm-plex-mono text-[9.5px] tracking-[0.26em] lowercase hidden sm:inline"
315+
style={{ color: typePalette.accent }}
316+
>
317+
{typePalette.kicker}
318+
</span>
319+
</div>
320+
321+
<div className="flex-1 flex flex-col md:flex-row md:items-center gap-2 md:gap-4 min-w-0">
322+
<p className="font-instr-serif italic text-[14.5px] md:text-[16px] leading-snug lowercase text-[#3C4845] flex-1">
323+
{banner.text}
324+
</p>
325+
{renderLink(
326+
'self-start md:self-auto shrink-0 inline-flex items-center gap-1 font-ibm-plex-mono text-[9.5px] tracking-[0.2em] lowercase px-3 py-1.5 rounded-full bg-white/60 shadow-[0_1px_3px_rgba(60,72,69,0.12)] text-[#5C6B67] hover:bg-[#8FA8BC]/15 hover:text-[#5F837B] transition-colors',
327+
)}
328+
</div>
329+
330+
<button
331+
type="button"
332+
onClick={handleDismiss}
333+
className="p-1 text-[#8A9894] hover:text-[#5F837B] transition-colors shrink-0 mt-0.5 md:mt-0"
334+
aria-label="Dismiss"
335+
>
336+
<XIcon size={16} weight="light" />
337+
</button>
338+
</div>
339+
</motion.div>
340+
)}
341+
</AnimatePresence>
342+
);
343+
}
344+
269345
/* ============================================================
270346
* BRUTALIST BANNER — legacy mono slab
271347
* ============================================================ */

src/components/CodeModal.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import { useVisualSettings } from '../context/VisualSettingsContext';
33
import BrutalistCodeModal from './BrutalistCodeModal';
44
import LuxeCodeModal from './LuxeCodeModal';
55
import TerracottaCodeModal from './TerracottaCodeModal';
6+
import MistCodeModal from './MistCodeModal';
67

78
const CodeModal = (props) => {
89
const { fezcodexTheme } = useVisualSettings();
910

1011
if (fezcodexTheme === 'luxe') return <LuxeCodeModal {...props} />;
1112
if (fezcodexTheme === 'terracotta') return <TerracottaCodeModal {...props} />;
13+
if (fezcodexTheme === 'mist') return <MistCodeModal {...props} />;
1214
return <BrutalistCodeModal {...props} />;
1315
};
1416

src/components/CommandPalette.jsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ import { useVisualSettings } from '../context/VisualSettingsContext';
33
import BrutalistCommandPalette from './BrutalistCommandPalette';
44
import LuxeCommandPalette from './LuxeCommandPalette';
55
import TerracottaCommandPalette from './TerracottaCommandPalette';
6+
import MistCommandPalette from './MistCommandPalette';
67

78
const CommandPalette = (props) => {
89
const { fezcodexTheme } = useVisualSettings();
910

1011
if (fezcodexTheme === 'luxe') return <LuxeCommandPalette {...props} />;
11-
if (fezcodexTheme === 'terracotta') return <TerracottaCommandPalette {...props} />;
12+
if (fezcodexTheme === 'terracotta')
13+
return <TerracottaCommandPalette {...props} />;
14+
if (fezcodexTheme === 'mist') return <MistCommandPalette {...props} />;
1215
return <BrutalistCommandPalette {...props} />;
1316
};
1417

src/components/ContactModal.jsx

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ const ContactModal = ({ isOpen, onClose }) => {
2525
const { fezcodexTheme } = useVisualSettings();
2626
const isLuxe = fezcodexTheme === 'luxe';
2727
const isTerracotta = fezcodexTheme === 'terracotta';
28+
const isMist = fezcodexTheme === 'mist';
2829

2930
const title = (() => {
3031
if (isLuxe) return 'Establish Contact';
3132
if (isTerracotta) return 'Correspondence';
33+
if (isMist) return 'Through the Fog';
3234
return 'Contact';
3335
})();
3436

@@ -49,15 +51,36 @@ const ContactModal = ({ isOpen, onClose }) => {
4951
</p>
5052
</div>
5153
)}
52-
{!isLuxe && !isTerracotta && (
54+
{isMist && (
55+
<div className="mb-1 flex items-center gap-3">
56+
<span
57+
aria-hidden="true"
58+
className="h-px w-[36px]"
59+
style={{
60+
background:
61+
'linear-gradient(90deg, rgba(95,131,123,0.6), transparent)',
62+
}}
63+
/>
64+
<p className="font-ibm-plex-mono lowercase text-[10px] tracking-[0.26em] text-[#8A9894]">
65+
channels · reachable in the half-light
66+
</p>
67+
</div>
68+
)}
69+
{!isLuxe && !isTerracotta && !isMist && (
5370
<p className="text-gray-400 mb-2 font-mono uppercase tracking-widest text-[10px]">
5471
{'//'} Establish connection via established protocols:
5572
</p>
5673
)}
5774

5875
<div
5976
className={`grid grid-cols-1 ${
60-
isLuxe ? 'gap-4' : isTerracotta ? 'gap-0 border-t border-[#1A161320]' : 'gap-3'
77+
isLuxe
78+
? 'gap-4'
79+
: isTerracotta
80+
? 'gap-0 border-t border-[#1A161320]'
81+
: isMist
82+
? 'gap-0'
83+
: 'gap-3'
6184
}`}
6285
>
6386
{config?.socials &&
@@ -88,6 +111,17 @@ const ContactModal = ({ isOpen, onClose }) => {
88111
/>
89112
);
90113
}
114+
if (isMist) {
115+
return (
116+
<MistContactLink
117+
key={link.id}
118+
href={link.url}
119+
icon={Icon}
120+
label={link.label}
121+
value={cleaned}
122+
/>
123+
);
124+
}
91125
return (
92126
<BrutalistContactLink
93127
key={link.id}
@@ -132,6 +166,38 @@ const TerracottaContactLink = ({ href, icon: Icon, label, value }) => (
132166
</a>
133167
);
134168

169+
const MistContactLink = ({ href, icon: Icon, label, value }) => (
170+
<a
171+
href={href}
172+
target="_blank"
173+
rel="noopener noreferrer"
174+
className="group relative grid grid-cols-[52px_140px_1fr_auto] items-center gap-4 rounded-xl px-4 py-4 transition-colors hover:bg-[#E5EBE9]/70"
175+
>
176+
<span
177+
aria-hidden="true"
178+
className="absolute bottom-0 left-0 right-0 h-px"
179+
style={{
180+
background:
181+
'linear-gradient(90deg, transparent, rgba(60,72,69,0.14), transparent)',
182+
}}
183+
/>
184+
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-white/70 text-[#5C6B67] shadow-[0_6px_18px_rgba(60,72,69,0.10)] group-hover:text-[#5F837B] transition-colors">
185+
<Icon size={20} weight="light" />
186+
</div>
187+
<span className="font-ibm-plex-mono lowercase text-[10px] tracking-[0.26em] text-[#8A9894] group-hover:text-[#5F837B] transition-colors">
188+
{label}
189+
</span>
190+
<span className="font-instr-serif italic text-[17px] text-[#3C4845] truncate">
191+
{value}
192+
</span>
193+
<ArrowUpRightIcon
194+
size={14}
195+
weight="light"
196+
className="text-[#8A9894] group-hover:text-[#5F837B] transition-colors"
197+
/>
198+
</a>
199+
);
200+
135201
const LuxeContactLink = ({ href, icon: Icon, label, value }) => (
136202
<a
137203
href={href}

src/components/GenericModal.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import { useVisualSettings } from '../context/VisualSettingsContext';
33
import BrutalistModal from './BrutalistModal';
44
import LuxeModal from './LuxeModal';
55
import TerracottaModal from './TerracottaModal';
6+
import MistModal from './MistModal';
67

78
const GenericModal = (props) => {
89
const { fezcodexTheme } = useVisualSettings();
910

1011
if (fezcodexTheme === 'luxe') return <LuxeModal {...props} />;
1112
if (fezcodexTheme === 'terracotta') return <TerracottaModal {...props} />;
13+
if (fezcodexTheme === 'mist') return <MistModal {...props} />;
1214
return <BrutalistModal {...props} />;
1315
};
1416

0 commit comments

Comments
 (0)