Compare commits
3 Commits
dedc1394cf
...
beb45844cc
| Author | SHA1 | Date | |
|---|---|---|---|
| beb45844cc | |||
| 5c4c547a45 | |||
| 95106a8899 |
@@ -206,4 +206,5 @@ export default {
|
|||||||
nextURL: "http://geekring.net/site/350/next",
|
nextURL: "http://geekring.net/site/350/next",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
wooModeOnByDefault: false,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,3 +12,9 @@
|
|||||||
async
|
async
|
||||||
src="//gc.zgo.at/count.js"
|
src="//gc.zgo.at/count.js"
|
||||||
></script>
|
></script>
|
||||||
|
|
||||||
|
<!-- Mochi -->
|
||||||
|
<script
|
||||||
|
src="https://mochi.meadow.cafe/reaper/mochi@upchur.ch/embed/1.js"
|
||||||
|
async
|
||||||
|
></script>
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="/css/index.css" />
|
<link rel="stylesheet" type="text/css" href="/css/index.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="/css/webfonts/webfonts.css" />
|
<link rel="stylesheet" type="text/css" href="/css/webfonts/webfonts.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="/css/code.css" />
|
<link rel="stylesheet" type="text/css" href="/css/code.css" />
|
||||||
|
<!-- Mochi webmentions -->
|
||||||
|
<link rel="webmention" href="https://mochi-webmentions.meadow.cafe/webmention/mochi@upchur.ch/1/receive" />
|
||||||
<!-- Indieweb profile links -->
|
<!-- Indieweb profile links -->
|
||||||
{% if not excludeProfilesFromHead %}{% for link in metadata.socialLinks %}{% if not link.excludeFromHead %}<link {% if link.customAttribute %} {{ link.customAttribute | safe }} {% endif %} href="{{ link.linkURL }}" />{% endif %}{% endfor %}{% endif %}
|
{% if not excludeProfilesFromHead %}{% for link in metadata.socialLinks %}{% if not link.excludeFromHead %}<link {% if link.customAttribute %} {{ link.customAttribute | safe }} {% endif %} href="{{ link.linkURL }}" />{% endif %}{% endfor %}{% endif %}
|
||||||
<!-- /Indieweb profile links -->
|
<!-- /Indieweb profile links -->
|
||||||
@@ -20,5 +22,6 @@
|
|||||||
</main>
|
</main>
|
||||||
{% include "footer.njk" %}
|
{% include "footer.njk" %}
|
||||||
{% include "weather.njk" %}
|
{% include "weather.njk" %}
|
||||||
|
{% include "wooMode.njk" %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<dialog id="siteSettings">
|
<dialog id="siteSettings">
|
||||||
<h2>Site Settings</h2>
|
<h2>Site Settings</h2>
|
||||||
{% include "weatherController.njk" %}
|
{% include "weatherController.njk" %}
|
||||||
|
{% include "wooModeController.njk" %}
|
||||||
<button id="settingsDone" onclick="siteSettings.close();">Done</button>
|
<button id="settingsDone" onclick="siteSettings.close();">Done</button>
|
||||||
</dialog>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,30 +1,4 @@
|
|||||||
<style>
|
<form class="siteSettingsToggle" id="weatherController">
|
||||||
#weatherController {
|
|
||||||
color: var(--text-color);
|
|
||||||
font-size: var(--step--2);
|
|
||||||
font-variation-settings: var(--font-variation-ui);
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: var(--ui-letter-spacing);
|
|
||||||
font-family: var(--font-family-ui);
|
|
||||||
& label {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
& input {
|
|
||||||
accent-color: var(--contrast-color);
|
|
||||||
background-color: var(--background-color);
|
|
||||||
border: var(--border-details);
|
|
||||||
border-color: var(--contrast-color);
|
|
||||||
border-radius: var(--border-radius);
|
|
||||||
color: var(--text-color);
|
|
||||||
&:focus {
|
|
||||||
box-shadow: 0 0 0 2px var(--contrast-color);
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<form id="weatherController">
|
|
||||||
<input type="checkbox" id="weatherToggle" {% if metadata.weatherOnByDefault %}checked{% endif %} />
|
<input type="checkbox" id="weatherToggle" {% if metadata.weatherOnByDefault %}checked{% endif %} />
|
||||||
<label for="weatherToggle">Show weather?</label>
|
<label for="weatherToggle">Show weather?</label>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
233
_includes/wooMode.njk
Normal file
233
_includes/wooMode.njk
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
<!-- Woo Mode -->
|
||||||
|
<!-- Based on https://codepen.io/tommyho/pen/JjgoZLK -->
|
||||||
|
{# This include replaces the page background with a crazy rainbow animated shader #}
|
||||||
|
|
||||||
|
<canvas id="shaderCanvas"></canvas>
|
||||||
|
<script src="/js/three.min.js"></script>
|
||||||
|
<script>
|
||||||
|
let scene, camera, renderer, uniforms, material, mesh;
|
||||||
|
|
||||||
|
function initWoo() {
|
||||||
|
scene = new THREE.Scene();
|
||||||
|
camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
||||||
|
|
||||||
|
renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('shaderCanvas'), antialias: true });
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
|
||||||
|
const vertexShader = `
|
||||||
|
varying vec2 vUv;
|
||||||
|
void main() {
|
||||||
|
vUv = uv;
|
||||||
|
gl_Position = vec4(position, 1.0);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const fragmentShader = `
|
||||||
|
uniform float time;
|
||||||
|
uniform vec2 resolution;
|
||||||
|
varying vec2 vUv;
|
||||||
|
|
||||||
|
#define PI 3.14159265358979323846
|
||||||
|
|
||||||
|
vec2 rotate(vec2 v, float a) {
|
||||||
|
float s = sin(a);
|
||||||
|
float c = cos(a);
|
||||||
|
mat2 m = mat2(c, -s, s, c);
|
||||||
|
return m * v;
|
||||||
|
}
|
||||||
|
|
||||||
|
float random(vec2 st) {
|
||||||
|
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
float noise(vec2 st) {
|
||||||
|
vec2 i = floor(st);
|
||||||
|
vec2 f = fract(st);
|
||||||
|
|
||||||
|
float a = random(i);
|
||||||
|
float b = random(i + vec2(1.0, 0.0));
|
||||||
|
float c = random(i + vec2(0.0, 1.0));
|
||||||
|
float d = random(i + vec2(1.0, 1.0));
|
||||||
|
|
||||||
|
vec2 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
|
||||||
|
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fbm(vec2 st) {
|
||||||
|
float value = 0.0;
|
||||||
|
float amplitude = 0.5;
|
||||||
|
float frequency = 0.0;
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
value += amplitude * noise(st);
|
||||||
|
st *= 2.0;
|
||||||
|
amplitude *= 0.5;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 palette(float t, vec3 a, vec3 b, vec3 c, vec3 d) {
|
||||||
|
return a + b * cos(6.28318 * (c * t + d));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 vibrancePalette(float t) {
|
||||||
|
vec3 a = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 b = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 c = vec3(1.0, 1.0, 1.0);
|
||||||
|
vec3 d = vec3(0.0, 0.33, 0.67);
|
||||||
|
return palette(t, a, b, c, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 warmPalette(float t) {
|
||||||
|
vec3 a = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 b = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 c = vec3(1.0, 1.0, 1.0);
|
||||||
|
vec3 d = vec3(0.0, 0.10, 0.20);
|
||||||
|
return palette(t, a, b, c, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 coolPalette(float t) {
|
||||||
|
vec3 a = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 b = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 c = vec3(1.0, 1.0, 1.0);
|
||||||
|
vec3 d = vec3(0.3, 0.20, 0.20);
|
||||||
|
return palette(t, a, b, c, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 rainbowPalette(float t) {
|
||||||
|
vec3 a = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 b = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 c = vec3(1.0, 1.0, 1.0);
|
||||||
|
vec3 d = vec3(0.0, 0.33, 0.67);
|
||||||
|
return palette(t, a, b, c, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 st = gl_FragCoord.xy / resolution.xy;
|
||||||
|
st.x *= resolution.x / resolution.y;
|
||||||
|
|
||||||
|
vec2 q = vec2(0.);
|
||||||
|
q.x = fbm(st + 0.1 * time);
|
||||||
|
q.y = fbm(st + vec2(1.0));
|
||||||
|
|
||||||
|
vec2 r = vec2(0.);
|
||||||
|
r.x = fbm(st + 1.0 * q + vec2(1.7, 9.2) + 0.15 * time);
|
||||||
|
r.y = fbm(st + 1.0 * q + vec2(8.3, 2.8) + 0.126 * time);
|
||||||
|
|
||||||
|
float f = fbm(st + r);
|
||||||
|
|
||||||
|
vec2 p = st * 2.0 - 1.0;
|
||||||
|
float a = atan(p.y, p.x);
|
||||||
|
float r2 = length(p);
|
||||||
|
|
||||||
|
vec2 uv = vec2(a / PI, r2);
|
||||||
|
uv = rotate(uv, time * 0.1);
|
||||||
|
|
||||||
|
vec3 color1 = vibrancePalette(f + time * 0.1);
|
||||||
|
vec3 color2 = warmPalette(length(q));
|
||||||
|
vec3 color3 = coolPalette(length(r.x));
|
||||||
|
vec3 color4 = rainbowPalette(f * 2.0 + time * 0.2);
|
||||||
|
|
||||||
|
vec3 color = mix(color1, color2, 0.5);
|
||||||
|
color = mix(color, color3, 0.3);
|
||||||
|
color = mix(color, color4, sin(time * 0.1) * 0.5 + 0.5);
|
||||||
|
|
||||||
|
color += 0.05 * vec3(1.0) * smoothstep(0.1, 0.2, fbm(10.0 * uv + time * 0.5));
|
||||||
|
|
||||||
|
// Add some extra vibrancy
|
||||||
|
color = pow(color, vec3(0.8));
|
||||||
|
color *= 1.1;
|
||||||
|
|
||||||
|
gl_FragColor = vec4(color, 1.0);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
uniforms = {
|
||||||
|
time: { value: 1.0 },
|
||||||
|
resolution: { value: new THREE.Vector2() }
|
||||||
|
};
|
||||||
|
|
||||||
|
material = new THREE.ShaderMaterial({
|
||||||
|
uniforms: uniforms,
|
||||||
|
vertexShader: vertexShader,
|
||||||
|
fragmentShader: fragmentShader
|
||||||
|
});
|
||||||
|
|
||||||
|
mesh = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), material);
|
||||||
|
scene.add(mesh);
|
||||||
|
|
||||||
|
onWindowResize();
|
||||||
|
window.addEventListener('resize', onWindowResize, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onWindowResize() {
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
uniforms.resolution.value.x = renderer.domElement.width;
|
||||||
|
uniforms.resolution.value.y = renderer.domElement.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate(timestamp) {
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
uniforms.time.value = timestamp * 0.001;
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
canvas {
|
||||||
|
display: block;
|
||||||
|
opacity: .35;
|
||||||
|
pointer-events: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const wooCanvas = document.getElementById("shaderCanvas");
|
||||||
|
const wooToggle = document.getElementById("wooToggle");
|
||||||
|
const wooPreference = localStorage.getItem("wooMode");
|
||||||
|
let forcedWoo = false;
|
||||||
|
|
||||||
|
// Initial preference check on page load
|
||||||
|
if ({% if metadata.wooModeOnByDefault == false %}!wooPreference || {% endif %}wooPreference == 0) {
|
||||||
|
forcedWoo ? null : wooCanvas.classList.add("hidden");
|
||||||
|
wooToggle.checked = false;
|
||||||
|
} else {
|
||||||
|
wooCanvas.classList.remove("hidden");
|
||||||
|
wooToggle.checked = true;
|
||||||
|
initWoo();
|
||||||
|
animate(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle setting toggle
|
||||||
|
wooToggle.addEventListener('change', function() {
|
||||||
|
if (this.checked) {
|
||||||
|
localStorage.setItem("wooMode", 1);
|
||||||
|
wooCanvas.classList.remove("hidden");
|
||||||
|
initWoo();
|
||||||
|
animate(0);
|
||||||
|
} else {
|
||||||
|
localStorage.setItem("wooMode", 0);
|
||||||
|
forcedWoo ? null : wooCanvas.classList.add("hidden");
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
{% if forcedWoo %}
|
||||||
|
// Handle forced woo
|
||||||
|
forcedWoo = true;
|
||||||
|
console.log("Forcing woo mode: woo!");
|
||||||
|
wooCanvas.classList.remove("hidden");
|
||||||
|
initWoo();
|
||||||
|
animate(0);
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<!-- /weather -->
|
||||||
4
_includes/wooModeController.njk
Normal file
4
_includes/wooModeController.njk
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<form class="siteSettingsToggle" id="wooModeController">
|
||||||
|
<input type="checkbox" id="wooToggle" {% if metadata.wooModeOnByDefault %}checked{% endif %} />
|
||||||
|
<label for="wooToggle">Woo mode?</label>
|
||||||
|
</form>
|
||||||
@@ -7,4 +7,4 @@ structuredData: none
|
|||||||
# Privacy Statement
|
# Privacy Statement
|
||||||
|
|
||||||
## Data collection and use
|
## Data collection and use
|
||||||
I don’t collect any of your personal information, full-stop. All webfonts, icons, and images are hosted locally (these things can sometimes be used to [track people across the internet](https://www.firstpost.com/world/how-google-uses-fonts-to-track-what-users-do-online-and-sell-data-to-advertisers-12496552.html) otherwise). I use [umami](https://umami.is), a free and open source, privacy-respecting analytics tool, to see how many people visit this website. As of 2025-12-16 I also use [Goat Counter](https://goatcounter.com) (also FLOSS and privacy-respecting) as a backup to umami, as my self-hosted umami instance shat the bed the other day and I lost a bunch of data.
|
I don’t collect any of your personal information, full-stop. All webfonts, icons, and images are hosted locally (these things can sometimes be used to [track people across the internet](https://www.firstpost.com/world/how-google-uses-fonts-to-track-what-users-do-online-and-sell-data-to-advertisers-12496552.html) otherwise). I use [umami](https://umami.is), a free and open source, privacy-respecting analytics tool, to see how many people visit this website. As of 2025-12-16 I also use [Goat Counter](https://goatcounter.com) and [Mochi](https://mochi.meadow.cafe/) (also FLOSS and privacy-respecting) as backups to umami, as my self-hosted umami instance shat the bed the other day and I lost a bunch of data.
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ structuredData: none
|
|||||||
# Changelog
|
# Changelog
|
||||||
* 2026-02-04
|
* 2026-02-04
|
||||||
* Added post comments via [Isso](https://isso-comments.de/). Please don't make me regret this.
|
* Added post comments via [Isso](https://isso-comments.de/). Please don't make me regret this.
|
||||||
|
* Add [Mochi](https://mochi.meadow.cafe/) privacy respecting analytics.
|
||||||
* 2026-02-01
|
* 2026-02-01
|
||||||
* Added [Woo-Woo Incense Description Generator](/special/woo-woo-incense-description-generator).
|
* Added [Woo-Woo Incense Description Generator](/special/woo-woo-incense-description-generator).
|
||||||
* 2026-01-21
|
* 2026-01-21
|
||||||
|
|||||||
7
content/now-burning/Now Burning_2026-02-04_15:27.md
Normal file
7
content/now-burning/Now Burning_2026-02-04_15:27.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
title: Morikage
|
||||||
|
manufacturer: Hikali Koh
|
||||||
|
date: 2026-02-04 15:27:00
|
||||||
|
time: 3:27 PM
|
||||||
|
---
|
||||||
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
layout: layouts/base.njk
|
layout: layouts/base.njk
|
||||||
title: "Woo-Woo Incense Description Generator"
|
title: "Woo-Woo Incense Description Generator"
|
||||||
structuredData: none
|
structuredData: none
|
||||||
|
forcedWoo: true
|
||||||
---
|
---
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Woo-Woo Incense Description Generator</h1>
|
<h1>Woo-Woo Incense Description Generator</h1>
|
||||||
@@ -38,193 +39,3 @@ structuredData: none
|
|||||||
<button onclick="generateWoo('wooContainer', 'wooButton')" id="wooButton">Generate Some Woo!</button>
|
<button onclick="generateWoo('wooContainer', 'wooButton')" id="wooButton">Generate Some Woo!</button>
|
||||||
<div class="card" id="wooContainer" style="padding: var(--space-s); margin-top: var(--space-l);">Click the button to generate woo…</div>
|
<div class="card" id="wooContainer" style="padding: var(--space-s); margin-top: var(--space-l);">Click the button to generate woo…</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Background effect from https://codepen.io/tommyho/pen/JjgoZLK -->
|
|
||||||
<canvas id="shaderCanvas"></canvas>
|
|
||||||
<script src="/js/three.min.js"></script>
|
|
||||||
<script>
|
|
||||||
let scene, camera, renderer, uniforms, material, mesh;
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
scene = new THREE.Scene();
|
|
||||||
camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
|
||||||
|
|
||||||
renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('shaderCanvas'), antialias: true });
|
|
||||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
||||||
|
|
||||||
const vertexShader = `
|
|
||||||
varying vec2 vUv;
|
|
||||||
void main() {
|
|
||||||
vUv = uv;
|
|
||||||
gl_Position = vec4(position, 1.0);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const fragmentShader = `
|
|
||||||
uniform float time;
|
|
||||||
uniform vec2 resolution;
|
|
||||||
varying vec2 vUv;
|
|
||||||
|
|
||||||
#define PI 3.14159265358979323846
|
|
||||||
|
|
||||||
vec2 rotate(vec2 v, float a) {
|
|
||||||
float s = sin(a);
|
|
||||||
float c = cos(a);
|
|
||||||
mat2 m = mat2(c, -s, s, c);
|
|
||||||
return m * v;
|
|
||||||
}
|
|
||||||
|
|
||||||
float random(vec2 st) {
|
|
||||||
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
|
|
||||||
}
|
|
||||||
|
|
||||||
float noise(vec2 st) {
|
|
||||||
vec2 i = floor(st);
|
|
||||||
vec2 f = fract(st);
|
|
||||||
|
|
||||||
float a = random(i);
|
|
||||||
float b = random(i + vec2(1.0, 0.0));
|
|
||||||
float c = random(i + vec2(0.0, 1.0));
|
|
||||||
float d = random(i + vec2(1.0, 1.0));
|
|
||||||
|
|
||||||
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
||||||
|
|
||||||
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
float fbm(vec2 st) {
|
|
||||||
float value = 0.0;
|
|
||||||
float amplitude = 0.5;
|
|
||||||
float frequency = 0.0;
|
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
value += amplitude * noise(st);
|
|
||||||
st *= 2.0;
|
|
||||||
amplitude *= 0.5;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 palette(float t, vec3 a, vec3 b, vec3 c, vec3 d) {
|
|
||||||
return a + b * cos(6.28318 * (c * t + d));
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 vibrancePalette(float t) {
|
|
||||||
vec3 a = vec3(0.5, 0.5, 0.5);
|
|
||||||
vec3 b = vec3(0.5, 0.5, 0.5);
|
|
||||||
vec3 c = vec3(1.0, 1.0, 1.0);
|
|
||||||
vec3 d = vec3(0.0, 0.33, 0.67);
|
|
||||||
return palette(t, a, b, c, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 warmPalette(float t) {
|
|
||||||
vec3 a = vec3(0.5, 0.5, 0.5);
|
|
||||||
vec3 b = vec3(0.5, 0.5, 0.5);
|
|
||||||
vec3 c = vec3(1.0, 1.0, 1.0);
|
|
||||||
vec3 d = vec3(0.0, 0.10, 0.20);
|
|
||||||
return palette(t, a, b, c, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 coolPalette(float t) {
|
|
||||||
vec3 a = vec3(0.5, 0.5, 0.5);
|
|
||||||
vec3 b = vec3(0.5, 0.5, 0.5);
|
|
||||||
vec3 c = vec3(1.0, 1.0, 1.0);
|
|
||||||
vec3 d = vec3(0.3, 0.20, 0.20);
|
|
||||||
return palette(t, a, b, c, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 rainbowPalette(float t) {
|
|
||||||
vec3 a = vec3(0.5, 0.5, 0.5);
|
|
||||||
vec3 b = vec3(0.5, 0.5, 0.5);
|
|
||||||
vec3 c = vec3(1.0, 1.0, 1.0);
|
|
||||||
vec3 d = vec3(0.0, 0.33, 0.67);
|
|
||||||
return palette(t, a, b, c, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec2 st = gl_FragCoord.xy / resolution.xy;
|
|
||||||
st.x *= resolution.x / resolution.y;
|
|
||||||
|
|
||||||
vec2 q = vec2(0.);
|
|
||||||
q.x = fbm(st + 0.1 * time);
|
|
||||||
q.y = fbm(st + vec2(1.0));
|
|
||||||
|
|
||||||
vec2 r = vec2(0.);
|
|
||||||
r.x = fbm(st + 1.0 * q + vec2(1.7, 9.2) + 0.15 * time);
|
|
||||||
r.y = fbm(st + 1.0 * q + vec2(8.3, 2.8) + 0.126 * time);
|
|
||||||
|
|
||||||
float f = fbm(st + r);
|
|
||||||
|
|
||||||
vec2 p = st * 2.0 - 1.0;
|
|
||||||
float a = atan(p.y, p.x);
|
|
||||||
float r2 = length(p);
|
|
||||||
|
|
||||||
vec2 uv = vec2(a / PI, r2);
|
|
||||||
uv = rotate(uv, time * 0.1);
|
|
||||||
|
|
||||||
vec3 color1 = vibrancePalette(f + time * 0.1);
|
|
||||||
vec3 color2 = warmPalette(length(q));
|
|
||||||
vec3 color3 = coolPalette(length(r.x));
|
|
||||||
vec3 color4 = rainbowPalette(f * 2.0 + time * 0.2);
|
|
||||||
|
|
||||||
vec3 color = mix(color1, color2, 0.5);
|
|
||||||
color = mix(color, color3, 0.3);
|
|
||||||
color = mix(color, color4, sin(time * 0.1) * 0.5 + 0.5);
|
|
||||||
|
|
||||||
color += 0.05 * vec3(1.0) * smoothstep(0.1, 0.2, fbm(10.0 * uv + time * 0.5));
|
|
||||||
|
|
||||||
// Add some extra vibrancy
|
|
||||||
color = pow(color, vec3(0.8));
|
|
||||||
color *= 1.1;
|
|
||||||
|
|
||||||
gl_FragColor = vec4(color, 1.0);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
uniforms = {
|
|
||||||
time: { value: 1.0 },
|
|
||||||
resolution: { value: new THREE.Vector2() }
|
|
||||||
};
|
|
||||||
|
|
||||||
material = new THREE.ShaderMaterial({
|
|
||||||
uniforms: uniforms,
|
|
||||||
vertexShader: vertexShader,
|
|
||||||
fragmentShader: fragmentShader
|
|
||||||
});
|
|
||||||
|
|
||||||
mesh = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), material);
|
|
||||||
scene.add(mesh);
|
|
||||||
|
|
||||||
onWindowResize();
|
|
||||||
window.addEventListener('resize', onWindowResize, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onWindowResize() {
|
|
||||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
||||||
uniforms.resolution.value.x = renderer.domElement.width;
|
|
||||||
uniforms.resolution.value.y = renderer.domElement.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
function animate(timestamp) {
|
|
||||||
requestAnimationFrame(animate);
|
|
||||||
uniforms.time.value = timestamp * 0.001;
|
|
||||||
renderer.render(scene, camera);
|
|
||||||
}
|
|
||||||
|
|
||||||
init();
|
|
||||||
animate(0);
|
|
||||||
</script>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
canvas {
|
|
||||||
display: block;
|
|
||||||
opacity: .35;
|
|
||||||
pointer-events: none;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ html {
|
|||||||
input.answer {
|
input.answer {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
input:not(.answer):not(#weatherToggle),
|
input:not(.answer, .siteSettingsToggle input),
|
||||||
textarea {
|
textarea {
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
border: var(--border-details);
|
border: var(--border-details);
|
||||||
@@ -866,6 +866,31 @@ sup {
|
|||||||
line-height: 0;
|
line-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Site Settings */
|
||||||
|
.siteSettingsToggle {
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: var(--step--2);
|
||||||
|
font-variation-settings: var(--font-variation-ui);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: var(--ui-letter-spacing);
|
||||||
|
font-family: var(--font-family-ui);
|
||||||
|
& label {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
& input {
|
||||||
|
accent-color: var(--contrast-color);
|
||||||
|
background-color: var(--background-color);
|
||||||
|
border: var(--border-details);
|
||||||
|
border-color: var(--contrast-color);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
color: var(--text-color);
|
||||||
|
&:focus {
|
||||||
|
box-shadow: 0 0 0 2px var(--contrast-color);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Tags */
|
/* Tags */
|
||||||
a.post-tag {
|
a.post-tag {
|
||||||
background-color: var(--color-gray-20);
|
background-color: var(--color-gray-20);
|
||||||
|
|||||||
Reference in New Issue
Block a user