mirror of
https://github.com/RGBCube/Site
synced 2025-08-01 13:37:49 +00:00
Add styles
This commit is contained in:
parent
f485e299d8
commit
21eb0464bf
8 changed files with 604 additions and 47 deletions
|
@ -1,6 +1,7 @@
|
||||||
import lume from "lume/mod.ts";
|
import lume from "lume/mod.ts";
|
||||||
|
|
||||||
import codeHighlight from "lume/plugins/code_highlight.ts";
|
import codeHighlight from "lume/plugins/code_highlight.ts";
|
||||||
|
import esbuild from "lume/plugins/esbuild.ts";
|
||||||
import feed from "lume/plugins/feed.ts";
|
import feed from "lume/plugins/feed.ts";
|
||||||
import jsx from "lume/plugins/jsx.ts";
|
import jsx from "lume/plugins/jsx.ts";
|
||||||
import minifyHTML from "lume/plugins/minify_html.ts";
|
import minifyHTML from "lume/plugins/minify_html.ts";
|
||||||
|
@ -10,6 +11,7 @@ const site = lume({
|
||||||
});
|
});
|
||||||
|
|
||||||
site.use(codeHighlight());
|
site.use(codeHighlight());
|
||||||
|
site.use(esbuild());
|
||||||
site.use(jsx());
|
site.use(jsx());
|
||||||
site.use(minifyHTML());
|
site.use(minifyHTML());
|
||||||
|
|
||||||
|
|
6
deno.lock
generated
6
deno.lock
generated
|
@ -2838,6 +2838,10 @@
|
||||||
"https://deno.land/x/deno_dom@v0.1.43/src/dom/utils-types.ts": "96db30e3e4a75b194201bb9fa30988215da7f91b380fca6a5143e51ece2a8436",
|
"https://deno.land/x/deno_dom@v0.1.43/src/dom/utils-types.ts": "96db30e3e4a75b194201bb9fa30988215da7f91b380fca6a5143e51ece2a8436",
|
||||||
"https://deno.land/x/deno_dom@v0.1.43/src/dom/utils.ts": "4c6206516fb8f61f37a209c829e812c4f5a183e46d082934dd14c91bde939263",
|
"https://deno.land/x/deno_dom@v0.1.43/src/dom/utils.ts": "4c6206516fb8f61f37a209c829e812c4f5a183e46d082934dd14c91bde939263",
|
||||||
"https://deno.land/x/deno_dom@v0.1.43/src/parser.ts": "e06b2300d693e6ae7564e53dfa5c9a9e97fdb8c044c39c52c8b93b5d60860be3",
|
"https://deno.land/x/deno_dom@v0.1.43/src/parser.ts": "e06b2300d693e6ae7564e53dfa5c9a9e97fdb8c044c39c52c8b93b5d60860be3",
|
||||||
|
"https://deno.land/x/denoflate@1.2.1/mod.ts": "f5628e44b80b3d80ed525afa2ba0f12408e3849db817d47a883b801f9ce69dd6",
|
||||||
|
"https://deno.land/x/denoflate@1.2.1/pkg/denoflate.js": "b9f9ad9457d3f12f28b1fb35c555f57443427f74decb403113d67364e4f2caf4",
|
||||||
|
"https://deno.land/x/denoflate@1.2.1/pkg/denoflate_bg.wasm.js": "d581956245407a2115a3d7e8d85a9641c032940a8e810acbd59ca86afd34d44d",
|
||||||
|
"https://deno.land/x/esbuild@v0.19.11/mod.js": "bd4916647799a0cd046dcf4eafd6ace09d22d5898870bd062206b8b6343d5e6a",
|
||||||
"https://deno.land/x/lume@v2.0.3/cli.ts": "ec79a3b06406f163de3c9228ffa3ab2381409fd3441056d7d67093a3259f477c",
|
"https://deno.land/x/lume@v2.0.3/cli.ts": "ec79a3b06406f163de3c9228ffa3ab2381409fd3441056d7d67093a3259f477c",
|
||||||
"https://deno.land/x/lume@v2.0.3/cli/build.ts": "f8c1068fd2b06df526d6d6c6e63ff7022049ce5ce1b133f2e4d74c0b3788c099",
|
"https://deno.land/x/lume@v2.0.3/cli/build.ts": "f8c1068fd2b06df526d6d6c6e63ff7022049ce5ce1b133f2e4d74c0b3788c099",
|
||||||
"https://deno.land/x/lume@v2.0.3/cli/create.ts": "85b0cf567e452616ea55ab9742f84957c385bb38d3f8b3fbcfd8c86dbcbc326c",
|
"https://deno.land/x/lume@v2.0.3/cli/create.ts": "85b0cf567e452616ea55ab9742f84957c385bb38d3f8b3fbcfd8c86dbcbc326c",
|
||||||
|
@ -2890,6 +2894,7 @@
|
||||||
"https://deno.land/x/lume@v2.0.3/deps/colors.ts": "659aa4bc7885d2d5f4f4c47da14b6bf04b3595535c491f27e3ce9c802934818e",
|
"https://deno.land/x/lume@v2.0.3/deps/colors.ts": "659aa4bc7885d2d5f4f4c47da14b6bf04b3595535c491f27e3ce9c802934818e",
|
||||||
"https://deno.land/x/lume@v2.0.3/deps/crypto.ts": "fb72af775aae9fb4d64b6e502a221668961a63ec7bab5678827e0cea46ded4e2",
|
"https://deno.land/x/lume@v2.0.3/deps/crypto.ts": "fb72af775aae9fb4d64b6e502a221668961a63ec7bab5678827e0cea46ded4e2",
|
||||||
"https://deno.land/x/lume@v2.0.3/deps/dom.ts": "7eef681d9eabb49c2fb230faa75e33371ab7bbe30a03f4f4c7d6d723742f775a",
|
"https://deno.land/x/lume@v2.0.3/deps/dom.ts": "7eef681d9eabb49c2fb230faa75e33371ab7bbe30a03f4f4c7d6d723742f775a",
|
||||||
|
"https://deno.land/x/lume@v2.0.3/deps/esbuild.ts": "e36187b1f1d5872631d4d9a846b99478fc31efe983d4d8709106f367e4dd2874",
|
||||||
"https://deno.land/x/lume@v2.0.3/deps/front_matter.ts": "5d023497eace3b327d4c1037a837ac8e0b6adf2b40310edbd881008176ddfaa2",
|
"https://deno.land/x/lume@v2.0.3/deps/front_matter.ts": "5d023497eace3b327d4c1037a837ac8e0b6adf2b40310edbd881008176ddfaa2",
|
||||||
"https://deno.land/x/lume@v2.0.3/deps/fs.ts": "86601d766967917078c94225d625dfb83a0f3c14dabc32ed97fe9aecb01f7b12",
|
"https://deno.land/x/lume@v2.0.3/deps/fs.ts": "86601d766967917078c94225d625dfb83a0f3c14dabc32ed97fe9aecb01f7b12",
|
||||||
"https://deno.land/x/lume@v2.0.3/deps/hex.ts": "13a69c4cd15a1727b878a8c64d592301dec2ee928ca4b372c4fdac32bb92af2a",
|
"https://deno.land/x/lume@v2.0.3/deps/hex.ts": "13a69c4cd15a1727b878a8c64d592301dec2ee928ca4b372c4fdac32bb92af2a",
|
||||||
|
@ -2925,6 +2930,7 @@
|
||||||
"https://deno.land/x/lume@v2.0.3/plugins/attributes.ts": "663afd522016ca597571820088af2e853d1341d44f11694cfc05265ea5efeda7",
|
"https://deno.land/x/lume@v2.0.3/plugins/attributes.ts": "663afd522016ca597571820088af2e853d1341d44f11694cfc05265ea5efeda7",
|
||||||
"https://deno.land/x/lume@v2.0.3/plugins/base_path.ts": "ab451b1c6911fbf4f3babf1e41e31500e3402e31b6a0b810418a2f3e1052ccdb",
|
"https://deno.land/x/lume@v2.0.3/plugins/base_path.ts": "ab451b1c6911fbf4f3babf1e41e31500e3402e31b6a0b810418a2f3e1052ccdb",
|
||||||
"https://deno.land/x/lume@v2.0.3/plugins/code_highlight.ts": "bd4ef987c4fd05c1c585238a490f9f56d48daefd4748b4647219575b8e1d42c0",
|
"https://deno.land/x/lume@v2.0.3/plugins/code_highlight.ts": "bd4ef987c4fd05c1c585238a490f9f56d48daefd4748b4647219575b8e1d42c0",
|
||||||
|
"https://deno.land/x/lume@v2.0.3/plugins/esbuild.ts": "a1b5bc51acdbe82b8ec179d922bc1cab898a834a38d3b75b8fdfa0920264a9e8",
|
||||||
"https://deno.land/x/lume@v2.0.3/plugins/feed.ts": "d6573ac801319cd842e0b260fd1645450c1aeb983fe1877fcdc243ad4c66f7fc",
|
"https://deno.land/x/lume@v2.0.3/plugins/feed.ts": "d6573ac801319cd842e0b260fd1645450c1aeb983fe1877fcdc243ad4c66f7fc",
|
||||||
"https://deno.land/x/lume@v2.0.3/plugins/inline.ts": "44ab46c70ff3461d33c727c571deb592126f12eb08790467ffdce2438f8c9471",
|
"https://deno.land/x/lume@v2.0.3/plugins/inline.ts": "44ab46c70ff3461d33c727c571deb592126f12eb08790467ffdce2438f8c9471",
|
||||||
"https://deno.land/x/lume@v2.0.3/plugins/json.ts": "f6429bbd865e3666ef3385fd205fcc92df02ca2c0f74f20baa5c0798a81e1642",
|
"https://deno.land/x/lume@v2.0.3/plugins/json.ts": "f6429bbd865e3666ef3385fd205fcc92df02ca2c0f74f20baa5c0798a81e1642",
|
||||||
|
|
38
site/404.tsx
38
site/404.tsx
|
@ -18,6 +18,43 @@ export default (_data: Lume.Data, helpers: Lume.Helpers) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<style
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: `
|
||||||
|
.face {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
grid-template-rows: repeat(2, 1fr);
|
||||||
|
box-shadow: 0 0 10px whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
.square {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.black {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magenta {
|
||||||
|
background-color: magenta;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame {
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
</style>
|
||||||
<Cube
|
<Cube
|
||||||
front={face}
|
front={face}
|
||||||
back={face}
|
back={face}
|
||||||
|
@ -26,5 +63,6 @@ export default (_data: Lume.Data, helpers: Lume.Helpers) => {
|
||||||
top={face}
|
top={face}
|
||||||
bottom={face}
|
bottom={face}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,6 +51,28 @@
|
||||||
<link rel="stylesheet" href="/assets/fonts.css">
|
<link rel="stylesheet" href="/assets/fonts.css">
|
||||||
</head">
|
</head">
|
||||||
<body>
|
<body>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
height: 100dvh;
|
||||||
|
width: 100dvw;
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration-line: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
{{ content }}
|
{{ content }}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -12,6 +12,97 @@ interface CubeProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Cube = (props: CubeProps) => (
|
const Cube = (props: CubeProps) => (
|
||||||
|
<>
|
||||||
|
<style
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: `
|
||||||
|
html {
|
||||||
|
font-size: min(9vw, 9vh, 4.5em);
|
||||||
|
overscroll-behavior: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: black;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame {
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
width: min-content;
|
||||||
|
|
||||||
|
padding: 0 0.3em;
|
||||||
|
border-radius: 1em;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame:hover {
|
||||||
|
background-color: yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene {
|
||||||
|
height: 100dvh;
|
||||||
|
width: 100dvw;
|
||||||
|
perspective: 15em;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cube {
|
||||||
|
height: 5em;
|
||||||
|
width: 5em;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
transform: translateZ(-calc(2.5em - 1px));
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.face {
|
||||||
|
width: 5em;
|
||||||
|
height: 5em;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.front {
|
||||||
|
transform: rotateY(0deg) translateZ(calc(2.5em - 1px));
|
||||||
|
}
|
||||||
|
|
||||||
|
.top {
|
||||||
|
/* Guess what? Yeah, you guessed right. Safari can't render shit. */
|
||||||
|
transform: rotateX(89.99999999999999deg) translateZ(calc(2.5em - 1px));
|
||||||
|
}
|
||||||
|
|
||||||
|
.back {
|
||||||
|
transform: rotateY(180deg) translateZ(calc(2.5em - 1px));
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom {
|
||||||
|
transform: rotateX(-89.99999999999999deg) translateZ(calc(2.5em - 1px));
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
transform: rotateY(89.99999999999999deg) translateZ(calc(2.5em - 1px));
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
transform: rotateY(-89.99999999999999deg) translateZ(calc(2.5em - 1px));
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
</style>
|
||||||
|
|
||||||
<div className="scene">
|
<div className="scene">
|
||||||
<div className="cube">
|
<div className="cube">
|
||||||
<div className="face front">{props.front || empty}</div>
|
<div className="face front">{props.front || empty}</div>
|
||||||
|
@ -22,6 +113,9 @@ const Cube = (props: CubeProps) => (
|
||||||
<div className="face bottom">{props.bottom || empty}</div>
|
<div className="face bottom">{props.bottom || empty}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="/assets/cube.js"></script>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default Cube;
|
export default Cube;
|
||||||
|
|
|
@ -2,13 +2,92 @@
|
||||||
layout: base.vto
|
layout: base.vto
|
||||||
---
|
---
|
||||||
|
|
||||||
<nav>
|
<style>
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4 {
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
text-wrap: pretty;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered {
|
||||||
|
font-size: large;
|
||||||
|
|
||||||
|
display: initial;
|
||||||
|
width: min(100vw - 2em, 50em);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rotated {
|
||||||
|
transform: rotateX(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
font-size: larger;
|
||||||
|
word-break: normal;
|
||||||
|
|
||||||
|
overflow-wrap: normal;
|
||||||
|
overflow-x: auto;
|
||||||
|
|
||||||
|
background-color: white;
|
||||||
|
padding: 0.3em 0.6em;
|
||||||
|
|
||||||
|
/* Rotated 180deg so it's top instead of bottom. */
|
||||||
|
border-top-left-radius: 1em;
|
||||||
|
border-top-right-radius: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a {
|
||||||
|
color: black;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 0.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
border-top: 0.15em solid white;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
font-size: small;
|
||||||
|
|
||||||
|
margin-bottom: 1em;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="centered">
|
||||||
|
<nav class="rotated">
|
||||||
|
<div class="rotated">
|
||||||
<a href="/">HOME</a>
|
<a href="/">HOME</a>
|
||||||
<a href="/about">ABOUT</a>
|
<a href="/about">ABOUT</a>
|
||||||
<a href="/blog">BLOG</a>
|
<a href="/blog">BLOG</a>
|
||||||
<a href="/contact">CONTACT</a>
|
<a href="/contact">CONTACT</a>
|
||||||
</nav>
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<div class="content">{{ content }}</div>
|
<div class="content">{{ content }}</div>
|
||||||
|
|
||||||
<footer>Copyright © RGBCube</footer>
|
<footer>Copyright © RGBCube</footer>
|
||||||
|
</div>
|
||||||
|
|
241
site/assets/cube.ts
Normal file
241
site/assets/cube.ts
Normal file
|
@ -0,0 +1,241 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
class Vec3 {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
z: number;
|
||||||
|
|
||||||
|
constructor(x: number, y: number, z: number) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
static zero() {
|
||||||
|
return new Vec3(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
length() {
|
||||||
|
return Math.sqrt(this.x ** 2 + this.y ** 2 + this.z ** 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
scale(factor: number) {
|
||||||
|
this.x *= factor;
|
||||||
|
this.y *= factor;
|
||||||
|
this.z *= factor;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize() {
|
||||||
|
const length = this.length();
|
||||||
|
|
||||||
|
if (length != 0) {
|
||||||
|
this.x /= length;
|
||||||
|
this.y /= length;
|
||||||
|
this.z /= length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static sub(v: Vec3, t: Vec3) {
|
||||||
|
return new Vec3(
|
||||||
|
v.x - t.x,
|
||||||
|
v.y - t.y,
|
||||||
|
v.z - t.z,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static sum(v: Vec3, t: Vec3) {
|
||||||
|
return new Vec3(
|
||||||
|
v.x + t.x,
|
||||||
|
v.y + t.y,
|
||||||
|
v.z + t.z,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Quat {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
z: number;
|
||||||
|
w: number;
|
||||||
|
|
||||||
|
constructor(x: number, y: number, z: number, w: number) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
this.w = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromAxis(axis: Vec3) {
|
||||||
|
const angle = axis.length();
|
||||||
|
|
||||||
|
axis.normalize();
|
||||||
|
|
||||||
|
const half = angle / 2;
|
||||||
|
|
||||||
|
const sinHalf = Math.sin(half);
|
||||||
|
const cosHalf = Math.cos(half);
|
||||||
|
|
||||||
|
const x = axis.x * sinHalf;
|
||||||
|
const y = axis.y * sinHalf;
|
||||||
|
const z = axis.z * sinHalf;
|
||||||
|
const w = cosHalf;
|
||||||
|
|
||||||
|
return new Quat(x, y, z, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static mul(q: Quat, r: Quat) {
|
||||||
|
return new Quat(
|
||||||
|
q.w * r.x + q.x * r.w + q.y * r.z - q.z * r.y,
|
||||||
|
q.w * r.y - q.x * r.z + q.y * r.w + q.z * r.x,
|
||||||
|
q.w * r.z + q.x * r.y - q.y * r.x + q.z * r.w,
|
||||||
|
q.w * r.w - q.x * r.x - q.y * r.y - q.z * r.z,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const friction = 3;
|
||||||
|
const sensitivity = 0.01;
|
||||||
|
|
||||||
|
const mouse = {
|
||||||
|
down: false,
|
||||||
|
lastMove: -10000,
|
||||||
|
previous: Vec3.zero(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const orient = {
|
||||||
|
__cube: document.querySelector(".cube"),
|
||||||
|
__value: new Quat(0, 0, 0, 1),
|
||||||
|
|
||||||
|
set(value: Quat) {
|
||||||
|
this.__value = value;
|
||||||
|
|
||||||
|
const q = this.__value;
|
||||||
|
|
||||||
|
// @ts-ignore: Style will never be null.
|
||||||
|
this.__cube.style.transform = `rotate3d(${q.x}, ${q.y}, ${q.z}, ${
|
||||||
|
Math.acos(q.w) * 2
|
||||||
|
}rad)`;
|
||||||
|
},
|
||||||
|
|
||||||
|
get(): Quat {
|
||||||
|
return this.__value;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let velocity = Vec3.zero();
|
||||||
|
let impulseThisFrame = Vec3.zero();
|
||||||
|
|
||||||
|
const handleUp = () => {
|
||||||
|
mouse.down = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("mouseup", handleUp);
|
||||||
|
document.addEventListener("touchend", handleUp);
|
||||||
|
|
||||||
|
const handleDown = (event: MouseEvent | TouchEvent) => {
|
||||||
|
// Disables link dragging that occurs when spinning.
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
mouse.down = true;
|
||||||
|
|
||||||
|
velocity = Vec3.zero();
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("mousedown", handleDown);
|
||||||
|
document.addEventListener("touchstart", handleDown);
|
||||||
|
|
||||||
|
const handleMove = (event: MouseEvent) => {
|
||||||
|
// Disables scrolling.
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (!mouse.down) return;
|
||||||
|
|
||||||
|
const newMouse = new Vec3(event.clientX, event.clientY, 0);
|
||||||
|
|
||||||
|
const timeDelta = (window.performance.now() - mouse.lastMove) / 1000;
|
||||||
|
|
||||||
|
if (timeDelta > 0.1) {
|
||||||
|
// This is a fresh scroll.
|
||||||
|
mouse.previous = newMouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
const delta = Vec3.sub(newMouse, mouse.previous);
|
||||||
|
|
||||||
|
mouse.previous = newMouse;
|
||||||
|
mouse.lastMove = window.performance.now();
|
||||||
|
|
||||||
|
const axis = new Vec3(-delta.y, delta.x, 0)
|
||||||
|
.normalize()
|
||||||
|
.scale(delta.length() * sensitivity);
|
||||||
|
|
||||||
|
impulseThisFrame = Vec3.sum(impulseThisFrame, axis);
|
||||||
|
|
||||||
|
const rotation = Quat.fromAxis(axis);
|
||||||
|
|
||||||
|
orient.set(Quat.mul(rotation, orient.get()));
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("mousemove", handleMove);
|
||||||
|
document.addEventListener("touchmove", (event) => {
|
||||||
|
const delta = event.changedTouches[0];
|
||||||
|
|
||||||
|
// @ts-ignore: We are overriding this for it to work as a MouseEvent.
|
||||||
|
event.clientX = delta.clientX;
|
||||||
|
// @ts-ignore:
|
||||||
|
event.clientY = delta.clientY;
|
||||||
|
|
||||||
|
handleMove(event as object as MouseEvent);
|
||||||
|
});
|
||||||
|
|
||||||
|
let lastUpdate = 0;
|
||||||
|
|
||||||
|
const updateFrame = (timestamp: number) => {
|
||||||
|
if (lastUpdate == 0) lastUpdate = timestamp;
|
||||||
|
|
||||||
|
const delta = (timestamp - lastUpdate) / 1000;
|
||||||
|
lastUpdate = timestamp;
|
||||||
|
|
||||||
|
if (mouse.down) {
|
||||||
|
velocity = impulseThisFrame.scale(1 / delta);
|
||||||
|
impulseThisFrame = Vec3.zero();
|
||||||
|
} else {
|
||||||
|
const decay = Math.exp(-delta * friction);
|
||||||
|
|
||||||
|
const effectiveDelta = friction > 0 ? (1 - decay) / friction : delta;
|
||||||
|
|
||||||
|
let theta = effectiveDelta * velocity.length();
|
||||||
|
|
||||||
|
velocity.x *= decay;
|
||||||
|
velocity.y *= decay;
|
||||||
|
velocity.z *= decay;
|
||||||
|
|
||||||
|
if (friction > 0 && velocity.length() < 0.00001) {
|
||||||
|
theta += velocity.length() / friction;
|
||||||
|
|
||||||
|
velocity.x = 0;
|
||||||
|
velocity.y = 0;
|
||||||
|
velocity.z = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.performance.now() - mouse.lastMove > 10000) {
|
||||||
|
const impulse = new Vec3(0.7, 0.7, -0.7);
|
||||||
|
velocity = Vec3.sum(impulse.scale(effectiveDelta * 3), velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
const axis = new Vec3(velocity.x, velocity.y, velocity.z)
|
||||||
|
.normalize()
|
||||||
|
.scale(theta);
|
||||||
|
|
||||||
|
const rotation = Quat.fromAxis(axis);
|
||||||
|
|
||||||
|
orient.set(Quat.mul(rotation, orient.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(updateFrame);
|
||||||
|
};
|
||||||
|
|
||||||
|
updateFrame(0);
|
|
@ -3,6 +3,80 @@ import Cube from "./_includes/cube.tsx";
|
||||||
export const title = "RGBCube";
|
export const title = "RGBCube";
|
||||||
|
|
||||||
export default (
|
export default (
|
||||||
|
<>
|
||||||
|
<style
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: `
|
||||||
|
.face::after {
|
||||||
|
z-index: -1;
|
||||||
|
|
||||||
|
content: "";
|
||||||
|
|
||||||
|
height: inherit;
|
||||||
|
width: inherit;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* I do not regret writing this. It's beautiful. */
|
||||||
|
|
||||||
|
.front {
|
||||||
|
background: linear-gradient(to bottom, cyan, blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.front::after {
|
||||||
|
background: linear-gradient(to bottom, white, magenta);
|
||||||
|
mask-image: linear-gradient(to left, magenta, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top {
|
||||||
|
background: linear-gradient(to bottom, lime, cyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top::after {
|
||||||
|
background: linear-gradient(to bottom, yellow, white);
|
||||||
|
mask-image: linear-gradient(to left, white, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.back {
|
||||||
|
background: linear-gradient(to bottom, yellow, red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.back::after {
|
||||||
|
background: linear-gradient(to bottom, lime, black);
|
||||||
|
mask-image: linear-gradient(to left, black, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom {
|
||||||
|
background: linear-gradient(to bottom, blue, black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom::after {
|
||||||
|
background: linear-gradient(to bottom, magenta, red);
|
||||||
|
mask-image: linear-gradient(to left, red, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
background: linear-gradient(to bottom, white, magenta);
|
||||||
|
}
|
||||||
|
|
||||||
|
.right::after {
|
||||||
|
background: linear-gradient(to bottom, yellow, red);
|
||||||
|
mask-image: linear-gradient(to left, red, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
background: linear-gradient(to bottom, lime, black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.left::after {
|
||||||
|
background: linear-gradient(to bottom, cyan, blue);
|
||||||
|
mask-image: linear-gradient(to left, blue, transparent);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
</style>
|
||||||
<Cube
|
<Cube
|
||||||
front={
|
front={
|
||||||
<a href="/about">
|
<a href="/about">
|
||||||
|
@ -25,4 +99,5 @@ export default (
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue