From 77745b65117a5ce92623dc7b83d3b9c20b3d0bb7 Mon Sep 17 00:00:00 2001 From: Ethan Davidson <31261035+EthanThatOneKid@users.noreply.github.com> Date: Tue, 23 Apr 2024 14:04:01 -0700 Subject: [PATCH] Landing page in HTML (#1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip * wip * wip * wip * add blur to tube * add first bubble * add box shadow * simplex noise bubble paths * example * add standard http file server * stretchy bubbles * add delay to stagger bubbles * update tube.svg * add perspective divs * add rising lands effect * wip * wip * wip todo: cubes show rise from the bottom * wip * wip * wip * Squashed commit of the following: commit 1c366c4361564b7dba59df55ca73a61ecd6c6c04 Author: EthanThatOneKid <31261035+EthanThatOneKid@users.noreply.github.com> Date: Mon Apr 22 10:28:31 2024 -0700 fix rising cubes animation commit a7a8ae1a39d857b65ea9f95d481b3ef254de839d Author: EthanThatOneKid <31261035+EthanThatOneKid@users.noreply.github.com> Date: Mon Apr 22 09:25:13 2024 -0700 Update index.css commit a52e75db411e289bfc69dd73e240b4e3d9c742b6 Author: EthanThatOneKid <31261035+EthanThatOneKid@users.noreply.github.com> Date: Mon Apr 22 09:20:28 2024 -0700 change text color of rising cubes * stagger rising rotation * add scroll timeline polyfill https://github.com/flackr/scroll-timeline * add favicon * add hljs syntax highlighting copy hljs output from 's Lab example. * add page headings * add grid to hero element * add grid to hero element with mobile responsiveness * seo: add description * Update index.html * Update index.html * add fl-icon class * add molecule blob behind hero logo animation * add baby goop character asset i love baby goop * add projects section * delete badges * add remaining recent projects choose more tube colors (with mom ♥) * Update index.html * fix grammar * fix grammar * remove unneeded punctuation --- .vscode/settings.json | 19 +++ README.md | 1 + baby-goop.png | Bin 0 -> 35434 bytes background-blob.css | 7 + deno.json | 11 ++ fl-logo.png | Bin 0 -> 17783 bytes gen.ts | 303 +++++++++++++++++++++++++++++++++++ index.css | 291 ++++++++++++++++++++++++++++++++++ index.html | 356 ++++++++++++++++++++++++++++++++++++++++++ keyframes.css | 283 +++++++++++++++++++++++++++++++++ main.ts | 3 + molecule-blob.svg | 1 + tube-blue.css | 15 ++ tube-blue.svg | 7 + tube-empty.css | 15 ++ tube-empty.svg | 5 + tube-green.css | 15 ++ tube-green.svg | 7 + tube-magenta.css | 15 ++ tube-magenta.svg | 7 + tube-orange.css | 15 ++ tube-orange.svg | 7 + tube-purple.css | 15 ++ tube-purple.svg | 7 + tube-turquoise.css | 15 ++ tube-turquoise.svg | 7 + tube-yellow.css | 15 ++ tube-yellow.svg | 7 + 28 files changed, 1449 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 baby-goop.png create mode 100644 background-blob.css create mode 100644 deno.json create mode 100644 fl-logo.png create mode 100644 gen.ts create mode 100644 index.css create mode 100644 index.html create mode 100644 keyframes.css create mode 100644 main.ts create mode 100644 molecule-blob.svg create mode 100644 tube-blue.css create mode 100644 tube-blue.svg create mode 100644 tube-empty.css create mode 100644 tube-empty.svg create mode 100644 tube-green.css create mode 100644 tube-green.svg create mode 100644 tube-magenta.css create mode 100644 tube-magenta.svg create mode 100644 tube-orange.css create mode 100644 tube-orange.svg create mode 100644 tube-purple.css create mode 100644 tube-purple.svg create mode 100644 tube-turquoise.css create mode 100644 tube-turquoise.svg create mode 100644 tube-yellow.css create mode 100644 tube-yellow.svg diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0d99cbf --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "deno.enable": true, + "deno.unstable": true, + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[markdown]": { + "editor.defaultFormatter": "denoland.vscode-deno" + }, + "[jsonc]": { + "editor.defaultFormatter": "denoland.vscode-deno" + }, + "[typescript]": { + "editor.defaultFormatter": "denoland.vscode-deno" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "denoland.vscode-deno" + }, + "files.eol": "\n" +} diff --git a/README.md b/README.md index 71c257d..9a63fce 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # fart.tools + 🧪 Official website of FartLabs. diff --git a/baby-goop.png b/baby-goop.png new file mode 100644 index 0000000000000000000000000000000000000000..b2804216bfac079d8036e5f9964797311cb48dd9 GIT binary patch literal 35434 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 C!F&M# literal 0 HcmV?d00001 diff --git a/gen.ts b/gen.ts new file mode 100644 index 0000000..6f8f75b --- /dev/null +++ b/gen.ts @@ -0,0 +1,303 @@ +import { createNoise2D } from "simplex-noise"; + +const noise = createNoise2D(); + +const green = "#C3EF3C"; +const purple = "#9D00FF"; +const yellow = "#FDBD01"; +const turquoise = "#16E2F5"; +const magenta = "#FF00FF"; +const orange = "#FF6700"; +const blue = "#1589FF"; + +// deno run gen.ts +// +if (import.meta.main) { + const path = [ + { x: 20, y: 20 }, + { x: 84, y: 20 }, + { x: 84, y: 84 }, + { x: 20, y: 84 }, + ]; + const verticesAmount = Deno.args[0] ? parseInt(Deno.args[0]) : 100; + + const emptyTubeSVG = renderEmptyTube(); + Deno.writeTextFileSync("tube-empty.svg", emptyTubeSVG); + + const emptyTubeCSS = renderTubeCSS("empty", "#ffffffaa"); + Deno.writeTextFileSync("tube-empty.css", emptyTubeCSS); + + const greenTubeSVG = renderGreenTube( + renderBubbles(path, verticesAmount, 30, green), + ); + Deno.writeTextFileSync("tube-green.svg", greenTubeSVG); + + const greenTubeCSS = renderTubeCSS("green", green); + Deno.writeTextFileSync("tube-green.css", greenTubeCSS); + + const purpleTubeSVG = renderPurpleTube( + renderBubbles(path, verticesAmount, 30, purple), + ); + Deno.writeTextFileSync("tube-purple.svg", purpleTubeSVG); + + const purpleTubeCSS = renderTubeCSS("purple", purple); + Deno.writeTextFileSync("tube-purple.css", purpleTubeCSS); + + const yellowTubeSVG = renderYellowTube( + renderBubbles(path, verticesAmount, 30, yellow), + ); + Deno.writeTextFileSync("tube-yellow.svg", yellowTubeSVG); + + const yellowTubeCSS = renderTubeCSS("yellow", yellow); + Deno.writeTextFileSync("tube-yellow.css", yellowTubeCSS); + + const turquoiseTubeSVG = renderTurquoiseTube( + renderBubbles(path, verticesAmount, 30, turquoise), + ); + Deno.writeTextFileSync("tube-turquoise.svg", turquoiseTubeSVG); + + const turquoiseTubeCSS = renderTubeCSS("turquoise", turquoise); + Deno.writeTextFileSync("tube-turquoise.css", turquoiseTubeCSS); + + const magentaTubeSVG = renderMagentaTube( + renderBubbles(path, verticesAmount, 30, magenta), + ); + Deno.writeTextFileSync("tube-magenta.svg", magentaTubeSVG); + + const magentaTubeCSS = renderTubeCSS("magenta", magenta); + Deno.writeTextFileSync("tube-magenta.css", magentaTubeCSS); + + const orangeTubeSVG = renderOrangeTube( + renderBubbles(path, verticesAmount, 30, orange), + ); + Deno.writeTextFileSync("tube-orange.svg", orangeTubeSVG); + + const orangeTubeCSS = renderTubeCSS("orange", orange); + Deno.writeTextFileSync("tube-orange.css", orangeTubeCSS); + + const blueTubeSVG = renderBlueTube( + renderBubbles(path, verticesAmount, 30, blue), + ); + Deno.writeTextFileSync("tube-blue.svg", blueTubeSVG); + + const blueTubeCSS = renderTubeCSS("blue", blue); + Deno.writeTextFileSync("tube-blue.css", blueTubeCSS); +} + +function renderTubeCSS(name: string, color: string) { + return `.border-tube-${name} { + border-image-slice: 31; + border-image-width: 28px; + border-image-outset: 4px; + border-image-repeat: stretch stretch; + border-image-source: url("tube-${name}.svg"); + border-style: solid; + padding: 20px; + border-radius: 2em; +} + +.border-tube-${name}[class*=" glow"], +.border-tube-${name}[class*="glow "] { + box-shadow: 0 0 42px 8px ${color}; +}\n`; +} + +function renderGreenTube(...children: string[]) { + return renderEmptyTube( + ``, + ...children, + ); +} + +function renderPurpleTube(...children: string[]) { + return renderEmptyTube( + ``, + ...children, + ); +} + +function renderYellowTube(...children: string[]) { + return renderEmptyTube( + ``, + ...children, + ); +} + +function renderTurquoiseTube(...children: string[]) { + return renderEmptyTube( + ``, + ...children, + ); +} + +function renderMagentaTube(...children: string[]) { + return renderEmptyTube( + ``, + ...children, + ); +} + +function renderOrangeTube(...children: string[]) { + return renderEmptyTube( + ``, + ...children, + ); +} + +function renderBlueTube(...children: string[]) { + return renderEmptyTube( + ``, + ...children, + ); +} + +function renderEmptyTube(...children: string[]) { + return [ + ``, + ...children, + ``, + ``, + ``, + `\n`, + ].join("\n"); +} + +function renderBubbles( + path: Vertex[], + amount: number, + totalBubbles: number, + color: string, +): string { + const duration = 8; + return Array.from( + { length: totalBubbles }, + (_, i) => + renderBubble( + path, + amount, + Math.random(), + color, + duration, + -i * (duration / totalBubbles), + ), + ).join(""); +} + +function renderBubble( + path: Vertex[], + amount: number, + seed: number, + color: string, + duration: number, + delay = 0, +): string { + const vertices = generateVertices(path, amount, seed); + return [ + ``, + `", + "", + ].join(""); +} + +function renderVertices(vertices: Vertex[]): string { + let path = "M "; + for (const vertex of vertices) { + path += `${vertex.x},${vertex.y} `; + } + + return path.trim() + " Z"; +} + +interface Vertex { + x: number; + y: number; +} + +/** + * iteratePath iterates over a path of vertices divided into `amount` segments. + */ +function* iteratePath( + path: Vertex[], + amount: number, +): Iterable { + const pathLength = path.length; + for (let i = 0; i < amount; i++) { + const t = i / (amount - 1); + const index = t * (pathLength - 1); + const indexFloor = Math.floor(index); + const indexCeil = Math.ceil(index); + const vertexA = path[indexFloor]; + const vertexB = path[indexCeil]; + const vertex = lerpVertex(vertexA, vertexB, index - indexFloor); + yield vertex; + } +} + +/** + * lerpVertex returns a vertex that is `t` percent between `a` and `b`. + */ +function lerpVertex(a: Vertex, b: Vertex, t: number): Vertex { + return { + x: lerp(a.x, b.x, t), + y: lerp(a.y, b.y, t), + }; +} + +/** + * lerp returns a value that is `t` percent between `a` and `b`. + */ +function lerp(a: number, b: number, t: number): number { + return a + (b - a) * t; +} + +/** + * getOffset returns a random offset based on the noise at the given position. + */ +function getOffset( + maxOffset: number, + theta: number, + offsetX = 0, + offsetY = offsetX, + offsetR = 0.5, +) { + const x = Math.cos(theta) * offsetR + offsetX; + const y = Math.sin(theta) * offsetR + offsetY; + return (noise(x, y) - 0.5) * maxOffset; +} + +/** + * generateVertices generates a set of vertices based on a path and a seed + * used for Simplex noise using the polar noise technique. + * + * @see + * [Coding Challenge #136.1: Polar Perlin Noise Loops](https://youtu.be/ZI1dmHv3MeM) + */ +function generateVertices( + path: Vertex[], + amount: number, + seed: number, + variance = 5, + fractionDigits = 2, +) { + if ( + path[0].x !== path[path.length - 1].x || + path[0].y !== path[path.length - 1].y + ) { + path.push({ x: path[0].x, y: path[0].y }); + } + + const seedX = seed * 1e3; + const seedY = seedX * -1; + return Array.from(iteratePath(path, amount)) + .map((v, i, { length }) => { + const theta = (i / length) * Math.PI * 2; + const offsetX = getOffset(variance, theta, seedX); + const offsetY = getOffset(variance, theta, seedY); + return { + x: Number((v.x + offsetX).toFixed(fractionDigits)), + y: Number((v.y + offsetY).toFixed(fractionDigits)), + }; + }); +} diff --git a/index.css b/index.css new file mode 100644 index 0000000..07a6662 --- /dev/null +++ b/index.css @@ -0,0 +1,291 @@ +@import url("https://fonts.googleapis.com/css2?family=Overpass:ital,wght@0,100..900;1,100..900&display=swap"); + +:root { + --green: #c3ef3c; + --dark-green: #004021; + --lighter-dark-green: #004927; + --darker-dark-green: #002d17; + + --secondary: #db7093; + --off-white: #ddd; + --dark-off-white: #aaa; +} + +::selection { + background-color: #db709384; +} + +body { + background-color: var(--dark-green); + color: var(--off-white); + font-family: sans-serif; + margin: 0; +} + +.sparkle:before, +.sparkle:after { + content: "✨"; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: "Overpass", sans-serif; +} + +.fl-icon { + position: absolute; + text-decoration: none; +} + +.fl-icon:hover { + animation: shake 560ms ease-in-out; +} + +.page-section { + max-width: 64ch; + margin: 0 auto 6em auto; + + @media (max-width: 800px) { + padding: 0 1em; + } +} + +nav { + margin-top: 1em; +} + +.page-nav-header { + font-family: "Overpass", sans-serif; + font-size: 1.5em; + font-weight: 700; +} + +.page-link, +.page-link-visible-on-hover { + color: var(--off-white); +} + +.page-link:visited, +.page-link-visible-on-hover:visited { + color: var(--dark-off-white); +} + +.page-link:hover, +.page-link-visible-on-hover:hover { + color: var(--secondary); +} + +.page-link-visible-on-hover { + text-decoration: none; +} + +.page-link-visible-on-hover:hover { + text-decoration: underline; +} + +.page-heading { + font-family: "Overpass", sans-serif; + font-size: 3em; +} + +.page-heading-2 { + font-family: "Overpass", sans-serif; + font-size: 2.34em; +} + +.hero { + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-template-rows: 1fr; + align-items: center; + justify-items: center; + + @media (max-width: 800px) { + grid-template-columns: 1fr; + } +} + +.hero h2 { + max-width: 64ch; +} + +.hero-animation-container { + display: flex; + justify-content: center; + align-items: center; + width: 125%; + height: 125%; + + @media (max-width: 800px) { + width: 100%; + height: 200%; + margin: 5em auto; + } +} + +.projects { + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-template-rows: auto; + grid-column-gap: 1em; + grid-row-gap: 1em; + + @media (max-width: 800px) { + grid-template-columns: 1fr; + } +} + +.project { + padding: 2em; + display: flex; + flex-direction: column; +} + +.topics { + margin-top: auto; +} + +.topic { + word-break: keep-all; + padding: 0.25em 0.5em; + border-radius: 5px; + background-color: var(--darker-dark-green); + color: var(--off-white); + display: inline-block; + margin: 2px; +} + +pre code { + white-space: pre-wrap; +} + +.cubes { + display: grid; + grid-template-columns: repeat(4, 1fr); + grid-template-rows: 1fr; + grid-column-gap: 0px; + grid-row-gap: 0px; + height: 42em; + margin: 4em auto; + justify-items: center; + max-width: 1000px; +} + +@media (max-width: 800px) { + .cubes { + grid-template-columns: 1fr; + } + + .cube:not(:nth-child(1)) { + display: none; + } +} + +.cube { + font-size: 4em; + width: 2em; + transform-style: preserve-3d; + + @media (reduced-motion: reduce) { + animation-timing-function: 0s linear; + } +} + +.cube:nth-child(1) { + animation: rise-fastest linear; + animation-timeline: view(); +} + +.cube:nth-child(2) { + animation: rise-fast linear; + animation-timeline: view(); +} + +.cube:nth-child(3) { + animation: rise linear; + animation-timeline: view(); +} + +.cube:nth-child(4) { + animation: rise-faster linear; + animation-timeline: view(); +} + +.side { + font-family: "Overpass", sans-serif; + font-weight: 900; + border-radius: 5px; + position: absolute; + width: 2em; + text-align: center; + line-height: 2em; +} + +.top { + transform: rotateX(90deg) translateZ(1em); + color: var(--darker-dark-green); + background-image: linear-gradient(#c3ef3caa, #c3ef3caa); + height: 2em; + outline: 2px solid var(--darker-dark-green); + animation: fade-in linear; + animation-timeline: view(); +} + +.left { + transform: rotateY(-90deg) translateZ(1em); + background-image: linear-gradient( + var(--lighter-dark-green) 0%, + rgba(0, 0, 0, 0) 100% + ); +} + +.front { + transform: translateZ(1em); + color: var(--green); + background-image: linear-gradient( + var(--darker-dark-green) 0%, + rgba(0, 0, 0, 0) 100% + ); +} + +.cube:nth-child(1) .front, +.cube:nth-child(1) .left { + animation: fade-in linear, lengthen-fastest linear; + animation-timeline: view(); +} + +.cube:nth-child(2) .front, +.cube:nth-child(2) .left { + animation: fade-in linear, lengthen-fast linear; + animation-timeline: view(); +} + +.cube:nth-child(3) .front, +.cube:nth-child(3) .left { + animation: fade-in linear, lengthen linear; + animation-timeline: view(); +} + +.cube:nth-child(4) .front, +.cube:nth-child(4) .left { + animation: fade-in linear, lengthen-faster linear; + animation-timeline: view(); +} + +footer { + margin-top: 4em; + border-top: 1px solid rgba(255, 255, 255, 0.1); +} + +footer p { + text-align: center; + width: 100%; +} + +.hljs { + background-color: var(--darker-dark-green); +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..156960f --- /dev/null +++ b/index.html @@ -0,0 +1,356 @@ + + + + + + FartLabs, where imagination becomes software + + + + + + + + + + + + + + + + + + +
+ +
+ +
+

+ Where imagination becomes great software +

+ + +
+
+ FartLabs logo animation +
+
+
+ +
+

+ Build modern software solutions in seconds +

+ +
import { Lab } from "labs/labs.ts";
+
+interface Note {
+  title?: string;
+  content: string;
+}
+
+const notesLab = new Lab()
+  .variable("notes", new Map<string, Note>())
+  .procedure(
+    "notes.add",
+    (note: Note, { notes }) => {
+      const id = crypto.randomUUID();
+      notes.set(id, note);
+      return { id };
+    },
+    ["notes"],
+  )
+  .procedure(
+    "notes.get",
+    ({ id }: { id: string }, { notes }) => {
+      return notes.get(id);
+    },
+    ["notes"],
+  )
+  .procedure(
+    "notes.list",
+    (_, { notes }) => {
+      return Array.from(notes.values());
+    },
+    ["notes"],
+  );
+
+notesLab.execute(
+  "notes.add",
+  { title: "Hello", content: "World" },
+);
+
+const notes = notesLab.execute(
+  "notes.list",
+  {},
+);
+
+console.log(notes);
+
+
+ +
+

+ Notable projects +

+ +

Software out the wazoo!

+ +
+
+

+ jsonx +

+ +

+ JSX runtime and compiler for composing JSON data. Visit the official + jsonx website + to play with JSON like never before! +

+ +
+ deno + jsr.io + jsx/tsx +
+
+ +
+

+ ht +

+ +

+ Type-safe HTML rendering library for Deno. Visit the generated + API documentation + to learn more! +

+ +
+ deno + html + jsr.io +
+
+ +
+

+ htx +

+ +

+ Library of @fartlabs/jsonx components for composing + HTML content. Visit the generated + API documentation + to learn more! +

+ +
+ deno + html + jsr.io + jsx/tsx +
+
+ +
+

+ rt +

+ +

+ Minimal HTTP router library based on the URLPattern API. Visit the + generated + API documentation + to learn more! +

+ +
+ deno + http + jsr.io +
+
+ +
+

+ rtx +

+ +

+ Library of @fartlabs/jsonx components for composing + @fartlabs/rt routers. Visit the generated + API documentation + to learn more! +

+ +
+ deno + http + jsr.io + jsx/tsx +
+
+ +
+

+ Labs +

+ +

+ Labs are data structures designed for composable and type-safe + management of variables and procedures at scale. +

+ +
+ codegen + deno + typescript +
+
+ +
+

+ Deno Blocks +

+ +

+ Blockly IDE integration with Fresh and Deno Subhosting. + Winner of Deno Subhosting + Hackathon (Ryan Dahl's favorite). Visit + Deno Blocks! +

+ +
+ blockly + deno + fresh + subhosting +
+
+
+
+ +
+

+ Rise to the occasion +

+
+ +
+
+
L
+
+
F
+
+ +
+
A
+
+
A
+
+ +
+
B
+
+
R
+
+ +
+
S
+
+
T
+
+
+ +
+

+ FAQs +

+ +

+ What is FartLabs? +

+

+ We maintain ethical, economically-sustainable, built-to-last, organic, + open-source software… out the wazoo! We specialize in + imagination-driven development. +

+ +

+ How do I join the community? +

+

+ Join our + Discord server + to chat with us and other members of the community. Also, check out our + GitHub org. +

+
+ +
+

+ © FartLabs + 🧪 +

+
+ + + + diff --git a/keyframes.css b/keyframes.css new file mode 100644 index 0000000..4925c54 --- /dev/null +++ b/keyframes.css @@ -0,0 +1,283 @@ +@keyframes lengthen-fastest { + 0% { + height: 0em; + } + + 20% { + height: 100%; + } + + 100% { + height: 100%; + } +} + +@keyframes lengthen-faster { + 0% { + height: 0em; + } + + 40% { + height: 100%; + } + + 100% { + height: 100%; + } +} + +@keyframes lengthen-fast { + 0% { + height: 0em; + } + + 60% { + height: 100%; + } + + 100% { + height: 100%; + } +} + +@keyframes lengthen { + 0% { + height: 0em; + } + + 80% { + height: 100%; + } + + 100% { + height: 100%; + } +} + +@keyframes rise-fastest { + 0% { + transform: translateY(1000px); + } + + 20% { + transform: translateY(0); + } + + 100% { + transform: translateY(0); + } +} + +@keyframes rise-faster { + 0% { + transform: translateY(1000px); + } + + 30% { + transform: translateY(0); + } + + 100% { + transform: translateY(0); + } +} + +@keyframes rise-fast { + 0% { + transform: translateY(1000px); + } + + 40% { + transform: translateY(0); + } + + 100% { + transform: translateY(0); + } +} + +@keyframes rise { + 0% { + transform: translateY(1000px); + } + + 50% { + transform: translateY(0); + } + + 100% { + transform: translateY(0); + } +} + +@keyframes fade-in { + 0% { + opacity: 0; + } + + 40% { + opacity: 1; + } + + 100% { + opacity: 1; + } +} + +@keyframes lengthen-fastest { + 0% { + height: 0em; + } + + 20% { + height: 100%; + } + + 100% { + height: 100%; + } +} + +@keyframes lengthen-faster { + 0% { + height: 0em; + } + + 30% { + height: 100%; + } + + 100% { + height: 100%; + } +} + +@keyframes lengthen-fast { + 0% { + height: 0em; + } + + 40% { + height: 100%; + } + + 100% { + height: 100%; + } +} + +@keyframes lengthen { + 0% { + height: 0em; + } + + 50% { + height: 100%; + } + + 100% { + height: 100%; + } +} + +@keyframes rise-fastest { + 0% { + transform: rotateX(-32deg) rotateY(-32deg) translateY(1000px); + } + + 20% { + transform: rotateX(-32deg) rotateY(32deg) translateY(0); + } + + 100% { + transform: rotateX(-32deg) rotateY(32deg) translateY(0); + } +} + +@keyframes rise-faster { + 0% { + transform: rotateX(-32deg) rotateY(-32deg) translateY(1000px); + } + + 30% { + transform: rotateX(-32deg) rotateY(32deg) translateY(0); + } + + 100% { + transform: rotateX(-32deg) rotateY(32deg) translateY(0); + } +} + +@keyframes rise-fast { + 0% { + transform: rotateX(-32deg) rotateY(-32deg) translateY(1000px); + } + + 40% { + transform: rotateX(-32deg) rotateY(32deg) translateY(0); + } + + 100% { + transform: rotateX(-32deg) rotateY(32deg) translateY(0); + } +} + +@keyframes rise { + 0% { + transform: rotateX(-32deg) rotateY(-32deg) translateY(1000px); + } + + 50% { + transform: rotateX(-32deg) rotateY(32deg) translateY(0); + } + + 100% { + transform: rotateX(-32deg) rotateY(32deg) translateY(0); + } +} + +@keyframes fade-in { + 0% { + opacity: 0; + } + + 40% { + opacity: 1; + } + + 100% { + opacity: 1; + } +} + +@keyframes shake { + 0% { + scale: 1; + transform: rotate(0deg); + } + + 20% { + transform: rotate(-25deg); + } + + 40% { + transform: rotate(10deg); + } + + 50% { + scale: 1.2; + } + + 60% { + transform: rotate(-25deg); + } + + 80% { + transform: rotate(10deg); + } + + 100% { + scale: 1; + transform: rotate(0deg); + } +} diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..e838936 --- /dev/null +++ b/main.ts @@ -0,0 +1,3 @@ +import { serveDir } from "@std/http/file-server"; + +Deno.serve((request) => serveDir(request)); diff --git a/molecule-blob.svg b/molecule-blob.svg new file mode 100644 index 0000000..202d58c --- /dev/null +++ b/molecule-blob.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tube-blue.css b/tube-blue.css new file mode 100644 index 0000000..ad3e868 --- /dev/null +++ b/tube-blue.css @@ -0,0 +1,15 @@ +.border-tube-blue { + border-image-slice: 31; + border-image-width: 28px; + border-image-outset: 4px; + border-image-repeat: stretch stretch; + border-image-source: url("tube-blue.svg"); + border-style: solid; + padding: 20px; + border-radius: 2em; +} + +.border-tube-blue[class*=" glow"], +.border-tube-blue[class*="glow "] { + box-shadow: 0 0 42px 8px #1589FF; +} diff --git a/tube-blue.svg b/tube-blue.svg new file mode 100644 index 0000000..c8e4768 --- /dev/null +++ b/tube-blue.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tube-empty.css b/tube-empty.css new file mode 100644 index 0000000..510f299 --- /dev/null +++ b/tube-empty.css @@ -0,0 +1,15 @@ +.border-tube-empty { + border-image-slice: 31; + border-image-width: 28px; + border-image-outset: 4px; + border-image-repeat: stretch stretch; + border-image-source: url("tube-empty.svg"); + border-style: solid; + padding: 20px; + border-radius: 2em; +} + +.border-tube-empty[class*=" glow"], +.border-tube-empty[class*="glow "] { + box-shadow: 0 0 42px 8px #ffffffaa; +} diff --git a/tube-empty.svg b/tube-empty.svg new file mode 100644 index 0000000..e488ffb --- /dev/null +++ b/tube-empty.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/tube-green.css b/tube-green.css new file mode 100644 index 0000000..2f06f9f --- /dev/null +++ b/tube-green.css @@ -0,0 +1,15 @@ +.border-tube-green { + border-image-slice: 31; + border-image-width: 28px; + border-image-outset: 4px; + border-image-repeat: stretch stretch; + border-image-source: url("tube-green.svg"); + border-style: solid; + padding: 20px; + border-radius: 2em; +} + +.border-tube-green[class*=" glow"], +.border-tube-green[class*="glow "] { + box-shadow: 0 0 42px 8px #C3EF3C; +} diff --git a/tube-green.svg b/tube-green.svg new file mode 100644 index 0000000..b7dd4d8 --- /dev/null +++ b/tube-green.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tube-magenta.css b/tube-magenta.css new file mode 100644 index 0000000..20462f5 --- /dev/null +++ b/tube-magenta.css @@ -0,0 +1,15 @@ +.border-tube-magenta { + border-image-slice: 31; + border-image-width: 28px; + border-image-outset: 4px; + border-image-repeat: stretch stretch; + border-image-source: url("tube-magenta.svg"); + border-style: solid; + padding: 20px; + border-radius: 2em; +} + +.border-tube-magenta[class*=" glow"], +.border-tube-magenta[class*="glow "] { + box-shadow: 0 0 42px 8px #FF00FF; +} diff --git a/tube-magenta.svg b/tube-magenta.svg new file mode 100644 index 0000000..b435623 --- /dev/null +++ b/tube-magenta.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tube-orange.css b/tube-orange.css new file mode 100644 index 0000000..cbcafe9 --- /dev/null +++ b/tube-orange.css @@ -0,0 +1,15 @@ +.border-tube-orange { + border-image-slice: 31; + border-image-width: 28px; + border-image-outset: 4px; + border-image-repeat: stretch stretch; + border-image-source: url("tube-orange.svg"); + border-style: solid; + padding: 20px; + border-radius: 2em; +} + +.border-tube-orange[class*=" glow"], +.border-tube-orange[class*="glow "] { + box-shadow: 0 0 42px 8px #FF6700; +} diff --git a/tube-orange.svg b/tube-orange.svg new file mode 100644 index 0000000..d4090ab --- /dev/null +++ b/tube-orange.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tube-purple.css b/tube-purple.css new file mode 100644 index 0000000..92c205a --- /dev/null +++ b/tube-purple.css @@ -0,0 +1,15 @@ +.border-tube-purple { + border-image-slice: 31; + border-image-width: 28px; + border-image-outset: 4px; + border-image-repeat: stretch stretch; + border-image-source: url("tube-purple.svg"); + border-style: solid; + padding: 20px; + border-radius: 2em; +} + +.border-tube-purple[class*=" glow"], +.border-tube-purple[class*="glow "] { + box-shadow: 0 0 42px 8px #9D00FF; +} diff --git a/tube-purple.svg b/tube-purple.svg new file mode 100644 index 0000000..03e0efd --- /dev/null +++ b/tube-purple.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tube-turquoise.css b/tube-turquoise.css new file mode 100644 index 0000000..1a82ac5 --- /dev/null +++ b/tube-turquoise.css @@ -0,0 +1,15 @@ +.border-tube-turquoise { + border-image-slice: 31; + border-image-width: 28px; + border-image-outset: 4px; + border-image-repeat: stretch stretch; + border-image-source: url("tube-turquoise.svg"); + border-style: solid; + padding: 20px; + border-radius: 2em; +} + +.border-tube-turquoise[class*=" glow"], +.border-tube-turquoise[class*="glow "] { + box-shadow: 0 0 42px 8px #16E2F5; +} diff --git a/tube-turquoise.svg b/tube-turquoise.svg new file mode 100644 index 0000000..a8945e8 --- /dev/null +++ b/tube-turquoise.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tube-yellow.css b/tube-yellow.css new file mode 100644 index 0000000..33d486f --- /dev/null +++ b/tube-yellow.css @@ -0,0 +1,15 @@ +.border-tube-yellow { + border-image-slice: 31; + border-image-width: 28px; + border-image-outset: 4px; + border-image-repeat: stretch stretch; + border-image-source: url("tube-yellow.svg"); + border-style: solid; + padding: 20px; + border-radius: 2em; +} + +.border-tube-yellow[class*=" glow"], +.border-tube-yellow[class*="glow "] { + box-shadow: 0 0 42px 8px #FDBD01; +} diff --git a/tube-yellow.svg b/tube-yellow.svg new file mode 100644 index 0000000..c16c65a --- /dev/null +++ b/tube-yellow.svg @@ -0,0 +1,7 @@ + + + + + + +