Refine PS1/PS2/PS3/NDS themes and add decorative background field

Rework console theme stylesheets and add opt-in .rb-bg cube field
(used by PS2 BIOS bobbing-cube background) wired through Shell.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 03:53:20 +02:00
parent b465233f71
commit 307e0b48da
7 changed files with 739 additions and 278 deletions
+186 -61
View File
@@ -1,49 +1,110 @@
/* ============================================================
Theme: PlayStation 1 — scoped to [data-theme="ps1"]
The gray BIOS shell: cool charcoal gradient, soft gray
panels, blocky understated type. Memory-card-manager calm.
Not the calm BIOS shell — the GAME. Late-90s real-time 3D:
no perspective correction (affine texture swim), unfiltered
polygons with jagged seams, low color depth faked with
ordered dithering on every surface. Murky fog palette,
chunky pixelated edges, vertices that won't sit still.
============================================================ */
[data-theme="ps1"] {
--p1-bg1: #3a4351;
--p1-bg2: #1c222c;
--p1-panel: #c7ccd4;
--p1-panel-dk: #9aa1ad;
--p1-ink: #2a2f38;
--p1-accent: #6b7585;
/* Murky low-bit polygon palette — fogged blue-black void,
CD-startup diamond magenta/cyan, dirty parchment UI. */
--p1-void1: #1a2230;
--p1-void2: #07090f;
--p1-fog: #3b4a63;
--p1-panel: #b9b29c; /* dirty unfiltered "texture" beige */
--p1-panel-dk: #837c66;
--p1-ink: #20242c;
--p1-mag: #c0307a; /* startup diamond */
--p1-cyan: #2f9fb3;
--p1-seam: #efe9d6; /* bright untextured polygon edge */
font-family: "Verdana", Geneva, Tahoma, sans-serif;
font-size: 13px;
color: var(--p1-ink);
/* keep every pixel hard — no smoothing, like the real hardware */
image-rendering: pixelated;
}
/* Ordered 4x4 dither tiles, reused everywhere for the low-color look.
Two-tone Bayer-ish stipple — tiny so it reads as texture grain. */
[data-theme="ps1"] {
--p1-dither-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4'%3E%3Crect x='0' y='0' width='1' height='1' fill='%23000' fill-opacity='0.28'/%3E%3Crect x='2' y='2' width='1' height='1' fill='%23000' fill-opacity='0.28'/%3E%3Crect x='2' y='0' width='1' height='1' fill='%23fff' fill-opacity='0.10'/%3E%3Crect x='0' y='2' width='1' height='1' fill='%23fff' fill-opacity='0.10'/%3E%3C/svg%3E");
--p1-dither-fog: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4'%3E%3Crect x='1' y='0' width='1' height='1' fill='%2307090f' fill-opacity='0.45'/%3E%3Crect x='3' y='2' width='1' height='1' fill='%2307090f' fill-opacity='0.45'/%3E%3Crect x='3' y='0' width='1' height='1' fill='%233b4a63' fill-opacity='0.5'/%3E%3Crect x='1' y='2' width='1' height='1' fill='%233b4a63' fill-opacity='0.5'/%3E%3C/svg%3E");
}
/* Affine "texture swim": PS1 had no perspective-correct mapping, so
surfaces warped as the camera moved. Fake it with a slow skew wobble. */
@keyframes ps1-swim {
0% { transform: skewX(0deg) skewY(0deg) scale(1); }
25% { transform: skewX(0.6deg) skewY(-0.4deg) scale(1.004); }
50% { transform: skewX(0deg) skewY(0.5deg) scale(1); }
75% { transform: skewX(-0.6deg) skewY(-0.3deg) scale(0.997); }
100% { transform: skewX(0deg) skewY(0deg) scale(1); }
}
/* Vertex jitter: low-precision vertex coords snapped to a grid made
geometry shudder. Tiny stepped translate on interactive bits. */
@keyframes ps1-jitter {
0%, 100% { transform: translate(0, 0); }
20% { transform: translate(0.5px, -0.5px); }
40% { transform: translate(-0.5px, 0.5px); }
60% { transform: translate(0.5px, 0.5px); }
80% { transform: translate(-0.5px, -0.5px); }
}
[data-theme="ps1"] body {
background: linear-gradient(160deg, var(--p1-bg1) 0%, var(--p1-bg2) 100%) fixed;
/* fogged void: dark dither over a vertical gradient = banding kill */
background:
var(--p1-dither-fog),
linear-gradient(178deg, var(--p1-void1) 0%, var(--p1-void2) 100%) fixed;
background-size: 4px 4px, cover;
}
[data-theme="ps1"] .rb-window {
background: var(--p1-panel);
border: 2px solid #fff;
border-radius: 3px;
background:
var(--p1-dither-dark),
var(--p1-panel);
background-size: 4px 4px, cover;
border: 0;
border-radius: 0;
padding: 0;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
/* jagged, untextured polygon silhouette — notched corners */
clip-path: polygon(
0 6px, 6px 6px, 6px 0,
calc(100% - 8px) 0, calc(100% - 8px) 5px, 100% 5px,
100% calc(100% - 7px), calc(100% - 6px) calc(100% - 7px), calc(100% - 6px) 100%,
7px 100%, 7px calc(100% - 6px), 0 calc(100% - 6px)
);
box-shadow: 0 12px 34px rgba(0, 0, 0, 0.65);
/* bright seam ring like flat-shaded geometry catching light */
outline: 2px solid var(--p1-seam);
outline-offset: -2px;
}
[data-theme="ps1"] .rb-titlebar {
height: 30px;
padding: 0 12px;
background: linear-gradient(180deg, #5b6473, #424b59);
color: #eef1f6;
background:
var(--p1-dither-dark),
linear-gradient(180deg, var(--p1-fog), var(--p1-void1));
background-size: 4px 4px, cover;
color: var(--p1-seam);
letter-spacing: 3px;
text-transform: uppercase;
font-size: 12px;
text-shadow: 1px 1px 0 #000; /* hard 1px shadow, no blur */
}
[data-theme="ps1"] .rb-titlebar-icon {
width: 14px;
height: 14px;
background: #eef1f6;
/* tiny CD glint */
border-radius: 50%;
box-shadow: inset 0 0 0 4px #5b6473, inset 0 0 0 5px #eef1f6;
/* startup diamond, hard-edged */
background: var(--p1-mag);
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
box-shadow: inset 0 0 0 2px var(--p1-cyan);
border-radius: 0;
image-rendering: pixelated;
animation: ps1-jitter 0.45s steps(2, end) infinite;
}
[data-theme="ps1"] .rb-titlebar-buttons {
display: none;
@@ -51,8 +112,11 @@
[data-theme="ps1"] .rb-menubar {
padding: 6px 10px;
background: var(--p1-panel-dk);
border-bottom: 1px solid #fff;
background:
var(--p1-dither-dark),
var(--p1-panel-dk);
background-size: 4px 4px, cover;
border-bottom: 2px solid var(--p1-void2);
}
[data-theme="ps1"] .rb-menu-link {
text-decoration: none;
@@ -63,8 +127,9 @@
letter-spacing: 1px;
}
[data-theme="ps1"] .rb-menu-link:hover {
background: var(--p1-ink);
color: #fff;
background: var(--p1-mag);
color: var(--p1-seam);
animation: ps1-jitter 0.4s steps(2, end) infinite;
}
[data-theme="ps1"] .rb-switcher-label {
font-size: 11px;
@@ -72,32 +137,39 @@
}
[data-theme="ps1"] .rb-switcher-select {
font: 12px Verdana, sans-serif;
background: #eef1f6;
border: 1px solid #fff;
border-radius: 2px;
background: var(--p1-seam);
color: var(--p1-ink);
border: 2px solid var(--p1-void2);
border-radius: 0;
padding: 2px 4px;
}
[data-theme="ps1"] .rb-content {
background: #e6e9ee;
background:
var(--p1-dither-dark),
#cfc8b2;
background-size: 4px 4px, cover;
margin: 8px;
padding: 20px 22px;
border-radius: 2px;
box-shadow: inset 0 0 0 1px #fff, inset 0 0 0 2px var(--p1-panel-dk);
border-radius: 0;
box-shadow: inset 0 0 0 2px var(--p1-seam), inset 0 0 0 4px var(--p1-panel-dk);
}
[data-theme="ps1"] .rb-statusbar {
padding: 4px 12px;
font-size: 11px;
color: #4a525f;
color: #2a2017;
letter-spacing: 1px;
text-transform: uppercase;
}
[data-theme="ps1"] .rb-taskbar {
height: 34px;
background: linear-gradient(180deg, #424b59, var(--p1-bg2));
border-top: 1px solid #5b6473;
background:
var(--p1-dither-dark),
linear-gradient(180deg, var(--p1-void1), var(--p1-void2));
background-size: 4px 4px, cover;
border-top: 2px solid var(--p1-fog);
}
[data-theme="ps1"] .rb-start {
display: flex;
@@ -105,21 +177,27 @@
gap: 7px;
height: 24px;
padding: 0 14px;
border: 1px solid #6b7585;
border-radius: 2px;
background: #4a525f;
color: #eef1f6;
border: 2px solid var(--p1-seam);
border-radius: 0;
background: var(--p1-void1);
color: var(--p1-seam);
font: 11px Verdana, sans-serif;
letter-spacing: 2px;
text-transform: uppercase;
cursor: pointer;
clip-path: polygon(4px 0, 100% 0, 100% calc(100% - 4px), calc(100% - 4px) 100%, 0 100%, 0 4px);
}
[data-theme="ps1"] .rb-start:hover {
animation: ps1-jitter 0.4s steps(2, end) infinite;
}
[data-theme="ps1"] .rb-start-logo {
width: 12px;
height: 12px;
border-radius: 50%;
background: #eef1f6;
box-shadow: inset 0 0 0 3px #4a525f, inset 0 0 0 4px #eef1f6;
border-radius: 0;
background: var(--p1-mag);
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
box-shadow: inset 0 0 0 2px var(--p1-cyan);
image-rendering: pixelated;
}
[data-theme="ps1"] .rb-task {
display: flex;
@@ -127,26 +205,28 @@
gap: 7px;
height: 24px;
padding: 0 12px;
border: 1px solid transparent;
border: 2px solid transparent;
background: transparent;
color: #aab2c0;
color: #8b93a3;
font-size: 11px;
letter-spacing: 1px;
text-transform: uppercase;
cursor: default;
}
[data-theme="ps1"] .rb-task-active {
border-color: #6b7585;
background: #4a525f;
color: #eef1f6;
border-color: var(--p1-seam);
background: var(--p1-void1);
color: var(--p1-seam);
}
[data-theme="ps1"] .rb-task-icon {
width: 10px;
height: 10px;
background: #aab2c0;
background: var(--p1-cyan);
clip-path: polygon(50% 0, 100% 100%, 0 100%);
image-rendering: pixelated;
}
[data-theme="ps1"] .rb-clock {
color: #cfd5de;
color: var(--p1-seam);
font-size: 11px;
padding: 0 14px;
letter-spacing: 2px;
@@ -158,17 +238,36 @@
letter-spacing: 3px;
text-transform: uppercase;
color: var(--p1-ink);
text-shadow: 2px 2px 0 var(--p1-mag); /* hard offset, no AA */
}
[data-theme="ps1"] .rb-page-sub {
margin: 0 0 18px;
color: #5a626f;
color: #3a2f22;
}
[data-theme="ps1"] .rb-post-card {
background: #f1f3f6;
border: 1px solid #fff;
border-radius: 2px;
background:
var(--p1-dither-dark),
#ddd6c0;
background-size: 4px 4px, cover;
border: 0;
border-radius: 0;
padding: 14px 16px;
box-shadow: 0 1px 0 var(--p1-panel-dk), inset 0 0 0 1px #d2d7df;
/* rough notched polygon card */
clip-path: polygon(
0 0, calc(100% - 7px) 0, 100% 7px,
100% 100%, 7px 100%, 0 calc(100% - 7px)
);
box-shadow: inset 0 0 0 2px var(--p1-seam), 3px 3px 0 var(--p1-void2);
/* the affine swim — slow, unsettling, always on */
animation: ps1-swim 6s ease-in-out infinite;
transform-origin: center;
}
[data-theme="ps1"] .rb-post-card:hover {
/* lean into the warp on focus */
animation-duration: 2.4s;
outline: 2px solid var(--p1-mag);
outline-offset: -2px;
}
[data-theme="ps1"] .rb-post-card-title a {
color: var(--p1-ink);
@@ -176,30 +275,37 @@
letter-spacing: 1px;
}
[data-theme="ps1"] .rb-post-card-title a:hover {
color: #000;
color: var(--p1-mag);
text-decoration: underline;
}
[data-theme="ps1"] .rb-post-date {
font-size: 11px;
color: #6b7585;
color: #5b513c;
text-transform: uppercase;
letter-spacing: 1px;
}
[data-theme="ps1"] .rb-tag {
font-size: 10px;
background: #c7ccd4;
border: 1px solid #fff;
background: var(--p1-void1);
color: var(--p1-seam);
border: 0;
padding: 1px 7px;
text-transform: uppercase;
letter-spacing: 1px;
clip-path: polygon(3px 0, 100% 0, calc(100% - 3px) 100%, 0 100%);
}
[data-theme="ps1"] .rb-readmore,
[data-theme="ps1"] .rb-back {
color: #3a4351;
color: var(--p1-cyan);
text-decoration: none;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 1px;
text-shadow: 1px 1px 0 var(--p1-void2);
}
[data-theme="ps1"] .rb-readmore:hover,
[data-theme="ps1"] .rb-back:hover {
color: var(--p1-mag);
}
[data-theme="ps1"] .rb-back {
display: inline-block;
@@ -209,20 +315,39 @@
letter-spacing: 2px;
text-transform: uppercase;
margin: 0 0 8px;
text-shadow: 2px 2px 0 var(--p1-mag);
}
[data-theme="ps1"] .rb-prose {
line-height: 1.7;
}
[data-theme="ps1"] .rb-prose code {
background: #c7ccd4;
border: 1px solid #fff;
border-radius: 2px;
background: var(--p1-void1);
color: var(--p1-seam);
border: 0;
border-radius: 0;
padding: 0 4px;
font-family: "Courier New", monospace;
}
[data-theme="ps1"] .rb-prose img {
/* unfiltered textures: nearest-neighbor scaling */
image-rendering: pixelated;
}
[data-theme="ps1"] .rb-prose blockquote {
border-left: 3px solid var(--p1-accent);
border-left: 4px solid var(--p1-mag);
margin: 12px 0;
padding: 4px 14px;
background: #dde1e8;
background:
var(--p1-dither-dark),
#c8c1ab;
background-size: 4px 4px, cover;
}
/* Respect reduced-motion: kill the swim/jitter, keep the look. */
@media (prefers-reduced-motion: reduce) {
[data-theme="ps1"] .rb-post-card,
[data-theme="ps1"] .rb-titlebar-icon,
[data-theme="ps1"] .rb-start:hover,
[data-theme="ps1"] .rb-menu-link:hover {
animation: none;
}
}