fuzzyworld-tools / commit
Projects page in Markdown; Projects and Agentic in the header
README.md | 2 +- server/content/projects.md | 143 +++++++++++++++++++++++++++++++++++++ server/gen.py | 3 +- server/install.sh | 3 + server/site/index.html | 2 +- server/site/projects-redirect.html | 13 ++++ server/site/style.css | 9 +++ 7 files changed, 172 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ca15ad8..6d73779 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ Every repo uses the shared hook via `core.hooksPath=~/fw/tools/server/hooks`. `p | `/<name>/ci/badge.svg` | status of the latest pipeline on the default branch | | `/ci/` | CI dashboard: running pipelines (each job's state and time), the queue, the last 50 results, for public repos | | `/<name>/files.json`, `/<name>/objects/<sha>` | for VS Code in the browser: every file's blob SHA and size, and each file's contents (≤ 1 MB) | -| `/why-i-left-gitlab/`, `/my-ai-use/`, `/contribute/` | about the site (`/why/` and `/principles/` redirect to the first). All are files in `server/content/` (Markdown, or an HTML fragment with a leading `<!-- title: … -->`), rendered by `fw content` into the common page layout. An image in that folder that a page mentions (``) is copied next to the page. A file starting with `_` (the `/how/` draft) is not built. `fw content` also writes `404.html` | +| `/projects/`, `/why-i-left-gitlab/`, `/my-ai-use/`, `/contribute/` | projects, and about the site (`/why/` and `/principles/` redirect to `/why-i-left-gitlab/`; the old `fuzzyworld.net/projects/` redirects to `/projects/`). All are files in `server/content/` (Markdown, or an HTML fragment with a leading `<!-- title: … -->`), rendered by `fw content` into the common page layout. An image in that folder that a page mentions (``) is copied next to the page. A file starting with `_` (the `/how/` draft) is not built. `fw content` also writes `404.html` | **Branches:** the default branch, and every branch **not yet merged** into it, get browse pages. A merged branch adds nothing new to read and would duplicate every page, so the branches page lists it with a link to its last diff --git a/server/content/projects.md b/server/content/projects.md new file mode 100644 index 0000000..96b3369 --- /dev/null +++ b/server/content/projects.md @@ -0,0 +1,143 @@ +title: Projects + +# Projects + +## <img src="https://apps.fuzzyworld.net/explodorama/icons/apple-touch-icon.png" class="small-logo" alt=""> [Explodorama](https://apps.fuzzyworld.net/explodorama/) + +A turn-based, mobile-first, roguelike take on the 1985 NES bomb-laying classic. Every bomb counts down with *your* moves, so nothing happens until you act — and you can see exactly what will burn before you commit. Clear enemies, uncover the hidden exit, and collect power-ups across a 20-level run. Early development. + +## <img src="https://apps.fuzzyworld.net/nordic-skating/favicon.png" class="small-logo" alt=""> [Nordic Skating](https://apps.fuzzyworld.net/nordic-skating/) + +An endless skate across an endless lake of thin black ice, for a phone. The ice sings under the blades the way real black ice does, and its pitch tells you how thin it is. Leave it alone and it skates itself; steer, and you choose where the lake forks. Every visit is a different lake — by day, at dusk, under the Milky Way or the northern lights. Inspired by National Geographic's [Hear the Otherworldly Sounds of Skating on Thin Ice](https://www.youtube.com/watch?v=v3O9vNi-dkA). + +## [auto-print](https://code.fuzzyworld.net/auto-print/) + +A command-line tool that turns markdown manuscripts into books: an epub, a docx, a pdf, and a Kindle kpf for each one. It's made for writers who keep their drafts in markdown next to their notes — it publishes only the story, plus any extra pages you name (a dedication, a character guide), and never changes the source files. One config file lists the books, and one command builds all of them, using [pandoc](https://pandoc.org) under the hood. I built it to turn my [upcoming writing](https://blog.fuzzyworld.net/upcoming/) into books. + +## 🛰 [Tower](https://apps.fuzzyworld.net/tower/) + +The companion website for [Conversations with Aliens](https://blog.fuzzyworld.net/upcoming/), a novel I'm working on. Tower is the story's fictional space station: a spinning cylinder orbiting Earth, with an inner surface the size of Wisconsin, lit by sunlight piped down its axis. Browse the unrolled surface map, view Tower from outside, or stand on its inner surface with the ground curving up on both sides and the far side of the world hanging 100 km overhead. The world generates itself live in the browser, complete with weather, a day/night cycle, railways, and a scenic tour. + +## <img src="https://apps.fuzzyworld.net/galaxy-z-flip7-butterchurn/icon-192.png" class="small-logo" alt=""> [BlueShadow](https://apps.fuzzyworld.net/galaxy-z-flip7-butterchurn/) + +A Milkdrop music visualizer that runs full-screen on the Galaxy Z Flip 7's closed cover screen, driven live by the phone's microphone. 395 presets, controlled entirely by gestures, installable as a PWA. Rendering is done by [butterchurn](https://github.com/jberg/butterchurn). + +## <img src="https://engye.fuzzyworld.net/favicon.png" class="small-logo" alt=""> [Engye](https://engye.fuzzyworld.net/) + +A web app for sharing files between devices using QR codes. No accounts, no cloud, just scan a QR code and the file is transferred directly between your devices using WebRTC. You can share one file at a time, or a whole queue of files. The app works entirely in the browser, and the file data is end-to-end encrypted, so the key never leaves your devices. It's a great way to quickly transfer files between your phone and computer without needing to email them or use a USB cable. + +## <img src="https://code.fuzzyworld.net/shadow-zone/raw/public/earth.png" class="small-logo" alt=""> [Shadow Zone](https://apps.fuzzyworld.net/shadow-zone/) + +An interactive seismic wave simulator that visualizes why earthquake waves can't reach certain parts of Earth's surface — the "shadow zones" created by the liquid outer core. Adjust core size and wave velocities, trace P- and S-wave paths using Snell's law, and explore alternate planetary structures like "Water Core" or "Giant Core." Runs entirely in the browser with no external dependencies. + +## <img src="https://apps.fuzzyworld.net/when-am-i/favicon.png" class="small-logo" alt=""> [When Am I?](https://apps.fuzzyworld.net/when-am-i/) + +Imagine you're a time traveler who ends up in a random place and time in history — what does a local say when you ask "When am I?" Pick a spot on an interactive map and choose a date; the app shows you the calendar system and local year that would have been in use there and then. + +## <img src="https://apps.fuzzyworld.net/dm/dice.png" class="small-logo" alt=""> [Solo Dungeon Master](https://apps.fuzzyworld.net/dm/) + +An AI-powered solo tabletop RPG that runs entirely in the browser, with Claude as your Dungeon Master. Pick from 10 races and 10 classes, then explore a narrative adventure in the Cypher System. You supply your own Anthropic API key — it never leaves your device. Adventure state saves to browser storage so you can resume where you left off, and encrypted URLs let you share a session without exposing your key. + +## <img src="https://code.fuzzyworld.net/herd/raw/plant.png" class="small-logo" alt=""> [Herd](https://apps.fuzzyworld.net/herd/) + +A browser game about herding sheep. Tap the field to send your border collie to that spot — the dog scares nearby sheep, so use it to push the flock toward the pen before time runs out. Sheep flock together naturally, so working from the sides and behind is more effective than chasing them head-on. Physics, flocking AI, and rendering are all hand-rolled with no game engine. + +## <img src="https://code.fuzzyworld.net/ai-chat-android-auto/raw/app/src/main/res/mipmap-mdpi/ic_launcher.png" class="small-logo" alt=""> [AI Chat for Android Auto](https://code.fuzzyworld.net/ai-chat-android-auto/) + +An Android Auto voice assistant that sends your spoken questions to an AI provider and reads the responses back through the car's speakers. + +## <img src="https://code.fuzzyworld.net/haunt/raw/favicon.png" class="small-logo" alt=""> [Haunt](https://code.fuzzyworld.net/haunt/) + +An Android app that uses WiFi Round-Trip Time (RTT) ranging to calculate your phone's position and automatically switch the correct Philips Hue light for whichever room you're in. No floor plans, no coordinate systems, no backend — just three Google WiFi pucks and a calibration step. + +## <img src="https://apps.fuzzyworld.net/send-dunes/favicon-32x32.png" class="small-logo" alt=""> [Send Dunes!](https://apps.fuzzyworld.net/send-dunes/) + +A sand dune simulation game where you control the wind to push, sculpt, and reshape a dune across a desert landscape. + +## <img src="https://apps.fuzzyworld.net/nuts/favicon-32x32.png" class="small-logo" alt=""> [Nuts](https://apps.fuzzyworld.net/nuts/) + +A phone-focused full-screen toy: a box of hex nuts bouncing around with 2D physics. Tilt your phone to shift gravity, shake it to scatter them, and feel haptic feedback on every wall collision. + +## <img src="https://apps.fuzzyworld.net/alphabeticals/favicon-32.png" class="small-logo" alt=""> [Alphabeticals](https://apps.fuzzyworld.net/alphabeticals/) + +A 1–10 player word-association card game for mobile browsers. Players take turns naming things from a category while playing letter cards from their hand. Use special cards to skip opponents, swap hands, or change the category. Last player holding cards loses. + +## <img src="https://apps.fuzzyworld.net/bubbles/favicon.ico" class="small-logo" alt=""> [Bubbles](https://apps.fuzzyworld.net/bubbles/) + +Your phone is a glass of water. Tilt it to slosh the liquid side to side; tilt past 45° and water spills over the rim permanently. Tap anywhere to drop a random object in — some float, some sink. Desktop users move the mouse instead of tilting. + +## <img src="https://apps.fuzzyworld.net/slide/favicon-32.png" class="small-logo" alt=""> [Slide!](https://apps.fuzzyworld.net/slide/) + +Multiplayer slingshot curling for 1–10 players in the browser. Pull back your puck like a slingshot and release to throw. Choose between nearest-to-jack or target-ring scoring across multiple rounds, with a running leaderboard. Join via link or QR code — no install required. + +## <img src="https://apps.fuzzyworld.net/flight/favicon-32x32.png" class="small-logo" alt=""> [Flight](https://apps.fuzzyworld.net/flight/) + +A browser-based hang glider flight simulator inspired by the hang glider levels of Pilotwings 64. Soar over hand-crafted terrain, ride thermals, race other players in real time, and share your own worlds. Includes a free-fly island and a timed desert race mode with a leaderboard. + +## <img src="https://apps.fuzzyworld.net/chance-it/favicon-32x32.png" class="small-logo" alt=""> [Chance It!](https://apps.fuzzyworld.net/chance-it/) + +A multiplayer push-your-luck dice game for 1–10 players, no install required. Roll 3 dice each turn, bank your gold, or press your luck for more. Hit 3 skulls in a single turn and you bust, losing all unbanked points. First to 13 wins. + +## <img src="https://apps.fuzzyworld.net/word-waltz/favicon-32x32.png" class="small-logo" alt=""> [Word Waltz](https://apps.fuzzyworld.net/word-waltz/) + +A two-player asynchronous Wordle duel. One player picks a secret 5-letter word; the other plays Wordle against it and scores based on how many guesses it takes. Then the roles swap — back and forth indefinitely, with a running scoreboard. All game state is end-to-end encrypted; the key lives only in the share URL. + +## <img src="https://apps.fuzzyworld.net/cat-playground/icons/favicon-32x32.png" class="small-logo" alt=""> [Cat Playground](https://apps.fuzzyworld.net/cat-playground/) + +An interactive web toy for cats. Animated critters (fish, ants, fireflies, laser dots…) wander across a full-screen tablet display. When the cat taps one, it reacts with animations and sounds. A human controls the experience from their phone by scanning a QR code — no app install required. + +## <img src="https://apps.fuzzyworld.net/secret-bangers/icons/favicon-32.png" class="small-logo" alt=""> [Secret Bangers](https://apps.fuzzyworld.net/secret-bangers/) + +A browser-based multiplayer implementation of the Love Letter card game, with historical figures (Casanova, Tesla, Kafka, Cleopatra…) as characters. 2–4 players join via QR code; all game logic runs in the browser and syncs through Firebase in real time. No accounts required. + +## <img src="https://apps.fuzzyworld.net/north-star/favicon.png" class="small-logo" alt=""> [Friend Compass](https://apps.fuzzyworld.net/north-star/) + +Real-time location sharing for a group of friends. Share a room link or QR code; everyone who joins sees each other as directional arrows on their screen. No accounts, no app install — just a mobile browser. Location data is encrypted; the key lives only in the room URL. + +## [Separator Page](https://apps.fuzzyworld.net/tools/separator-page/) + +This is a simple web page that can be used as a separator/container for other web pages. It has been recently rewritten and now supports custom icons. + +I use it with FireFox and Tree Style Tab to organize my browsing, but you can use it in any other browser that supports nested/vertical tabs, or even just as a random page where you can customize the title, the icons, and the body. + + + +## [Quotable](https://apps.fuzzyworld.net/quotable/) + +Quotable is a web and Android app that shows random quotes. + +The Android version can pop-up regular notifications, so you can get random quotes throughout the day. + +The Android version is not yet on the Google Play store, so you'll need to sideload it. + +## [template](https://code.fuzzyworld.net/template/) + +This is an OSS CLI for automating folder/file creation. + +## [Hawk](https://apps.fuzzyworld.net/hawk/) + +This is a web app that allows you to specify a duration (eg. "5:32"), then Hawk will find a song in your Spotify library with that length, and with one click you can start playing this song through Spotify. + +## [Godot 2D shooter experimentation](https://code.fuzzyworld.net/godot-shooter/) + +This is my first real foray into using a game engine, so I'm experimenting with Godot and making a simple 2D space shooter. + +Try the work-in-progress game [here](https://apps.fuzzyworld.net/godot-shooter/). + +## [Find Stone Beer](https://code.fuzzyworld.net/find-stone-beer/) + +Go app that uses [https://find.stonebrewing.com/ API](https://find.stonebrewing.com/) to notify me when Arrogant Bastard is shipped to stores around me. [Pushover](https://pushover.net/) is used to deliver messages to my phone. This was a proof-of-concept implementation to figure out how to provide regular notifications without running a server. + +## [Quantum Inspiration](https://code.fuzzyworld.net/quantum-inspiration/) + +This is a similar notification implementation to "Find Stone Beer", but this app uses [Australian National University Quantum Numbers API](https://quantumnumbers.anu.edu.au/) to pick a [random Wikipedia article](https://en.wikipedia.org/w/api.php?format=json&action=query&generator=random&grnnamespace=0&grnlimit=256) and send it to me every morning. If a particular theory of the [multiverse is correct](https://en.wikipedia.org/wiki/Multiverse), then every day 256 versions of me will receive a different article, and will thus lead to a *slightly different* day. Mostly, though, this was just something to do for fun. + +## [Task Heap](https://apps.fuzzyworld.net/task-heap/) + +Task Heap is a Flutter task-organizing web app. The basic concept here is to have a heap of tasks, then skipping big or complex tasks until you find a task that feels "doable". Eventually, all tasks will get done, as you complete the tasks in the order that works for you. + +## [Dao](https://code.fuzzyworld.net/dao-game/) + +Dao is a TypeScript version of [the game Dao](https://en.wikipedia.org/wiki/Dao_%28game%29). + +Play it [here](https://apps.fuzzyworld.net/dao-game/). diff --git a/server/gen.py b/server/gen.py index e64ef56..5cacbb2 100755 --- a/server/gen.py +++ b/server/gen.py @@ -142,7 +142,8 @@ def url(*parts): HOME_URL = "https://fuzzyworld.net" # Site-wide navigation, in the header of every page on both sites: (section, label, site, path). -NAV = [("code", "Code", "code", "/"), ("apps", "Apps", "apps", "/"), ("ci", "CI", "code", "/ci/"), +NAV = [("code", "Code", "code", "/"), ("apps", "Apps", "apps", "/"), ("projects", "Projects", "code", "/projects/"), + ("my-ai-use", "Agentic", "code", "/my-ai-use/"), ("ci", "CI", "code", "/ci/"), ("contribute", "Contribute", "code", "/contribute/")] SITE_URLS = {"code": BASE_URL, "apps": APPS_URL} diff --git a/server/install.sh b/server/install.sh index c31b7a5..1c1fcd6 100755 --- a/server/install.sh +++ b/server/install.sh @@ -34,6 +34,9 @@ chmod 644 "$apps"/_shared.css "$apps"/_icons.css "$apps"/style.css "$apps"/favic # Main fuzzyworld.net site main_site=~/fuzzyworld.net cp ~/fw/tools/server/site/index.html ~/fw/tools/server/site/main.css "$main_site/" +mkdir -p "$main_site/projects" +cp ~/fw/tools/server/site/projects-redirect.html "$main_site/projects/index.html" # the old projects page, now /projects/ on code. +chmod 644 "$main_site/projects/index.html" cp ~/fw/tools/server/site/_shared.css ~/fw/tools/server/site/_icons.css "$main_site/" cp ~/fw/tools/server/site/favicon.ico ~/fw/tools/server/site/linkedin.png ~/fw/tools/server/site/calendar.png ~/fw/tools/server/site/github.png ~/fw/tools/server/site/gitlab.png "$main_site/" chmod 644 "$main_site"/index.html "$main_site"/main.css "$main_site"/_shared.css "$main_site"/_icons.css "$main_site"/favicon.ico "$main_site"/linkedin.png "$main_site"/calendar.png "$main_site"/github.png "$main_site"/gitlab.png diff --git a/server/site/index.html b/server/site/index.html index ae677ae..d94726b 100644 --- a/server/site/index.html +++ b/server/site/index.html @@ -8,7 +8,7 @@ <link rel="stylesheet" href="/main.css"> </head> <body> -<header class="site"><div class="bar"><a class="brand" href="/">fuzzyworld</a><nav class="site-nav" aria-label="Site"><a href="https://code.fuzzyworld.net/">Code</a><a href="https://apps.fuzzyworld.net/">Apps</a><a href="https://code.fuzzyworld.net/ci/">CI</a><a href="https://code.fuzzyworld.net/contribute/">Contribute</a></nav></div></header> +<header class="site"><div class="bar"><a class="brand" href="/">fuzzyworld</a><nav class="site-nav" aria-label="Site"><a href="https://code.fuzzyworld.net/">Code</a><a href="https://apps.fuzzyworld.net/">Apps</a><a href="https://code.fuzzyworld.net/projects/">Projects</a><a href="https://code.fuzzyworld.net/my-ai-use/">Agentic</a><a href="https://code.fuzzyworld.net/ci/">CI</a><a href="https://code.fuzzyworld.net/contribute/">Contribute</a></nav></div></header> <main> <h1>Welcome to Pavel Safronov's website</h1> <p>I'm a software engineer who dabbles in fiction writing.</p> diff --git a/server/site/projects-redirect.html b/server/site/projects-redirect.html new file mode 100644 index 0000000..f16e1fd --- /dev/null +++ b/server/site/projects-redirect.html @@ -0,0 +1,13 @@ +<!doctype html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<title>Projects moved</title> +<link rel="canonical" href="https://code.fuzzyworld.net/projects/"> +<meta http-equiv="refresh" content="0; url=https://code.fuzzyworld.net/projects/"> +</head> +<body> +<p>The projects page moved to <a href="https://code.fuzzyworld.net/projects/">code.fuzzyworld.net/projects/</a>.</p> +</body> +</html> diff --git a/server/site/style.css b/server/site/style.css index 20891d8..787eaf7 100644 --- a/server/site/style.css +++ b/server/site/style.css @@ -313,6 +313,15 @@ td.author { white-space: nowrap; } +/* Project icons in headings (the Projects page) */ +.small-logo { + display: inline-block; + width: 1em; + height: 1em; + margin-right: 0.3em; + vertical-align: -0.1em; +} + /* Claude Code output tokens per commit (log and usage pages) */ td.cost { color: var(--site-muted);