flat mode, a few more buttons, etc
4
.gitattributes
vendored
|
@ -1,4 +1,4 @@
|
||||||
*.png filter=lfs diff=lfs merge=lfs -text
|
*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
*.gif filter=lfs diff=lfs merge=lfs -text
|
*.gif filter=lfs diff=lfs merge=lfs -text
|
||||||
*.mp3 filter=lfs diff=lfs merge=lfs -text
|
*.webp filter=lfs diff=lfs merge=lfs -text
|
||||||
*.ogg filter=lfs diff=lfs merge=lfs -text
|
*.kra filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|
9
Makefile
|
@ -1,9 +1,9 @@
|
||||||
CSS = $(wildcard *.css) $(shell find fonts -type f)
|
CSS = $(wildcard *.css) $(shell find fonts -type f)
|
||||||
PAGES = index.html pubkey.txt
|
PAGES = index.html pubkey.txt
|
||||||
MEDIA = \
|
MEDIA = \
|
||||||
$(wildcard media/*.png) $(wildcard media/*.svg) $(wildcard media/*.webp) \
|
$(wildcard media/*.png) $(wildcard media/*.gif) $(wildcard media/*.webp) \
|
||||||
$(wildcard media/flags/*) $(wildcard media/buttons/*) \
|
$(wildcard media/flags/*) $(wildcard media/buttons/*) \
|
||||||
8831.png 8831-quox.png
|
$(wildcard media/icons/*) $(wildcard media/bg/*) 8831.png 8831-quox.png
|
||||||
SCRIPTS = $(patsubst %.ts,%.js,$(wildcard *.ts))
|
SCRIPTS = $(patsubst %.ts,%.js,$(wildcard *.ts))
|
||||||
MISC = $(shell find .well-known -type f)
|
MISC = $(shell find .well-known -type f)
|
||||||
ALL = $(CSS) $(PAGES) $(MEDIA) $(SCRIPTS) $(MISC)
|
ALL = $(CSS) $(PAGES) $(MEDIA) $(SCRIPTS) $(MISC)
|
||||||
|
@ -53,11 +53,6 @@ $(BUILDDIR)/%_dim.png: %.png
|
||||||
@echo $(notdir $@)
|
@echo $(notdir $@)
|
||||||
@convert -channel A -evaluate Multiply 0.75 $< $@
|
@convert -channel A -evaluate Multiply 0.75 $< $@
|
||||||
|
|
||||||
$(BUILDDIR)/%.GIF: %.ICO
|
|
||||||
@echo $*.GIF
|
|
||||||
@mkdir -p $(dir $@)
|
|
||||||
@convert '$<[0]' $@
|
|
||||||
|
|
||||||
$(BUILDDIR)/%.js: %.ts
|
$(BUILDDIR)/%.js: %.ts
|
||||||
tsc --strict --noUncheckedIndexedAccess --noEmitOnError \
|
tsc --strict --noUncheckedIndexedAccess --noEmitOnError \
|
||||||
--lib dom,es2021 --target es2015 \
|
--lib dom,es2021 --target es2015 \
|
||||||
|
|
116
base.css
|
@ -1,4 +1,4 @@
|
||||||
@import url(fonts/muller/muller.css);
|
@import url(fonts/muller/muller.css) (prefers-reduced-data: no-preference);
|
||||||
|
|
||||||
|
|
||||||
/* OUTER */
|
/* OUTER */
|
||||||
|
@ -7,22 +7,31 @@
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
min-height: 100lvh;
|
||||||
scrollbar-gutter: stable;
|
scrollbar-gutter: stable;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font-family: Muller, sans-serif;
|
|
||||||
font-size: large;
|
font-size: large;
|
||||||
|
font-family: Muller, sans-serif;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
||||||
background: var(--gradient);
|
background: var(--gradient) fixed;
|
||||||
color: black;
|
color: black;
|
||||||
|
|
||||||
--gradient:
|
--gradient:
|
||||||
linear-gradient(120deg, #fae58f, #fab6ba, #d1aeff, #89d6ff, #43f3ae);
|
linear-gradient(120deg, #fae58f, #fab6ba, #d1aeff, #89d6ff, #43f3ae);
|
||||||
|
--shadow-hsl: 330deg 40% 40%;
|
||||||
}
|
}
|
||||||
|
|
||||||
body { margin: 0; }
|
@media (prefers-reduced-data: reduce) {
|
||||||
|
html {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body { margin: 0; }
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
html {
|
html {
|
||||||
|
@ -33,7 +42,6 @@ body { margin: 0; }
|
||||||
hsl(150deg 30% 20%),
|
hsl(150deg 30% 20%),
|
||||||
hsl(30deg 30% 20%),
|
hsl(30deg 30% 20%),
|
||||||
hsl(350deg 30% 20%));
|
hsl(350deg 30% 20%));
|
||||||
|
|
||||||
color: #ffd;
|
color: #ffd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +49,10 @@ body { margin: 0; }
|
||||||
|
|
||||||
/* TOP MENU */
|
/* TOP MENU */
|
||||||
|
|
||||||
#face-menu { place-self: center; }
|
#face-menu {
|
||||||
|
align-self: center;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.menu input, .menu label {
|
.menu input, .menu label {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -54,8 +65,10 @@ body { margin: 0; }
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
font-size: 125%;
|
font-size: 125%;
|
||||||
font-weight: 500;
|
|
||||||
|
|
||||||
background: hsl(var(--menu-bg-hsl) / 50%);
|
background: hsl(var(--menu-bg-hsl) / 50%);
|
||||||
border: 2px solid hsl(var(--menu-bg-hsl));
|
border: 2px solid hsl(var(--menu-bg-hsl));
|
||||||
|
@ -77,25 +90,12 @@ body { margin: 0; }
|
||||||
.menu li {
|
.menu li {
|
||||||
display: flex;
|
display: flex;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
flex: 1 0 4em;
|
||||||
}
|
}
|
||||||
.menu label {
|
.menu label {
|
||||||
padding: .25em 1.25em;
|
padding: .25em 1.25em;
|
||||||
}
|
flex: 1 0 auto;
|
||||||
.menu :checked + label {
|
text-align: center;
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu label { position: relative; }
|
|
||||||
.menu label::after {
|
|
||||||
content: ' ';
|
|
||||||
z-index: -1;
|
|
||||||
position: absolute;
|
|
||||||
inset: 0 0 100% 0;
|
|
||||||
background: hsl(var(--menu-bg-hsl));
|
|
||||||
transition: inset .15s linear;
|
|
||||||
}
|
|
||||||
.menu :checked + label::after {
|
|
||||||
bottom: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -112,7 +112,8 @@ body { margin: 0; }
|
||||||
);
|
);
|
||||||
background: var(--base-background);
|
background: var(--base-background);
|
||||||
|
|
||||||
border: 10px solid white;
|
--border-thickness: 10px;
|
||||||
|
border: var(--border-thickness) solid white;
|
||||||
padding: 2em;
|
padding: 2em;
|
||||||
|
|
||||||
color: hsl(var(--hue) 40% 10%);
|
color: hsl(var(--hue) 40% 10%);
|
||||||
|
@ -188,6 +189,12 @@ strong { font-weight: 700; }
|
||||||
--bg-angle: 135deg;
|
--bg-angle: 135deg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* this one makes more sense to show if there is a paint before
|
||||||
|
* the script runs */
|
||||||
|
#hello {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* extra #cube selector for specificity */
|
/* extra #cube selector for specificity */
|
||||||
#cube #hello {
|
#cube #hello {
|
||||||
--bg-image: url(media/wave.png);
|
--bg-image: url(media/wave.png);
|
||||||
|
@ -199,6 +206,12 @@ strong { font-weight: 700; }
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
#cube #hello { --bg-image: url(media/wave-neon.png); }
|
#cube #hello { --bg-image: url(media/wave-neon.png); }
|
||||||
}
|
}
|
||||||
|
@media (prefers-reduced-data: reduce) {
|
||||||
|
#cube #hello { --bg-image: url(media/wave.webp); }
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: dark) and (prefers-reduced-data: reduce) {
|
||||||
|
#cube #hello { --bg-image: url(media/wave-neon.webp); }
|
||||||
|
}
|
||||||
|
|
||||||
#id, #id ::selection, #flags img {
|
#id, #id ::selection, #flags img {
|
||||||
--hue: 10deg;
|
--hue: 10deg;
|
||||||
|
@ -248,9 +261,13 @@ strong { font-weight: 700; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
#cube #activities {
|
#cube #activities { --bg-image: url(media/quobl-neon.png); }
|
||||||
--bg-image: url(media/quobl-neon.png);
|
|
||||||
}
|
}
|
||||||
|
@media (prefers-reduced-data: reduce) {
|
||||||
|
#cube #activities { --bg-image: url(media/quobl.webp); }
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: dark) and (prefers-reduced-data: reduce) {
|
||||||
|
#cube #activities { --bg-image: url(media/quobl-neon.png); }
|
||||||
}
|
}
|
||||||
|
|
||||||
#links, #links ::selection {
|
#links, #links ::selection {
|
||||||
|
@ -290,21 +307,21 @@ strong { font-weight: 700; }
|
||||||
#links a:hover { text-decoration: none; }
|
#links a:hover { text-decoration: none; }
|
||||||
|
|
||||||
#links #gallery {
|
#links #gallery {
|
||||||
--icon: url(media/niss-icon.png);
|
--icon: url(media/favicon.png);
|
||||||
--fg: hsl(280deg 38% 43%);
|
--fg: hsl(280deg 38% 43%);
|
||||||
--bg: hsl(100deg 99% 81%);
|
--bg: hsl(100deg 99% 81%);
|
||||||
image-rendering: pixelated;
|
image-rendering: pixelated;
|
||||||
}
|
}
|
||||||
|
|
||||||
#links #code {
|
#links #code {
|
||||||
--icon: url(media/forgejo.svg);
|
--icon: url(media/icons/forgejo.svg);
|
||||||
--fg: white;
|
--fg: white;
|
||||||
--icon-bg: #171e26;
|
--icon-bg: #171e26;
|
||||||
--bg: #c2410c;
|
--bg: #c2410c;
|
||||||
}
|
}
|
||||||
|
|
||||||
#links #blog {
|
#links #blog {
|
||||||
--icon: url(media/blog.png);
|
--icon: url(media/icons/blog.png);
|
||||||
--fg: #ffeebb;
|
--fg: #ffeebb;
|
||||||
--bg: #332255;
|
--bg: #332255;
|
||||||
/* image-rendering: pixelated; */
|
/* image-rendering: pixelated; */
|
||||||
|
@ -315,61 +332,61 @@ strong { font-weight: 700; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#links #itaku {
|
#links #itaku {
|
||||||
--icon: url(media/itaku.svg);
|
--icon: url(media/icons/itaku.svg);
|
||||||
--fg: #ffeb3b;
|
--fg: #ffeb3b;
|
||||||
--bg: #303030;
|
--bg: #303030;
|
||||||
}
|
}
|
||||||
|
|
||||||
#links #weasyl {
|
#links #weasyl {
|
||||||
--icon: url(media/weasyl.svg);
|
--icon: url(media/icons/weasyl.svg);
|
||||||
--fg: white;
|
--fg: white;
|
||||||
--bg: #970000;
|
--bg: #970000;
|
||||||
}
|
}
|
||||||
|
|
||||||
#links #fa {
|
#links #fa {
|
||||||
--icon: url(media/furaffinity.png);
|
--icon: url(media/icons/furaffinity.png);
|
||||||
--icon-bg: #20242a;
|
--icon-bg: #20242a;
|
||||||
--bg: #353b45;
|
--bg: #353b45;
|
||||||
--fg: white;
|
--fg: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
#links #da {
|
#links #da {
|
||||||
--icon: url(media/deviantart.png);
|
--icon: url(media/icons/deviantart.png);
|
||||||
--icon-bg: #000608;
|
--icon-bg: #000608;
|
||||||
--bg: #314537;
|
--bg: #314537;
|
||||||
--fg: #e7ede4;
|
--fg: #e7ede4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#links #kofi {
|
#links #kofi {
|
||||||
--icon: url(media/ko-fi.webp);
|
--icon: url(media/icons/ko-fi.webp);
|
||||||
--icon-bg: #def3ff;
|
--icon-bg: #def3ff;
|
||||||
--bg: white;
|
--bg: white;
|
||||||
--fg: #ff5966;
|
--fg: #ff5966;
|
||||||
}
|
}
|
||||||
|
|
||||||
#links #artfight {
|
#links #artfight {
|
||||||
--icon: url(media/artfight.png);
|
--icon: url(media/icons/artfight.png);
|
||||||
--icon-bg: #222222;
|
--icon-bg: #222222;
|
||||||
--bg: #a65178;
|
--bg: #a65178;
|
||||||
--fg: white;
|
--fg: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
#links #chitter {
|
#links #chitter {
|
||||||
--icon: url(media/chitter.png);
|
--icon: url(media/icons/chitter.png);
|
||||||
--bg: #582c58;
|
--bg: #582c58;
|
||||||
--icon-bg: #2c162c;
|
--icon-bg: #2c162c;
|
||||||
--fg: white;
|
--fg: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
#links #cohost {
|
#links #cohost {
|
||||||
--icon: url(media/cohost.svg);
|
--icon: url(media/icons/cohost.svg);
|
||||||
--bg: #ffab5c;
|
--bg: #ffab5c;
|
||||||
--icon-bg: #83254f;
|
--icon-bg: #83254f;
|
||||||
--fg: black;
|
--fg: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
#links #bluesky {
|
#links #bluesky {
|
||||||
--icon: url(media/bluesky.svg);
|
--icon: url(media/icons/bluesky.svg);
|
||||||
--bg: #161e27;
|
--bg: #161e27;
|
||||||
--fg: white;
|
--fg: white;
|
||||||
}
|
}
|
||||||
|
@ -464,6 +481,7 @@ strong { font-weight: 700; }
|
||||||
#friends #abyss a { background: #1e2e5f; color: #f8e1c2; }
|
#friends #abyss a { background: #1e2e5f; color: #f8e1c2; }
|
||||||
|
|
||||||
#nissbuttons {
|
#nissbuttons {
|
||||||
|
margin: 2em auto 0;
|
||||||
align-self: end;
|
align-self: end;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -471,6 +489,10 @@ strong { font-weight: 700; }
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#nissbuttons p {
|
||||||
|
text-align: right;
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
#nissbuttons * { margin: 0; }
|
#nissbuttons * { margin: 0; }
|
||||||
|
|
||||||
#six, #six ::selection {
|
#six, #six ::selection {
|
||||||
|
@ -486,19 +508,11 @@ strong { font-weight: 700; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
#cube #six {
|
#cube #six { --bg-image: url(media/kesi-neon.png); }
|
||||||
--bg-image: url(media/kesi-neon.png);
|
|
||||||
}
|
}
|
||||||
|
@media (prefers-reduced-data: reduce) {
|
||||||
|
#cube #activities { --bg-image: url(media/kesi.webp); }
|
||||||
}
|
}
|
||||||
|
@media (prefers-color-scheme: dark) and (prefers-reduced-data: reduce) {
|
||||||
.zoom * { transition: all 0.25s ease-in; }
|
#cube #activities { --bg-image: url(media/kesi-neon.webp); }
|
||||||
.zoom > :hover {
|
|
||||||
scale: 125%;
|
|
||||||
filter: drop-shadow(4px 4px 5px rgb(0 0 0 / 60%));
|
|
||||||
}
|
}
|
||||||
.zoom > :hover:nth-child(5n) { rotate: 17deg; }
|
|
||||||
.zoom > :hover:nth-child(5n+1) { rotate: -12deg; }
|
|
||||||
.zoom > :hover:nth-child(5n+2) { rotate: 8deg; }
|
|
||||||
.zoom > :hover:nth-child(5n+3) { rotate: -23deg; }
|
|
||||||
.zoom > :hover:nth-child(10n+4) { rotate: 26deg; }
|
|
||||||
.zoom > :hover:nth-child(10n+9) { rotate: -6deg; }
|
|
||||||
|
|
41
cube.css
|
@ -1,11 +1,32 @@
|
||||||
|
@media (prefers-reduced-motion: no-preference) and
|
||||||
|
(min-height: 650px) and (min-width: 650px) {
|
||||||
|
|
||||||
|
/* LAYOUT BASICS */
|
||||||
|
|
||||||
body {
|
body {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 5em 1fr 5em;
|
grid-template-rows: 5em 1fr;
|
||||||
|
|
||||||
perspective: 440vw;
|
perspective: 440vw;
|
||||||
perspective-origin: 50% 120%;
|
perspective-origin: 50% 120%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* MENU ANIMATION */
|
||||||
|
|
||||||
|
.menu label { position: relative; }
|
||||||
|
.menu label::after {
|
||||||
|
content: ' ';
|
||||||
|
z-index: -1;
|
||||||
|
position: absolute;
|
||||||
|
inset: 0 0 100% 0;
|
||||||
|
background: hsl(var(--menu-bg-hsl));
|
||||||
|
transition: inset .15s linear;
|
||||||
|
}
|
||||||
|
.menu :checked + label::after {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* CUBE ASSEMBLY */
|
/* CUBE ASSEMBLY */
|
||||||
/* the rest is in cube.ts */
|
/* the rest is in cube.ts */
|
||||||
|
|
||||||
|
@ -19,7 +40,7 @@ html {
|
||||||
/* cube shadow */
|
/* cube shadow */
|
||||||
html {
|
html {
|
||||||
background:
|
background:
|
||||||
radial-gradient(circle, hsl(330deg 40% 40% / 70%), transparent 58%),
|
radial-gradient(circle, hsl(var(--shadow-hsl) / 70%), transparent 58%),
|
||||||
var(--gradient);
|
var(--gradient);
|
||||||
background-blend-mode: multiply;
|
background-blend-mode: multiply;
|
||||||
}
|
}
|
||||||
|
@ -58,3 +79,19 @@ html {
|
||||||
@keyframes breathe {
|
@keyframes breathe {
|
||||||
35% { transform: translateZ(var(--breathe)) var(--base-transform); }
|
35% { transform: translateZ(var(--breathe)) var(--base-transform); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
|
.zoom * { transition: all 0.25s ease-in; }
|
||||||
|
.zoom > :hover {
|
||||||
|
scale: 110%;
|
||||||
|
filter: drop-shadow(4px 4px 5px rgb(0 0 0 / 60%));
|
||||||
|
}
|
||||||
|
.zoom > :hover:nth-child(5n) { rotate: 4deg; }
|
||||||
|
.zoom > :hover:nth-child(5n+1) { rotate: -2deg; }
|
||||||
|
.zoom > :hover:nth-child(5n+2) { rotate: 1deg; }
|
||||||
|
.zoom > :hover:nth-child(5n+3) { rotate: -3deg; }
|
||||||
|
.zoom > :hover:nth-child(10n+4) { rotate: 4deg; }
|
||||||
|
.zoom > :hover:nth-child(10n+9) { rotate: -1deg; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
108
flat.css
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
@media (prefers-reduced-motion: reduce),
|
||||||
|
(max-height: 649px), (max-width: 649px) {
|
||||||
|
|
||||||
|
/* LAYOUT */
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: grid;
|
||||||
|
grid-template: "menu" 5em "body" 1fr;
|
||||||
|
/* height: 100vh; height: 100dvh; */
|
||||||
|
/* width: 100vw; width: 100dvw; */
|
||||||
|
}
|
||||||
|
|
||||||
|
#face-menu { grid-area: menu; }
|
||||||
|
#outer { grid-area: body; }
|
||||||
|
|
||||||
|
#outer {
|
||||||
|
position: relative;
|
||||||
|
height: 90%;
|
||||||
|
width: 90%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#outer::after {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
box-shadow: 0 0 40px hsl(var(--shadow-hsl) / 40%);
|
||||||
|
mix-blend-mode: multiply;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not really a cube any more. but */
|
||||||
|
#cube, #cube > section {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
}
|
||||||
|
#cube > section { overflow: auto; }
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
html { --shadow-hsl: 60deg 100% 96%; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* BACKGROUND FIXES */
|
||||||
|
|
||||||
|
@media (max-width: 649px) {
|
||||||
|
#cube #hello {
|
||||||
|
background-size: auto 80%, auto, auto;
|
||||||
|
background-position: bottom -20% right 60%, center, center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-height: 649px) {
|
||||||
|
#cube #hello {
|
||||||
|
background-size: auto 80%, auto, auto;
|
||||||
|
background-position: bottom right, center, center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media (max-width: 649px) {
|
||||||
|
#cube #activities {
|
||||||
|
background-size: auto 30%, auto, auto;
|
||||||
|
background-position: bottom left 70%, center, center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#cube #six {
|
||||||
|
background-position: bottom left 70%, center, center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 649px) {
|
||||||
|
#cube #six {
|
||||||
|
background-size: auto 100%, auto, auto;
|
||||||
|
background-position: bottom left 70%, center, center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-height: 649px) {
|
||||||
|
#cube #six {
|
||||||
|
background-size: cover;
|
||||||
|
background-position: top 15% center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TRANSITIONS */
|
||||||
|
|
||||||
|
#face-menu :checked + label {
|
||||||
|
background: hsl(var(--menu-bg-hsl));
|
||||||
|
}
|
||||||
|
#face-menu label {
|
||||||
|
transition: background 0.1s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cube > section[data-selected=true] {
|
||||||
|
z-index: 1;
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.1s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cube > section[data-selected=false] {
|
||||||
|
z-index: -1;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0s 0.1s ease-in;
|
||||||
|
}
|
||||||
|
/* todo make sure this works ok with screen readers */
|
||||||
|
|
||||||
|
}
|
85
index.html
|
@ -8,13 +8,13 @@
|
||||||
<link rel=me href=https://chitter.xyz/@niss>
|
<link rel=me href=https://chitter.xyz/@niss>
|
||||||
<link rel=me href=https://cohost.org/niss>
|
<link rel=me href=https://cohost.org/niss>
|
||||||
|
|
||||||
<link rel=icon href=media/niss-icon.png>
|
<link rel=icon href=media/favicon.png>
|
||||||
<link rel=stylesheet href=base.css>
|
<link rel=stylesheet href=base.css>
|
||||||
<link rel=stylesheet href=cube.css
|
<link rel=stylesheet href=cube.css>
|
||||||
media='(prefers-reduced-motion: no-preference)'>
|
<link rel=stylesheet href=flat.css>
|
||||||
<!--
|
<noscript>
|
||||||
<link rel=stylesheet href=flat.css media='(prefers-reduced-motion)'>
|
<link rel=stylesheet href=static.css>
|
||||||
-->
|
</noscript>
|
||||||
|
|
||||||
<meta property=og:type content=article>
|
<meta property=og:type content=article>
|
||||||
<meta property=og:title content="the gec zone">
|
<meta property=og:title content="the gec zone">
|
||||||
|
@ -26,8 +26,8 @@
|
||||||
<meta name=twitter:image content="XXXXXX">
|
<meta name=twitter:image content="XXXXXX">
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<script src=cube.js type=module></script>
|
|
||||||
<script src=shuffle.js type=module></script>
|
<script src=shuffle.js type=module></script>
|
||||||
|
<script src=run.js type=module></script>
|
||||||
|
|
||||||
<nav id=face-menu>
|
<nav id=face-menu>
|
||||||
<menu class='menu hide-boxes'>
|
<menu class='menu hide-boxes'>
|
||||||
|
@ -52,6 +52,13 @@
|
||||||
<h2> hey </h2>
|
<h2> hey </h2>
|
||||||
|
|
||||||
<p> i’m niss. what’s up
|
<p> i’m niss. what’s up
|
||||||
|
|
||||||
|
<noscript>
|
||||||
|
<p> this page needs javascript for the full effect, sorry.
|
||||||
|
|
||||||
|
<p> it was hard enough to make it work cross-browser as it is.
|
||||||
|
<small>[grumbles at safari]</small>
|
||||||
|
</noscript>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id=id>
|
<section id=id>
|
||||||
|
@ -169,7 +176,11 @@
|
||||||
|
|
||||||
<li id=goaty>
|
<li id=goaty>
|
||||||
<a href=https://goatygoats.com title=goaty>
|
<a href=https://goatygoats.com title=goaty>
|
||||||
|
<picture>
|
||||||
|
<source srcset=media/buttons/goaty_still.gif
|
||||||
|
media='(prefers-reduced-motion: reduce)'>
|
||||||
<img src=media/buttons/goaty.gif alt=goaty>
|
<img src=media/buttons/goaty.gif alt=goaty>
|
||||||
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<li id=tenna>
|
<li id=tenna>
|
||||||
|
@ -177,7 +188,11 @@
|
||||||
|
|
||||||
<li id=gulfie>
|
<li id=gulfie>
|
||||||
<a href=https://gulfie.online title=gulfie>
|
<a href=https://gulfie.online title=gulfie>
|
||||||
|
<picture>
|
||||||
|
<source srcset=media/buttons/gulfie_still.png
|
||||||
|
media='(prefers-reduced-motion: reduce)'>
|
||||||
<img src=media/buttons/gulfie.png alt=gulfie>
|
<img src=media/buttons/gulfie.png alt=gulfie>
|
||||||
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<li id=river>
|
<li id=river>
|
||||||
|
@ -192,7 +207,11 @@
|
||||||
|
|
||||||
<li id=myno>
|
<li id=myno>
|
||||||
<a href=https://zatzhing.me title=myno>
|
<a href=https://zatzhing.me title=myno>
|
||||||
|
<picture>
|
||||||
|
<source srcset=media/buttons/myno_still.png
|
||||||
|
media='(prefers-reduced-motion: reduce)'>
|
||||||
<img src=media/buttons/myno.gif alt=myno>
|
<img src=media/buttons/myno.gif alt=myno>
|
||||||
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<li id=abyss>
|
<li id=abyss>
|
||||||
|
@ -200,7 +219,11 @@
|
||||||
|
|
||||||
<li id=cr>
|
<li id=cr>
|
||||||
<a href=https://candiedreptile.club/bloglet/ title=candiedreptile>
|
<a href=https://candiedreptile.club/bloglet/ title=candiedreptile>
|
||||||
|
<picture>
|
||||||
|
<source srcset=media/buttons/candiedreptile_still.png
|
||||||
|
media='(prefers-reduced-motion: reduce)'>
|
||||||
<img src=media/buttons/candiedreptile.gif alt=candiedreptile>
|
<img src=media/buttons/candiedreptile.gif alt=candiedreptile>
|
||||||
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<li id=spiral>
|
<li id=spiral>
|
||||||
|
@ -213,12 +236,20 @@
|
||||||
|
|
||||||
<li id=pebble>
|
<li id=pebble>
|
||||||
<a href=https://pebble.pet title=pebble>
|
<a href=https://pebble.pet title=pebble>
|
||||||
|
<picture>
|
||||||
|
<source srcset=media/buttons/pebble_still.png
|
||||||
|
media='(prefers-reduced-motion: reduce)'>
|
||||||
<img src=media/buttons/pebble.gif alt=pebble>
|
<img src=media/buttons/pebble.gif alt=pebble>
|
||||||
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<li id=beeps>
|
<li id=beeps>
|
||||||
<a href=https://beeps.website title=beeps>
|
<a href=https://beeps.website title=beeps>
|
||||||
|
<picture>
|
||||||
|
<source srcset=media/buttons/beeps_still.png
|
||||||
|
media='(prefers-reduced-motion: reduce)'>
|
||||||
<img src=media/buttons/beeps.gif alt=beeps>
|
<img src=media/buttons/beeps.gif alt=beeps>
|
||||||
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<li id=cobalt>
|
<li id=cobalt>
|
||||||
|
@ -233,12 +264,20 @@
|
||||||
|
|
||||||
<li id=dusty>
|
<li id=dusty>
|
||||||
<a href=https://chcl.se title=dusty>
|
<a href=https://chcl.se title=dusty>
|
||||||
|
<picture>
|
||||||
|
<source srcset=media/buttons/dusty_still.png
|
||||||
|
media='(prefers-reduced-motion: reduce)'>
|
||||||
<img src=media/buttons/dusty.gif alt=dusty>
|
<img src=media/buttons/dusty.gif alt=dusty>
|
||||||
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<li id=tsunderdog>
|
<li id=tsunderdog>
|
||||||
<a href=https://www.tsunderdog.art title=tsunderdog>
|
<a href=https://www.tsunderdog.art title=tsunderdog>
|
||||||
|
<picture>
|
||||||
|
<source srcset=media/buttons/tsunderdog_still.png
|
||||||
|
media='(prefers-reduced-motion: reduce)'>
|
||||||
<img src=media/buttons/tsunderdog.gif alt=tsunderdog>
|
<img src=media/buttons/tsunderdog.gif alt=tsunderdog>
|
||||||
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<li id=ionchy>
|
<li id=ionchy>
|
||||||
|
@ -251,7 +290,11 @@
|
||||||
|
|
||||||
<li id=tuxedodragon>
|
<li id=tuxedodragon>
|
||||||
<a href=https://tuxedodragon.art title=tuxedodragon>
|
<a href=https://tuxedodragon.art title=tuxedodragon>
|
||||||
|
<picture>
|
||||||
|
<source srcset=media/buttons/tuxedodragon_still.gif
|
||||||
|
media='(prefers-reduced-motion: reduce)'>
|
||||||
<img src=media/buttons/tuxedodragon.gif alt=tuxedodragon>
|
<img src=media/buttons/tuxedodragon.gif alt=tuxedodragon>
|
||||||
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<li id=hthrflwrs>
|
<li id=hthrflwrs>
|
||||||
|
@ -261,11 +304,29 @@
|
||||||
|
|
||||||
<li id=creature0354>
|
<li id=creature0354>
|
||||||
<a href=https://creature0354.neocities.org title=creature0354>
|
<a href=https://creature0354.neocities.org title=creature0354>
|
||||||
|
<picture>
|
||||||
|
<source srcset=media/buttons/creature0354_still.png
|
||||||
|
media='(prefers-reduced-motion: reduce)'>
|
||||||
<img src=media/buttons/creature0354.gif alt=creature0354>
|
<img src=media/buttons/creature0354.gif alt=creature0354>
|
||||||
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<li id=violet>
|
<li id=violet>
|
||||||
<a href=https://violet.pm title=violet class=txt>violet</a>
|
<a href=https://violet.pm title=violet class=txt>violet</a>
|
||||||
|
|
||||||
|
<li id=alloyed>
|
||||||
|
<a href=https://alloyed.me title='Kit!'>
|
||||||
|
<picture>
|
||||||
|
<source srcset=media/buttons/alloyed_still.png
|
||||||
|
media='(prefers-reduced-motion: reduce)'>
|
||||||
|
<img src=media/buttons/alloyed.gif alt='Kit!'>
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<li id=renko>
|
||||||
|
<a href=https://https://renkotsuban.com title=renkotsuban>
|
||||||
|
<img src=media/buttons/renkotsuban.gif alt=renkotsuban>
|
||||||
|
</a>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -275,7 +336,11 @@
|
||||||
<ul class='zoom shuffle'>
|
<ul class='zoom shuffle'>
|
||||||
<li>
|
<li>
|
||||||
<a href=https://cohost.org id=cohost-button title='i was on cohost'>
|
<a href=https://cohost.org id=cohost-button title='i was on cohost'>
|
||||||
|
<picture>
|
||||||
|
<source srcset=media/buttons/cohost_still.gif
|
||||||
|
media='(prefers-reduced-motion: reduce)'>
|
||||||
<img src=media/buttons/cohost.gif alt='i was on cohost'>
|
<img src=media/buttons/cohost.gif alt='i was on cohost'>
|
||||||
|
</picture>
|
||||||
<!-- button by https://mykocalico.neocities.org/ -->
|
<!-- button by https://mykocalico.neocities.org/ -->
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
@ -292,7 +357,11 @@
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href=https://corru.observer id=corru title='corru.observer'>
|
<a href=https://corru.observer id=corru title='corru.observer'>
|
||||||
|
<picture>
|
||||||
|
<source srcset=media/buttons/corru_still.gif
|
||||||
|
media='(prefers-reduced-motion: reduce)'>
|
||||||
<img src=media/buttons/corru.gif alt='corru.observer'>
|
<img src=media/buttons/corru.gif alt='corru.observer'>
|
||||||
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
|
@ -303,7 +372,7 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id=nissbuttons>
|
<section id=nissbuttons>
|
||||||
<p> niss buttons for you → </p>
|
<p>if you wanna link to me:</p>
|
||||||
<img src=8831.png alt='niss button' title='by me'>
|
<img src=8831.png alt='niss button' title='by me'>
|
||||||
<img src=8831-quox.png alt='q.t. button' title='by candiedreptile'>
|
<img src=8831-quox.png alt='q.t. button' title='by candiedreptile'>
|
||||||
</section>
|
</section>
|
||||||
|
|
BIN
media/artfight.png
(Stored with Git LFS)
BIN
media/blog.png
(Stored with Git LFS)
BIN
media/buttons/alloyed.gif
(Stored with Git LFS)
Normal file
BIN
media/buttons/alloyed_still.png
(Stored with Git LFS)
Normal file
BIN
media/buttons/beeps_still.png
(Stored with Git LFS)
Normal file
BIN
media/buttons/candiedreptile.gif
(Stored with Git LFS)
BIN
media/buttons/candiedreptile_still.png
(Stored with Git LFS)
Normal file
BIN
media/buttons/cdromca.png
(Stored with Git LFS)
BIN
media/buttons/cobalt.png
(Stored with Git LFS)
BIN
media/buttons/cohost.gif
(Stored with Git LFS)
BIN
media/buttons/cohost_still.gif
(Stored with Git LFS)
Normal file
BIN
media/buttons/corru.gif
(Stored with Git LFS)
BIN
media/buttons/corru_still.gif
(Stored with Git LFS)
Normal file
BIN
media/buttons/creature0354_still.png
(Stored with Git LFS)
Normal file
BIN
media/buttons/dex.png
(Stored with Git LFS)
BIN
media/buttons/dino.png
(Stored with Git LFS)
BIN
media/buttons/dusty_still.png
(Stored with Git LFS)
Normal file
BIN
media/buttons/goaty.gif
(Stored with Git LFS)
BIN
media/buttons/goaty_still.gif
(Stored with Git LFS)
Normal file
BIN
media/buttons/gulfie_still.png
(Stored with Git LFS)
Normal file
BIN
media/buttons/hthrflwrs.png
(Stored with Git LFS)
BIN
media/buttons/inhuman.png
(Stored with Git LFS)
BIN
media/buttons/krita.png
(Stored with Git LFS)
BIN
media/buttons/myno_still.png
(Stored with Git LFS)
Normal file
BIN
media/buttons/pebble.gif
(Stored with Git LFS)
BIN
media/buttons/pebble_still.png
(Stored with Git LFS)
Normal file
BIN
media/buttons/renkotsuban.gif
(Stored with Git LFS)
Normal file
BIN
media/buttons/tsunderdog_still.png
(Stored with Git LFS)
Normal file
BIN
media/buttons/tuxedodragon.gif
(Stored with Git LFS)
BIN
media/buttons/tuxedodragon_still.gif
(Stored with Git LFS)
Normal file
BIN
media/chitter.png
(Stored with Git LFS)
|
@ -1 +0,0 @@
|
||||||
<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.41421" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="a"><path clip-rule="evenodd" d="m0 0h32v32h-32z"/></clipPath><metadata/><path d="m0 0h32v32h-32z" fill="none"/><g clip-path="url(#a)"><path d="m0 0h32v32h-32z"/><path d="m30 2h-28v22l1 .5-1 .5v5h28v-5l-1-.5 1-.5z" fill="#4d4d4d"/><path d="m2 24h28v1h-28z" fill="#333"/><g fill="#808080"><path d="m4 26h2v1h-2z"/><path d="m4 28h2v1h-2z"/><path d="m7 26h2v1h-2z"/><path d="m7 28h2v1h-2z"/><path d="m10 26h2v1h-2z"/><path d="m10 28h2v1h-2z"/></g><path d="m25 26h3v3h-3z" fill="#219555"/><circle cx="14.5" cy="27.5" fill="#333" r="1.5"/><circle cx="18.5" cy="27.5" fill="#333" r="1.5"/><circle cx="22.5" cy="27.5" fill="#333" r="1.5"/><path d="m24 4 1 .501 1-.501h.002c1.103 0 1.998.895 1.998 1.998v2.002l-.157.23.037 8.55.12.205v3.015c0 1.105-.895 2-2 2-2.37 0-6 0-6 0l-1-.239-1 .239h-6l-1-.211-1 .211h-4l-1.664-2 .014-6.683-.35-.317v-7c0-.53.211-1.039.586-1.414.124-.125.264-.231.414-.318l1 .304 1-.572h5l1 .376 1-.376h2l1 .535 1-.535z"/><path d="m6 4h1v4h-2v-3.732c.301-.174.646-.268 1-.268z" fill="#060"/><path d="m8 7h2v7h-2z" fill="#060"/><path d="m8 13h2v3h-2z" fill="#0f0"/><path d="m10 14h2v7h-2z" fill="#060"/><path d="m10 20h2v2h-2z" fill="#0f0"/><path d="m12 4h2v5h-2z" fill="#060"/><path d="m12 8h2v3h-2z" fill="#0f0"/><path d="m18 15h2v7h-2z" fill="#060"/><path d="m18 21h2v1h-2z" fill="#0f0"/><path d="m16 4h2v2h-2z" fill="#060"/><path d="m16 5h2v3h-2z" fill="#0f0"/><path d="m22 12h2v7h-2z" fill="#060"/><path d="m22 18h2v3h-2z" fill="#0f0"/><path d="m5 7h2v3h-2z" fill="#0f0"/><path d="m24 4h2v5h-2z" fill="#060"/><path d="m24 8h2v3h-2z" fill="#0f0"/><path d="m15 11h2v7h-2z" fill="#060"/><path d="m15 17h2v3h-2z" fill="#0f0"/><path d="m27 8h1v7h-1z" fill="#060"/><path d="m27 14h1v3h-1z" fill="#0f0"/><path d="m4 13h2v7h-2z" fill="#060"/><path d="m6 19h-2v1c0 1.105.895 2 2 2z" fill="#0f0"/><path d="m20 5h2v7h-2z" fill="#060"/><path d="m20 11h2v3h-2z" fill="#0f0"/></g></svg>
|
|
Before (image error) Size: 2 KiB |
BIN
media/deviantart.png
(Stored with Git LFS)
BIN
media/favicon.png
(Stored with Git LFS)
Normal file
BIN
media/flags/nb.png
(Stored with Git LFS)
BIN
media/flags/pan.png
(Stored with Git LFS)
BIN
media/flags/polyam.png
(Stored with Git LFS)
BIN
media/flags/quoi.png
(Stored with Git LFS)
BIN
media/furaffinity.png
(Stored with Git LFS)
Before (image error) Size: 15 KiB |
BIN
media/icons/artfight.png
(Stored with Git LFS)
Normal file
BIN
media/icons/blog.png
(Stored with Git LFS)
Normal file
Before (image error) Size: 2.2 KiB After (image error) Size: 2.2 KiB |
BIN
media/icons/chitter.png
(Stored with Git LFS)
Normal file
Before (image error) Size: 4.4 KiB After (image error) Size: 4.4 KiB |
BIN
media/icons/deviantart.png
(Stored with Git LFS)
Normal file
Before (image error) Size: 671 B After (image error) Size: 671 B |
BIN
media/icons/furaffinity.png
(Stored with Git LFS)
Normal file
Before (image error) Size: 3 KiB After (image error) Size: 3 KiB |
BIN
media/icons/ko-fi.webp
(Stored with Git LFS)
Normal file
Before (image error) Size: 1.7 KiB After (image error) Size: 1.7 KiB |
Before (image error) Size: 566 B After (image error) Size: 566 B |
BIN
media/kesi-neon.png
(Stored with Git LFS)
BIN
media/kesi-neon.webp
(Stored with Git LFS)
Normal file
BIN
media/kesi.png
(Stored with Git LFS)
BIN
media/ko-fi.webp
Before ![]() (image error) Size: 4.6 KiB |
BIN
media/kra/kesi-neon.kra
(Stored with Git LFS)
Normal file
BIN
media/kra/niss-icon.kra
(Stored with Git LFS)
Normal file
BIN
media/kra/quobl-neon.kra
(Stored with Git LFS)
Normal file
BIN
media/kra/quobl.kra
(Stored with Git LFS)
Normal file
BIN
media/kra/wave-neon.kra
(Stored with Git LFS)
Normal file
BIN
media/kra/wave.kra
(Stored with Git LFS)
Normal file
BIN
media/mlem_static.png
(Stored with Git LFS)
BIN
media/niss-icon.png
(Stored with Git LFS)
BIN
media/quobl-neon.png
(Stored with Git LFS)
BIN
media/quobl-neon.webp
(Stored with Git LFS)
Normal file
BIN
media/quobl.kra
BIN
media/quobl.png
(Stored with Git LFS)
BIN
media/quobl.webp
(Stored with Git LFS)
Normal file
BIN
media/quoxtrans.png
(Stored with Git LFS)
BIN
media/wave-neon.png
(Stored with Git LFS)
BIN
media/wave-neon.webp
(Stored with Git LFS)
Normal file
BIN
media/wave.kra
BIN
media/wave.png
(Stored with Git LFS)
BIN
media/wave.webp
(Stored with Git LFS)
Normal file
166
cube.ts → run.ts
|
@ -1,7 +1,13 @@
|
||||||
type Face = 'front' | 'top' | 'back' | 'bottom' | 'left' | 'right';
|
/** one of the six document sections */
|
||||||
|
export type Pane = 'hello' | 'id' | 'activities' | 'links' | 'friends' | 'six';
|
||||||
|
|
||||||
type Pane = 'hello' | 'id' | 'activities' | 'links' | 'friends' | 'six';
|
export const allPanes: Pane[] =
|
||||||
const panes: Pane[] = ['hello', 'id', 'activities', 'links', 'friends', 'six'];
|
['hello', 'id', 'activities', 'links', 'friends', 'six'];
|
||||||
|
|
||||||
|
namespace Cube {
|
||||||
|
|
||||||
|
/** location on the cube in space */
|
||||||
|
export type Face = 'front' | 'top' | 'back' | 'bottom' | 'left' | 'right';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* - for front, left, right: up is up
|
* - for front, left, right: up is up
|
||||||
|
@ -9,9 +15,9 @@ const panes: Pane[] = ['hello', 'id', 'activities', 'links', 'friends', 'six'];
|
||||||
* - for top: up is away from you
|
* - for top: up is away from you
|
||||||
* - for bottom: up is towards you
|
* - for bottom: up is towards you
|
||||||
*/
|
*/
|
||||||
type Orientation = 'up' | 'left' | 'down' | 'right';
|
export type Orientation = 'up' | 'left' | 'down' | 'right';
|
||||||
|
|
||||||
type Place = [Face, Orientation];
|
export type Place = [Face, Orientation];
|
||||||
|
|
||||||
|
|
||||||
function table<A extends string, B = A>(m: Record<A, B>): (x: A) => B {
|
function table<A extends string, B = A>(m: Record<A, B>): (x: A) => B {
|
||||||
|
@ -26,13 +32,13 @@ const doCcwO =
|
||||||
table<Orientation>({up: 'left', left: 'down', down: 'right', right: 'up'});
|
table<Orientation>({up: 'left', left: 'down', down: 'right', right: 'up'});
|
||||||
|
|
||||||
|
|
||||||
type Direction = 'up' | 'left' | 'down' | 'right';
|
export type RotateXY = 'up' | 'left' | 'down' | 'right';
|
||||||
type Rotation = 'cw' | 'ccw';
|
export type RotateZ = 'cw' | 'ccw';
|
||||||
type Movement = Direction | Rotation;
|
export type Rotation = RotateXY | RotateZ;
|
||||||
|
|
||||||
// if you rotate the cube "up" (along the x axis), face f becomes up(f)
|
// if you rotate the cube "up" (along the x axis), face f becomes up(f)
|
||||||
// et cetera
|
// et cetera
|
||||||
const faceMoves: Record<Movement, (f: Face) => Face> = {
|
const moveF: Record<Rotation, (f: Face) => Face> = {
|
||||||
up: table({
|
up: table({
|
||||||
front: 'top', top: 'back', back: 'bottom',
|
front: 'top', top: 'back', back: 'bottom',
|
||||||
bottom: 'front', left: 'left', right: 'right'
|
bottom: 'front', left: 'left', right: 'right'
|
||||||
|
@ -59,9 +65,7 @@ const faceMoves: Record<Movement, (f: Face) => Face> = {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
const orientationMoves:
|
const moveO: Record<Rotation, (f: Face, o: Orientation) => Orientation> = {
|
||||||
Record<Movement, (f: Face, o: Orientation) => Orientation> =
|
|
||||||
{
|
|
||||||
up(f, o) {
|
up(f, o) {
|
||||||
switch (f) {
|
switch (f) {
|
||||||
case 'left': return doCcwO(o);
|
case 'left': return doCcwO(o);
|
||||||
|
@ -98,40 +102,41 @@ const orientationMoves:
|
||||||
ccw(f, o) { return f == 'back' ? doCwO(o) : doCcwO(o); }
|
ccw(f, o) { return f == 'back' ? doCwO(o) : doCcwO(o); }
|
||||||
};
|
};
|
||||||
|
|
||||||
function applyMoves([f, o]: Place, ms: Movement[]): Place {
|
export function applyMoves(p: Place, ms: Rotation[]): Place {
|
||||||
for (const m of ms) {
|
return ms.reduce(([f, o], m) => [moveF[m](f), moveO[m](f, o)], p);
|
||||||
o = orientationMoves[m](f, o);
|
|
||||||
f = faceMoves[m](f);
|
|
||||||
}
|
|
||||||
return [f, o];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const toFront = table<Face, Direction[]>({
|
/** the sequence of movements to put this place on the front */
|
||||||
|
export function toFrontUpright([f, o]: Place): [RotateXY[], RotateZ[]] {
|
||||||
|
const toFront: (f: Face) => RotateXY[] =
|
||||||
|
table<Face, RotateXY[]>({
|
||||||
front: [], top: ['down'], back: ['left', 'left'],
|
front: [], top: ['down'], back: ['left', 'left'],
|
||||||
bottom: ['up'], left: ['right'], right: ['left']
|
bottom: ['up'], left: ['right'], right: ['left']
|
||||||
});
|
});
|
||||||
|
|
||||||
const toUpright = table<Orientation, Rotation[]>({
|
const toUpright: (o: Orientation) => RotateZ[] =
|
||||||
|
table<Orientation, RotateZ[]>({
|
||||||
up: [], left: ['cw'], down: ['cw', 'cw'], right: ['ccw']
|
up: [], left: ['cw'], down: ['cw', 'cw'], right: ['ccw']
|
||||||
});
|
});
|
||||||
|
|
||||||
function toFrontUpright([f, o]: Place): [Direction[], Rotation[]] {
|
|
||||||
const directions = toFront(f);
|
const directions = toFront(f);
|
||||||
const rotations = toUpright(applyMoves([f, o], directions)[1]);
|
const rotations = toUpright(applyMoves([f, o], directions)[1]);
|
||||||
return [directions, rotations];
|
return [directions, rotations];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const movementToTransform = table<Movement, string>({
|
const movementToTransform = table<Rotation, string>({
|
||||||
up: 'rotateX(.25turn)', down: 'rotateX(-.25turn)',
|
up: 'rotateX(.25turn)', down: 'rotateX(-.25turn)',
|
||||||
left: 'rotateY(-.25turn)', right: 'rotateY(.25turn)',
|
left: 'rotateY(-.25turn)', right: 'rotateY(.25turn)',
|
||||||
cw: 'rotateZ(.25turn)', ccw: 'rotateZ(-.25turn)'
|
cw: 'rotateZ(.25turn)', ccw: 'rotateZ(-.25turn)'
|
||||||
});
|
});
|
||||||
|
|
||||||
function movementsToTransform(ms: Movement[]) {
|
/** the css `transform` value corresponding to this sequence of movements */
|
||||||
return ms.map(movementToTransform).join(' ');
|
export function movementsToTransform(ms: Rotation[]): string {
|
||||||
|
return ms.length > 0 ? ms.map(movementToTransform).join(' ') : 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const faceToTransform = table<Face, string>({
|
const faceToTransform = table<Face, string>({
|
||||||
front: '', top: 'rotateX(.25turn)',
|
front: '', top: 'rotateX(.25turn)',
|
||||||
back: 'rotateX(.5turn)', bottom: 'rotateX(-.25turn)',
|
back: 'rotateX(.5turn)', bottom: 'rotateX(-.25turn)',
|
||||||
|
@ -143,52 +148,57 @@ const orientationToTransform = table<Orientation, string>({
|
||||||
down: 'rotateZ(-.5turn)', right: 'rotateZ(.25turn)'
|
down: 'rotateZ(-.5turn)', right: 'rotateZ(.25turn)'
|
||||||
});
|
});
|
||||||
|
|
||||||
function toTransform(f: Face, o: Orientation): string {
|
/**
|
||||||
|
* the css `transform` value that will bring the given place to the
|
||||||
|
* front and upright
|
||||||
|
*/
|
||||||
|
export function placeToTransform([f, o]: Place): string {
|
||||||
const ft = faceToTransform(f);
|
const ft = faceToTransform(f);
|
||||||
const ot = orientationToTransform(o);
|
const ot = orientationToTransform(o);
|
||||||
return ft || ot ? `${ft} ${ot}` : 'none';
|
return ft || ot ? `${ft} ${ot}` : 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Conf = Record<Pane, Place>;
|
/** a map of where each pane is on the cube */
|
||||||
|
export type Conf = Record<Pane, Place>;
|
||||||
|
|
||||||
// the back face is 'down' so it has the same visual orientation as other side faces
|
/** initial cube configuration with `hello` at the front */
|
||||||
let current: Conf = {
|
let current: Conf = {
|
||||||
hello: ['front', 'up'], id: ['left', 'up'],
|
hello: ['front', 'up'], id: ['left', 'up'],
|
||||||
activities: ['back', 'down'], links: ['right', 'up'],
|
activities: ['back', 'down'], links: ['right', 'up'],
|
||||||
friends: ['bottom', 'up'], six: ['top', 'up'],
|
friends: ['bottom', 'up'], six: ['top', 'up'],
|
||||||
};
|
};
|
||||||
|
// the back face is 'down' so it has the same visual orientation as other side
|
||||||
|
// faces
|
||||||
|
|
||||||
function applyConfiguration(): void {
|
/** apply the css transforms to each pane element */
|
||||||
for (const pane of panes) {
|
export function applyConfiguration(): void {
|
||||||
|
for (const pane of allPanes) {
|
||||||
const element = document.getElementById(pane)!;
|
const element = document.getElementById(pane)!;
|
||||||
const [face, ori] = current[pane];
|
const place = current[pane];
|
||||||
|
|
||||||
element.style.setProperty('--base-transform', toTransform(face, ori));
|
element.style.setProperty('--base-transform', placeToTransform(place));
|
||||||
element.style.pointerEvents = face == 'front' ? 'auto' : 'none';
|
element.style.pointerEvents = place[0] == 'front' ? 'auto' : 'none';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function move(c: Conf, ...ms: Movement[]): Conf {
|
export function move(c: Conf, ...ms: Rotation[]): Conf {
|
||||||
let res: Partial<Conf> = {};
|
let res: Partial<Conf> = {};
|
||||||
for (const p of panes) { res[p] = applyMoves(c[p], ms) }
|
for (const pane of allPanes) { res[pane] = applyMoves(c[pane], ms) }
|
||||||
return res as Conf;
|
return res as Conf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function animateMoveWith(ds: Direction[], rs: Rotation[]): void {
|
export function animateMoveWith(ds: RotateXY[], rs: RotateZ[]): void {
|
||||||
const outer = document.getElementById('outer')!;
|
const outer = document.getElementById('outer')!;
|
||||||
const cube = document.getElementById('cube')!;
|
const cube = document.getElementById('cube')!;
|
||||||
|
|
||||||
cube.dataset.moving = 'true';
|
cube.dataset.moving = 'true';
|
||||||
|
|
||||||
cube.style.transition = '0.4s cubic-bezier(.4, -0.29, .43, 1.26)';
|
cube.style.transition = '0.4s cubic-bezier(.4, -0.29, .43, 1.26)';
|
||||||
outer.style.transition = `0.4s 0.25s cubic-bezier(.48, 0, .44, 1.07)`;
|
outer.style.transition = `0.4s 0.25s cubic-bezier(.48, 0, .44, 1.07)`;
|
||||||
|
|
||||||
function transitionListener(elem: HTMLElement): () => void {
|
function transitionListener(elem: HTMLElement): () => void {
|
||||||
function handler(e: Event) {
|
function handler(e: Event) { if (e.target == elem) { finish(); } }
|
||||||
if (e.target == elem) { finish(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
elem.addEventListener('transitionend', handler);
|
elem.addEventListener('transitionend', handler);
|
||||||
return () => elem.removeEventListener('transitionend', handler);
|
return () => elem.removeEventListener('transitionend', handler);
|
||||||
|
@ -210,48 +220,84 @@ function animateMoveWith(ds: Direction[], rs: Rotation[]): void {
|
||||||
function finish() {
|
function finish() {
|
||||||
removeOuter(); removeCube();
|
removeOuter(); removeCube();
|
||||||
|
|
||||||
outer.style.transition = cube.style.transition =
|
|
||||||
outer.style.transform = cube.style.transform = 'none';
|
|
||||||
delete cube.dataset.moving;
|
delete cube.dataset.moving;
|
||||||
|
outer.style.transition = cube.style.transition = 'none';
|
||||||
|
outer.style.transform = cube.style.transform = 'none';
|
||||||
|
|
||||||
current = move(current, ...ds, ...rs);
|
current = move(current, ...ds, ...rs);
|
||||||
applyConfiguration();
|
applyConfiguration();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function animateMoveTo(pane: Pane): void {
|
export function animateMoveTo(pane: Pane): void {
|
||||||
const [ds, rs] = toFrontUpright(current[pane]);
|
animateMoveWith(...toFrontUpright(current[pane]));
|
||||||
|
history.replaceState(null, '🦎', `#${pane}`);
|
||||||
|
}
|
||||||
|
|
||||||
animateMoveWith(ds, rs);
|
export function squashCube() {
|
||||||
history.replaceState(null, '', `#${pane}`);
|
for (const pane of allPanes) {
|
||||||
|
const elem = document.getElementById(pane)!
|
||||||
|
elem.style.setProperty('--base-transform', 'none');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function instantMoveTo(pane: Pane): void {
|
||||||
|
current = move(current, ...toFrontUpright(current[pane]).flat());
|
||||||
|
applyConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LEFT() { animateMoveWith(['left'], []); }
|
||||||
|
export function RIGHT() { animateMoveWith(['right'], []); }
|
||||||
|
export function UP() { animateMoveWith(['up'], []); }
|
||||||
|
export function DOWN() { animateMoveWith(['down'], []); }
|
||||||
|
export function CW() { animateMoveWith([], ['cw']); }
|
||||||
|
export function CCW() { animateMoveWith([], ['ccw']); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace Flat {
|
||||||
|
|
||||||
|
export function fadeTo(newPane: Pane): void {
|
||||||
|
for (const pane of allPanes) {
|
||||||
|
const here = pane == newPane;
|
||||||
|
document.getElementById(pane)!.dataset.selected = `${here}`;
|
||||||
|
if (here) { history.replaceState(null, '🦎', `#${pane}`); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let reducedMotion =
|
||||||
|
matchMedia(`(prefers-reduced-motion: reduce),
|
||||||
|
(max-height: 649px), (max-width: 649px)`);
|
||||||
|
|
||||||
|
function switchTo(pane: Pane): void {
|
||||||
|
if (reducedMotion.matches) { Cube.instantMoveTo(pane); }
|
||||||
|
else { Cube.animateMoveTo(pane); }
|
||||||
|
Flat.fadeTo(pane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function setup(): void {
|
function setup(): void {
|
||||||
for (const pane of panes) {
|
const here = location.hash.slice(1) || 'hello';
|
||||||
|
|
||||||
|
for (const pane of allPanes) {
|
||||||
const box = document.getElementById(`b-${pane}`) as HTMLInputElement;
|
const box = document.getElementById(`b-${pane}`) as HTMLInputElement;
|
||||||
box.addEventListener('change', () => {
|
box.addEventListener('change', () => {
|
||||||
if (box.checked) { animateMoveTo(pane); }
|
if (box.checked) { switchTo(pane); }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (location.hash == `#${pane}`) {
|
if (pane == here) {
|
||||||
current = move(current, ...toFrontUpright(current[pane]).flat());
|
Cube.instantMoveTo(pane);
|
||||||
|
Flat.fadeTo(pane);
|
||||||
box.checked = true;
|
box.checked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
applyConfiguration();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', setup);
|
document.addEventListener('DOMContentLoaded', setup);
|
||||||
|
|
||||||
/*
|
|
||||||
function LEFT() { animateMoveWith(['left'], []); }
|
|
||||||
function RIGHT() { animateMoveWith(['right'], []); }
|
|
||||||
function UP() { animateMoveWith(['up'], []); }
|
|
||||||
function DOWN() { animateMoveWith(['down'], []); }
|
|
||||||
function CW() { animateMoveWith([], ['cw']); }
|
|
||||||
function CCW() { animateMoveWith([], ['ccw']); }
|
|
||||||
*/
|
|
||||||
|
|
||||||
export {};
|
export {};
|
57
static.css
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/* (removing the cube shadow) */
|
||||||
|
html { background: var(--gradient) fixed; }
|
||||||
|
|
||||||
|
body { display: unset; }
|
||||||
|
|
||||||
|
/* doesn't do anything without js */
|
||||||
|
#face-menu { display: none; }
|
||||||
|
|
||||||
|
#outer, #cube {
|
||||||
|
position: unset;
|
||||||
|
height: unset;
|
||||||
|
width: unset;
|
||||||
|
max-width: max(100%, 45em);
|
||||||
|
}
|
||||||
|
|
||||||
|
#outer::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#outer {
|
||||||
|
margin: 2em auto 5em;
|
||||||
|
padding: 0 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cube > section {
|
||||||
|
position: relative;
|
||||||
|
inset: unset;
|
||||||
|
overflow: unset;
|
||||||
|
}
|
||||||
|
#cube > section + section {
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
#cube > section::after {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
inset: calc(0px - var(--border-thickness));
|
||||||
|
box-shadow: 0 0 40px hsl(var(--shadow-hsl) / 40%);
|
||||||
|
mix-blend-mode: multiply;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cube #hello {
|
||||||
|
background-size: auto 95%, auto, auto;
|
||||||
|
background-position: bottom right;
|
||||||
|
padding-right: 45%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cube #activities {
|
||||||
|
background-size: auto 5em, auto, auto;
|
||||||
|
background-position: bottom left;
|
||||||
|
padding-bottom: 6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cube #six {
|
||||||
|
background-size: auto 100%, auto, auto;
|
||||||
|
background-position: bottom right;
|
||||||
|
}
|