Files
RetroBlog/src/themes/ps1.css
T
kawa 307e0b48da 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>
2026-06-07 03:53:20 +02:00

354 lines
10 KiB
CSS

/* ============================================================
Theme: PlayStation 1 — scoped to [data-theme="ps1"]
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"] {
/* 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 {
/* 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-dither-dark),
var(--p1-panel);
background-size: 4px 4px, cover;
border: 0;
border-radius: 0;
padding: 0;
/* 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:
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;
/* 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;
}
[data-theme="ps1"] .rb-menubar {
padding: 6px 10px;
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;
padding: 3px 10px;
color: var(--p1-ink);
text-transform: uppercase;
font-size: 11px;
letter-spacing: 1px;
}
[data-theme="ps1"] .rb-menu-link:hover {
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;
text-transform: uppercase;
}
[data-theme="ps1"] .rb-switcher-select {
font: 12px Verdana, sans-serif;
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:
var(--p1-dither-dark),
#cfc8b2;
background-size: 4px 4px, cover;
margin: 8px;
padding: 20px 22px;
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: #2a2017;
letter-spacing: 1px;
text-transform: uppercase;
}
[data-theme="ps1"] .rb-taskbar {
height: 34px;
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;
align-items: center;
gap: 7px;
height: 24px;
padding: 0 14px;
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: 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;
align-items: center;
gap: 7px;
height: 24px;
padding: 0 12px;
border: 2px solid transparent;
background: transparent;
color: #8b93a3;
font-size: 11px;
letter-spacing: 1px;
text-transform: uppercase;
cursor: default;
}
[data-theme="ps1"] .rb-task-active {
border-color: var(--p1-seam);
background: var(--p1-void1);
color: var(--p1-seam);
}
[data-theme="ps1"] .rb-task-icon {
width: 10px;
height: 10px;
background: var(--p1-cyan);
clip-path: polygon(50% 0, 100% 100%, 0 100%);
image-rendering: pixelated;
}
[data-theme="ps1"] .rb-clock {
color: var(--p1-seam);
font-size: 11px;
padding: 0 14px;
letter-spacing: 2px;
}
[data-theme="ps1"] .rb-page-title {
margin: 0 0 4px;
font-size: 24px;
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: #3a2f22;
}
[data-theme="ps1"] .rb-post-card {
background:
var(--p1-dither-dark),
#ddd6c0;
background-size: 4px 4px, cover;
border: 0;
border-radius: 0;
padding: 14px 16px;
/* 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);
text-decoration: none;
letter-spacing: 1px;
}
[data-theme="ps1"] .rb-post-card-title a:hover {
color: var(--p1-mag);
text-decoration: underline;
}
[data-theme="ps1"] .rb-post-date {
font-size: 11px;
color: #5b513c;
text-transform: uppercase;
letter-spacing: 1px;
}
[data-theme="ps1"] .rb-tag {
font-size: 10px;
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: 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;
margin-bottom: 12px;
}
[data-theme="ps1"] .rb-article-title {
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: 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: 4px solid var(--p1-mag);
margin: 12px 0;
padding: 4px 14px;
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;
}
}