This morning marked a quiet return.
Back to the YMCA after a long holiday hiatus. Long enough that the habit had started to feel theoretical. Long enough that the bathing suit and sweats had been sitting in the corner of my closet like a polite but persistent reminder.
Walking through the doors again felt familiar and slightly humbling. The smell of chlorine drifting out from the pool. The low mechanical rhythm of treadmills in motion. The soft clank of weight stacks settling back into place. None of it had changed. Which, in a strange way, was reassuring.
The holidays have a way of bending routines. Meals get heavier. Evenings get longer. Motivation negotiates for more couch time. And while there is nothing wrong with rest, there is something steadying about returning to motion.
The first few movements felt honest. Muscles remembering what they are supposed to do. Lungs negotiating terms. No personal records were threatened today. That was not the point. The point was simply showing up again.
There is a particular kind of victory in resuming something good after letting it drift. Not dramatic. Not loud. Just a quiet re-alignment. A small promise renewed.
By the time I walked back out into the daylight, there was that familiar post-workout clarity. Not euphoria. Just a sense that the gears had been re-engaged.
Routines wait for us. Sometimes patiently. And today, I went back to meet one of mine.
Day 20,834 – seed 570015014144

Today turns a page.
The Year of the Fire Horse arrives with a kind of restless energy. Horse years are said to carry motion, independence, forward momentum. Add fire to that, and it feels less like a quiet candle and more like a forge. Heat that shapes. Heat that transforms.
There is something fitting about that thought. A horse does not idle for long. It moves. It tests fences. It runs because running is what it was built to do. Fire does not apologize for being bright. It simply burns.
I like the symbolism of beginning again under that banner. Not a timid start. Not a cautious shuffle into the months ahead. But a year that invites courage. Initiative. Maybe even a little boldness.
The lunar new year always feels different from January 1. Less about resolutions and more about rhythm. Cycles. A reminder that time does not just march forward in straight lines. It circles back, renews itself, offers another chance to step differently into familiar terrain.
So here is to the Fire Horse. To motion after stillness. To warmth in cold places. To the quiet decision to run toward what matters.
May this year carry strength without recklessness, passion without burnout, and forward motion without losing sight of where we started.
#doodle #lunarnewyear2026 #yearofthefirehorse
Hour 500,005. Never thought I’d make it.
Nice palindrome, if nothing else.
Day 20,834, seed 570014142729
Today moved quietly.
Not in a sleepy way. Just steady. Like it knew exactly how much it needed to be and refused to be any more than that.
Somewhere along the way, the calendar and the clock quietly noted a small personal milestone: passing the 500,005th hour. No fanfare, no fireworks, just another tick forward in the long, ongoing accumulation of days, which somehow made it feel even more meaningful.
The morning light came in soft and undecided, the kind that does not commit to drama. No grand sunrise performance. Just a gradual brightening of corners. Coffee tasted like coffee. Floors creaked in familiar places. The small rituals held their shape.
Later on, the grill came to life and the in-laws stopped by, the backyard filling with that familiar mixture of conversation, laughter, and the steady sound of food cooking over open heat. Veggie burgers made their way onto plates, simple and good, the kind of meal that works best when nobody is in a hurry and everyone stays just a little longer than planned.
Outside, the air had that in-between feeling. Not quite winter, not quite spring. The trees stood patient. The birds seemed to be negotiating something among themselves. Even the wind felt measured, as if it had agreed not to make a scene.
Nothing dramatic happened. No sudden revelations. No plot twists.
And that was the gift of it.
Some days arrive like a thunderclap. Others just sit down beside you and keep you company. Today was the second kind. The kind that asks nothing more than attention. Sometimes that is enough.
Mouse and fog / bunny and skunk
Day 20,831 Webs doodler update – 570012094830
Web drawing now has wind and a few color mods
https://svonberg.org/wp-content/uploads/2026/02/webs2.html
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″>
<title>Zen Spiderweb Generator</title>
<script src=”https://cdn.tailwindcss.com”></script>
<style>
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: #111827;
font-family: ‘Segoe UI’, Tahoma, Geneva, Verdana, sans-serif;
transition: background 1s ease;
}
#canvas-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
canvas {
display: block;
}
/* Custom Scrollbar */
.custom-scroll::-webkit-scrollbar {
width: 6px;
}
.custom-scroll::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.05);
}
.custom-scroll::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
border-radius: 3px;
}
.custom-scroll::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.4);
}
/* Range Slider Styling */
input[type=range] {
-webkit-appearance: none;
width: 100%;
background: transparent;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 16px;
width: 16px;
border-radius: 50%;
background: #e5e7eb;
cursor: pointer;
margin-top: -6px;
box-shadow: 0 0 5px rgba(0,0,0,0.5);
transition: transform 0.1s;
}
input[type=range]::-webkit-slider-thumb:hover {
transform: scale(1.1);
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 4px;
cursor: pointer;
background: rgba(255, 255, 255, 0.2);
border-radius: 2px;
}
/* Section dividers */
.control-group {
border-top: 1px solid rgba(255,255,255,0.1);
padding-top: 1rem;
margin-top: 1rem;
}
/* Zen Button Specifics */
#open-btn {
z-index: 50; /* Ensure it is above everything */
transition: all 0.3s ease;
box-shadow: 0 0 15px rgba(0,0,0,0.5);
}
#open-btn:hover {
transform: scale(1.1) rotate(90deg);
}
</style>
</head>
<body>
<!– Canvas Layer –>
<div id=”canvas-container”>
<canvas id=”webCanvas”></canvas>
</div>
<!– UI Overlay –>
<div id=”ui-layer” class=”absolute top-0 right-0 p-4 md:p-6 z-10 w-full md:w-[400px] h-full pointer-events-none transition-transform duration-500 ease-in-out transform translate-x-0″>
<!– Main Controls Panel –>
<div id=”controls-panel” class=”bg-gray-900/90 backdrop-blur-md border border-gray-700/50 rounded-2xl p-5 shadow-2xl text-gray-200 custom-scroll h-full max-h-full overflow-y-auto pointer-events-auto flex flex-col”>
<div class=”flex justify-between items-center mb-4 flex-shrink-0″>
<div>
<h1 class=”text-xl font-light tracking-wider text-white”>Silk Weaver</h1>
<p class=”text-xs text-gray-400″>Procedural Generator v2.1</p>
</div>
<button id=”close-btn” class=”p-2 text-gray-300 hover:text-white transition-colors bg-white/10 hover:bg-white/20 rounded-lg flex items-center gap-2″ title=”Enter Zen Mode”>
<span class=”text-xs font-medium uppercase tracking-wider”>Zen Mode</span>
<svg xmlns=”http://www.w3.org/2000/svg” width=”18″ height=”18″ viewBox=”0 0 24 24″ fill=”none” stroke=”currentColor” stroke-width=”2″ stroke-linecap=”round” stroke-linejoin=”round”><path d=”M15 3h6v6M14 10l6.1-6.1M9 21H3v-6M10 14l-6.1 6.1″/></svg>
</button>
</div>
<div class=”space-y-4 flex-grow”>
<!– THEME SELECTOR –>
<div>
<label class=”text-xs uppercase tracking-widest text-indigo-400 font-semibold mb-2 block”>Atmosphere</label>
<div class=”grid grid-cols-4 gap-2″>
<button class=”theme-btn bg-gray-800 border-2 border-indigo-500 rounded h-8 w-full hover:brightness-110 transition-all” data-theme=”midnight” title=”Midnight”></button>
<button class=”theme-btn bg-green-900 border-2 border-transparent hover:border-gray-400 rounded h-8 w-full transition-all” data-theme=”forest” title=”Forest”></button>
<button class=”theme-btn bg-purple-900 border-2 border-transparent hover:border-gray-400 rounded h-8 w-full transition-all” data-theme=”sunset” title=”Sunset”></button>
<button class=”theme-btn bg-black border-2 border-transparent hover:border-gray-400 rounded h-8 w-full transition-all” data-theme=”cyber” title=”Cyber”></button>
</div>
</div>
<!– CORE SHAPE –>
<div class=”control-group”>
<label class=”text-xs uppercase tracking-widest text-indigo-400 font-semibold mb-3 block”>Structure</label>
<div class=”space-y-4″>
<div>
<div class=”flex justify-between text-xs text-gray-400 mb-1″>
<span>Radial Spokes</span>
<span id=”val-density”>12</span>
</div>
<input type=”range” id=”density” min=”5″ max=”30″ value=”12″ step=”1″>
</div>
<div>
<div class=”flex justify-between text-xs text-gray-400 mb-1″>
<span>Spiral Spacing</span>
<span id=”val-spacing”>20</span>
</div>
<input type=”range” id=”spacing” min=”10″ max=”60″ value=”20″ step=”5″>
</div>
<div>
<div class=”flex justify-between text-xs text-gray-400 mb-1″>
<span>Center Size</span>
<span id=”val-centerSize”>50</span>
</div>
<input type=”range” id=”centerSize” min=”0″ max=”200″ value=”50″ step=”10″>
</div>
</div>
</div>
<!– PHYSICS & CHAOS –>
<div class=”control-group”>
<label class=”text-xs uppercase tracking-widest text-indigo-400 font-semibold mb-3 block”>Physics & Chaos</label>
<div class=”space-y-4″>
<div>
<div class=”flex justify-between text-xs text-gray-400 mb-1″>
<span>Thread Slack (Gravity)</span>
<span id=”val-slack”>0.5</span>
</div>
<input type=”range” id=”slack” min=”0″ max=”1″ value=”0.5″ step=”0.1″>
</div>
<div>
<div class=”flex justify-between text-xs text-gray-400 mb-1″>
<span>Tear Probability</span>
<span id=”val-tears”>0%</span>
</div>
<input type=”range” id=”tears” min=”0″ max=”0.4″ value=”0″ step=”0.05″>
</div>
<div>
<div class=”flex justify-between text-xs text-gray-400 mb-1″>
<span>Irregularity</span>
<span id=”val-chaos”>0.3</span>
</div>
<input type=”range” id=”chaos” min=”0″ max=”1″ value=”0.3″ step=”0.1″>
</div>
</div>
</div>
<!– VISUALS –>
<div class=”control-group”>
<label class=”text-xs uppercase tracking-widest text-indigo-400 font-semibold mb-3 block”>Visual FX</label>
<div class=”space-y-4″>
<div>
<div class=”flex justify-between text-xs text-gray-400 mb-1″>
<span>Glow Strength</span>
<span id=”val-glow”>Low</span>
</div>
<input type=”range” id=”glow” min=”0″ max=”20″ value=”0″ step=”1″>
</div>
<div>
<div class=”flex justify-between text-xs text-gray-400 mb-1″>
<span>Wind Speed</span>
<span id=”val-wind”>0</span>
</div>
<input type=”range” id=”wind” min=”0″ max=”5″ value=”0″ step=”0.5″>
</div>
<div class=”flex items-center justify-between”>
<span class=”text-sm text-gray-300″>Morning Dew</span>
<label class=”relative inline-flex items-center cursor-pointer”>
<input type=”checkbox” id=”dew-toggle” class=”sr-only peer”>
<div class=”w-9 h-5 bg-gray-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[”] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-indigo-500″></div>
</label>
</div>
</div>
</div>
<!– SYSTEM –>
<div class=”control-group”>
<div class=”flex items-center justify-between”>
<span class=”text-sm text-gray-300″>Instant Draw</span>
<label class=”relative inline-flex items-center cursor-pointer”>
<input type=”checkbox” id=”instant-toggle” class=”sr-only peer”>
<div class=”w-9 h-5 bg-gray-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[”] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-indigo-500″></div>
</label>
</div>
</div>
</div>
<!– Actions –>
<div class=”mt-6 grid grid-cols-2 gap-3 flex-shrink-0″>
<button id=”generate-btn” class=”col-span-2 bg-indigo-600 hover:bg-indigo-500 text-white font-medium py-3 px-4 rounded-xl transition-all shadow-lg shadow-indigo-500/20 active:scale-95 flex justify-center items-center gap-2″>
<svg xmlns=”http://www.w3.org/2000/svg” width=”16″ height=”16″ viewBox=”0 0 24 24″ fill=”none” stroke=”currentColor” stroke-width=”2″ stroke-linecap=”round” stroke-linejoin=”round”><path d=”M21 12a9 9 0 1 1-6.219-8.56″/></svg>
Re-Weave
</button>
<button id=”download-btn” class=”bg-gray-800 hover:bg-gray-700 text-gray-300 text-sm py-2 px-3 rounded-lg transition-colors border border-gray-700″>
Save Img
</button>
<button id=”clear-btn” class=”bg-gray-800 hover:bg-red-900/30 text-gray-300 hover:text-red-200 text-sm py-2 px-3 rounded-lg transition-colors border border-gray-700″>
Clear
</button>
</div>
</div>
</div>
<!– Zen Mode Restore Button (Fixed Visibility) –>
<button id=”open-btn” class=”fixed bottom-6 right-6 bg-white/10 hover:bg-white/20 text-white p-4 rounded-full backdrop-blur-md border border-white/30 hidden transition-all” title=”Exit Zen Mode”>
<svg xmlns=”http://www.w3.org/2000/svg” width=”28″ height=”28″ viewBox=”0 0 24 24″ fill=”none” stroke=”currentColor” stroke-width=”2″ stroke-linecap=”round” stroke-linejoin=”round”><circle cx=”12″ cy=”12″ r=”3″></circle><path d=”M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z”></path></svg>
</button>
<script>
/**
* Core Logic for Spiderweb Generator
*/
const canvas = document.getElementById(‘webCanvas’);
const ctx = canvas.getContext(‘2d’);
// State
let width, height;
let centerX, centerY;
let animationFrameId;
let time = 0; // For wind animation
// Web Data
let spokes = [];
let spirals = [];
let currentDrawIndex = 0;
let isConstructing = false; // Is the initial build animation running?
// Theme Configuration
const themes = {
midnight: { bg: ‘#111827’, web: ‘rgba(255, 255, 255, 0.2)’, dew: ‘rgba(255, 255, 255, 0.6)’ },
forest: { bg: ‘#064e3b’, web: ‘rgba(209, 250, 229, 0.2)’, dew: ‘rgba(167, 243, 208, 0.6)’ },
sunset: { bg: ‘linear-gradient(to bottom, #4c1d95, #c2410c)’, web: ‘rgba(254, 215, 170, 0.3)’, dew: ‘rgba(255, 237, 213, 0.7)’ },
cyber: { bg: ‘#000000’, web: ‘rgba(50, 255, 100, 0.3)’, dew: ‘rgba(50, 255, 100, 0.8)’ }
};
// Settings
const settings = {
theme: ‘midnight’,
spokeCount: 12,
spacing: 20, // Distance between spiral loops
centerSize: 50,
slack: 0.5,
chaos: 0.3,
tears: 0.0,
glow: 0,
wind: 0.0,
speed: 15,
dew: false,
instant: false
};
// UI Elements
const uiLayer = document.getElementById(‘ui-layer’);
const openBtn = document.getElementById(‘open-btn’);
const themeBtns = document.querySelectorAll(‘.theme-btn’);
// Helper: Random Range
const random = (min, max) => Math.random() * (max – min) + min;
// Helper: Apply Wind to a Point
// Returns a new object so we don’t mutate original geometry permanently
function applyWind(point) {
if (settings.wind <= 0.1) return point;
// Simple vertex displacement based on time and Y position
// Stronger effect further from center?
const dist = Math.sqrt((point.x – centerX)**2 + (point.y – centerY)**2);
const distFactor = Math.min(dist / 500, 1);
const offsetX = Math.sin(time * 0.002 + point.y * 0.01) * (settings.wind * 10) * distFactor;
const offsetY = Math.cos(time * 0.003 + point.x * 0.01) * (settings.wind * 5) * distFactor;
return {
x: point.x + offsetX,
y: point.y + offsetY
};
}
// Initialization
function resize() {
width = window.innerWidth;
height = window.innerHeight;
canvas.width = width;
canvas.height = height;
centerX = width / 2;
centerY = height / 2;
generateWebData();
startDrawing();
}
window.addEventListener(‘resize’, resize);
// Generate the mathematical model of the web
function generateWebData() {
spokes = [];
spirals = [];
// 1. Generate Spokes (Radials)
const baseAngle = (Math.PI * 2) / settings.spokeCount;
const maxRadius = Math.max(width, height) * 0.8;
for (let i = 0; i < settings.spokeCount; i++) {
let angleOffset = (Math.random() – 0.5) * settings.chaos;
let angle = (i * baseAngle) + angleOffset;
let length = maxRadius * random(0.8, 1.2);
spokes.push({
angle: angle,
length: length,
endX: centerX + Math.cos(angle) * length,
endY: centerY + Math.sin(angle) * length
});
}
// 2. Generate Spiral Segments
let currentRadius = settings.centerSize;
let spokeIndex = 0;
// Prevent infinite loops
let safetyCount = 0;
while (safetyCount < 5000) {
safetyCount++;
let s1 = spokes[spokeIndex];
let nextIndex = (spokeIndex + 1) % spokes.length;
let s2 = spokes[nextIndex];
// R1 and R2 allow the spiral to spiral outwards
let r1 = currentRadius + random(-5, 5) * (settings.chaos * 5);
// Look ahead: The connection point on the next spoke is slightly further out
let spiralStep = (settings.spacing / settings.spokeCount);
let r2 = r1 + spiralStep + random(-2, 2) * (settings.chaos * 5);
// Stop if off screen
if (r1 > s1.length || r2 > s2.length) break;
// Probability to skip a segment (Tear)
if (Math.random() > settings.tears) {
let p1 = {
x: centerX + Math.cos(s1.angle) * r1,
y: centerY + Math.sin(s1.angle) * r1
};
let p2 = {
x: centerX + Math.cos(s2.angle) * r2,
y: centerY + Math.sin(s2.angle) * r2
};
// Control Point for Catenary (gravity sag)
let midX = (p1.x + p2.x) / 2;
let midY = (p1.y + p2.y) / 2;
// Pull vector towards center
let dirX = midX – centerX;
let dirY = midY – centerY;
let pullFactor = settings.slack * 0.4;
let cpX = midX – (dirX * pullFactor);
let cpY = midY – (dirY * pullFactor);
spirals.push({
p1: p1,
p2: p2,
cp: {x: cpX, y: cpY},
dew: Math.random() > 0.7
});
}
// Advance
spokeIndex = nextIndex;
currentRadius += spiralStep; // Increment radius constantly around the spiral
if (currentRadius > Math.max(width, height) * 0.7) break;
}
}
function getThemeColors() {
return themes[settings.theme] || themes[‘midnight’];
}
function drawDew(p1, p2, count) {
const theme = getThemeColors();
ctx.fillStyle = theme.dew;
for(let i=1; i<count; i++) {
const t = i/count;
const x = p1.x + (p2.x – p1.x) * t;
const y = p1.y + (p2.y – p1.y) * t;
ctx.beginPath();
ctx.arc(x, y, random(0.5, 1.5), 0, Math.PI * 2);
ctx.fill();
}
}
function drawDewOnCurve(p1, cp, p2) {
const theme = getThemeColors();
ctx.fillStyle = theme.dew;
const drops = Math.floor(random(1, 4));
for (let i = 0; i < drops; i++) {
const t = random(0.2, 0.8);
// Bezier Point
const x = (1 – t) * (1 – t) * p1.x + 2 * (1 – t) * t * cp.x + t * t * p2.x;
const y = (1 – t) * (1 – t) * p1.y + 2 * (1 – t) * t * cp.y + t * t * p2.y;
ctx.beginPath();
ctx.arc(x, y, random(0.5, 1.8), 0, Math.PI * 2);
ctx.fill();
}
}
function startDrawing() {
if (isConstructing) isConstructing = false; // Reset current build
currentDrawIndex = 0;
// Set Background based on theme
const theme = getThemeColors();
if (theme.bg.includes(‘gradient’)) {
document.body.style.background = theme.bg;
} else {
document.body.style.backgroundColor = theme.bg;
document.body.style.backgroundImage = ‘none’;
}
if (settings.instant) {
currentDrawIndex = spirals.length;
} else {
isConstructing = true;
}
if (!animationFrameId) animate();
}
function renderFrame() {
ctx.clearRect(0, 0, width, height);
const theme = getThemeColors();
// Setup Glow
if (settings.glow > 0) {
ctx.shadowBlur = settings.glow;
ctx.shadowColor = theme.web;
} else {
ctx.shadowBlur = 0;
}
// 1. Draw Spokes
ctx.strokeStyle = theme.web;
ctx.lineWidth = 1;
ctx.lineCap = “round”;
// Only draw spokes if we are generating or they are always visible
spokes.forEach(spoke => {
const start = applyWind({x: centerX, y: centerY});
const end = applyWind({x: spoke.endX, y: spoke.endY});
ctx.beginPath();
ctx.moveTo(start.x, start.y);
ctx.lineTo(end.x, end.y);
ctx.stroke();
});
// 2. Draw Spirals
// If constructing, limit by currentDrawIndex. If done, draw all.
const limit = isConstructing ? currentDrawIndex : spirals.length;
// Batch drawing for performance? Canvas handles single paths better
// But we need individual segments for wind
ctx.strokeStyle = theme.web; // Re-apply incase changed
ctx.lineWidth = Math.max(0.5, 0.8 – (settings.spokeCount * 0.01)); // Thinner webs for high density
ctx.beginPath();
for(let i=0; i < limit; i++) {
let seg = spirals[i];
// Apply wind to all control points
let p1 = applyWind(seg.p1);
let p2 = applyWind(seg.p2);
let cp = applyWind(seg.cp);
ctx.moveTo(p1.x, p1.y);
ctx.quadraticCurveTo(cp.x, cp.y, p2.x, p2.y);
}
ctx.stroke();
// 3. Draw Dew (Separate pass for color change)
if (settings.dew) {
ctx.shadowBlur = 0; // No glow on dew for crispness
for(let i=0; i < limit; i++) {
let seg = spirals[i];
if (seg.dew) {
// Recalculate positions for dew to match wind
let p1 = applyWind(seg.p1);
let p2 = applyWind(seg.p2);
let cp = applyWind(seg.cp);
drawDewOnCurve(p1, cp, p2);
}
}
}
// Logic for Construction Animation
if (isConstructing) {
let speed = Math.floor(settings.speed + (currentDrawIndex / 50));
currentDrawIndex += speed;
if (currentDrawIndex >= spirals.length) {
currentDrawIndex = spirals.length;
isConstructing = false;
}
}
}
function animate(timestamp) {
time = timestamp || 0;
renderFrame();
animationFrameId = requestAnimationFrame(animate);
}
// UI Interactions
function updateDisplay(id, val) {
const el = document.getElementById(`val-${id}`);
if (el) el.innerText = val;
}
// Attach listeners to all range inputs
[‘density’, ‘spacing’, ‘centerSize’, ‘slack’, ‘chaos’, ‘tears’, ‘glow’, ‘wind’].forEach(id => {
const input = document.getElementById(id);
input.addEventListener(‘input’, (e) => {
let val = parseFloat(e.target.value);
// Special formatting
if (id === ‘tears’) updateDisplay(id, Math.round(val * 100) + ‘%’);
else if (id === ‘glow’) updateDisplay(id, val === 0 ? ‘Off’ : (val > 15 ? ‘High’ : ‘Low’));
else updateDisplay(id, val);
// Map to settings
if (id === ‘density’) settings.spokeCount = parseInt(val);
else if (id === ‘spacing’) settings.spacing = parseInt(val);
else if (id === ‘centerSize’) settings.centerSize = parseInt(val);
else settings[id] = val;
// Regen logic
if ([‘density’, ‘spacing’, ‘centerSize’, ‘chaos’, ‘tears’, ‘slack’].includes(id)) {
generateWebData();
if (!settings.instant && !isConstructing) startDrawing(); // Restart anim if structural change
}
});
});
// Theme Buttons
themeBtns.forEach(btn => {
btn.addEventListener(‘click’, (e) => {
themeBtns.forEach(b => b.classList.remove(‘border-indigo-500’));
themeBtns.forEach(b => b.classList.add(‘border-transparent’));
e.target.classList.remove(‘border-transparent’);
e.target.classList.add(‘border-indigo-500’);
settings.theme = e.target.getAttribute(‘data-theme’);
startDrawing();
});
});
document.getElementById(‘dew-toggle’).addEventListener(‘change’, (e) => {
settings.dew = e.target.checked;
});
document.getElementById(‘instant-toggle’).addEventListener(‘change’, (e) => {
settings.instant = e.target.checked;
});
document.getElementById(‘generate-btn’).addEventListener(‘click’, () => {
generateWebData();
startDrawing();
});
document.getElementById(‘clear-btn’).addEventListener(‘click’, () => {
isConstructing = false;
currentDrawIndex = 0;
spokes = [];
spirals = [];
ctx.clearRect(0,0,width,height);
});
document.getElementById(‘download-btn’).addEventListener(‘click’, () => {
const link = document.createElement(‘a’);
link.download = `spiderweb_${settings.theme}.png`;
link.href = canvas.toDataURL();
link.click();
});
// Zen Mode Logic
const closeBtn = document.getElementById(‘close-btn’);
let uiVisible = true;
function toggleUI() {
uiVisible = !uiVisible;
if (uiVisible) {
uiLayer.classList.remove(‘translate-x-full’);
openBtn.classList.add(‘hidden’);
} else {
uiLayer.classList.add(‘translate-x-full’);
// Remove hidden immediately, CSS transitions handle the rest if you want opacity,
// but for now simple display toggling ensures it’s clickable.
openBtn.classList.remove(‘hidden’);
}
}
closeBtn.addEventListener(‘click’, toggleUI);
openBtn.addEventListener(‘click’, toggleUI);
document.addEventListener(‘click’, (e) => {
// If Zen mode is active (UI hidden) and we aren’t clicking the restore button
if (!uiVisible && !openBtn.contains(e.target)) {
// Gentle regen in Zen mode
generateWebData();
startDrawing();
}
});
// Start
resize();
animate();
</script>
</body>
</html>
Raccoon and Skunk for Valentine’s
Via yani
I messaged myself someone else’s Epstein story and IG put me on restriction. I can still post and even share stories, but I’m not allowed to message! Yeah, *I’M* the problem! So if you messaged me, I can’t respond for 3 days. Thanks IG for protecting PDFs!

Guess what’s coming?
#doodle #fridaythe13th #thursdaythe12thisthenewfridaythe13th #thursdaythe12th

Deer and tabby cat feb 12 2026
Kitty is new to me, not sure which of the venison brood came by
“The Hangman” from 1964 based on the poem by Maurice Ogden. Film made by Les Goldman and Paul Julian. “The 1964 animated short film Hangman, directed by Paul Julian and Les Goldman, is a 16.4K cautionary tale about apathy and complicity, based on Maurice Ogden’s 1951 poem. It depicts a mysterious figure erecting a gallows in a town square, systematically executing citizens while the fearful populace: remains silent, only for the narrator to realize he is next.”
The ending of "The Hangman" from 1964 based on the poem by Maurice Ogden. Film made by Les Goldman and Paul Julian.
— Scottobear (@scottobear.bsky.social) 2026-02-12T09:48:05.228Z
Putting the wait in perspective

There’s a specific kind of internal hum that starts the moment you hit “Checkout” on a piece of niche tech. It’s been a minute since I’ve been this genuinely keyed up for a mail call, but the wait for the x4 has me checking tracking tabs like it’s a competitive sport.
To keep my sanity, I did what any self-respecting nerd does: I opened a spreadsheet.
Putting the wait into perspective helps dampen the “where is it?” anxiety. My device left Shenzhen nine days ago. Since then, it’s been navigating a gauntlet of weather patterns, logistics hubs, and handoff hops.
Here is the breakdown of its 7,842-mile trek:
* Distance Covered: 7,105 miles (roughly 90% of the trip).
* Average Speed: A steady 36 mph.
* Touchpoints: 8 distinct scans across the globe.
It’s currently cleared the customs hurdle, and with the bulk of the journey in the rearview mirror, I’m optimistic for a delivery before the 14th.
Some people have that “buy it and forget it” zen mindset. I am not those people. I can’t just let it arrive “whenever.” To bridge the gap, I’ve been curate-stacking my digital environment:
* Customizing the Vibe: Designing a fresh set of wallpapers.
* Community Building: Getting the account settled over at readme.club.
* The Library: Hoarding choice EPUB files like a digital dragon.
I’m also diving back into Calibre. I haven’t touched the software in nearly a decade, but seeing that it’s still the gold standard for library management is a testament to its staying power. Getting a Calibre server spun up is next on the weekend warrior list.
The SD card is “ready-ish,” and the Android apps are already staged on my phone and tablet. Software-wise, I’m leaning toward Crosspoint. If I can swing a multi-boot setup to test the waters of every OS flavor available, that’s the dream.
A Snowy Afternoon Hike on the Blue Ridge Parkway
An afternoon hike along the Appalachian Trail, running roughly parallel to the Blue Ridge Parkway in Botetourt, was timed just before the snowfall so the snow showers could be seen as they arrived. A brief stop at Purgatory Overlook offered this captured view, one that never loses its appeal no matter the season.







ereader wallpaper/sleep screens













dungeon map maker
Day 20826 – 570007063317
Woolgathering: What most people call their “self” is, for the most part, a bundle of different moods, impulses, and roles fighting for control. “I decided” usually means “one impulse temporarily won.”
If this sounds preposterous, spend some time in honest “self-observation”. I’m betting you find a constellation of “selves” rather a self.
The “self” you experience when hearing a nostalgic song, for example, can be very different from the “self” that you experience after stubbing your toe or getting cut off in traffic. Often dramatically different.