source
this page contains all of the Haskell code that's used to generate this website . the full source repository is on SourceHut . i've also written about the story behind this design .
Pages.hs
1module Pages
2 ( pageWrapper
3 , mainPages
4 , tagPages
5 , postPages
6 , projectPages
7 , bookPage
8 ) where
9
10import Zoxuli
11import Lucid hiding (h2_, h3_, h4_, h5_, h6_)
12import Lucid.Base (makeAttribute)
13import Optics
14import GHC.Generics (Generic)
15import Data.Maybe (fromMaybe)
16import Data.List (elemIndex, intersperse)
17import Data.Text (Text, pack)
18import Control.Monad (when)
19import Control.Monad.State.Lazy (get, lift)
20import qualified Data.Set as Set
21
22pageWrapper :: Bool -> Page -> Page
23pageWrapper showNav page = page & #html .~ ( do
24 doctype_
25 html_ [lang_ "en"] $ do
26 head_ $ do
27 title_ . toHtml $ "eevie nebulæ | " <> page.title
28 meta_ [charset_ "UTF-8"]
29 meta_ [name_ "viewport", content_ "width=device-width, initial-scale=1"]
30 meta_ [name_ "author", content_ "eevie nebulæ"]
31 meta_ [name_ "description", content_ "negentropic equilibrium"]
32 link_ [rel_ "stylesheet", href_ "/css/styles.css"]
33 link_ [rel_ "icon", href_ "data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🌌</text></svg>"]
34 body_ $ do
35 when showNav $
36 header_ $ do
37 nav_ $ do
38 p_ $ link False homePage "eevie nebulæ"
39 ul_ $ mapM_ navLink
40 [postsPage, projectsPage, tagsPage, metaPage]
41 hr_ []
42 main_ $ do
43 h1_ $ toHtml page.title
44 page.html
45 lift get <&> (^? #_Two % #footnotes) >>= \case
46 Just footnotes@(_:_) -> do
47 div_ [class_ "footnotes"] $ do
48 h2_ "footnotes"
49 ol_ $ mapM_ renderFootnote footnotes
50 _ -> pure ()
51 lift get <&> (^? #_Two % #backlinks) >>= \case
52 Just backlinks@(_:_) -> do
53 div_ [class_ "backlinks"] $ do
54 h2_ "backlinks"
55 ul_ $ mapM_ renderBacklink backlinks
56 _ -> pure ()
57 )
58 where navLink :: Page -> Zoxuli
59 navLink p = li_ $ link False p p.title
60 renderFootnote :: Footnote -> Zoxuli
61 renderFootnote (Footnote index content) =
62 li_ [id_ $ "fn" <> pack (show index)] $ do
63 content; " "
64 a_ [ href_ $ "#r" <> pack (show index)
65 , makeAttribute "aria-label" "return to content" ]
66 "[back]"
67 renderBacklink :: Link -> Zoxuli
68 renderBacklink ln = li_ $ do
69 toHtml ln.destinationTitle; " : \""
70 a_ [href_ $ "/" <> ln.destinationPath <> ".html#"
71 <> slugify ln.body] $
72 toHtml ln.body
73 "\""
74
75-- | main pages
76
77mainPages :: [Page]
78mainPages =
79 [ homePage
80 , metaPage
81 , faqPage
82 , projectsPage
83 , postsPage
84 , tagsPage
85 , seriesPage
86 , sourcePage
87 , contactPage
88 , todoPage
89 , anticopyrightPage
90 , downloadPage
91 , digitalArtPage
92 , photographyPage ]
93
94homePage :: Page
95homePage = makePage "home" $ do
96 h2_ "featured post"
97 p_ $ div_ [class_ "border"] $ do
98 p_ [style_ "font-size: 120%"] $
99 b_ $ link True (fst theOasisPost) "the oasis"
100 blockquote_ $ em_ "for a long time , i've been thinking about how to build a kinder & more radical version of the OASIS from Ready Player One using currently available technology [...]"
101 p_ $ link False postsPage "more posts ..."
102 hr_ []
103 h2_ "featured project"
104 p_ $ div_ [class_ "border"] $ do
105 p_ [style_ "font-size: 120%"] $
106 b_ $ link True (fst zoxuliProject) "zoxuli"
107 blockquote_ $ em_ "years ago , it started with a humble goal that many could relate to . i wanted to make a website to put my writing on [...]"
108 p_ $ link False projectsPage "more projects ..."
109 hr_ []
110 div_ [style_ "text-align: center"] $ do
111 h2_ "negentropic equilibrium"
112 p_ $ do "after all that "; b_ "pain"
113 p_ $ do "after all that "; b_ "trauma"
114 p_ $ do "grinding your ability to act to a "; b_ "halt"
115 p_ $ do "you can still "; b_ "choose"; " to keep going"
116 p_ $ do "keep "; b_ "healing"
117 p_ $ do "keep "; b_ "fighting"
118 p_ $ b_ "with any scrap of leverage you've got left"
119 p_ $ em_ "for as long as agency exists"
120
121metaPage :: Page
122metaPage = makePage "meta" $ do
123 ul_ $ do
124 li_ $ link False faqPage "frequently asked questions"
125 li_ $ link False contactPage "contact me"
126 li_ $ link False downloadPage "download this website"
127 li_ $ link False sourcePage "source code"
128 li_ $ link False anticopyrightPage "anticopyright"
129 li_ $ link False todoPage "todo"
130
131faqPage :: Page
132faqPage = makePage "FAQ" $ p_ $ do
133 img_ [ src_ "/img/avatar.png"
134 , class_ "pixel-art avatar"
135 , alt_ "a pixel art portrait of eevie floating amongst magic sigils" ]
136 h2_ "who are you ?"
137 p_ $ do "hi ! i'm "; b_ "eevie"; " , pronouns she/fæ ."
138 h2_ "what do you do ?"
139 p_ $ do "i'm currently working on the intersection of anti-fascism , veganism , & transhumanism ."
140 h2_ "how do i leave a comment ?"
141 p_ $ do
142 link True contactPage "contact me"
143 " with your name ( optional ) & comment , & i might add it ."
144 p_ "feel free to let me know if you notice any factual inaccuracies ior accessibility issues on my website !"
145 h2_ "what does ior & eor mean ?"
146 p_ $ do
147 "i dislike the ambiguity of the word \"or\" in cases where it could be "
148 a_ [href_ "https://en.wikipedia.org/wiki/Logical_disjunction"] "inclusive"
149 " eor "
150 a_ [href_ "https://en.wikipedia.org/wiki/Exclusive_or"] "exclusive"
151 " , so i call inclusive-or \"ior\" & exclusive-or \"eor\" ."
152 h2_ "why do you put extra spaces around punctuation ?"
153 p_ $ do
154 "this style is easier for me to read . one reason is that commas & "
155 a_ [href_ "https://en.wikipedia.org/wiki/Terminal_punctuation"] "terminal punctuation"
156 " stand out more , so it requires less effort to keep track of where i am within the structure of a sentence ."
157 h2_ "where am i ?"
158 code "haskell" "go North\nlook"
159 p_ $ do
160 "you hover to the center of a sea of emerald grass that ripples in slow-motion waves . warm gusts guide the smell of rain through the chilled night air . your sigils pepper the orb around you , threaded by semantic strands cast off from your imagined hands . your gaze turns to the edge of the sea where the "
161 link True (fst wallOfShardsPost) "wall of shards"
162 " approaches forebodingly ."
163
164anticopyrightPage :: Page
165anticopyrightPage = makePage "anticopyright" $ do
166 p_ $ do
167 "see "; link True (fst unlicensePost) "this post"
168 " for why i am against copyright ."
169 p_ $ do
170 "all media , text , & other content on this website are in the public domain under "
171 a_ [href_ "https://creativecommons.org/publicdomain/zero/1.0/?ref=chooser-v1"] "CC0 1.0 Universal"
172 " , with the following exceptions :"
173 ul_ $ do
174 li_ $ do
175 "the CSS for syntax highlighing was generated by "
176 a_ [href_ "https://github.com/alecthomas/chroma"] "chroma"
177 " , which is under the "
178 a_ [href_ "https://github.com/alecthomas/chroma/blob/master/COPYING"] "MIT license"
179 li_ $ do
180 a_ [href_ "https://www.dafont.com/offenbacher-reform-cat.font"] "Offenbacher Reform"
181 " by Peter Wiegel is under the "
182 a_ [href_ "https://openfontlicense.org/"] "SIL Open Font License"
183
184downloadPage :: Page
185downloadPage = makePage "download" $ do
186 h2_ "archive"
187 p_ "a full archive of this website is available for offline viewing :"
188 p_ $ a_ [href_ "/eevie.dev.tar.gz"] "download archive"
189 h2_ "book"
190 p_ $ do
191 "there is a book page containing every post , designed for printing ior saving as a PDF :"
192 p_ $ link False bookPage "view book"
193 h2_ "source"
194 p_ "one can clone the source repository of this site using git :"
195 code "bash" "git clone https://git.sr.ht/~nebulae/eevie.dev"
196
197projectsPage :: Page
198projectsPage = makePage "projects" $ do
199 h2_ "art"
200 ul_ $ do
201 li_ $ link True digitalArtPage "digital"
202 li_ $ a_ [href_ "https://plokta.bandcamp.com/"] "music"
203 li_ $ link True photographyPage "photography"
204 h2_ "software"
205 ul_ $ do
206 mapM_ (li_ . projectPreview) projectPages
207 li_ $ do
208 b_ $ a_ [href_ "https://git.sr.ht/~nebulae/concur_vite"] "Concur + Vite"
209 " - a purescript-concur starter template"
210 li_ $ do
211 b_ $ a_ [href_ "yarnstar/index.html"] "[WIP] yarnstar"
212 " - an implementation of Nova in Elm"
213 li_ $ do
214 b_ $ a_ [href_ "https://git.sr.ht/~nebulae/nova_conjure"] "[WIP] NovaConjure"
215 " - interactive fiction witchcraft in Nova"
216 li_ $ do
217 b_ $ a_ [href_ "https://git.sr.ht/~nebulae/antibubble"] "[WIP] Antibubble"
218 " - nested bubble world exploration game"
219
220postsPage :: Page
221postsPage = makePage "posts" $ do
222 p_ "in which i externalize the technicolor collapse of techno-synaptic maps of mind matter i’m made of ."
223 ul_ $ mapM_ (li_ . postPreview) postPages
224 microblog
225
226microblog :: Zoxuli
227microblog = do
228 h2_ "microblog"
229 p_ "for shorter thoughts !"
230 micropost "2024-12-06" $ do
231 "low back creaking"; br_ []
232 "dizzy when standing"; br_ []
233 "both eyes blurring"; br_ []
234 "can't we learn while moving ?"
235 micropost "2024-06-09" $ do
236 "i hate the term "
237 a_ [href_ "https://en.wikipedia.org/wiki/Overfishing"] "\"overfishing\""
238 " , because it implies that there’s an acceptable amount of "
239 a_ [href_ "https://animalequality.org/issues/fish/"] "fishing"
240 " ."
241 where micropost :: Text -> Zoxuli -> Zoxuli
242 micropost date content =
243 p_ $ div_ [class_ "border"] $ do
244 p_ $ b_ $ toHtml date
245 p_ content
246
247bookPage :: Page
248bookPage = makePage "book" $ do
249 h2_ "chapters"
250 ol_ $ mapM_ (li_ . toHtml . (^. #title)) pages
251 mapM_ chapter pages
252 where pages :: [Page]
253 pages = (fst <$> postPages') <> (fst <$> projectPages')
254 chapter :: Page -> Zoxuli
255 chapter page = do
256 hr_ []
257 h1_ $ toHtml page.title
258 page.html
259
260tagsPage :: Page
261tagsPage = makePage "tags" $ do
262 p_ "hypertext flowed through the cracks in the ground , illuminated by ambient amethyst light from the sky above ."
263 ul_ $ mapM_ (li_ . tagPreview) allTags
264
265seriesPage :: Page
266seriesPage = makePage "series" $ do
267 mapM_ renderSeries allSeries
268
269sourcePage :: Page
270sourcePage = makePage "source" $ do
271 p_ $ do
272 "this page contains all of the "
273 linkToAnchor True (fst howIUseComputersPost) "language" "Haskell"
274 " code that's used to generate this website . the full source repository is on "
275 a_ [href_ "https://git.sr.ht/~nebulae/eevie.dev"]
276 "SourceHut"
277 " . i've also written about the "
278 link True (fst zoxuliProject) "story behind this design"
279 " . "
280 lift get <&> (^? #_Two % #srcFiles) >>= \case
281 Just srcFiles -> mapM_ renderSrcFile srcFiles
282 _ -> pure ()
283 where renderSrcFile :: SrcFile -> Zoxuli
284 renderSrcFile f = do
285 h2_ f.name
286 p_ $ a_ [href_ $ "/src/" <> f.name] "raw file"
287 rawHtml f.content
288
289contactPage :: Page
290contactPage = makePage "contact" $ do
291 p_ $ do
292 "email : "
293 span_ [class_ "email"] $ do
294 "eevie@sent"; b_ "obfuscation-text"; ".com"
295 h2_ "don't contact me if ..."
296 p_ $ do "if you "; em_ "intentionally"; " propagate any of the following , i do "; em_ "not"; " want to hear from you :"
297 ul_ $ do
298 li_ "fascism"
299 li_ "nationalism"
300 li_ "classism"
301 li_ "speciesism"
302 li_ "substratism"
303 li_ "ageism"
304 li_ "antisemitism"
305 li_ "racism"
306 li_ "colorism"
307 li_ "sexism"
308 li_ "deathism"
309 li_ "ableism"
310 li_ "sanism"
311 li_ "transphobia"
312 li_ "enbyphobia"
313 li_ "interphobia"
314 li_ "aphobia"
315 li_ "lesbophobia"
316 li_ "homophobia"
317 li_ "biphobia"
318 li_ "fatphobia"
319 li_ "pluralphobia"
320 todo "create a PGP key"
321
322todo :: Text -> Zoxuli
323todo title = link True todoPage $ "todo : " <> title
324
325todoPage :: Page
326todoPage = makePage "todo" $ do
327 ul_ $ do
328 li_ $ do
329 "follow Seirdy's "
330 a_ [href_ "https://seirdy.one/posts/2020/11/23/website-best-practices/"] "best practices for inclusive textual websites"
331 li_ $ do
332 "make an "; inlineCode "md"; " function that uses the "
333 a_ [href_ "https://hackage.haskell.org/package/cmark"] "cmark"
334 " library"
335 li_ "RSS/Atom feeds"
336 li_ "N24 manager , swirlsaber , particle art , & helix lavender theme"
337 p_ "any todos across the site are linked to this page , so you can view them in the list of backlinks :"
338
339photo :: Text -> Text -> Zoxuli
340photo file alt = img_
341 [ src_ $ "/img/" <> file
342 , style_ "width: 100%"
343 , alt_ alt ]
344
345digitalArtPage :: Page
346digitalArtPage = makePage "digital art" $ do
347 h2_ "trans hacker fæ"
348 photo "trans-hacker-fae-code.jpg" "a woman wearing a glass, polygonal skirt & round, glitchy sunglasses spreads her neon-colored wings. she is standing on a snowy hill beside a lamppost, & there is a city with towering skyscrapers across an ocean bay in the background. an overlay over her vision shows a terminal window with cute ASCII art borders. she just updated her source code so that she doesn't compromise with the gender police."
349 p_ $ do
350 "( "
351 a_ [href_ "/img/trans-hacker-fae.jpg"] "version without overlay"
352 " )"
353 p_ "this image is about how i used to be so gaslit into submission that i’d frequently compromise with people who didn’t want me to exist , but now transphobes only make me want to scream & cry & then continue living on anyway in absolute , prideful defiance ."
354 p_ $ do
355 "made using "
356 a_ [href_ "https://www.blender.org/"] "Blender"
357 " , "
358 a_ [href_ "https://godotengine.org/"] "Godot"
359 " , & "
360 a_ [href_ "https://krita.org/en/"] "Krita"
361 " ."
362 h2_ "spiky swamp"
363 photo "spiky_swamp.jpg" "a cloaked, humanoid creature with glowing eyes & a spiky tail stands beside a gramophone on a boardwalk in a misty swamp. trees with wide bases & black spikes are scattered around."
364 p_ "this is a screenshot from my first attempt at making a low-poly 3D game ."
365
366photographyPage :: Page
367photographyPage = makePage "photography" $ do
368 photo "banner.png" "a dithered photograph of blue & pink flowers"
369 photo "plants5.jpg" "a beetle resting on the center of a fully bloomed flower"
370 photo "plants4.jpg" "a small butterfly in a bright field of flowers"
371 photo "plants1.jpg" "a brightly lit plant with bundles of fuzzy pink flowers"
372 photo "plants2.jpg" "a bundle of fuzzy white flowers in a verdant garden"
373 photo "plants3.jpg" "stalks of bamboo in a forest with large bokeh in the background"
374
375-- | tag pages
376
377taggedPages :: [Page]
378taggedPages = (fst <$> projectPages) <> (fst <$> postPages)
379
380allTags :: [Text]
381allTags = deduplicate $ concatMap (^. #tags) taggedPages
382 where deduplicate = Set.toList . Set.fromList
383
384pagesWithTag :: Text -> [Page]
385pagesWithTag tag = filter (elem tag . (^. #tags)) taggedPages
386
387tagPreview :: Text -> Zoxuli
388tagPreview tag = do
389 toHtml . show . length $ pagesWithTag tag; " - "
390 a_ [href_ $ "/tags/" <> slugify tag <> ".html"] $ toHtml tag
391
392renderTags :: [Text] -> Zoxuli
393renderTags tags =
394 sequence_ . intersperse " , " $ renderTag <$> tags
395 where renderTag :: Text -> Zoxuli
396 renderTag tag =
397 a_ [ href_ $ "/tags/" <> slugify tag <> ".html" ]
398 $ toHtml tag
399
400tagPages :: [Page]
401tagPages = makeTagPage <$> allTags
402
403makeTagPage :: Text -> Page
404makeTagPage tag = Page tag path [] html
405 where path = "tags/" <> slugify tag
406 html = do
407 p_ $ do "pages tagged \""; toHtml tag; "\":"
408 ul_ . mapM_ (\p -> li_ $ link False p p.title)
409 $ pagesWithTag tag
410
411-- | page series
412
413data Series = Series
414 { name :: Text
415 , pages :: [Page] } deriving (Generic)
416
417allSeries :: [Series]
418allSeries = [computingSeries]
419
420computingSeries :: Series
421computingSeries = Series "liberatory computing"
422 [ fst theOasisPost
423 , fst unlicensePost
424 , fst timelineSplittingPost
425 , fst queerCybersecPost
426 , fst howIUseComputersPost
427 , fst zoxuliProject ]
428
429renderSeries :: Series -> Zoxuli
430renderSeries series = do
431 h2_ series.name
432 ol_ . mapM_ (\p -> li_ $ link False p p.title)
433 $ series.pages
434
435seriesNav :: Page -> Maybe Zoxuli
436seriesNav page =
437 if null seriesWithPage then Nothing
438 else Just $ mapM_ renderSeriesNav seriesWithPage
439 where seriesWithPage = filter (elem page . (^. #pages)) allSeries
440 renderSeriesNav :: Series -> Zoxuli
441 renderSeriesNav (Series name ps) = span_ $ do
442 let next xs x = lookup x . zip xs $ tail xs
443 maybeLink t = maybe (pure ()) $ \p -> link False p t
444 position = (+ 1) . fromMaybe 1 $ elemIndex page ps
445 b_ "series"; " : "
446 toHtml . show $ position; "/"
447 toHtml . show $ length ps
448 " in "
449 a_ [ href_ $ "/series.html#" <> slugify name ]
450 . toHtml $ name
451 " : "
452 maybeLink "[previous]" $ next (reverse ps) page
453 " "
454 maybeLink "[next]" $ next ps page
455
456-- | project pages
457
458projectWrapper :: Project -> Project
459projectWrapper project =
460 project & _1 % #html %~ (meta <>)
461 where meta = do
462 p_ [class_ "description"] .
463 toHtml $ project ^. _2 % #description
464 toc
465 ul_ $ do
466 li_ $ a_ [ href_ $ project ^. _2 % #repo ] $
467 b_ "📦 SourceHut page"
468 maybe (pure ()) li_ . seriesNav $ fst project
469 li_ $ do
470 b_ "tags"; " : "
471 renderTags $ project ^. _1 % #tags
472
473projectPreview :: Project -> Zoxuli
474projectPreview project = do
475 b_ $ link False (fst project) $ project ^. _1 % #title
476 " - "; toHtml $ project ^. _2 % #description
477
478projectPages :: [Project]
479projectPages = projectWrapper <$> projectPages'
480
481projectPages' :: [Project]
482projectPages' =
483 [ zoxuliProject
484 , swirlmaniaProject
485 , coaltonRaylibProject
486 ]
487
488zoxuliProject :: Project
489zoxuliProject = makeProject "zoxuli"
490 "a lucid static site generator"
491 "https://git.sr.ht/~nebulae/zoxuli"
492 ["web dev", "haskell", "programming"] $ do
493 h2_ "a humble goal"
494 p_ "years ago , it started with a humble goal that many could relate to . i wanted to make a website to put my writing on ."
495 p_ "this would lead me on an unexpectedly long journey that ends at the website you're on today ."
496 h2_ "static site generators"
497 p_ $ do
498 "i started off by learning about "
499 a_ [href_ "https://wordpress.com/"] "WordPress"
500 " , then quickly realized that the WordPress interface was not accessible for me , although i would not have known to describe the problem like that at the time ."
501 p_ $ do
502 "looking for other options , i discovered "
503 a_ [href_ "https://en.wikipedia.org/wiki/Static_site_generator"] "static site generators"
504 " ( SSGs ) , which had the nice property that they were interfaced with using a text editor & a terminal window , which was more accessible to me . so i tried my best to learn an SSG called "
505 a_ [href_ "https://jekyllrb.com/"] "Jekyll"
506 " , but the documentation was too advanced for me at the time . i moved on to other projects for a while ."
507 h2_ "a new problem"
508 p_ "a while later , after i had learned more about programming for other reasons , i realized i could now understand the Jekyll documentation !"
509 p_ $ do "except ... now my expectations for my website had changed significantly . now i wanted :"
510 ul_ $ do
511 li_ "excellent accessibility"
512 li_ "post series with navigation"
513 li_ "tables of contents"
514 li_ "tags that work across multiple categories of pages"
515 li_ "backlinks"
516 li_ "footnotes"
517 li_ "breadcrumbs"
518 li_ "control over where & how the aforementioned elements appear"
519 li_ "syntax highlighting"
520 li_ "LaTeX"
521 li_ "semantic markup"
522 li_ "no JavaScript"
523 li_ "broken link checking"
524 li_ "simple & powerful extensibility in a comfortable language"
525 li_ "the ability to write pages in any markup format"
526 li_ "a fast development feedback loop"
527 p_ $ do
528 "i thought , hey , that's a lot of stuff to ask for , but there are "
529 a_ [href_ "https://jamstack.org/generators/"] "hundreds"
530 " ( eor likely thousands ) of SSGs , so surely at least one of them can do all that ?"
531 h2_ "SSG frenzy"
532 p_ $ do
533 "i tried a lot of SSGs . the three that got me closest to all of my goals were "
534 a_ [href_ "https://soupault.app/"] "Soupault"; " , "
535 a_ [href_ "https://bagatto.co/"] "Bagatto"; " , & "
536 a_ [href_ "https://jaspervdj.be/hakyll/"] "Hakyll"
537 " . but none of those got me everything ( "
538 todo "explain their strengths & shortcomings in detail"
539 " ) . there might be another one out there , but i didn't find it ."
540 p_ "not to worry though , because after trying so many SSGs, i was intimately familiar with the tradeoffs involved in their design , & felt comfortable writing my own from scratch ."
541 h2_ "zoxuli : first attempt"
542 p_ $ do
543 "my first attempt ( "
544 todo "share zoxuli v1"
545 " ) was written in Common Lisp , & was most similar to Bagatto ."
546 p_ $ do
547 "the core idea was to have the user of the zoxuli library write a data structure describing the inputs & outputs of the site in Lisp , & the markup files ( ior stylesheet , ior whatever else - it was filetype agnostic ) could contain snippets of lisp surrounded by "
548 inlineCode ".("; " & "; inlineCode ")."
549 " that would be evaluated when the site was built ."
550 p_ $ do
551 "this meant that - as an example - if one wanted to generate backlinks , one could create a "
552 inlineCode ".(link <args>)."
553 " function that would be used anywhere they needed links in their markup . the function would both render the link HTML ( using "
554 a_ [href_ "https://github.com/ruricolist/spinneret"] "spinneret"
555 " ) that gets inserted back into that position by zoxuli , & also store the link data into a variable . during the second pass , calls to a "
556 inlineCode ".(backlinks)."
557 " function would convert the collected links into backlinks & render them into HTML wherever they are needed ."
558 h2_ "zoxuli : final version"
559 p_ "after giving version one a proper go , these were my issues with it :"
560 ul_ $ do
561 li_ "i ended up using so many Lisp functions in the markup that i felt like i would've been better off just writing the markup in spinneret"
562 li_ "my implementation resulted in slower build times than i had hoped"
563 li_ $ do
564 "around that time , i realized i don't like programming in Lisp nearly as much as Haskell , especially after learning "
565 a_ [href_ "https://www.parsonsmatt.org/2018/05/19/ghcid_for_the_win.html"] "how to use ghcid"
566 " properly"
567 li_ $ do
568 "i also discovered the "
569 a_ [href_ "https://hackage.haskell.org/package/lucid"] "lucid"
570 " library for Haskell that i favored over spinneret for a few reasons"
571 p_ "incorporating these observations , the final version of zoxuli is basically just a thin scaffold around lucid . the only thing from my prior criteria for an SSG that it doesn't support is the ability to use any markup format , but i enjoy writing lucid more than any other markup format i've tried , so that doesn't bother me ."
572 p_ $ do
573 "i ported this website from Hakyll to zoxuli & i'm quite pleased with the experience . the source code for this website is on the "
574 link True sourcePage "source page"
575 " . "
576
577swirlmaniaProject :: Project
578swirlmaniaProject = makeProject "swirlmania"
579 "a StepMania level processor"
580 "https://git.sr.ht/~nebulae/swirlmania"
581 ["stepmania", "exercise", "rust"] $ do
582 h2_ "what it is"
583 p_ $ do
584 "swirlmania is a CLI "
585 a_ [href_ "https://www.stepmania.com/"] "StepMania"
586 " simfile ( .ssc ) processor with support for generating tech charts without double steps ."
587 p_ "swirlmania has five modes for different levels of \"tech\" difficulty . put simply , \"tech\" here refers to how far the player's body may need to turn to hit the arrow patterns ."
588 h2_ "why i made it"
589 p_ $ do
590 "i enjoy playing "
591 a_ [href_ "https://projectoutfox.com/"] "Project OutFox"
592 " ( a fork of StepMania ) on a dance pad for exercise , but finding simfiles ( which may also be refered to as charts/songs/levels ) that are of a consistent difficulty level can be challenging . i also have a strong preference for mid-speed technical maps without jumps , which makes things even more challenging . matching those criteria severely limits the song selection , but i would prefer to choose from any available level pack ."
593 p_ $ do
594 "charting my own simfiles , eor processing levels by hand is far too costly to my time for what is intended to be an exercise device , so i decided to write a program to process pre-existing levels automatically . there are a few level processors already in existence such as "
595 a_ [href_ "https://github.com/phr00t/AutoStepper"] "AutoStepper"
596 " , but as far as i can tell , none of them consistently maintain flow ( no double steps ) at higher tech levels . i'd also like to support more tech patterns in the future ."
597
598coaltonRaylibProject :: Project
599coaltonRaylibProject = makeProject "coalton-raylib"
600 "games programming in Coalton"
601 "https://git.sr.ht/~nebulae/coalton-raylib"
602 ["game dev", "coalton", "common lisp", "programming"] $ do
603 h2_ "the problem"
604 p_ "i love programming in ML-family languages like Haskell & OCaml , but they typically aren't interactive like Common Lisp , which makes programming games more difficult ."
605 p_ $ do
606 "this is because one must restart the entire program they're working on every time a new change is compiled"
607 footnote "there are ways to smooth this over , but they can add a lot of complexity"
608 " ."
609 h2_ "one possible solution"
610 p_ $ do
611 "as an ML language built on top of Common Lisp , "
612 a_ [href_ "https://coalton-lang.github.io/20211010-introducing-coalton/"] "Coalton"
613 " can provide a statically typed , functional ( with typeclasses ! ) , & highly interactive game programming environment ."
614 p_ $ do
615 "coalton-raylib is an example project i've shared that uses the "
616 a_ [href_ "https://www.raylib.com/"] "raylib"
617 " graphics library ."
618 p_ $ do
619 "i've written the draw loop in Common Lisp , & the data model & update functions in Coalton"
620 footnote "that's just the method i found to be the most ergonomic , but i'm certain that others could find better ways of architecting a game with Coalton"
621 " . this means that data & functions can be selectively reevaluated while the game is running , all while benefiting from compile-time type errors if a mistake is made !"
622 h2_ "conclusion"
623 p_ "this was just a small experiment , that i figured i'd share in case it's useful for anyone else . i'm not sure if i'll use this for a larger game eor not , given that Coalton hasn't reached 1.0 yet , but it's great to know that it's a possibility ."
624
625-- | post pages
626
627postWrapper :: Post -> Post
628postWrapper post =
629 post & _1 % #html %~ (meta <>)
630 where meta = do
631 toc
632 ul_ $ do
633 li_ $ b_ $ toHtml $ post ^. _2 % #date
634 maybe (pure ()) li_ . seriesNav $ fst post
635 li_ $ do
636 b_ "tags"; " : "
637 renderTags $ post ^. _1 % #tags
638
639postPreview :: Post -> Zoxuli
640postPreview post = do
641 link False (fst post) $ post ^. _1 % #title
642
643postPages :: [Post]
644postPages = reverseChronological $ postWrapper <$> postPages'
645
646postPages' :: [Post]
647postPages' =
648 [ theOasisPost
649 , timelineSplittingPost
650 , compulsorySchoolingPost
651 , howIUseComputersPost
652 , unlicensePost
653 , veganTipsPost
654 , queerCybersecPost
655 , inferiPost
656 , wallOfShardsPost ]
657
658theOasisPost :: Post
659theOasisPost = makePost "the oasis" "2024-11-25"
660 ["virtual reality", "security", "game dev", "programming", "inclusive design", "formal verification"] $ do
661 h2_ "introduction"
662 p_ $ do
663 "for a long time , i've been thinking about how to build a kinder & more radical version of the "
664 a_ [href_ "https://readyplayerone.fandom.com/wiki/OASIS"] "OASIS"
665 " from "
666 a_ [href_ "https://en.wikipedia.org/wiki/Ready_Player_One"] "Ready Player One"
667 " using currently available technology . this page outlines my current vision for it . i'll be throwing a lot of ideas together somewhat haphazardly , so expect unintended inconsistencies : this is more of an aspirational wishlist than a formal specification ."
668 h2_ "motivation"
669 p_ "gaps in our scientific knowledge limit the range of actions we can take , & some of those gaps could take eons to fill . i view simulated worlds as a stopgap that can approximate what it would be like to take actions outside of that range . categorical examples :"
670 ul_ $ do
671 li_ $ do
672 "unlimited "
673 a_ [href_ "#agency-over-avatar-&-environment"] "creative expression"
674 li_ $ a_ [href_ "https://en.wikipedia.org/wiki/Morphological_freedom"] "morphological freedom"
675 li_ "realistic interaction between people any distance apart"
676 li_ $ do
677 a_ [href_ "#formal-verification"] "formally verified"
678 " "; a_ [href_ "#abuse-protection"] "abuse protection"
679 h2_ "primary values"
680 h3_ "agency over avatar & environment"
681 blockquote_ [cite_ "https://applied-langua.ge/posts/here-is-a-loud-announcement.html#orga51f75c"] $ do
682 p_ "Maximalist computing is designing protocols and platforms which support doing \"everything\", and in a pleasant manner. It is, in one way, an extension of the idea of computing, which is to simulate anything"
683 p_ $ do
684 " — Applied Language , "
685 cite_ $ a_ [href_ "https://applied-langua.ge/posts/here-is-a-loud-announcement.html#orga51f75c"] "Maximalist computing"
686 ul_ $ do
687 li_ $ do
688 "programmable , like "
689 a_ [href_ "https://resonite.com/"] "Resonite"
690 " is using "
691 a_ [href_ "https://wiki.resonite.com/ProtoFlux"] "ProtoFlux"
692 " ; the freedom to modify systems . see "
693 a_ [href_ "https://youtu.be/eS8KeCOJBFA?si=WiUEa41EypVRfGvP"] "Rustybot's video on programming a flying device"
694 " for a demonstration"
695 li_ $ do
696 "introspection to the core ; the ability to inspect any property of the oasis from inside it . this facilitates "
697 a_ [href_ "https://plato.stanford.edu/entries/agency/"] "agency"
698 " , if the fulfillment of one's agency's "
699 a_ [href_ "https://plato.stanford.edu/entries/action/#ConsAim"] "constitutive aim"
700 " is contingent on having accurate models of the world"
701 li_ $ do "no "; a_ [href_ "https://www.deceptive.design/types"] "deceptive design patterns"; " ior advertisements"
702 li_ $ do "no "; a_ [href_ "https://en.wikipedia.org/wiki/Artificial_scarcity"] "artificial scarcity"
703 ul_ $ do
704 li_ $ do link True (fst unlicensePost) "public domain"; " source code"
705 li_ "anticapitalist ( unlike the OASIS )"
706 li_ "no leveling hierarchy that locks features for new people"
707 li_ $ do "no "; a_ [href_ "https://www.defectivebydesign.org/what_is_drm"] "DRM"
708 li_ $ do "no "; a_ [href_ "https://youtu.be/YQ_xWvX1n9g?si=G0hjss5DYLXjdKPe"] "NFTs"; " ior cryptocurrencies"
709 li_ "no limits on changing account metadata like usernames , with the exception of a UUID for persistent blocklists"
710 h3_ "inclusive design"
711 blockquote_ [cite_ "https://100daysofa11y.com/2019/12/03/accommodation-versus-inclusive-design/"] $ do
712 p_ $ do "physical spaces have to find a \"universal\" solution ("; b_ "one size fits all"; ") once those spaces are built. In digital spaces, we have the flexibility of taking the \"inclusive\" approach to tailor our product so that "; b_ "one size fits one"
713 p_ $ do
714 " — Amy Carney , "
715 cite_ $ a_ [href_ "https://100daysofa11y.com/2019/12/03/accommodation-versus-inclusive-design/"] "Accommodation versus Inclusive Design"
716 ul_ $ do
717 li_ $ do
718 "create a core protocol like "
719 a_ [href_ "https://en.wikipedia.org/wiki/Secure_Scuttlebutt"] "SSB"
720 " eor "
721 a_ [href_ "https://en.wikipedia.org/wiki/ActivityPub"] "ActivityPub"
722 " to allow for multiple apps built upon it . "
723 a_ [href_ "https://en.wikipedia.org/wiki/Inclusive_design"] "inclusive design"
724 " suggests that a greater number of interfaces , each specialized for different groups of users , can result in more inclusive interfaces than a single interface for everyone would be"
725 li_ $ do
726 a_ [href_ "https://iep.utm.edu/qualia/"] "qualia"
727 "-agnostic object representation ; don't privilege one type of experience over another . for example , the data representing a teacup in the oasis should not favor a 3D mesh for visual representation any more ior less than a textual description of it . it follows that all aspects of the oasis could be experienced as parser-based "
728 a_ [href_ "https://www.ifwiki.org/Parser-based_interactive_fiction"] "interactive fiction"
729 " , ior more specifically , as a "
730 a_ [href_ "https://en.wikipedia.org/wiki/Multi-user_dungeon"] "MUD"
731 " . pure text can be accessed over a sweeping range of input & output devices , such as "
732 a_ [href_ "https://en.wikipedia.org/wiki/Refreshable_braille_display"] "refreshable braille displays"
733 " . here are few examples of what creation & programming could look like within interactive fiction :"
734 ul_ $ do
735 li_ $ a_ [href_ "https://netjam.org/quoth/"] "Quoth"
736 li_ $ a_ [href_ "https://github.com/seisatsu/DennisMUD"] "DennisMUD"
737 li_ $ a_ [href_ "https://wiki.xxiivv.com/site/paradise.html"] "Paradise"
738 li_ $ a_ [href_ "https://git.sr.ht/~nebulae/nova_conjure"] "NovaConjure"
739 li_ $ do
740 "support many programming paradigms to accommodate varied neurotypes & prevent a "
741 a_ [href_ "https://permacomputing.net/monoculture/"] "monoculture"
742 " . the base language should make the creation of new languages ( spanning the range of each "
743 a_ [href_ "https://madhadron.com/programming/seven_ur_languages.html"] "ur-language"
744 " , & beyond ) simpler , as "
745 a_ [href_ "https://beautifulracket.com/appendix/domain-specific-languages.html"] "Racket"
746 " ior "
747 a_ [href_ "https://wiki.haskell.org/Embedded_domain_specific_language"] "Haskell"
748 " do"
749 ul_ $ do
750 li_ $ do
751 "this could allow esoteric languages with radically different approaches like "
752 a_ [href_ "https://www.dangermouse.net/esoteric/piet/samples.html"] "Piet"
753 " to flourish"
754 li_ $ do
755 link True (fst coaltonRaylibProject) "Coalton"
756 " & "
757 a_ [href_ "https://hazel.org/"] "Hazel"
758 " show that "
759 a_ [href_ "https://en.wikipedia.org/wiki/ML_(programming_language)"] "ML"
760 "-style programming can integrate into a highly dynamic simulation"
761 li_ "thorough documentation for people with any degree of computing knowledge"
762 li_ $ do
763 "provide an accessibility toolkit so people can create new assistive devices within the oasis more easily , & handle "
764 a_ [href_ "https://en.wikipedia.org/wiki/Internationalization_and_localization"] "i18n & l10n"
765 li_ "avoid anthropocentric assumptions to future-proof the possible inclusion of non-human animals , AI agents , aliens , etc."
766 li_ $ do
767 "allow "
768 a_ [href_ "https://pluralpedia.org/w/Plurality"] "plural"
769 " systems to easily switch between profiles to match who is fronting , along with tools for communication between headmates"
770 li_ $ do
771 "runs natively on Linux , "
772 a_ [href_ "https://en.wikipedia.org/wiki/Berkeley_Software_Distribution"] "BSD"
773 " , & others"
774 li_ $ do
775 "see the "
776 a_ [href_ "https://gameaccessibilityguidelines.com/full-list/"] "Game Accessibility Guidelines"
777 " for more ideas in this realm"
778 h3_ "abuse protection"
779 p_ "most multiplayer video games are woefully unequipped to protect the average player from abuse , let alone marginalized players . while the prevalence of abusive people is primarily a social problem , there are still plenty of ways the oasis could ( technologically , since it's a digital space ) protect people from them , in the same way that encryption can protect online accounts from being hacked ."
780 p_ "abuse protection is perhaps the most challenging aspect to encode into a software system , because adversaries can quickly render one's defenses obsolete by finding vulnerabilities . given this , the oasis will require enough flexibility for the people most affected by abuse to have the agency to change the design of those defenses ."
781 ul_ $ do
782 li_ $ do
783 "use fine-grained "
784 a_ [href_ "https://crochet.qteati.me/docs/reference/system/security/why.html"] "capability security"
785 " for "
786 a_ [href_ "https://medium.com/@robotlolita/dependencies-are-bad-but-necessary-806f38f65df4"] "safer dependencies"
787 " while programming in the oasis ( like "
788 a_ [href_ "https://crochet.qteati.me/docs/reference/system/whats-crochet.html"] "Crochet"
789 " does ) , & for limiting the capabilities other people have for interacting with you . a simple example of the latter : if somebody wanted to place a hat they made onto your avatar , you would need to grant them the \"attach objects to avatar\" capability before they could do so"
790 li_ $ do "sometimes it can be hard to defend yourself while you're being attacked . the ability to give "; em_ "highly"; " trusted people control over a subset of your capabilities could offset some of the burden & allow for faster responses to abuse . this control could be overridden ior revoked at any time"
791 li_ $ do
792 "alternatives to the standard block/report/votekick options should be explored . in my experience , blocking is implemented too weakly , reporting is too slow & relies on a moderation hierarchy , & votekicks require social consensus , which can be nearly impossible to acquire if one's a target of bigotry . see my post on the "
793 link True (fst timelineSplittingPost) "timeline splitting block"
794 " for more on this topic"
795 li_ $ do
796 "distributed/decentralized to counter emergent hierarchy & co-optation by corporations ior the state . the protocol should be ( non-blockchain ) "
797 a_ [href_ "https://en.wikipedia.org/wiki/Peer-to-peer"] "P2P"
798 " by default , with optional "
799 a_ [href_ "https://en.wikipedia.org/wiki/Federation_(information_technology)"] "federation"
800 " for specific instances where it's useful"
801 li_ $ do
802 "forums , git hosting , & any other external infrastructure should avoid regime-compliant software like Discord & GitHub if possible , & have a moderation policy that is "
803 a_ [href_ "https://raddle.me/wiki/defining_our_terms"] "intolerant of bigotry"
804 li_ $ do
805 "multi-factor authentication , including "
806 a_ [href_ "https://en.wikipedia.org/wiki/Universal_2nd_Factor"] "U2F"
807 li_ $ do
808 "accessible over "
809 a_ [href_ "https://www.torproject.org/"] "TOR"
810 " & "
811 a_ [href_ "https://geti2p.net/en/"] "I2P"
812 li_ $ do
813 a_ [href_ "https://en.wikipedia.org/wiki/Homomorphic_encryption#Fully_homomorphic_encryption"] "fully homomorphic encryption"
814 " could allow people to rely on the computational resources of others without necessarily trusting them"
815 li_ $ do
816 "compatible with "
817 a_ [href_ "https://permacomputing.net/salvage_computing/"] "salvage computing"
818 " . if the oasis is to be built upon new hardware , it must wait until the current system of "
819 a_ [href_ "https://youtu.be/vmtaWQxBYFk?si=UotkxTCkwUbPqgQ4"] "exploitative electronics production"
820 " is destroyed , & a kinder means of production has taken its place"
821 h3_ "formal verification"
822 p_ "preventing bugs becomes increasingly important as immersion improves . suppose someone uses a device that lets them feel physical pain within the oasis . when other people have the capability to physically torture them , bugs could cause the usual protection mechanisms to fail , resulting in extremely traumatic experiences ."
823 ul_ $ do
824 li_ $ do
825 "deductive verification using "
826 a_ [href_ "https://en.wikipedia.org/wiki/Dependent_type"] "dependently typed"
827 " programming ( a "
828 a_ [href_ "https://en.wikipedia.org/wiki/Formal_verification"] "formal verification"
829 " approach ) could ensure , using mathematical proofs , that entire sets of bugs cannot occur . this would be used in conjunction with "
830 a_ [href_ "https://en.wikipedia.org/wiki/Secure_by_design"] "secure design"
831 " to prevent exploits in addition to bugs"
832 li_ "dependent types are notoriously time consuming to learn about ( i am still a beginner ) , & would likely significantly decrease the number of people who could contribute to that portion of the codebase . here are a few possible ways to alleviate this issue :"
833 ul_ $ do
834 li_ "improve the learning materials . it is uncertain how much this would help , but i am hopeful over a very long time frame"
835 li_ $ do
836 "use "
837 a_ [href_ "https://en.wikipedia.org/wiki/Refinement_type"] "refinement types"
838 " where possible . "
839 a_ [href_ "https://ucsd-progsys.github.io/liquidhaskell/"] "LiquidHaskell"
840 " could be combined with "
841 a_ [href_ "https://wiki.portal.chalmers.se/agda/pmwiki.php"] "Agda"
842 " using "
843 a_ [href_ "https://agda.github.io/agda2hs/"] "agda2hs"
844 " , for instance"
845 li_ $ do
846 a_ [href_ "https://github.com/magmide/magmide"] "Magmide"
847 " is a research project trying to solve this issue , & introduces something called the \"split Logic/Host\" architecture that could be promising , but i don't fully understand it yet"
848 li_ $ do
849 "the core protocol implementation should be as small as possible , to make it easier to understand & audit . this goal could extend to the implementation language itself , by choosing a simple theorem prover like "
850 a_ [href_ "https://medium.com/@maiavictor/towards-a-simple-theorem-prover-5005a1e66a6f"] "Cedille"
851 " , eor "
852 a_ [href_ "https://whatisrt.github.io/meta-cedille/2019/06/25/syntactic-metaprogramming-i.html"] "Meta-cedille"
853 " if syntactic metaprogramming were helpful"
854 h2_ "further reading"
855 p_ "i still have much to learn about P2P protocols , capability security , & dependent types before i could begin an implementation . here are a few documents i'd like to read next ( all freely available online ) :"
856 ul_ $ do
857 li_ $ a_ [href_ "https://en.wikibooks.org/wiki/The_World_of_Peer-to-Peer_(P2P)"] "The World of Peer-to-Peer"
858 li_ $ a_ [href_ "https://ssbc.github.io/scuttlebutt-protocol-guide/"] "the Scuttlebutt Protocol Guide"
859 li_ $ a_ [href_ "https://softwarefoundations.cis.upenn.edu/"] "Software Foundations"
860 li_ $ a_ [href_ "https://plfa.github.io/"] "Programming Language Foundations in Agda"
861 li_ $ a_ [href_ "https://beautifulracket.com/"] "Beautiful Racket"
862 li_ $ a_ [href_ "https://crochet.qteati.me/docs/reference/system/index.html"] "The Crochet System"
863 li_ $ a_ [href_ "https://fuchsia.dev/fuchsia-src/concepts/principles/secure"] "Fuchsia OS security docs"
864 h2_ "conclusion"
865 p_ "many subsets of this outline already exist to various degrees across cyberspace , so there are plenty of already solved problems to build on top of ."
866 p_ $ do
867 "that said , this is an enormous project , & not something i could do alone . if you know of ways to refine ior contribute to the oasis , feel free to "
868 link True contactPage "contact me"
869 " !"
870
871timelineSplittingPost :: Post
872timelineSplittingPost = makePost "timeline splitting block" "2024-11-16"
873 ["game dev", "security", "queer"] $ do
874 h2_ "safety features aren't strong enough"
875 p_ $ do
876 "when i've visited social spaces in "
877 a_ [href_ "https://en.wikipedia.org/wiki/Virtual_reality"] "virtual reality"
878 " , i am often harassed to an extreme degree because my \"tranny faggot\" voice outs me as a subhuman worthy of death , according to them . some of the insufficiencies i've noticed in current implementations of blocking , reporting , & votekicking are as follows :"
879 ul_ $ do
880 li_ "there are typically too many bigots in the room for a votekick to get the majority , rendering it fruitless against the pervasiveness of transmisogyny"
881 li_ "sometimes people will follow me around & cover my face with their hands eor another object so i can't see the menu to block them . eor they will scream in my ears so i can't focus"
882 li_ "in some games i can't reliably obtain a person's username in order to block them , because there's an easy way for them to hide it from me temporarily , like running away"
883 li_ "if they notice that i'm planning to block them , because i'm navigating to that portion of the menu , ior i've just blocked one of their collaborators , they may votekick me in response . in some games , being kicked resets everything that was open on the menu , so there's no way to find that person again to complete the block"
884 li_ "even if i were able to , blocking 5+ people every time i join a new lobby would get rather tedious using the current menu interfaces"
885 li_ "when i block someone , they can still affect the environment around them . this could entail writing hateful messages on objects , throwing things at me , destroying things i'm trying to create , distracting people i actually want to talk to , etc."
886 li_ "when other people can't see who i've blocked , i inevitably waste time explaining how i can't hear the vile drivel that blocked people are spraying at me . this gets confusing when there are a lot of blocked & unblocked people in the same location"
887 li_ "reports i've made haven't resulted in much action , & if they do , it usually takes at least a week"
888 h3_ "trivial fixes"
889 p_ "potential patches for some of the above issues :"
890 ul_ $ do
891 li_ "don't make social consensus necessary to completely remove someone from your environment"
892 li_ "allow hiding & muting your surroundings while using the menu"
893 li_ "ensure it's easy to see the username of anyone you're interacting with"
894 li_ "add an option to share who you've blocked with others , along with your reasons for each block"
895 li_ "allow blocking discreetly & in bulk"
896 li_ "add a shortcut so you can block faster"
897 h2_ "a more potent kind of block"
898 p_ $ do "my experiences have motivated me to think of an entirely different way to implement blocking ."
899 p_ $ do
900 "suppose you're in "
901 link True (fst theOasisPost) "the oasis"
902 " , & you decide to block someone named S because they're telling you to kill yourself . in this thought experiment , blocking simply hides their avatar & audio from you . after being blocked , they draw the message \"kill yourself\" on an empty whiteboard ."
903 p_ "should the message be visible to you ?"
904 p_ "if you can see it , then S has successfully worked around the blocking mechanism , even if it's to a lesser degree than before . they've still violated your boundary ."
905 p_ $ do "if you can't see it , then how would the oasis hide the message from you ? other people may still want to see S's influence on the world . this would require the world to be split into two separate states at once , which could be thought of as different "; em_ "timelines"; " ."
906 p_ "so , if you perform a timeline splitting block ( TSB ) on S , you will enter new timeline forked off from the current one . everybody else will remain in the original timeline , but they will be given the option to join you ."
907 h3_ "timeline divergence"
908 p_ "a cross-timeline \"overlay\" could show people's avatars & audio from the original timeline on top of your fork , but this would only be useful temporarily . divergence between timelines over time would degrade cross-timeline communication about the world ."
909 p_ "as time goes on , the pressure for people to pick a side in conflicts would increase . a TSB is intended as a last resort , because it removes most of the blocked person's ability to causally affect you , & possibly others ."
910 p_ $ do
911 "sophisticated tools for merging timelines à la "
912 a_ [href_ "https://git-scm.com/docs/git-merge"] "git"
913 " could prevent people from losing changes when switching timelines ."
914 h3_ "choosing timelines"
915 p_ "another question : how will people who were less involved in the conflict know which timeline to join ? they would need to ask around , if it mattered to them . people would have the ability to visit any timeline they're not blocked in , to assist inquiry . additionally , the menu could have a place to write your reason for a TSB , that would be shown in notifications , ior possibly a history log ."
916
917compulsorySchoolingPost :: Post
918compulsorySchoolingPost = makePost "compulsory schooling is abusive" "2024-10-11"
919 ["youth liberation", "philosophy"] $ do
920 h2_ "even if ..."
921 p_ "even if you didn't feel confined while in school , it doesn't mean that none of the other kids could tell they were in confinement ."
922 p_ "even if schools are sometimes better than the life a kid would have to live at home , it doesn't mean that they're not in confinement ."
923 p_ "even if schools sometimes manage to teach kids things they actually care about , it doesn't mean that they're not , in many ways , treated like prison inmates in the process ."
924 h2_ "the problem"
925 p_ $ do "coercing an entire age group of people into spending the majority of their waking hours in an environment they didn't choose , around people they didn't choose , eating food they didn't choose , doing tasks they didn't choose , holding their bodies in positions they didn't choose , all while possibly being assaulted physically ior emotionally by bullies with no true recourse , "; em_ "is abusive ."
926 p_ $ do
927 "if someone did the same thing to "; b_ "all"; " adults"
928 footnote "not entirely hypothetical ; wage slavery approaches a weaker form of this"
929 " , & justified it by saying that it's some variation of being \"for their own good !\" , would that be okay ? i sure don't think so , & adult supremacy prevents many people who agree from extrapolating that judgement to children ."
930 p_ "even as an adult , i'm still resentful of every adult who was knowingly complicit in keeping all of my friends & i in confinement when i was young . i refuse to simply \"forgive & forget\" the traumatizing dehumanization of adult supremacy , as one particularly childist relative still demands of me ."
931 h2_ "how to fix it"
932 p_ "my take is fairly straightforward :"
933 ul_ $ do
934 li_ "make educational facilities & resources entirely opt-in"
935 li_ "make each component of those resources granularly opt-in . give kids the ability to only go the amount that they feel like , & no more than that !"
936 li_ "actually give children agency over the design of those resources , & give them full control over what they get to learn about"
937 li_ "stop conditioning adult staff to act like fucking cops"
938 li_ "be extremely cautious about creating pressure on children to visit any given educational environment"
939 p_ $ do
940 "unfortunately , this is only part of the equation . for this to be a fully satisfying solution , many other things about our cultures would need to radically change as well . one such example would be the creation of far more safe , uncommercialized \""
941 a_ [href_ "https://en.wikipedia.org/wiki/Third_place"] "third places"
942 "\" than are currently available ."
943 hr_ []
944 h2_ "an aside on argumentation for youth liberation"
945 p_ "it saddens me how infrequently adults believe ior show empathy for those of us who talk openly about the ways adult supremacy has traumatized us ."
946 p_ "it's also sad when even the people who ostensibly agree that ( for example ) compulsory education is a problem decide to only argue against it through an adult supremacist frame , measuring any potential harm by how much it deprives children of attributes that only the adults around them deemed desirable ."
947 p_ "for instance , they'll argue that an oppressive school environment makes children uncomfortable , & that is bad because then they can't \"learn\" ( the subjects chosen by adults ) as effectively , & that is only bad because then they can't \"operate in society\" ( which if one inquires further , is usually some stand-in for greasing the cogs of capitalism & the state ) as smoothly , ior know how to \"respect authority\" ( i.e. learn to interact frictionlessly with everyone else who takes for granted & is complicit in the abuse ) properly ."
948 p_ $ do
949 "but what they blatantly omit from their arguments is that compulsory schooling is a problem "
950 em_ "because it's abusive to assert ownership over another person , steal their agency , & gaslight them about their personhood"
951 " ."
952 p_ "if one fully believes that children are people , they should be able to confidently state why compulsory schooling should be abolished using reasons that aren't downstream of potential benefits to adults . doing otherwise only serves to deepen the power dynamic along another axis ."
953
954queerCybersecPost :: Post
955queerCybersecPost = makePost "queer cybersecurity resources" "2024-07-07"
956 ["security", "privacy", "queer", "guide"] $ do
957 h2_ "introduction"
958 p_ "this is a list of resources for improving one's digital security posture , prioritizing relevance to the risks queer folks face . i hope it's helpful !"
959 p_ $ do b_ "note"; " : these resources may have changed since i've shared them , & i don't necessarily endorse every strategy they recommend . security is highly contextual . try to confirm that any advice you encounter is not factually inaccurate , outdated , ior coming from a hostile source before incorporating it into your strategy ."
960 h2_ "privacy & security"
961 "these links are rather general in purpose , so you may need to explore them a bit to find what you are looking for :"
962 ul_ $ do
963 li_ $ a_ [href_ "https://gendersec.tacticaltech.org/wiki/index.php/Complete_manual"] "Zen & the art of making tech work for you - Gender & Tech Resources"
964 li_ $ a_ [href_ "https://ssd.eff.org/"] "Surveillance Self-Defense - Electronic Frontier Foundation"
965 li_ $ a_ [href_ "https://www.privacyguides.org/en/"] "Privacy Guides"
966 h2_ "doxing"
967 p_ "these guides go over restorative & preventative strategies for people affected by doxing :"
968 ul_ $ do
969 li_ $ a_ [href_ "https://crashoverridenetwork.tumblr.com/post/114270394687/so-youve-been-doxed-a-guide-to-best-practices"] "So You’ve Been Doxed - Crash Override Network"
970 li_ $ a_ [href_ "https://gendersec.tacticaltech.org/wiki/index.php/Self-dox"] "Self-dox - Gender & Tech Resources"
971 li_ $ a_ [href_ "https://arstechnica.com/information-technology/2015/03/anti-doxing-strategy-or-how-to-avoid-50-qurans-and-287-of-chick-fil-a/"] "Anti-doxing Strategy - Ars Technica"
972 h2_ "social media"
973 p_ $ do
974 "i'd strongly advise looking into safer alternatives ( such as well moderated instances on the "
975 a_ [href_ "https://www.fediverse.to/"] "fediverse"
976 " ) , but if that's impractical for whatever reason , this website has a list of comprehensive guides for dealing with harassment , abuse , & privacy settings on mainstream social media sites :"
977 p_ $ a_ [href_ "https://righttobe.org/guides/how-to-use-social-media-safely/"] "How To Use Social Media Safely - Right To Be"
978
979inferiPost :: Post
980inferiPost = makePost "inferi monologue" "2024-05-20" ["fiction"] $ do
981 p_ $ do
982 "a headcannon of how "
983 a_ [href_ "https://pottermore.fandom.com/wiki/Inferi"] "inferi"
984 " would greet travelers :"
985 blockquote_ $ do
986 p_ "we , stacked like acrobats under the cavern lake surface , writhing in place without sound nor purpose , do cordially invite you & yours to our celebration . we know you’re busy , but spare us a second , & we’ll show you how cozy our waters can be ."
987 p_ "what ? you don’t want to drown ? do we look like we’re drowning to you ? there’s more of us here than you could ever find up there - don’t you want friends ? you’ll drown in an absence of human contact if you don’t join us soon ."
988 p_ $ do "i mean , come on . look at us . we have it all . we’re never alone , & we have each other’s backs , in a lattice configuration , & we never have to worry about defectors , because the waters are so "; b_ "cozy"; " ."
989 p_ "what ? you don’t want to become incorporated into an evil horde ? do we look like an evil horde to you ? we all think you’re a [REDACTED] . you’ve been out of the water so long you’re maladjusted & don’t know right from wrong . i’m confident that even the other , more reasonable land-dwellers would agree with me ."
990 p_ "you’re on your own , kiddo . we offered our gracious invitation , & you disrespected us . you know , there are those among us who used to be like you . then they joined us , & served their time , & now we’re all one big jolly family . i hope that one day , when you’re one of us like they are , you’ll be thankful we took you under our wing ."
991 p_ "stop struggling , [REDACTED] ."
992 p_ $ em_ "we already told you , the waters are cozy ."
993
994howIUseComputersPost :: Post
995howIUseComputersPost = makePost "how i use computers" "2024-08-24"
996 ["qubesOS", "programming", "haskell", "purescript"] $ do
997 h2_ "introduction"
998 p_ $ do
999 "what follows is an outline of the various hardware & software i currently use for daily computing tasks , in case it's useful for someone else . this is not a prescription of how other people should use technology , nor is it a description of "
1000 link True (fst theOasisPost) "my ideal computing environment"
1001 " ."
1002 todo "explain choices in more detail"
1003 h2_ "hardware"
1004 p_ "if i need to purchase a new device , i prefer to find one that is already used , due to the numerous ethical issues with the production of electronics by large companies ."
1005 p_ $ do
1006 "my primary computer is a Thinkpad T430 running "
1007 a_ [href_ "https://www.qubes-os.org/"] "QubesOS"
1008 " . i chose this laptop because , out of the options that can be flashed with "
1009 a_ [href_ "https://www.coreboot.org/"] "coreboot"
1010 " , it was old enough to be somewhat affordable"
1011 footnote "around 200 USD on Newegg"
1012 " , while still running fast enough for most tasks that don't involve graphics ( & some that do ) ."
1013 p_ "i don't use any peripherals except for a large monitor , to maintain good posture . i have tried mechanical keyboards , but i dislike like how they feel & sound compared to the built-in Thinkpad keyboard . split keyboards are more ergonomic though , so it would be nice to find a split rubber dome keyboard ."
1014 p_ $ do
1015 "my \"smart\"phone is a Pixel 4a"
1016 footnote "this was also around 200 USD on eBay"
1017 " running CalyxOS"
1018 footnote "i am planning to switch to GrapheneOS soon , for the additional security features & ability to use TalkBack , a screen reader . i could not figure out how to enable a screen reader on CalyxOS ."
1019 " ."
1020 h2_ "software"
1021 p_ $ do
1022 "i primarily use CalyxOS for taking notes with "
1023 a_ [href_ "https://f-droid.org/packages/com.orgzly/"] "Orgzly"
1024 " , tracking sleep with "
1025 a_ [href_ "https://f-droid.org/packages/hu.vmiklos.plees_tracker/"] "Plees Tracker"
1026 " , web browsing away from home , insecure communications , & listening to audio-based educational materials ."
1027 p_ "i use QubesOS for web browsing , programming , Serious Writing , & other forms of expression ."
1028 p_ $ do
1029 "i chose QubesOS because i find "
1030 a_ [href_ "https://en.wikipedia.org/wiki/Ambient_authority"] "ambient authority"
1031 " horrifying , but i'm not aware of any robust "
1032 a_ [href_ "https://en.wikipedia.org/wiki/Capability-based_security"] "capability-based"
1033 " operating systems that would fill the same need for me ."
1034 p_ $ do
1035 "QubesOS is slow & "
1036 a_ [href_ "https://github.com/QubesOS/qubes-issues/issues/5907"] "doesn't have screen reader support"
1037 " yet , but it does have some great features like configuration using "
1038 a_ [href_ "https://www.qubes-os.org/doc/salt/"] "Salt"
1039 footnote $ do
1040 "ior maybe even Nix-like configuration in the future if "
1041 a_ [href_ "https://spectrum-os.org/"] "Spectrum"
1042 " goes well"
1043 ", Whonix qubes , & offline qubes . here are a few things i've learned that make it more tolerable :"
1044 ul_ $ do
1045 li_ $ do
1046 "install "
1047 a_ [href_ "https://i3wm.org/"] "i3"
1048 ul_ $ do
1049 li_ $ do
1050 "name qubes using two-character strings so they can be searched for more quickly using "
1051 a_ [href_ "https://wiki.archlinux.org/title/Dmenu"] "dmenu"
1052 li_ "make shortcuts for locking the screen & toggling the status bar"
1053 li_ $ do "make a shortcut ( mine is bound to "; kbd_ "Alt"; " + ";kbd_ "i"; " ) for opening a dmenu list of helper scripts & frequently opened programs"
1054 li_ $ do "use Salt , but not for "; em_ "everything"; " . some tasks are much simpler ior faster with a shell script in dom0 , so i use a top-level shell script to apply salt files & do other things"
1055 li_ $ do
1056 "dark mode can be enabled in "
1057 a_ [href_ "https://xfce.org/"] "XFCE"
1058 " qubes by "
1059 inlineCode "qvm-run"
1060 "ing the following command in each of them :"
1061 code "bash" "xfconf-query -c xsettings -p /Net/ThemeName -s 'Adwaita-dark'"
1062 li_ $ do
1063 "it may not always seem like it at first , but most tasks can be automated from dom0 , including mounting & attaching drives inside qubes . i take advantage of this in a backup script that backs up specific qubes using "
1064 a_ [href_ "https://www.borgbackup.org/"] "BorgBackup"
1065 li_ "i wrote a shell script that copies dotfiles from one qube to the others & applies them , so i only have to clone my dotfiles in one place , but still have my bash aliases , helix config , etc. in every qube"
1066 li_ $ do
1067 a_ [href_ "https://wiki.archlinux.org/title/Rofi"] "rofi"
1068 " can be opened inside a qube using "
1069 inlineCode "qvm-run"
1070 " in dom0 scripts , but the rofi flag "
1071 inlineCode "-normal-window"
1072 " must be added to disable "
1073 inlineCode "override_redirect"
1074 " , which allows the program window to appear undecorated & on top in "
1075 a_ [href_ "https://en.wikipedia.org/wiki/X_Window_System"] "X11"
1076 h2_ "programming"
1077 h3_ "language"
1078 p_ $ do
1079 "currently , the languages i find most useful are "
1080 a_ [href_ "https://www.haskell.org/"] "Haskell"
1081 " & "
1082 a_ [href_ "https://www.purescript.org/"] "PureScript"
1083 " ( which is very similar to Haskell , but compiles to JavaScript ) ."
1084 p_ "a few things i like about them are :"
1085 ul_ $ do
1086 li_ "very clean syntax"
1087 li_ $ a_ [href_ "https://en.wikipedia.org/wiki/Pure_function"] "functional purity"
1088 li_ $ a_ [href_ "https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system"] "Hindley-Milner type system"
1089 li_ $ a_ [href_ "https://en.wikipedia.org/wiki/Type_class"] "typeclasses"
1090 li_ $ do
1091 a_ [href_ "https://hoogle.haskell.org/"] "Hoogle"
1092 "/"
1093 a_ [href_ "https://pursuit.purescript.org/"] "Pursuit"
1094 li_ $ do
1095 a_ [href_ "https://github.com/ndmitchell/ghcid"] "ghcid"
1096 "/"
1097 a_ [href_ "https://github.com/kRITZCREEK/pscid"] "pscid"
1098 li_ "high abstraction power"
1099 li_ $ do
1100 "automatically "
1101 a_ [href_ "https://en.wikipedia.org/wiki/Currying"] "curried"
1102 " functions"
1103 li_ $ a_ [href_ "https://en.wikipedia.org/wiki/Lazy_evaluation"] "lazy evaluation"
1104 li_ $ do
1105 a_ [href_ "https://en.wikipedia.org/wiki/Row_polymorphism"] "row polymorphism"
1106 " ( PureScript only )"
1107 li_ $ do
1108 "wonderful libraries like "
1109 a_ [href_ "https://github.com/ajnsit/concur"] "Concur"
1110 " , "
1111 a_ [href_ "https://hackage.haskell.org/package/optics"] "optics"
1112 " & "
1113 a_ [href_ "https://hackage.haskell.org/package/apecs"] "apecs"
1114 p_ $ do
1115 "i'm autistic & get overwhelmed by extraneous detail "; em_ "very"; " easily , so i view many of these as accessibility features"
1116 footnote "however , i have heard that for some people , these languages are unpleasant to work with for the some of the same reasons ."
1117 " , because of way they encourage code that is easy to read & reduce the number of things i must keep in working memory at once - while still feeling quite empowering ."
1118 p_ $ do
1119 "for native programs that target embedded devices ior need to be "
1120 a_ [href_ "https://en.wikipedia.org/wiki/Static_build"] "statically built"
1121 " ior "
1122 a_ [href_ "https://en.wikipedia.org/wiki/Cross_compiler"] "cross compiled"
1123 " , "
1124 a_ [href_ "https://www.rust-lang.org/"] "Rust"
1125 " is a nice language that provides a somewhat similar experience to Haskell , while making those tasks much easier ."
1126 p_ $ do
1127 "i've experimented a lot with "
1128 a_ [href_ "https://nixos.org/"] "Nix"
1129 " for provisioning systems & development environments , but i'm hesitant to recommend using it , particularly if , like me , one is significantly constrained by the power of their computer hardware / disk space / network speed , ior are marginalized in some way"
1130 footnote $ do
1131 "i've seen many folks point out that the "
1132 a_ [href_ "https://discourse.nixos.org/"] "Nix forum"
1133 " & subreddit have been particularly ineffectual at fighting bigotry & fascist rhetoric , which has been corroborated by my own experience . from what i can understand , the community has also become a place of heavy conflict after a considerable amount of members were okay with the Nix convention being sponsored by an evil \"defence\" technology company called "
1134 a_ [href_ "https://en.wikipedia.org/wiki/Anduril_Industries"] "Anduril"
1135 " ."
1136 " . i've definitely benefited from Nix before , but those benefits have only barely outweighed the many negatives i've experienced along the way . maybe "
1137 a_ [href_ "https://lix.systems/"] "Lix"
1138 " & "
1139 a_ [href_ "https://auxolotl.org/en/"] "Aux"
1140 " will manage to solve some of those issues ."
1141 h3_ "code editor"
1142 p_ $ do
1143 "the code editor i use most often is "
1144 a_ [href_ "https://helix-editor.com/"] "helix"; " ."
1145 p_ $ do
1146 "my first editor was Sublime Text , then VSCodium , then Atom , & i finally found an editor i liked when i tried vim & realized i could mostly avoid using the mouse"
1147 footnote "using a mouse as an input device is fine , & i wish development software would use it more often . my issue is the precision required in most mouse-driven interfaces . precise clicks are difficult for me, & it would be much more accessible if elements that have a larger hitbox ( like radial menus ) were used more often ."
1148 " . once i was proficient with vim , i moved on to "
1149 a_ [href_ "https://github.com/doomemacs/doomemacs"] "Doom Emacs"
1150 " ."
1151 p_ "Emacs has a lot going for it , like radical introspection & extensibility , but it was just too slow for me . the language servers for Haskell & PureScript would often crash my qube because of how much memory they used in Emacs . i also disliked dealing with the Doom abstraction , but when i tried going without it , maintaining a complex configuration was too time consuming ."
1152 p_ "so , i switched to helix . it is rarely too slow for me , even in a qube with 4GB of RAM . it hardly requires any configuration to match my Doom Emacs setup . after learning them properly , i've also grown to appreciate the Kakoune-inspired keybindings more than vim's ."
1153
1154unlicensePost :: Post
1155unlicensePost = makePost "why i use the Unlicense & CC0" "2024-07-21"
1156 ["anticopyright", "philosophy"] $ do
1157 h2_ "introduction"
1158 p_ $ do
1159 "i don't know that much about the specifics of copyright law ; this post is more of a philosophical exploration of the concept of \"intellectual property\" in general"
1160 footnote "it's also not a comprehensive argument , as there are quite a few reasons i dislike \"intellectual property\" that aren't mentioned here ."
1161 " ."
1162 h2_ "\"intellectual property\" relies on death"
1163 p_ "what would \"perfect\" copyright enforcement look like ? extrapolating what i see as the current system’s telos , it would look like protected \"intellectual property\" being physically impossible to create for everyone in the universe except for the \"owner\" ."
1164 p_ "every time new \"intellectual property\" is created , everyone else’s agency decreases by some amount . it is a system reliant on death , because if death were abolished , all of the most important expressions would get copyrighted eventually , & never expire , rendering most people born after that period unable to express much ."
1165 p_ "so , if copyright decreases everyone’s agency , uses death as a mechanism to redistribute temporal privilege , & relies on the distributed violence of the state to enforce all of this , what’s the alternative ?"
1166 h2_ "copyleft & copyfarleft"
1167 p_ "efforts to use the system against itself , like copyleft & copyfarleft , are admirable in terms of what they aim to achieve . they can stop people who use one's work from restricting others as much as they would have otherwise ."
1168 p_ "but if one has the option to forgo copyright entirely , i’m not convinced that copyleft is preferable . it still relies on the copyright system in a significant way . why rely on an inefficient system that harms others , when one could oppose harmful usage of their work through other channels ?"
1169 p_ "some people claim that once one has given up their \"intellectual property\" , they have no \"right\" to oppose anyone’s usage of it . this would only make sense if the legal system were the only way to stop harm ."
1170 p_ "as an example , if somebody used a painting i made in a widely shared fascist propaganda video without permission , there are numerous reasons why this is bad that are not \"they stole my 'intellectual property'\" . there are also countless ways to counteract this other than to wait around for the copyright system to punish them in a way that isn’t even responding directly to what was wrong about what they did in the first place ."
1171 h2_ "even copyleft causes psychic damage"
1172 p_ "another unfortunate side effect of copyleft’s strategy is that , similar to permissive licenses , even users of copyleft software that are trying their best to make their derivatives freely available have to worry about the chance that they misunderstand something & get punished by the legal system ."
1173 p_ $ do
1174 "anecdotally , trying to make sense of the rules for using copyleft software"
1175 footnote "which is an instance of trying to navigate the legal system"
1176 " was very difficult & stressful for me . i have a particularly low tolerance for that kind of thing , but i doubt that this is an uncommon experience more generally , at least to a lesser extent ."
1177 p_ "in contrast , i don't have those issues when i’m using public domain software , because there aren't so many rules to keep track of ."
1178 h2_ "releasing work into the public domain"
1179 p_ $ do
1180 "regarding anticopyright praxis , my current preference is to use the "
1181 a_ [href_ "https://unlicense.org/"] "Unlicense"
1182 " for code , & "
1183 a_ [href_ "https://creativecommons.org/public-domain/cc0/"] "CC0"
1184 " for everything else ."
1185 p_ "one could also release work without a license notice at all , if they felt like their audience could trust them enough to not do anything about \"infringements\" ."
1186
1187veganTipsPost :: Post
1188veganTipsPost = makePost "a few vegan tips" "2024-07-03"
1189 ["vegan", "guide"] $ do
1190 h2_ "introduction"
1191 p_ "here are a few things i’ve learned since becoming vegan that weren’t immediately obvious , ior aren’t discussed as often by vegans because they’re about keeping insects ior wild animals safe ."
1192 p_ "i'm not an expert on animal welfare , so i may be mistaken about some of these . but i still think it's worth sharing the little ways we can avoid harming other living beings in everyday life ."
1193 h2_ "the tips"
1194 ul_ $ do
1195 li_ "be careful with stickers & sticky things . bugs can become trapped on them easily"
1196 li_ $ do "be "; em_ "very"; " distrustful of unfamiliar non-vegans’ assessments of whether things are vegan eor not"
1197 li_ $ do
1198 "if bugs get trapped in the bathtub frequently , leaving a long strip of toilet paper draped into the tub when it's not in use can function as an escape route for them to climb out on"
1199 footnote "i almost never see bugs trapped in the tub anymore after doing this"
1200 li_ $ do
1201 "if one shares a home with rodents , there are effective methods to keep them out of living spaces without harming them , like sealing gaps in the home with steel wool , & being very careful to keep any traces of food tidy & well sealed . "
1202 todo "link to a detailed guide"
1203 li_ "don’t assume that random household items like toilet paper are vegan by default"
1204 li_ $ do
1205 "fireworks are "
1206 a_ [href_ "https://www.animal-ethics.org/how-fireworks-harm-nonhuman-animals/"] "harmful ior deadly"
1207 " to many living things"
1208 li_ "avoid unnecessary loud noises that could distress nearby animals . some music may be an exception , though , if it's not too loud"
1209 li_ "don’t walk when the ground is unlit to avoid crushing bugs"
1210 li_ $ do "reduce ior eliminate reliance on car travel for "; em_ "many"; " reasons"
1211 li_ "recreational fires often burn insects alive & wood smoke can be harmful to animals"
1212 li_ "avoid planting poisonous plants where wild animals might eat them"
1213 h2_ "related writing"
1214 p_ $ do
1215 "if one's interested in more practical advice of this nature , i can recommend the writings of a researcher named "
1216 a_ [href_ "https://briantomasik.com/"] "Brian Tomasik"
1217 " . while i often disagree with his politics & conclusions on many topics , as far as i can tell , he is earnestly trying to reduce the harm caused to wild animals & insects ( among others ) more than most people i’ve encountered . he also documents his ideas in a very comprehensive & accessible way ."
1218
1219wallOfShardsPost :: Post
1220wallOfShardsPost = makePost "wall of shards" "2024-05-10"
1221 ["fiction"] $ do
1222 h2_ "loading world ..."
1223 p_ $ do
1224 "type "; inlineCode "start"
1225 " to collect a shard ."
1226 code "haskell" "start"
1227 p_ $ em_ "shard count : 2"
1228 h2_ "your lab"
1229 p_ "you're sitting in your office chair . all of your research tools are systematically organized around you , with your computer terminal at the center of it all . your friend b6e is sitting here , staring at one of the photos on your wall , although you can't tell which one ."
1230 code "haskell" "talkTo b6e"
1231 p_ "you break the silence ."
1232 blockquote_ "are you ready to get started ?"
1233 blockquote_ "yeah . what will it feel like , exactly ? like will i even notice you're there ?"
1234 blockquote_ "well , i'm not completely sure , but it will probably be similar to what it feels like to focus on your thoughts in one of those terrible dining areas with televisions all over . difficult , & a struggle to not zone out & succumb to the noise ."
1235 blockquote_ "too bad i can't take a nap during it ."
1236 blockquote_ "i know right . well , if you're ready then have a seat & i'll start projecting ."
1237 p_ "she sits down & puts on the acrylic beanie . all of the cables dangling off of it match her hair color , which gives the illusion that her hair extends onto the floor ."
1238 code "haskell" "use Terminal"
1239 p_ $ do
1240 "you swivel over to your terminal & execute "
1241 inlineCode "1ntr0j3ct.hs"; " ."
1242 blockquote_ "you named the script using leetspeak ?"
1243 blockquote_ "yep , it makes words taste better ."
1244 p_ "you get up & lie down on your yoga mat . your vision starts to fade ..."
1245 h2_ "the center"
1246 p_ "a sea of tall , green grass stretches endlessly in all directions except to the west , where a short , smoothly vertical cliff face wraps a plateau . you're sitting at the junction of a boardwalk splitting off to the north , south , & east ."
1247 p_ "you're not sure why , but this location feels like the central point in her mind , where all other synapse clusters meet . why then is it so barren ?"
1248 p_ "it's dark , but the moon is bright enough that you can see sheets of rain sweeping the expanse . the rain & wind produce a soothing noise that ripples in waves off of the grass ."
1249 p_ "even farther in the distance , you hear another ceaseless noise coming from all directions except up & down . it's a harsh , glass grinding static , but not quite painful because of how faint it is ."
1250 code "haskell" "go West"
1251 p_ "there is a cliff face to the west . you hover up to the top edge ."
1252 h2_ "eastern plateau ridge"
1253 p_ "you aren't that much higher than the boardwalks below , but you can see much farther into the distance from up here . there is a sliver of deep crimson shimmer spanning the entire horizon . maybe that's what's making that grinding noise ?"
1254 p_ "the footpath you're on continues to the north & south . to the west , the top of the plateau slopes downward toward a pool of glowing purple liquid . the pool appears to converge & warp in upon itself , almost as if a tiny black hole were floating a few meters above the surface ."
1255 p_ "there's a rectangular slot in the ground close by , but you can't see what's in it from here ."
1256 code "haskell" "examine Slot"
1257 h2_ "slot machine"
1258 p_ "now that you're closer to the slot , you notice a hand-written sign next to it that says :"
1259 blockquote_ "slot machine : enter the slot & slide like a coin to a random location"
1260 p_ "somebody walks over to you & asks what you're doing ."
1261 blockquote_ "hello ! i'm trying to figure out what the deal with this slot thing is ."
1262 blockquote_ "no you're not . i saw you over there trying to vandalize my hand-written sign ."
1263 blockquote_ "you what ? i didn't even touch the sign ."
1264 blockquote_ "then how did all of those purple stains get on it ?"
1265 p_ "you glance at the sign again . it does appear more stained than you remember it . you wonder , aloud :"
1266 blockquote_ "maybe it's from that pool over there ? whatever gravity well is swirling above the pool might have become volatile ."
1267 blockquote_ "that's certainly a possiblity . but it seems much more likely that you hated my handwriting style & wanted to destroy it yourself ."
1268 blockquote_ "you serious ? i didn't even think of the handwriting style until now. it was perfectly serviceable ."
1269 blockquote_ "oh ."
1270 p_ "they gaze into the distance uncomfortably ."
1271 p_ "the grinding sound grows louder , & the crimson glow brighter ."
1272 p_ $ em_ "shard count : 3"
1273 code "haskell" "ask SignPainter . about Sound"
1274 p_ "you ask the sign painter if they know where that sound is coming from ."
1275 blockquote_ "no ."
1276 code "haskell" "ask SignPainter . about CrimsonGlow"
1277 p_ "you ask them if they know what the crimson glow is coming from ."
1278 blockquote_ "no ."
1279 p_ "the sign painter sits on the ground , placing their legs into the slot . they carefully lower the rest of their body into the slot & let go. a few seconds later the sound of them sliding fades away completely ."
1280 p_ "it starts to rain . the droplets are purple , & stains your grey dress ."
1281 code "haskell" "go East"
1282 p_ "you hover back down the cliff face & land on the boardwalk again ."
1283 h2_ "the center"
1284 p_ "it feels nice to return to the center . that plateau to the west had an unpleasant vibe . the boardwalk continues to the north , south , & east ."
1285 code "haskell" "go West"
1286 p_ "you look back at the cliff face . a voice in your head says it may be a good idea to return to the slot machine , because it could spit you out where you need to go much faster than hovering there yourself ."
1287 p_ "but no . that would be a gamble ."
1288 p_ "you don't like leaving things to chance ."
1289 code "haskell" "go North"
1290 p_ "with your mind made up , you hover northward along the boardwalk ."
1291 h2_ "an expanse"
1292 p_ "you've reached the end of the boardwalk . this location is so far from the plateau that it's barely visible through the rain . the crimson glow to the north stretches higher into the sky here . it's like the source of the grinding noise is a wall in the distance that wraps around the boundary of b6e's mind ."
1293 p_ "there is a swarm of winged , metal centipedes flying over your head ."
1294 p_ "the grinding sound is loud enough here to put you on edge ."
1295 p_ $ em_ "shard count : 4"
1296 code "haskell" "ask Centipede . about Sound"
1297 p_ "you call out to the centipedes above you ."
1298 blockquote_ "excuse me , would any of you be able to help me answer a quick question ?"
1299 p_ "one of them lands in front of you . they are wearing a really cool sweater with a fractal pattern knitted onto it ."
1300 blockquote_ "i might be able to help ya ! what's ur question ?"
1301 blockquote_ "oh nice ! thank you . do you know what that glass grinding noise in the distance is ?"
1302 blockquote_ "ya mean death ?"
1303 blockquote_ "what ?"
1304 blockquote_ "death . like the thing that happens when ya have a shard count of 11 ? looks like ya have 4 shards . ya might wanna stop thinkin' 'bout the wall !! you'll get less shards that way !"
1305 p_ "the other centipedes start gliding to the southeast ."
1306 blockquote_ "that's what the shard count is about ? why would thinking about the wall give you more shards ? by the wall you mean that crimson thing in the distance , right ?"
1307 blockquote_ "hey kid i'm sorry but i gotta go my friends are leavin' & i don't wanna get left behind but i'm sure someone else can help ya out ! althoughhh a lotta people might be hesitant ( ior worse ) to talk about the shards . not sure what to tell ya 'bout that ."
1308 blockquote_ "ok , well thanks for the info . i'll keep searching then ."
1309 blockquote_ "be careful ."
1310 p_ "they fly away ."
1311 code "haskell" "save"
1312 p_ $ em_ "serializing timeline ..."
1313 p_ $ em_ "game saved ."
1314 p_ $ em_ $ do
1315 "enter the code "
1316 inlineCode "5nJ0kL3-001"
1317 " to restore the game to this point in time ."
1318 code "haskell" "pop"
Zoxuli.hs
1module Zoxuli
2 ( Zoxuli
3 , PassData(..), PassOne(..), PassTwo(..)
4 , slugify
5 , rawHtml
6 , Link(..), link, linkToAnchor
7 , Code(..), code, inlineCode
8 , h1_, h2_, h3_, h4_, h5_, h6_
9 , toc
10 , Footnote(..), footnote
11 , Page(..), makePage
12 , Project, ProjectMeta(..), makeProject
13 , Post, PostMeta(..), makePost
14 , reverseChronological
15 , SrcFile(..)
16 ) where
17
18import Lucid hiding (h2_, h3_, h4_, h5_, h6_)
19import qualified Lucid as L
20import Lucid.Base (TermRaw, termRaw)
21import Optics
22import GHC.Generics (Generic)
23import Control.Monad (when)
24import Control.Monad.State.Lazy (State, get, modify, lift)
25import Data.Text (Text, replace, toLower, pack, unpack)
26import Data.List (sortBy)
27
28type Zoxuli = HtmlT (State PassData) ()
29
30data PassData = One PassOne | Two PassTwo
31 deriving (Generic)
32
33data PassOne = PassOne
34 { links :: [Link]
35 , headers :: [Header]
36 , footnotes :: [Zoxuli]
37 , codes :: [Code] } deriving (Generic)
38
39data PassTwo = PassTwo
40 { backlinks :: [Link]
41 , headers :: [Header]
42 , footnotes :: [Footnote]
43 , footnoteIndex :: Int
44 , codes :: [Text]
45 , srcFiles :: [SrcFile] } deriving (Generic)
46
47data Link = Link
48 { body :: Text
49 , destinationTitle :: Text
50 , destinationPath :: Text }
51
52link :: Bool -> Page -> Text -> Zoxuli
53link createBacklink page =
54 link' createBacklink page Nothing
55
56linkToAnchor :: Bool -> Page -> Text -> Text -> Zoxuli
57linkToAnchor createBacklink page anchor =
58 link' createBacklink page (Just anchor)
59
60link' :: Bool -> Page -> Maybe Text -> Text -> Zoxuli
61link' createBacklink page anchor body = do
62 when createBacklink $ do
63 let newLink = [Link body page.title page.path]
64 lift . modify $ #_One % #links %~ (<> newLink)
65 a_ [ href_ $ "/" <> page.path <> ".html"
66 <> maybe "" ("#" <>) anchor
67 , id_ $ slugify body ]
68 $ toHtml body
69
70data Code = Code
71 { lang :: Text
72 , body :: Text }
73
74code :: Text -> Text -> Zoxuli
75code lang body = lift get >>= \case
76 One _ -> lift . modify $ #_One % #codes %~ (<> newCode)
77 Two s -> case s.codes of
78 (c:rest) -> do
79 rawHtml c
80 lift . modify $ #_Two % #codes .~ rest
81 _ -> pure ()
82 where newCode = [Code lang body]
83
84inlineCode :: Zoxuli -> Zoxuli
85inlineCode = code_ [class_ "verbatim"]
86
87data Header = Header
88 { level :: Int
89 , body :: Text } deriving (Generic)
90
91hx_ :: Int -> (Zoxuli -> Zoxuli) -> Text -> Zoxuli
92hx_ level headerFunction body = do
93 let newHeader = [Header level body]
94 lift . modify $ #_One % #headers %~ (<> newHeader)
95 headerFunction $ do
96 a_ [ href_ $ "#" <> slugify body
97 , id_ $ slugify body ]
98 $ toHtml body
99
100h2_ :: Text -> Zoxuli
101h2_ = hx_ 2 L.h2_
102
103h3_ :: Text -> Zoxuli
104h3_ = hx_ 3 L.h3_
105
106h4_ :: Text -> Zoxuli
107h4_ = hx_ 4 L.h4_
108
109h5_ :: Text -> Zoxuli
110h5_ = hx_ 5 L.h5_
111
112h6_ :: Text -> Zoxuli
113h6_ = hx_ 6 L.h6_
114
115toc :: Zoxuli
116toc = lift get <&> (^? #_Two % #headers) >>= \case
117 Just headers@(_:_) -> details_ [class_ "toc"] $ do
118 summary_ "table of contents"
119 ol_ $ tocList headers
120 _ -> pure ()
121
122tocList :: [Header] -> Zoxuli
123tocList [] = pure ()
124tocList ((Header level body) : rest) = do
125 let (nested, following) =
126 break (\h -> h.level == level) rest
127 li_ . a_ [ href_ $ "#" <> slugify body ] $ toHtml body
128 if null nested then pure () else ol_ $ tocList nested
129 tocList following
130
131data Footnote = Footnote Int Zoxuli
132
133footnote :: Zoxuli -> Zoxuli
134footnote content = lift get >>= \case
135 One _ -> lift . modify $ #_One % #footnotes %~ (<> [content])
136 Two s -> do
137 sup_ .
138 a_ [ href_ $ "#fn" <> pack (show s.footnoteIndex)
139 , id_ $ "r" <> pack (show s.footnoteIndex) ]
140 $ do "["; toHtml $ show s.footnoteIndex; "]"
141 lift . modify $ #_Two % #footnoteIndex %~ (+ 1)
142
143slugify :: Text -> Text
144slugify = replace " " "-" . toLower
145
146rawHtml :: TermRaw arg result => arg -> result
147rawHtml = termRaw "div"
148
149data Page = Page
150 { title :: Text
151 , path :: Text
152 , tags :: [Text]
153 , html :: Zoxuli } deriving (Generic)
154
155instance Eq Page where
156 a == b = a.path == b.path
157
158makePage :: Text -> Zoxuli -> Page
159makePage title = Page title path []
160 where path = case title of
161 "home" -> "index"
162 _ -> slugify title
163
164type Project = (Page, ProjectMeta)
165
166data ProjectMeta = ProjectMeta
167 { description :: Text
168 , repo :: Text } deriving (Generic)
169
170makeProject :: Text -> Text -> Text -> [Text] -> Zoxuli -> Project
171makeProject title description repo tags html =
172 (Page title path tags html, ProjectMeta description repo)
173 where path = "projects/" <> slugify title
174
175type Post = (Page, PostMeta)
176
177data PostMeta = PostMeta
178 { date :: Text
179 , author :: Text } deriving (Generic)
180
181makePost :: Text -> Text -> [Text] -> Zoxuli -> Post
182makePost title date tags html =
183 (Page title path tags html, PostMeta date "eevie")
184 where path = "posts/" <> slugify title
185
186reverseChronological :: [Post] -> [Post]
187reverseChronological = sortBy comp
188 where comp a b = getInt b `compare` getInt a
189 getInt :: Post -> Int
190 getInt p = read $ unpack $ replace "-" "" $ p ^. _2 % #date
191
192data SrcFile = SrcFile
193 { name :: Text
194 , content :: Text }
Main.hs
1module Main (main) where
2
3import Zoxuli
4import Pages
5import Lucid hiding (h2_, h3_, h4_, h5_, h6_)
6import Optics
7import System.Directory (createDirectoryIfMissing)
8import System.FilePath ((</>))
9import System.Process (spawnCommand, readProcess)
10import Control.Monad (void)
11import Control.Monad.State.Lazy (evalState, execState)
12import Data.Maybe (fromMaybe)
13import Data.Text (Text, unpack, pack)
14import Data.Foldable (foldrM)
15import Data.Map (Map)
16import qualified Data.Map as Map
17import qualified Data.ByteString.Lazy as BS
18
19-- | page rendering and writing
20
21main :: IO ()
22main = do
23 createBuildDirectories
24 copyStaticFiles
25 copySrcFiles
26 writePages =<< getSrcFiles
27 createArchive
28
29buildDir :: FilePath
30buildDir = "site"
31
32createBuildDirectories :: IO ()
33createBuildDirectories =
34 mapM_ (createDirectoryIfMissing True)
35 [ buildDir
36 , buildDir </> "projects"
37 , buildDir </> "posts"
38 , buildDir </> "tags" ]
39
40copyStaticFiles :: IO ()
41copyStaticFiles = void $ spawnCommand $ "cp -r static/* " <> buildDir
42
43copySrcFiles :: IO ()
44copySrcFiles = void $ spawnCommand $ "cp -r app " <> buildDir <> "/src"
45
46getSrcFiles :: IO [SrcFile]
47getSrcFiles = do
48 let getFileContents name = do
49 content <- readFile $ "app" </> name
50 highlightCode $ Code "haskell" $ pack content
51 srcFileNames = ["Pages.hs", "Zoxuli.hs", "Main.hs"]
52 srcFileContents <- mapM getFileContents srcFileNames
53 pure $ zipWith SrcFile (pack <$> srcFileNames) srcFileContents
54
55writePages :: [SrcFile] -> IO ()
56writePages srcFiles = do
57 passTwoData <- foldrM runPassOne Map.empty allPages
58 let passTwoData' = passTwoData <&> (#_Two % #srcFiles .~ srcFiles)
59 mapM_ (\p -> writePage p.path $ runPassTwo passTwoData' p)
60 allPages
61
62allPages :: [Page]
63allPages = pageWrapper False bookPage :
64 (pageWrapper True <$> (
65 mainPages
66 <> (fst <$> projectPages)
67 <> (fst <$> postPages)
68 <> tagPages ))
69
70runPassOne :: Page -> Map Text PassData -> IO (Map Text PassData)
71runPassOne page acc =
72 let passOneData = execState
73 (renderBST page.html) (One (PassOne [] [] [] [])) in
74 case passOneData of
75 One (PassOne links headers footnotes codes) -> do
76 codes' <- mapM highlightCode codes
77 let acc' = Map.alter fromPassOne page.title acc
78 footnotes' = zipWith Footnote [1..] footnotes
79 fromPassOne (Just (Two d)) =
80 Just . Two $ d & #headers .~ headers
81 & #footnotes .~ footnotes'
82 & #codes .~ codes'
83 fromPassOne _ = Just . Two $
84 PassTwo [] headers footnotes' 1 codes' []
85 pure $ foldr (makeBacklinks page) acc' links
86 _ -> pure acc
87
88-- the theme css is generated with the following command:
89-- `chroma --html-styles --style "algol_nu"`
90highlightCode :: Code -> IO Text
91highlightCode c =
92 pack <$> readProcess "chroma"
93 [ "--html"
94 , "--html-only" -- only return code fragment
95 , "--html-lines" -- include line numbers
96 , "--lexer", unpack c.lang ]
97 (unpack c.body)
98
99makeBacklinks
100 :: Page -> Link -> Map Text PassData -> Map Text PassData
101makeBacklinks page ln backlinks =
102 if page.title == "book" then backlinks
103 else Map.alter addBacklink ln.destinationTitle backlinks
104 where backlink = Link ln.body page.title page.path
105 addBacklink (Just (Two d)) =
106 Just . Two $ d & #backlinks %~ cons backlink
107 addBacklink _ = Just . Two $
108 PassTwo [backlink] [] [] 1 [] []
109
110runPassTwo :: Map Text PassData -> Page -> BS.ByteString
111runPassTwo passOneData page =
112 evalState (renderBST page.html) pageData
113 where pageData = fromMaybe (Two (PassTwo [] [] [] 1 [] [])) $
114 Map.lookup page.title passOneData
115
116writePage :: Text -> BS.ByteString -> IO ()
117writePage path = BS.writeFile (buildDir </> unpack path <> ".html")
118
119createArchive :: IO ()
120createArchive = void $ spawnCommand
121 $ "cd " <> buildDir <> " && tar -czvf eevie.dev.tar.gz *"
backlinks
- zoxuli : "source page"