diff --git a/assets/images/FTL.jpg b/assets/images/FTL.jpg new file mode 100644 index 0000000..82f2eeb Binary files /dev/null and b/assets/images/FTL.jpg differ diff --git a/assets/images/alphacol.jpg b/assets/images/alphacol.jpg new file mode 100644 index 0000000..4aec0d2 Binary files /dev/null and b/assets/images/alphacol.jpg differ diff --git a/assets/images/apioform.jpg b/assets/images/apioform.jpg new file mode 100644 index 0000000..955f180 Binary files /dev/null and b/assets/images/apioform.jpg differ diff --git a/assets/images/csproblem.jpg b/assets/images/csproblem.jpg new file mode 100644 index 0000000..b6f7388 Binary files /dev/null and b/assets/images/csproblem.jpg differ diff --git a/assets/images/emu-war.jpg b/assets/images/emu-war.jpg new file mode 100644 index 0000000..6a9290a Binary files /dev/null and b/assets/images/emu-war.jpg differ diff --git a/assets/images/flight.jpg b/assets/images/flight.jpg new file mode 100644 index 0000000..d1e8652 Binary files /dev/null and b/assets/images/flight.jpg differ diff --git a/assets/images/fractalart.jpg b/assets/images/fractalart.jpg new file mode 100644 index 0000000..d8a0957 Binary files /dev/null and b/assets/images/fractalart.jpg differ diff --git a/assets/images/gol.jpg b/assets/images/gol.jpg new file mode 100644 index 0000000..0259229 Binary files /dev/null and b/assets/images/gol.jpg differ diff --git a/assets/images/guihacker.jpg b/assets/images/guihacker.jpg new file mode 100644 index 0000000..dccc7f9 Binary files /dev/null and b/assets/images/guihacker.jpg differ diff --git a/assets/images/heavscp.jpg b/assets/images/heavscp.jpg new file mode 100644 index 0000000..17ae386 Binary files /dev/null and b/assets/images/heavscp.jpg differ diff --git a/assets/images/ideas.jpg b/assets/images/ideas.jpg new file mode 100644 index 0000000..620d5c6 Binary files /dev/null and b/assets/images/ideas.jpg differ diff --git a/assets/images/incdec.jpg b/assets/images/incdec.jpg new file mode 100644 index 0000000..321f351 Binary files /dev/null and b/assets/images/incdec.jpg differ diff --git a/assets/images/infipage.jpg b/assets/images/infipage.jpg new file mode 100644 index 0000000..fef2eea Binary files /dev/null and b/assets/images/infipage.jpg differ diff --git a/assets/images/joe.jpg b/assets/images/joe.jpg new file mode 100644 index 0000000..2af80d8 Binary files /dev/null and b/assets/images/joe.jpg differ diff --git a/assets/images/lorem.jpg b/assets/images/lorem.jpg new file mode 100644 index 0000000..b9e66c7 Binary files /dev/null and b/assets/images/lorem.jpg differ diff --git a/assets/images/nemc.jpg b/assets/images/nemc.jpg new file mode 100644 index 0000000..2f3bb66 Binary files /dev/null and b/assets/images/nemc.jpg differ diff --git a/assets/images/new-website.jpg b/assets/images/new-website.jpg new file mode 100644 index 0000000..19a5eb9 Binary files /dev/null and b/assets/images/new-website.jpg differ diff --git a/assets/images/osbill.jpg b/assets/images/osbill.jpg new file mode 100644 index 0000000..cc01f07 Binary files /dev/null and b/assets/images/osbill.jpg differ diff --git a/assets/images/osmarkscalculator.jpg b/assets/images/osmarkscalculator.jpg new file mode 100644 index 0000000..931cb90 Binary files /dev/null and b/assets/images/osmarkscalculator.jpg differ diff --git a/assets/images/otherstuff.jpg b/assets/images/otherstuff.jpg new file mode 100644 index 0000000..d00bd7d Binary files /dev/null and b/assets/images/otherstuff.jpg differ diff --git a/assets/images/phones.jpg b/assets/images/phones.jpg new file mode 100644 index 0000000..fda7e56 Binary files /dev/null and b/assets/images/phones.jpg differ diff --git a/assets/images/points.jpg b/assets/images/points.jpg new file mode 100644 index 0000000..86620e8 Binary files /dev/null and b/assets/images/points.jpg differ diff --git a/assets/images/rpncalc2.jpg b/assets/images/rpncalc2.jpg new file mode 100644 index 0000000..f46649d Binary files /dev/null and b/assets/images/rpncalc2.jpg differ diff --git a/assets/images/rpncalc3.jpg b/assets/images/rpncalc3.jpg new file mode 100644 index 0000000..c35c6ff Binary files /dev/null and b/assets/images/rpncalc3.jpg differ diff --git a/assets/images/rpncalc4.jpg b/assets/images/rpncalc4.jpg new file mode 100644 index 0000000..ad80664 Binary files /dev/null and b/assets/images/rpncalc4.jpg differ diff --git a/assets/images/rssgood.jpg b/assets/images/rssgood.jpg new file mode 100644 index 0000000..b21e1cc Binary files /dev/null and b/assets/images/rssgood.jpg differ diff --git a/assets/images/scorer.jpg b/assets/images/scorer.jpg new file mode 100644 index 0000000..1af2874 Binary files /dev/null and b/assets/images/scorer.jpg differ diff --git a/assets/images/stack.jpg b/assets/images/stack.jpg new file mode 100644 index 0000000..7a82a1e Binary files /dev/null and b/assets/images/stack.jpg differ diff --git a/assets/images/themes.jpg b/assets/images/themes.jpg new file mode 100644 index 0000000..8f8ea70 Binary files /dev/null and b/assets/images/themes.jpg differ diff --git a/assets/images/tictactoe.jpg b/assets/images/tictactoe.jpg new file mode 100644 index 0000000..5b894c0 Binary files /dev/null and b/assets/images/tictactoe.jpg differ diff --git a/assets/images/whorl.jpg b/assets/images/whorl.jpg new file mode 100644 index 0000000..8918065 Binary files /dev/null and b/assets/images/whorl.jpg differ diff --git a/assets/images/wsterm.jpg b/assets/images/wsterm.jpg new file mode 100644 index 0000000..5169db9 Binary files /dev/null and b/assets/images/wsterm.jpg differ diff --git a/assets/js/h4xx0r.js b/assets/js/h4xx0r.js index f993fc5..bc76f7c 100644 --- a/assets/js/h4xx0r.js +++ b/assets/js/h4xx0r.js @@ -81,6 +81,7 @@ function jargon() { } else { var raw = thing + " " + choose(jargonWords.participles) .replace("writing", "wrote") + .replace("breaking", "broken") .replace("overriding", "overriden") .replace("shutting", "shut") .replace("ying", "ied") diff --git a/assets/sw.js b/assets/sw.js index 14bb5d9..88a6222 100644 --- a/assets/sw.js +++ b/assets/sw.js @@ -71,7 +71,7 @@ const getResponse = async req => { } try { console.log("Requesting", req.url) - const response = await fetchWithTimeout(req.clone(), 5000) + const response = await fetchWithTimeout(req.clone(), 10000) if (response.status < 400) { console.log("Caching request to", req.url) cache.put(req, response.clone()) diff --git a/blog/other-stuff.md b/blog/other-stuff.md index 015ad64..388fb1f 100644 --- a/blog/other-stuff.md +++ b/blog/other-stuff.md @@ -38,7 +38,8 @@ Obviously this is just stuff *I* like; you might not like it, which isn't really * [Schlock Mercenary](https://www.schlockmercenary.com/), a *very* long-running space opera webcomic. It's been running for something like 20 years, and the art and such improve over time. * [Freefall](http://freefall.purrsia.com/), a hard-science-fiction webcomic. * [Mage Errant](https://www.goodreads.com/series/252085-mage-errant) - a moderately-long-by-now fantasy series with a very vibrant world, and which actually considers the geopolitical implications of there being beings around ("Great Powers") able to act as one-man armies. -* [Arcane Ascension](https://www.goodreads.com/series/201441-arcane-ascension) - fun progression fantasy series with (... like most of these, actually) worldbuilding I like and good characters. I have only read the first two, since I'm writing this just as the third came out +* [Arcane Ascension](https://www.goodreads.com/series/201441-arcane-ascension) - fun progression fantasy series with (... like most of these, actually) worldbuilding I like and good characters. I have only read the first two, since I got distracted and have not read much of the third. Somewhat overly long at times. +* [Void Star](https://www.goodreads.com/book/show/29939057-void-star) - somewhat weird and good. The prose is very... poetic is probably the best word (it contains phrases like "isoclines of commitment and dread", "concentric and innumerable" and "high empyrean")... which I enjoyed, but it is polarizing. The setting seems like a generally reasonable extrapolation of a bunch of ongoing trends into the future, although it's unclear exactly *when* it is (some of the book implies 2150 or so, but this seems implausible). Its most interesting characteristic is that it absolutely does not tell you what's going on ever: an interview I read said it was written out of order, and that makes sense (another fun quirk of it is that the chapters are generally very short). I think I know most of what happens now, but it has taken a while. Special mentions (i.e. "I haven't gotten around to reading these but they are well-reviewed and sound interesting") to: * [The Divine Cities](https://www.goodreads.com/series/159695-the-divine-cities) by Robert Jackson Bennet. diff --git a/blog/rssgood.md b/blog/rssgood.md new file mode 100644 index 0000000..383bab7 --- /dev/null +++ b/blog/rssgood.md @@ -0,0 +1,29 @@ +--- +title: "RSS: good and useful" +description: RSS/Atom are protocols for Internet-based newsletter/feed services. They're surprisingly well-supported and you should consider using them. +created: 14/05/2022 +--- +RSS stands for Really Simple Syndication, and it's an underappreciated protocol for generally "following" things on the internet. +Most people do this via proprietary platforms with feed/notification functionality, the problems of which are obvious, or email. +Email, though, is push-based - you subscribe to a service and it communicates with your email server whenever a new item is published. +While this allows new content to be received in near-real-time, it has the significant disadvantage that unsubscription can be difficult and nonstandardized, and your address can be used by anyone else to send you unwanted mails. + +RSS inverts this; an RSS reader application periodically checks a list of RSS feeds by downloading them from their servers and displays all new content it finds. +This makes it a lot easier to manage a lot of feeds or items as an end user, particularly since lots of reader software will also let you categorize feeds to better manage content. +It's also easier for site admins: because of rampant spam running your own email server (without email from it being immediately discarded) is tricky, so it's generally required to integrate some external, paid service instead. +RSS only requires serving an XML file, which is very easy to do on top of an existing website, which is probably why it's still pretty widely implemented. + +Yes, despite RSS's relative lack of use nowadays, a surprisingly large amount of sites still support it (some might use Atom, a slightly different protocol, but good reader applications support both transparently): + +* WordPress, a very popular platform for blogs, has RSS support enabled by default (just go to `/feed/`). +* YouTube has RSS feeds for channels' videos: `https://www.youtube.com/feeds/videos.xml?channel_id=[ID of channel to follow]`. +* Some web fiction sites (e.g. Royal Road, Archive Of Our Own) have per-story RSS feeds. +* osmarks.net has an RSS feed, linked on the main page somewhere: [https://osmarks.net/rss.xml](https://osmarks.net/rss.xml) - this does only cover blog posts and not experiments, as those aren't actually timestamped. +* Blogspot blogs have feeds at `/rss.xml`. +* The BBC has RSS feeds described here: [https://www.bbc.com/news/10628494](https://www.bbc.com/news/10628494). +* Otherwise, you can ctrl+F for "RSS" or "Atom" or "feed" or "subscribe" and might be successful, or try URLs like `/feed`, `/feed.xml`, `/feed.atom`, `/index.xml`, `/rss` or `/rss.xml`. + +As for RSS readers to use these with, there are many implementations available. +I use [Miniflux](https://miniflux.app/), since it's self-hosted and accessible on multiple devices via the web, and has nice features like keyboard controls, scraping websites which omit some content from RSS feeds, and an integration API which I use to plug it into my convoluted mess of custom scripting. +The [Awesome Self-Hosted list](https://github.com/awesome-selfhosted/awesome-selfhosted#feed-readers) has many other reader applications like this. +If you prefer something which runs locally as a desktop application, [Wikipedia has a list](https://en.wikipedia.org/wiki/Comparison_of_feed_aggregators) (I haven't actually checked this space myself). \ No newline at end of file diff --git a/experiments/flight/index.html b/experiments/flight/index.html new file mode 100644 index 0000000..daa75ca --- /dev/null +++ b/experiments/flight/index.html @@ -0,0 +1,240 @@ +--- +title: Flying Thing +description: Fly an ominous flying square around above some ground! Includes special relativity! +--- + +
+ +
+
+
+
+
+
+ +
+
+
+ diff --git a/experiments/guihacker/index.html b/experiments/guihacker/index.html index 826c3bc..eccf6ee 100644 --- a/experiments/guihacker/index.html +++ b/experiments/guihacker/index.html @@ -23,7 +23,7 @@ description: My fork of GUIHa top: 0; left: 0; } - .bars-and-stuff{ + .bars-and-stuff { left: 66.6%; } @@ -31,7 +31,9 @@ description: My fork of GUIHa position: fixed; overflow: hidden; } - p{margin:0} + p { + margin:0 + } nav { display: none; diff --git a/experiments/heavpoot-game/index.html b/experiments/heavpoot-game/index.html index de8fb5a..a999c16 100644 --- a/experiments/heavpoot-game/index.html +++ b/experiments/heavpoot-game/index.html @@ -1,5 +1,5 @@ --- -title: Heavpoot's Game +title: Heav's Game slug: heavscp description: It is pitch black (if you ignore all of the lighting). You are likely to be eaten by Heavpoot's terrible writing skills, and/or lacerated/shot/[REDACTED]. Vaguely inspired by the SCP Foundation. --- diff --git a/experiments/osmarkscalculator/index.html b/experiments/osmarkscalculator/index.html new file mode 100644 index 0000000..76040a8 --- /dev/null +++ b/experiments/osmarkscalculator/index.html @@ -0,0 +1,75 @@ +--- +title: osmarkscalculator +description: Unholy horrors moved from the depths of my projects directory to your browser. Theoretically, this is a calculator. Good luck using it. +--- + +

+
+
+
+
\ No newline at end of file
diff --git a/experiments/osmarkscalculator/osmarkscalculator.js b/experiments/osmarkscalculator/osmarkscalculator.js
new file mode 100644
index 0000000..ff80f01
--- /dev/null
+++ b/experiments/osmarkscalculator/osmarkscalculator.js
@@ -0,0 +1,32 @@
+let wasm_bindgen;(function(){const __exports={};let wasm;__exports.init_context=function(){wasm.init_context();};__exports.load_defaults=function(){wasm.load_defaults();};let WASM_VECTOR_LEN=0;let cachedUint8Memory0=new Uint8Array();function getUint8Memory0(){if(cachedUint8Memory0.byteLength===0){cachedUint8Memory0=new Uint8Array(wasm.memory.buffer);}
+return cachedUint8Memory0;}
+const cachedTextEncoder=new TextEncoder('utf-8');const encodeString=(typeof cachedTextEncoder.encodeInto==='function'?function(arg,view){return cachedTextEncoder.encodeInto(arg,view);}:function(arg,view){const buf=cachedTextEncoder.encode(arg);view.set(buf);return{read:arg.length,written:buf.length};});function passStringToWasm0(arg,malloc,realloc){if(realloc===undefined){const buf=cachedTextEncoder.encode(arg);const ptr=malloc(buf.length);getUint8Memory0().subarray(ptr,ptr+buf.length).set(buf);WASM_VECTOR_LEN=buf.length;return ptr;}
+let len=arg.length;let ptr=malloc(len);const mem=getUint8Memory0();let offset=0;for(;offset0x7F)break;mem[ptr+offset]=code;}
+if(offset!==len){if(offset!==0){arg=arg.slice(offset);}
+ptr=realloc(ptr,len,len=offset+arg.length*3);const view=getUint8Memory0().subarray(ptr+offset,ptr+len);const ret=encodeString(arg,view);offset+=ret.written;}
+WASM_VECTOR_LEN=offset;return ptr;}
+let cachedInt32Memory0=new Int32Array();function getInt32Memory0(){if(cachedInt32Memory0.byteLength===0){cachedInt32Memory0=new Int32Array(wasm.memory.buffer);}
+return cachedInt32Memory0;}
+const cachedTextDecoder=new TextDecoder('utf-8',{ignoreBOM:true,fatal:true});cachedTextDecoder.decode();function getStringFromWasm0(ptr,len){return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr,ptr+len));}
+__exports.run_program=function(program){try{const retptr=wasm.__wbindgen_add_to_stack_pointer(-16);const ptr0=passStringToWasm0(program,wasm.__wbindgen_malloc,wasm.__wbindgen_realloc);const len0=WASM_VECTOR_LEN;wasm.run_program(retptr,ptr0,len0);var r0=getInt32Memory0()[retptr/4+0];var r1=getInt32Memory0()[retptr/4+1];return getStringFromWasm0(r0,r1);}finally{wasm.__wbindgen_add_to_stack_pointer(16);wasm.__wbindgen_free(r0,r1);}};__exports.deinit_context=function(){wasm.deinit_context();};async function load(module,imports){if(typeof Response==='function'&&module instanceof Response){if(typeof WebAssembly.instantiateStreaming==='function'){try{return await WebAssembly.instantiateStreaming(module,imports);}catch(e){if(module.headers.get('Content-Type')!='application/wasm'){console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",e);}else{throw e;}}}
+const bytes=await module.arrayBuffer();return await WebAssembly.instantiate(bytes,imports);}else{const instance=await WebAssembly.instantiate(module,imports);if(instance instanceof WebAssembly.Instance){return{instance,module};}else{return instance;}}}
+function getImports(){const imports={};imports.wbg={};return imports;}
+function initMemory(imports,maybe_memory){}
+function finalizeInit(instance,module){wasm=instance.exports;init.__wbindgen_wasm_module=module;cachedInt32Memory0=new Int32Array();cachedUint8Memory0=new Uint8Array();return wasm;}
+function initSync(module){const imports=getImports();initMemory(imports);if(!(module instanceof WebAssembly.Module)){module=new WebAssembly.Module(module);}
+const instance=new WebAssembly.Instance(module,imports);return finalizeInit(instance,module);}
+async function init(input){if(typeof input==='undefined'){let src;if(typeof document==='undefined'){src=location.href;}else{src=document.currentScript.src;}
+input=src.replace(/\.js$/,'_bg.wasm');}
+const imports=getImports();if(typeof input==='string'||(typeof Request==='function'&&input instanceof Request)||(typeof URL==='function'&&input instanceof URL)){input=fetch(input);}
+initMemory(imports);const{instance,module}=await load(await input,imports);return finalizeInit(instance,module);}
+wasm_bindgen=Object.assign(init,{initSync},__exports);})();let loaded=false
+onmessage=async ev=>{if(!loaded){await wasm_bindgen("./osmarkscalculator.wasm")
+loaded=true}
+var[fn,...args]=ev.data
+let init=false
+if(fn==="deinit"){wasm_bindgen.deinit_context()
+init=false}else if(fn==="run"){const start=performance.now()
+try{if(!init){wasm_bindgen.init_context()
+wasm_bindgen.load_defaults()
+init=true;}
+postMessage(["ok",wasm_bindgen.run_program(args[0]),performance.now()-start])}catch(e){postMessage(["error",e.toString(),performance.now()-start])}}}
\ No newline at end of file
diff --git a/experiments/osmarkscalculator/osmarkscalculator.wasm b/experiments/osmarkscalculator/osmarkscalculator.wasm
new file mode 100644
index 0000000..2e833c3
Binary files /dev/null and b/experiments/osmarkscalculator/osmarkscalculator.wasm differ
diff --git a/src/index.js b/src/index.js
index 3b8c187..4ad92e5 100644
--- a/src/index.js
+++ b/src/index.js
@@ -133,7 +133,7 @@ const applyTemplate = async (template, input, getOutput, options = {}) => {
     return page.data
 }
 
-const addColors = R.map(x => ({ ...x, bgcol: hashColor(x.title, 0.5, 0.85), bordercol: hashColor(x.title, 0.7, 0.6) }))
+const addColors = R.map(x => ({ ...x, bgcol: hashColor(x.title, 0.7, 0.85) }))
 
 const processExperiments = async () => {
     const templates = globalData.templates
@@ -230,13 +230,21 @@ const genServiceWorker = async () => {
 }
 const copyAsset = subpath => fse.copy(path.join(assetsDir, subpath), path.join(outAssets, subpath))
 
+const doImages = async () => {
+    copyAsset("images")
+    globalData.images = {}
+    for (const image of await fse.readdir(path.join(assetsDir, "images"), { encoding: "utf-8" })) {
+        globalData.images[image.split(".").slice(0, -1).join(".")] = "/assets/images/" + image
+    }
+}
+
 const tasks = {
     errorPages: { deps: ["pagedeps"], fn: processErrorPages },
     templates: { deps: [], fn: loadTemplates },
     pagedeps: { deps: ["templates", "css"] },
     css: { deps: [], fn: compileCSS },
     writeBuildID: { deps: [], fn: writeBuildID },
-    index: { deps: ["openring", "pagedeps", "blog", "experiments"], fn: index },
+    index: { deps: ["openring", "pagedeps", "blog", "experiments", "images"], fn: index },
     openring: { deps: [], fn: runOpenring },
     rss: { deps: ["blog"], fn: genRSS },
     blog: { deps: ["pagedeps"], fn: processBlog },
@@ -245,7 +253,7 @@ const tasks = {
     manifest: { deps: ["assetsDir"], fn: genManifest },
     minifyJS: { deps: ["assetsDir"], fn: minifyJSTask },
     serviceWorker: { deps: [], fn: genServiceWorker },
-    images: { deps: ["assetsDir"], fn: () => copyAsset("images") },
+    images: { deps: ["assetsDir"], fn: doImages },
     offlinePage: { deps: ["assetsDir", "pagedeps"], fn: () => applyTemplate(globalData.templates.experiment, path.join(assetsDir, "offline.html"), () => path.join(outAssets, "offline.html"), {}) },
     assets: { deps: ["manifest", "minifyJS", "serviceWorker", "images"] },
     main: { deps: ["writeBuildID", "index", "errorPages", "assets", "experiments", "blog", "rss"] }
diff --git a/style.sass b/style.sass
index 6813990..0044e96 100644
--- a/style.sass
+++ b/style.sass
@@ -70,6 +70,12 @@ ul
 
 .isso
     padding: 1em
+    overflow-x: clip
+
+button, select, input, textarea, .textarea
+    border-radius: 0 !important
+    border: 1px solid gray
+    box-shadow: none !important
 
 .achievements
     position: fixed
@@ -105,3 +111,8 @@ ul
         text-align: right
         font-size: 0.8rem
         color: #555
+
+.imbox
+    display: flex
+    img
+        padding-right: 1em
\ No newline at end of file
diff --git a/templates/index.pug b/templates/index.pug
index cc351f6..b812ee2 100644
--- a/templates/index.pug
+++ b/templates/index.pug
@@ -7,21 +7,27 @@ block content
             Stuff I say, conveniently accessible on the internet.
         div.blog
             each post in posts
-                div(style=`background: ${post.bgcol}; border: 1px solid ${post.bordercol}`)
+                .imbox(style=`background: ${post.bgcol}`)
+                    if images.hasOwnProperty(post.slug)
+                        img(src=images[post.slug])
                     div
-                        a.title(href=`/${post.slug}/`)= post.title
-                    small= renderDate(post.updated)
-                    div.description!= post.description
+                        div
+                            a.title(href=`/${post.slug}/`)= post.title
+                        small= renderDate(post.updated)
+                        div.description!= post.description
 
         h2 Experiments
         p.
             Various random somewhat useless web projects I have put together over many years. Made with at least four different JS frameworks.
         div.experiments
             each experiment in experiments
-                div(style=`background: ${experiment.bgcol}; border: 1px solid ${experiment.bordercol}`)
+                .imbox(style=`background: ${experiment.bgcol}`)
+                    if images.hasOwnProperty(experiment.slug)
+                        img(src=images[experiment.slug])
                     div
-                        a.title(href=`/${experiment.slug}/`)= experiment.title
-                    span.description!= experiment.description
+                        div
+                            a.title(href=`/${experiment.slug}/`)= experiment.title
+                        span.description!= experiment.description
 
         p Get updates to the blog (not experiments) in your favourite RSS reader using the RSS feed.
         p View some of my projects (and whatever else) at