nevermind, statics don't rly suck
This commit is contained in:
parent
adc3a38395
commit
428246706f
13 changed files with 532 additions and 5 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -173,5 +173,3 @@ dist
|
||||||
|
|
||||||
# Finder (MacOS) folder config
|
# Finder (MacOS) folder config
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
html
|
|
|
@ -1,6 +1,6 @@
|
||||||
import indexTemplate from "./generators/index.html.txt";
|
import indexTemplate from "./templates/index.html.txt";
|
||||||
import workTemplate from "./generators/work.html.txt";
|
import workTemplate from "./templates/work.html.txt";
|
||||||
import readmeTemplate from "./generators/README.md.txt";
|
import readmeTemplate from "./templates/README.md.txt";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
|
|
||||||
export const generate = async (works: string[]) => {
|
export const generate = async (works: string[]) => {
|
||||||
|
|
31
html/001-platform-provenance/index.html
Normal file
31
html/001-platform-provenance/index.html
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>com.mekanoe.art // 001-platform-provenance</title>
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<link rel="stylesheet" href="work.css" />
|
||||||
|
<main>
|
||||||
|
<canvas id="canvas" width="1280" height="720"></canvas>
|
||||||
|
<div id="telemetry">XX.X FPS (XX.X ms)</div>
|
||||||
|
</main>
|
||||||
|
<script
|
||||||
|
src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/3.4.2/gl-matrix-min.min.js"
|
||||||
|
integrity="sha512-cR3oS5mKRWD+38vYi1CNJk1DLpi104ovuQBuVv9p7nNxeqzSNiHzlboK2BZQybmpTi1QNnQ5unYajpURcMjeZQ=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
></script>
|
||||||
|
<script src="/001-platform-provenance/main.js" type="module"></script>
|
62
html/001-platform-provenance/main.js
Normal file
62
html/001-platform-provenance/main.js
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import {
|
||||||
|
App,
|
||||||
|
BasicPlane,
|
||||||
|
Shader
|
||||||
|
} from "../chunk-2775206da9dea9ea.js";
|
||||||
|
|
||||||
|
// src/001-platform-provenance/main.ts
|
||||||
|
var app2 = new App({ fov: 20 });
|
||||||
|
var gl = app2.gl;
|
||||||
|
var shader2 = new Shader(app2).attach(gl.VERTEX_SHADER, `
|
||||||
|
attribute vec4 aVertexPosition;
|
||||||
|
attribute vec2 aTextureCoord;
|
||||||
|
|
||||||
|
uniform mat4 uModelViewMatrix;
|
||||||
|
uniform mat4 uProjectionMatrix;
|
||||||
|
|
||||||
|
varying highp vec2 vTextureCoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
|
||||||
|
vTextureCoord = aTextureCoord;
|
||||||
|
}
|
||||||
|
`).attach(gl.FRAGMENT_SHADER, `
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
uniform float uTime;
|
||||||
|
uniform float uSinTime;
|
||||||
|
uniform float uCosTime;
|
||||||
|
|
||||||
|
varying highp vec2 vTextureCoord;
|
||||||
|
|
||||||
|
vec3 rgb2hsv(vec3 c) {
|
||||||
|
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||||
|
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
|
||||||
|
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
|
||||||
|
|
||||||
|
float d = q.x - min(q.w, q.y);
|
||||||
|
float e = 1.0e-10;
|
||||||
|
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hsv2rgb(vec3 c) {
|
||||||
|
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||||
|
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
||||||
|
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float zComponent = uSinTime * 0.001 * 0.5 + 0.5;
|
||||||
|
vec3 hsv = rgb2hsv(vec3(vTextureCoord, zComponent));
|
||||||
|
hsv.x += uTime * 0.0001;
|
||||||
|
hsv.y = 1.0;
|
||||||
|
hsv.z = 1.0;
|
||||||
|
vec3 rgb = hsv2rgb(hsv);
|
||||||
|
|
||||||
|
gl_FragColor = vec4(rgb, 1.0);
|
||||||
|
gl_FragColor = clamp(gl_FragColor, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
`).link();
|
||||||
|
var plane = new BasicPlane(app2);
|
||||||
|
plane.attachShader(shader2);
|
||||||
|
app2.loop();
|
31
html/002-enter-the-third/index.html
Normal file
31
html/002-enter-the-third/index.html
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>com.mekanoe.art // 002-enter-the-third</title>
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<link rel="stylesheet" href="work.css" />
|
||||||
|
<main>
|
||||||
|
<canvas id="canvas" width="1280" height="720"></canvas>
|
||||||
|
<div id="telemetry">XX.X FPS (XX.X ms)</div>
|
||||||
|
</main>
|
||||||
|
<script
|
||||||
|
src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/3.4.2/gl-matrix-min.min.js"
|
||||||
|
integrity="sha512-cR3oS5mKRWD+38vYi1CNJk1DLpi104ovuQBuVv9p7nNxeqzSNiHzlboK2BZQybmpTi1QNnQ5unYajpURcMjeZQ=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
></script>
|
||||||
|
<script src="/002-enter-the-third/main.js" type="module"></script>
|
27
html/002-enter-the-third/main.js
Normal file
27
html/002-enter-the-third/main.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import {
|
||||||
|
App,
|
||||||
|
BasicPlane,
|
||||||
|
Shader
|
||||||
|
} from "../chunk-2775206da9dea9ea.js";
|
||||||
|
|
||||||
|
// src/002-enter-the-third/main.ts
|
||||||
|
var app2 = new App({ fov: 20 });
|
||||||
|
var gl = app2.gl;
|
||||||
|
var shader2 = new Shader(app2).attach(gl.VERTEX_SHADER, `
|
||||||
|
attribute vec4 aVertexPosition;
|
||||||
|
attribute vec2 aTextureCoord;
|
||||||
|
|
||||||
|
uniform mat4 uModelViewMatrix;
|
||||||
|
uniform mat4 uProjectionMatrix;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
|
||||||
|
}
|
||||||
|
`).attach(gl.FRAGMENT_SHADER, `
|
||||||
|
void main() {
|
||||||
|
gl_FragColor = vec4(1.0);
|
||||||
|
}
|
||||||
|
`).link();
|
||||||
|
var plane = new BasicPlane(app2);
|
||||||
|
plane.attachShader(shader2);
|
||||||
|
app2.loop();
|
225
html/chunk-2775206da9dea9ea.js
Normal file
225
html/chunk-2775206da9dea9ea.js
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
// src/shader.js
|
||||||
|
class Shader {
|
||||||
|
constructor(app) {
|
||||||
|
this.gl = app.gl;
|
||||||
|
this.app = app;
|
||||||
|
this.program = this.gl.createProgram();
|
||||||
|
}
|
||||||
|
attach(type, source) {
|
||||||
|
console.log("attaching shader", { type, source });
|
||||||
|
const shader = this.gl.createShader(type);
|
||||||
|
this.gl.shaderSource(shader, source);
|
||||||
|
this.gl.compileShader(shader);
|
||||||
|
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
|
||||||
|
throw new Error("An error occurred compiling the shaders: " + this.gl.getShaderInfoLog(shader));
|
||||||
|
}
|
||||||
|
this.gl.attachShader(this.program, shader);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
link() {
|
||||||
|
this.gl.linkProgram(this.program);
|
||||||
|
if (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS)) {
|
||||||
|
throw new Error("Unable to initialize the shader program: " + this.gl.getProgramInfoLog(this.program));
|
||||||
|
}
|
||||||
|
console.log("shader linked");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
location(name) {
|
||||||
|
if (name[0] === "a") {
|
||||||
|
return this.gl.getAttribLocation(this.program, name);
|
||||||
|
} else if (name[0] === "u") {
|
||||||
|
return this.gl.getUniformLocation(this.program, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateTime() {
|
||||||
|
const time = this.app.now();
|
||||||
|
const sinTime = Math.sin(time);
|
||||||
|
const cosTime = Math.cos(time);
|
||||||
|
this.gl.uniform1f(this.location("uTime"), time);
|
||||||
|
this.gl.uniform1f(this.location("uSinTime"), sinTime);
|
||||||
|
this.gl.uniform1f(this.location("uCosTime"), cosTime);
|
||||||
|
}
|
||||||
|
activate(projectionMatrix, modelViewMatrix) {
|
||||||
|
this.gl.useProgram(this.program);
|
||||||
|
this.gl.uniformMatrix4fv(this.location("uProjectionMatrix"), false, projectionMatrix);
|
||||||
|
this.gl.uniformMatrix4fv(this.location("uModelViewMatrix"), false, modelViewMatrix);
|
||||||
|
this.updateTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/object.js
|
||||||
|
class Object {
|
||||||
|
constructor(app) {
|
||||||
|
this.gl = app.gl;
|
||||||
|
this.app = app;
|
||||||
|
this.vertexPositions = new Float32Array([]);
|
||||||
|
this.positionBuffer = null;
|
||||||
|
this.textureBuffer = null;
|
||||||
|
}
|
||||||
|
initBuffer(data, draw = this.gl.STATIC_DRAW) {
|
||||||
|
const buffer = this.gl.createBuffer();
|
||||||
|
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
|
||||||
|
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(data), draw);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
attachShader(shader) {
|
||||||
|
this.shader = shader;
|
||||||
|
this.vertexPosition = shader.location("aVertexPosition");
|
||||||
|
this.textureCoord = shader.location("aTextureCoord");
|
||||||
|
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
|
||||||
|
this.gl.vertexAttribPointer(this.vertexPosition, 2, this.gl.FLOAT, false, 0, 0);
|
||||||
|
this.gl.enableVertexAttribArray(this.vertexPosition);
|
||||||
|
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.textureBuffer);
|
||||||
|
this.gl.vertexAttribPointer(this.textureCoord, 2, this.gl.FLOAT, false, 0, 0);
|
||||||
|
this.gl.enableVertexAttribArray(this.textureCoord);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
draw2D() {
|
||||||
|
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
|
||||||
|
this.shader.activate(this.app.projectionMatrix, this.app.modelViewMatrix);
|
||||||
|
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, this.vertexPositions.length / 2);
|
||||||
|
}
|
||||||
|
draw3D() {
|
||||||
|
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
|
||||||
|
this.shader.activate(this.app.projectionMatrix, this.app.modelViewMatrix);
|
||||||
|
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, this.vertexPositions.length / 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/basic-plane.js
|
||||||
|
class BasicPlane extends Object {
|
||||||
|
constructor(app) {
|
||||||
|
super(app);
|
||||||
|
this.vertexPositions = new Float32Array([
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
]);
|
||||||
|
this.positionBuffer = this.initBuffer(this.vertexPositions);
|
||||||
|
this.textureBuffer = this.initBuffer(new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]));
|
||||||
|
this.app.onUpdate(() => this.draw2D());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/telemetry.js
|
||||||
|
class Telemetry {
|
||||||
|
constructor(app, selector = "#telemetry") {
|
||||||
|
this.app = app;
|
||||||
|
this.el = document.querySelector(selector);
|
||||||
|
if (this.el && location.search.includes("telemetry")) {
|
||||||
|
this.el.style.display = "block";
|
||||||
|
this.app.onAfterUpdate(() => this.onAfterUpdate());
|
||||||
|
}
|
||||||
|
this.frameTimes = [];
|
||||||
|
this.maxFrameTimes = 100;
|
||||||
|
this.lastFrameTime = 0;
|
||||||
|
}
|
||||||
|
insertTime(time) {
|
||||||
|
this.frameTimes.push(time);
|
||||||
|
if (this.frameTimes.length > this.maxFrameTimes) {
|
||||||
|
this.frameTimes.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onAfterUpdate() {
|
||||||
|
const frameTime = this.app.now() - this.lastFrameTime;
|
||||||
|
this.insertTime(frameTime);
|
||||||
|
const averageFrameTime = this.frameTimes.reduce((a, b) => a + b, 0) / this.frameTimes.length;
|
||||||
|
const framesPerSecond = 1000 / averageFrameTime;
|
||||||
|
this.el.innerHTML = `
|
||||||
|
${framesPerSecond.toFixed(1)} FPS (${averageFrameTime.toFixed(3)} ms)<br />
|
||||||
|
bU: ${this.app.registry.onBeforeUpdate.length} | U: ${this.app.registry.onUpdate.length} | aU: ${this.app.registry.onAfterUpdate.length}
|
||||||
|
`;
|
||||||
|
this.lastFrameTime = this.app.now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/app.js
|
||||||
|
class App {
|
||||||
|
constructor(config = {
|
||||||
|
fov: 45
|
||||||
|
}) {
|
||||||
|
this._now = 0;
|
||||||
|
this.registry = {
|
||||||
|
onStart: [],
|
||||||
|
onUpdate: [],
|
||||||
|
onBeforeUpdate: [],
|
||||||
|
onAfterUpdate: []
|
||||||
|
};
|
||||||
|
this.config = config;
|
||||||
|
this.canvas = document.querySelector("canvas");
|
||||||
|
this.canvas.width = window.innerWidth;
|
||||||
|
this.canvas.height = window.innerHeight;
|
||||||
|
this.gl = this.canvas.getContext("webgl2");
|
||||||
|
if (this.gl === null) {
|
||||||
|
document.querySelector("main").innerHTML = `<div><i>your browser didn't let me set up webgl</i></div>`;
|
||||||
|
throw new Error("Unable to initialize WebGL. Your browser or machine may not support it.");
|
||||||
|
}
|
||||||
|
const gl = this.gl;
|
||||||
|
const fieldOfView = this.config.fov * Math.PI / 180;
|
||||||
|
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
|
||||||
|
const zNear = 0.1;
|
||||||
|
const zFar = 100;
|
||||||
|
const projectionMatrix = glMatrix.mat4.create();
|
||||||
|
glMatrix.mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);
|
||||||
|
const modelViewMatrix = glMatrix.mat4.create();
|
||||||
|
glMatrix.mat4.translate(modelViewMatrix, modelViewMatrix, [-0, 0, -6]);
|
||||||
|
this.projectionMatrix = projectionMatrix;
|
||||||
|
this.modelViewMatrix = modelViewMatrix;
|
||||||
|
this.clear();
|
||||||
|
this.onBeforeUpdate(() => this.clear());
|
||||||
|
this.telemetry = new Telemetry(this);
|
||||||
|
}
|
||||||
|
clear() {
|
||||||
|
const gl = this.gl;
|
||||||
|
gl.clearColor(0, 0, 0, 1);
|
||||||
|
gl.clearDepth(1);
|
||||||
|
gl.enable(gl.DEPTH_TEST);
|
||||||
|
gl.depthFunc(gl.LEQUAL);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
onStart(fn) {
|
||||||
|
this.registry.onStart.push(fn);
|
||||||
|
}
|
||||||
|
onUpdate(fn) {
|
||||||
|
this.registry.onUpdate.push(fn);
|
||||||
|
}
|
||||||
|
onBeforeUpdate(fn) {
|
||||||
|
this.registry.onBeforeUpdate.push(fn);
|
||||||
|
}
|
||||||
|
onAfterUpdate(fn) {
|
||||||
|
this.registry.onAfterUpdate.push(fn);
|
||||||
|
}
|
||||||
|
start() {
|
||||||
|
this.registry.onStart.forEach((fn) => fn(this));
|
||||||
|
}
|
||||||
|
update() {
|
||||||
|
this.registry.onBeforeUpdate.forEach((fn) => fn(this));
|
||||||
|
this.registry.onUpdate.forEach((fn) => fn(this));
|
||||||
|
this.registry.onAfterUpdate.forEach((fn) => fn(this));
|
||||||
|
}
|
||||||
|
oneShot() {
|
||||||
|
requestAnimationFrame((now) => {
|
||||||
|
this._now = now;
|
||||||
|
this.start();
|
||||||
|
this.update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
loop() {
|
||||||
|
const run = (now) => {
|
||||||
|
this._now = now;
|
||||||
|
this.update();
|
||||||
|
requestAnimationFrame(run);
|
||||||
|
};
|
||||||
|
requestAnimationFrame(run);
|
||||||
|
}
|
||||||
|
now() {
|
||||||
|
return this._now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Shader, BasicPlane, App };
|
52
html/index.css
Normal file
52
html/index.css
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
font-size: 2.5rem;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& .subtext {
|
||||||
|
font-size: 1rem;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
color: hsl(39, 68.6%, 31.2%);
|
||||||
|
& a:hover {
|
||||||
|
color: hsl(39, 100%, 80%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 3rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
& a {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: transparent;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
color: hsl(39, 100%, 80%);
|
||||||
|
& a {
|
||||||
|
text-decoration-color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "▸";
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
89
html/index.html
Normal file
89
html/index.html
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>com.mekanoe.art //</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
font-family: "Atkinson Hyperlegible", sans-serif;
|
||||||
|
background-color: hsl(32, 19%, 14%);
|
||||||
|
color: hsl(39, 75%, 51%);
|
||||||
|
line-height: 1.5;
|
||||||
|
text-shadow: 1px 1px 3px hsl(38, 45%, 22%);
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
font-size: 2.5rem;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& .subtext {
|
||||||
|
font-size: 1rem;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
color: hsl(39, 68.6%, 31.2%);
|
||||||
|
& a:hover {
|
||||||
|
color: hsl(39, 100%, 80%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 3rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
& a {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: transparent;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
color: hsl(39, 100%, 80%);
|
||||||
|
& a {
|
||||||
|
text-decoration-color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "â¸";
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<main>
|
||||||
|
<header>
|
||||||
|
<div>com.mekanoe.art //</div>
|
||||||
|
<div class="subtext">
|
||||||
|
<< noeidelon >>
|
||||||
|
<a href="https://github.com/mekanoe/noeidelon">[github]</a>
|
||||||
|
<a href="https://sapphic.engineer/noe" rel="me">[fedi]</a>
|
||||||
|
<br />a collection of 3D works
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<section id="works">
|
||||||
|
<ul>
|
||||||
|
<li><a href="/002-enter-the-third">./002-enter-the-third</a></li>
|
||||||
|
<li><a href="/001-platform-provenance">./001-platform-provenance</a></li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</main>
|
12
html/work.css
Normal file
12
html/work.css
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#telemetry {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
color: white;
|
||||||
|
font: monospace;
|
||||||
|
z-index: 100;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
display: none;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue