change things, images

This commit is contained in:
osmarks 2022-11-23 16:58:50 +00:00
parent d0feda98e1
commit 568248177b
45 changed files with 420 additions and 15 deletions

BIN
assets/images/FTL.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
assets/images/alphacol.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
assets/images/apioform.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
assets/images/csproblem.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
assets/images/emu-war.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
assets/images/flight.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
assets/images/gol.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
assets/images/guihacker.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
assets/images/heavscp.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
assets/images/ideas.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
assets/images/incdec.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

BIN
assets/images/infipage.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
assets/images/joe.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
assets/images/lorem.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
assets/images/nemc.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
assets/images/osbill.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
assets/images/phones.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
assets/images/points.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
assets/images/rpncalc2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
assets/images/rpncalc3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
assets/images/rpncalc4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
assets/images/rssgood.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

BIN
assets/images/scorer.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
assets/images/stack.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
assets/images/themes.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
assets/images/tictactoe.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

BIN
assets/images/whorl.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
assets/images/wsterm.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -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")

View File

@ -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())

View File

@ -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.

29
blog/rssgood.md Normal file
View File

@ -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).

View File

@ -0,0 +1,240 @@
---
title: Flying Thing
description: Fly an ominous flying square around above some ground! Includes special relativity!
---
<style>
body {
box-sizing: border-box;
font-family: 'Fira Sans', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
#controls {
border: 1px solid blue;
padding: 1em;
margin: 1em;
}
#controls select {
border: 1px solid blue;
padding: 0.2em;
}
#container {
display: flex;
}
</style>
<div id="container">
<canvas id="thing" width=800 height=800></canvas>
<div id="controls-container">
<div id="controls">
<label><select name="mechanics"><option>Relativistic</option><option>Newtonian</option><option>Aristotlean</option></select> Mechanics</label><br>
<label><select name="ground"><option>Noise</option><option>Time-Varying</option><option>Flat</option><option>Triangles</option><option>Catenary</option></select> Ground</label><br>
<label><select name="controls"><option>Absolute Orientation</option><option>Relative Orientation</option></select> Controls</label><br>
<label><select name="restitution"><option>1</option><option>&lt; 1</option><option>&gt; 1</option></select> e</label><br>
<label><select name="gravity"><option>Normal</option><option>High</option><option>Off</option></select> Gravity</label>
</div>
</div>
</div>
<script>
var settings = {}
for (const input of document.querySelectorAll("#controls input, #controls select")) {
const read = () => { settings[input.getAttribute("name")] = input.getAttribute("type") === "checkbox" ? input.checked : input.value }
read()
input.addEventListener("input", read)
}
var ctx = window.thing.getContext("2d")
const angleToVec = theta => [Math.cos(theta), Math.sin(theta)]
const zipWith = (f, xs, ys) => xs.map((x, i) => f(x, ys[i]))
const sum = xs => xs.reduce((a, y) => a + y, 0)
const vecAdd = (a, b) => zipWith((x, y) => x + y, a, b)
const hadamardProduct = (a, b) => zipWith((x, y) => x * y, a, b)
const scalarMult = (a, n) => a.map(x => x * n)
const dotProduct = (a, b) => sum(hadamardProduct(a, b))
const vecLength = a => Math.sqrt(sum(a.map(x => x ** 2)))
const normalize = a => scalarMult(a, 1/vecLength(a))
function vsub(x, y) { return vecAdd(x, scalarMult(y, -1)) }
function derivativeApproximation(f, a) {
var delta = 0.000001
return (f(a + delta) - f(a)) / delta
}
const rotate90CW = ([x, y]) => [y, -x]
var pixelDimensions = [window.thing.width, window.thing.height]
var position = [0.5, 0.5]
var velocity = [0, 0]
var keys = {}
window.onkeydown = ev => {
keys[ev.key] = true
}
window.onkeyup = ev => {
keys[ev.key] = false
}
const toScreen = v => hadamardProduct(v, pixelDimensions)
function draw(start, end, color) {
ctx.fillStyle = color
var start = toScreen(start)
var end = toScreen(end)
ctx.fillRect(start[0], start[1], end[0] - start[0], end[1] - start[1])
}
function drawLine(color, start, ...points) {
ctx.lineWidth = 2
ctx.strokeStyle = color
ctx.beginPath()
var s = toScreen(start)
ctx.moveTo(s[0], s[1])
for (const point of points) {
var p = toScreen(point)
ctx.lineTo(p[0], p[1])
}
ctx.stroke()
}
var SPEED_OF_LIGHT = 0.01
const gamma = v => (1 - (v/SPEED_OF_LIGHT)**2) ** (-0.5)
const gammaDerivative = v => (v/(SPEED_OF_LIGHT**2))*((1-(v/SPEED_OF_LIGHT)**2)**(-1.5))
const noiseSeed = Math.random() * (2**32-1)
const hash = (str, seed = 0) => {
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed
for (let i = 0, ch; i < str.length; i++) {
ch = str.charCodeAt(i)
h1 = Math.imul(h1 ^ ch, 2654435761)
h2 = Math.imul(h2 ^ ch, 1597334677)
}
h1 = Math.imul(h1 ^ (h1>>>16), 2246822507) ^ Math.imul(h2 ^ (h2>>>13), 3266489909)
h2 = Math.imul(h2 ^ (h2>>>16), 2246822507) ^ Math.imul(h1 ^ (h1>>>13), 3266489909)
return 4294967296 * (2097151 & h2) + (h1>>>0)
}
const cartesianProduct = (xs, ys) => xs.flatMap(x => ys.map(y => [x, y]))
const gradients = cartesianProduct([-1, -0.5, 0.5, 1], [-1, -0.5, 0.5, 1]).map(normalize)
const gradientFor = (x, y) => gradients[hash(x+"."+y, noiseSeed) % gradients.length]
const interpolate = (a0, a1, w) => (a1 - a0) * (3.0 - w * 2.0) * w * w + a0
const perlin = (x, y) => {
const i = Math.floor(x), j = Math.floor(y)
const u = x - i, v = y - j
const n00 = dotProduct(gradientFor(i, j), [u, v])
const n01 = dotProduct(gradientFor(i + 1, j), [u - 1, v])
const n10 = dotProduct(gradientFor(i, j + 1), [u, v - 1])
const n11 = dotProduct(gradientFor(i + 1, j + 1), [u - 1, v - 1])
return interpolate(interpolate(n00, n01, u), interpolate(n10, n11, u), v)
}
const GROUND_FUNCTIONS = {
"Time-Varying": x => perlin(x * 10, x * 10 + Date.now() / 10000) * 0.25 + 0.75,
"Noise": x => perlin(x * 10, x * 10) * 0.25 + 0.75,
"Flat": x => 0.75,
"Triangles": x => 0.25*(Math.abs(10*x-Math.floor(10*x)-0.5)) + 0.75,
"Catenary": x => 1.3-Math.cosh(x-0.5)*0.5
}
const E_COEFFICIENTS = {
"1": 1,
"< 1": 0.5,
"> 1": 1.5
}
const GRAVITY = {
"Normal": 0.0001,
"High": 0.0005,
"Off": 0
}
var direction = -Math.PI/2
var lastTime
var SIMITERS = 1
function loop(timestamp) {
if (lastTime) {
var timestep = timestamp - lastTime
var scaling = 0.5 * timestep / 16.666666666666666666666666666666666666666
lastTime = timestamp
} else {
requestAnimationFrame(loop)
lastTime = timestamp
return
}
var groundFunc = GROUND_FUNCTIONS[settings.ground]
var reldir = settings.controls === "Relative Orientation"
const scale = x => scalarMult(x, scaling)
draw([0, 0], [1, 1], "black")
ctx.fillStyle = "gray"
for (let i = 0; i < pixelDimensions[0]; i++) {
var gameX = i / pixelDimensions[0]
var gameH = groundFunc(gameX)
var pixelH = gameH * pixelDimensions[1]
ctx.fillRect(i, pixelH, 1, pixelDimensions[1] - pixelH)
}
drawLine("green", position, vecAdd(position, scalarMult(velocity, 20)))
if (reldir) {
drawLine("blue", position, vecAdd(position, scalarMult(angleToVec(direction), 0.05)))
}
draw(vsub(position, [-0.005, -0.005]), vsub(position, [0.005, 0.005]), "white")
scaling /= SIMITERS
for (var i = 0; i < SIMITERS; i++) {
position = vecAdd(scale(velocity), position)
var force = [0, GRAVITY[settings.gravity]]
if (keys["w"]) {
if (reldir) {
force = vecAdd(force, scalarMult(angleToVec(direction), 0.001))
} else {
force = vecAdd(force, [0, -0.001])
}
}
if (keys["a"]) {
if (reldir) {
direction -= 0.05
} else {
force = vecAdd(force, [-0.0005, 0])
}
}
if (keys["d"]) {
if (reldir) {
direction += 0.05
} else {
force = vecAdd(force, [0.0005, 0])
}
}
if (keys["s"]) {
if (reldir) {
force = vecAdd(force, scalarMult(angleToVec(direction), -0.0005))
} else {
force = vecAdd(force, [0, 0.0005])
}
}
var divisor = settings.mechanics === "Relativistic" ? gamma(vecLength(velocity)) ** 3 : 1 //gamma(vecLength(velocity)) + gammaDerivative(vecLength(velocity)) * vecLength(velocity)
if (isNaN(divisor)) {
console.log("luminal limit exceeded, resetting")
divisor = 1
velocity = [0, 0]
}
var velocityChange = scalarMult(scale(force), 1/divisor)
//console.log(gamma(vecLength(velocity)), velocity, velocityChange)
if (settings.mechanics === "Aristotlean") {
velocity = scalarMult(velocityChange, 60)
} else {
velocity = vecAdd(velocity, velocityChange)
}
if (position[1] > 1) { position[1] = 0 }
if (position[1] < 0) { position[1] = 1 }
if (position[0] > 1) { position[0] = 0 }
if (position[0] < 0) { position[0] = 1 }
//console.log(GROUND(position[0]), position[0])
if (position[1] > groundFunc(position[0])) {
var groundVector = normalize([1, derivativeApproximation(groundFunc, position[0])])
var normalVector = rotate90CW(groundVector)
velocity = vecAdd(scalarMult(groundVector, dotProduct(velocity, groundVector)),
scalarMult(normalVector, -E_COEFFICIENTS[settings.restitution] * dotProduct(velocity, normalVector)))
position[1] = groundFunc(position[0])
}
}
requestAnimationFrame(loop)
}
requestAnimationFrame(loop)
</script>

View File

@ -23,7 +23,7 @@ description: <a href="https://github.com/osmarks/guihacker">My fork</a> of GUIHa
top: 0;
left: 0;
}
.bars-and-stuff{
.bars-and-stuff {
left: 66.6%;
}
@ -31,7 +31,9 @@ description: <a href="https://github.com/osmarks/guihacker">My fork</a> of GUIHa
position: fixed;
overflow: hidden;
}
p{margin:0}
p {
margin:0
}
nav {
display: none;

View File

@ -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.
---

View File

@ -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.
---
<textarea id="program" style="width: 100%; resize: vertical" rows="5"></textarea>
<pre id="output"></pre>
<button id="go">Go</button>
<button id="clear">Clear Context</button>
<select id="examples">
</select>
<script>
const examples = {
"blank": "",
"factorial": `Fac[n] = Fac[n-1]*n
Fac[0] = 1
Fac[17]
`,
"expand": "(a+b)*(c+d)*(e+f)*(g+h)",
"expand2": "(a+b)^3*(b+c)-d",
"fibonacci": `Fib[n] = Fib[n-1] + Fib[n-2]
Fib[0] = 0
Fib[1] = 1
Fib[6]
`,
"predicate": `IsEven[x] = 0
IsEven[x#Eq[Mod[x, 2], 0]] = 1
IsEven[3] - IsEven[4]`,
"derivative": `D[3*x^3 + 6*x, x]`,
"simplify": `x^a/x^(a+1)`,
"simplify2": "Negate[a+b] + b",
"arith": `(12+55)^3-75+16/(2*2)+5+3*4`,
"subst": "Subst[x=4, x+4+4+4+4]"
}
const examplesSelector = document.querySelector("#examples")
const program = document.querySelector("#program")
for (const name of Object.keys(examples)) {
const opt = document.createElement("option")
opt.value = name
opt.appendChild(document.createTextNode(name))
examplesSelector.appendChild(opt)
}
examplesSelector.addEventListener("change", () => {
program.value = examples[examplesSelector.value]
})
var worker = new Worker("osmarkscalculator.js")
const forceKill = () => {
console.warn("Force-terminating worker.")
worker.terminate()
worker = new Worker("osmarkscalculator.js")
}
const write = data => {
const out = document.querySelector("#output")
while (out.firstChild) { out.removeChild(out.firstChild) }
out.appendChild(document.createTextNode(data))
}
document.querySelector("#go").addEventListener("click", () => {
console.log(program.value)
write("Running...")
worker.postMessage(["run", program.value])
var timeout = setTimeout(() => {
forceKill()
write("Execution timeout")
}, 5000)
worker.onmessage = ev => {
const [status, result, time] = ev.data
if (status === "ok") {
write(result + `\nin ${time}ms`)
} else {
write("Internal error: " + result + `\nin ${time}ms`)
}
clearInterval(timeout)
}
})
document.querySelector("#clear").addEventListener("click", () => worker.postMessage(["deinit"]))
</script>

View File

@ -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(;offset<len;offset++){const code=arg.charCodeAt(offset);if(code>0x7F)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])}}}

Binary file not shown.

View File

@ -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"] }

View File

@ -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

View File

@ -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 <a href="/rss.xml">RSS feed</a>.
p View some of my projects (and whatever else) at