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 "macroquad.js is under the "
181 a_ [href_ "https://github.com/not-fl3/macroquad/blob/master/LICENSE-MIT"] "MIT license"
182 " license"
183 li_ $ do
184 a_ [href_ "https://www.dafont.com/offenbacher-reform-cat.font"] "Offenbacher Reform"
185 " by Peter Wiegel is under the "
186 a_ [href_ "https://openfontlicense.org/"] "SIL Open Font License"
187
188downloadPage :: Page
189downloadPage = makePage "download" $ do
190 h2_ "archive"
191 p_ "a full archive of this website is available for offline viewing :"
192 p_ $ a_ [href_ "/eevie.dev.tar.gz"] "download archive"
193 h2_ "book"
194 p_ $ do
195 "there is a book page containing every post , designed for printing ior saving as a PDF :"
196 p_ $ link False bookPage "view book"
197 h2_ "source"
198 p_ "one can clone the source repository of this site using git :"
199 code "bash" "git clone https://git.sr.ht/~nebulae/eevie.dev"
200
201projectsPage :: Page
202projectsPage = makePage "projects" $ do
203 h2_ "art"
204 ul_ $ do
205 li_ $ link True digitalArtPage "digital"
206 li_ $ a_ [href_ "https://plokta.bandcamp.com/"] "music"
207 li_ $ link True photographyPage "photography"
208 h2_ "software"
209 ul_ $ do
210 mapM_ (li_ . projectPreview) projectPages
211 li_ $ do
212 b_ $ a_ [href_ "yarnstar/index.html"] "yarnstar"
213 " - an implementation of Nova in Elm"
214 li_ $ do
215 b_ $ a_ [href_ "https://git.sr.ht/~nebulae/concur_vite"] "Concur + Vite"
216 " - a purescript-concur starter template"
217 li_ $ do
218 b_ $ a_ [href_ "miraquad/index.html"] "[WIP] Miraquad"
219 " - create 2D games in Mira"
220 li_ $ do
221 b_ $ a_ [href_ "https://git.sr.ht/~nebulae/nova_conjure"] "[WIP] NovaConjure"
222 " - interactive fiction witchcraft in Nova"
223 li_ $ do
224 b_ $ a_ [href_ "https://git.sr.ht/~nebulae/antibubble"] "[WIP] Antibubble"
225 " - nested bubble world exploration game"
226
227postsPage :: Page
228postsPage = makePage "posts" $ do
229 p_ "in which i externalize the technicolor collapse of techno-synaptic maps of mind matter i’m made of ."
230 ul_ $ mapM_ (li_ . postPreview) postPages
231 microblog
232
233microblog :: Zoxuli
234microblog = do
235 h2_ "microblog"
236 p_ "for shorter thoughts !"
237 micropost "2024-12-06" $ do
238 "low back creaking"; br_ []
239 "dizzy when standing"; br_ []
240 "both eyes blurring"; br_ []
241 "can't we learn while moving ?"
242 micropost "2024-06-09" $ do
243 "i hate the term "
244 a_ [href_ "https://en.wikipedia.org/wiki/Overfishing"] "\"overfishing\""
245 " , because it implies that there’s an acceptable amount of "
246 a_ [href_ "https://animalequality.org/issues/fish/"] "fishing"
247 " ."
248 where micropost :: Text -> Zoxuli -> Zoxuli
249 micropost date content =
250 p_ $ div_ [class_ "border"] $ do
251 p_ $ b_ $ toHtml date
252 p_ content
253
254bookPage :: Page
255bookPage = makePage "book" $ do
256 h2_ "chapters"
257 ol_ $ mapM_ (li_ . toHtml . (^. #title)) pages
258 mapM_ chapter pages
259 where pages :: [Page]
260 pages = (fst <$> postPages') <> (fst <$> projectPages')
261 chapter :: Page -> Zoxuli
262 chapter page = do
263 hr_ []
264 h1_ $ toHtml page.title
265 page.html
266
267tagsPage :: Page
268tagsPage = makePage "tags" $ do
269 p_ "hypertext flowed through the cracks in the ground , illuminated by ambient amethyst light from the sky above ."
270 ul_ $ mapM_ (li_ . tagPreview) allTags
271
272seriesPage :: Page
273seriesPage = makePage "series" $ do
274 mapM_ renderSeries allSeries
275
276sourcePage :: Page
277sourcePage = makePage "source" $ do
278 p_ $ do
279 "this page contains all of the "
280 linkToAnchor True (fst howIUseComputersPost) "language" "Haskell"
281 " code that's used to generate this website . the full source repository is on "
282 a_ [href_ "https://git.sr.ht/~nebulae/eevie.dev"]
283 "SourceHut"
284 " . i've also written about the "
285 link True (fst zoxuliProject) "story behind this design"
286 " . "
287 lift get <&> (^? #_Two % #srcFiles) >>= \case
288 Just srcFiles -> mapM_ renderSrcFile srcFiles
289 _ -> pure ()
290 where renderSrcFile :: SrcFile -> Zoxuli
291 renderSrcFile f = do
292 h2_ f.name
293 p_ $ a_ [href_ $ "/src/" <> f.name] "raw file"
294 rawHtml f.content
295
296contactPage :: Page
297contactPage = makePage "contact" $ do
298 p_ $ do
299 "email : "
300 span_ [class_ "email"] $ do
301 "eevie@sent"; b_ "obfuscation-text"; ".com"
302 h2_ "don't contact me if ..."
303 p_ $ do "if you "; em_ "intentionally"; " propagate any of the following , i do "; em_ "not"; " want to hear from you :"
304 ul_ $ do
305 li_ "fascism"
306 li_ "nationalism"
307 li_ "classism"
308 li_ "speciesism"
309 li_ "substratism"
310 li_ "ageism"
311 li_ "antisemitism"
312 li_ "racism"
313 li_ "colorism"
314 li_ "sexism"
315 li_ "deathism"
316 li_ "ableism"
317 li_ "sanism"
318 li_ "transphobia"
319 li_ "enbyphobia"
320 li_ "interphobia"
321 li_ "aphobia"
322 li_ "lesbophobia"
323 li_ "homophobia"
324 li_ "biphobia"
325 li_ "fatphobia"
326 li_ "pluralphobia"
327 todo "create a PGP key"
328
329todo :: Text -> Zoxuli
330todo title = link True todoPage $ "todo : " <> title
331
332todoPage :: Page
333todoPage = makePage "todo" $ do
334 ul_ $ do
335 li_ $ do
336 "follow Seirdy's "
337 a_ [href_ "https://seirdy.one/posts/2020/11/23/website-best-practices/"] "best practices for inclusive textual websites"
338 li_ $ do
339 "make an "; inlineCode "md"; " function that uses the "
340 a_ [href_ "https://hackage.haskell.org/package/cmark"] "cmark"
341 " library"
342 li_ "RSS/Atom feeds"
343 li_ "N24 manager , swirlsaber , particle art , & helix lavender theme"
344 p_ "any todos across the site are linked to this page , so you can view them in the list of backlinks :"
345
346photo :: Text -> Text -> Zoxuli
347photo file alt = img_
348 [ src_ $ "/img/" <> file
349 , style_ "width: 100%"
350 , alt_ alt ]
351
352digitalArtPage :: Page
353digitalArtPage = makePage "digital art" $ do
354 h2_ "trans hacker fæ"
355 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."
356 p_ $ do
357 "( "
358 a_ [href_ "/img/trans-hacker-fae.jpg"] "version without overlay"
359 " )"
360 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 ."
361 p_ $ do
362 "made using "
363 a_ [href_ "https://www.blender.org/"] "Blender"
364 " , "
365 a_ [href_ "https://godotengine.org/"] "Godot"
366 " , & "
367 a_ [href_ "https://krita.org/en/"] "Krita"
368 " ."
369 h2_ "spiky swamp"
370 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."
371 p_ "this is a screenshot from my first attempt at making a low-poly 3D game ."
372
373photographyPage :: Page
374photographyPage = makePage "photography" $ do
375 photo "banner.png" "a dithered photograph of blue & pink flowers"
376 photo "plants5.jpg" "a beetle resting on the center of a fully bloomed flower"
377 photo "plants4.jpg" "a small butterfly in a bright field of flowers"
378 photo "plants1.jpg" "a brightly lit plant with bundles of fuzzy pink flowers"
379 photo "plants2.jpg" "a bundle of fuzzy white flowers in a verdant garden"
380 photo "plants3.jpg" "stalks of bamboo in a forest with large bokeh in the background"
381
382-- | tag pages
383
384taggedPages :: [Page]
385taggedPages = (fst <$> projectPages) <> (fst <$> postPages)
386
387allTags :: [Text]
388allTags = deduplicate $ concatMap (^. #tags) taggedPages
389 where deduplicate = Set.toList . Set.fromList
390
391pagesWithTag :: Text -> [Page]
392pagesWithTag tag = filter (elem tag . (^. #tags)) taggedPages
393
394tagPreview :: Text -> Zoxuli
395tagPreview tag = do
396 toHtml . show . length $ pagesWithTag tag; " - "
397 a_ [href_ $ "/tags/" <> slugify tag <> ".html"] $ toHtml tag
398
399renderTags :: [Text] -> Zoxuli
400renderTags tags =
401 sequence_ . intersperse " , " $ renderTag <$> tags
402 where renderTag :: Text -> Zoxuli
403 renderTag tag =
404 a_ [ href_ $ "/tags/" <> slugify tag <> ".html" ]
405 $ toHtml tag
406
407tagPages :: [Page]
408tagPages = makeTagPage <$> allTags
409
410makeTagPage :: Text -> Page
411makeTagPage tag = Page tag path [] html
412 where path = "tags/" <> slugify tag
413 html = do
414 p_ $ do "pages tagged \""; toHtml tag; "\":"
415 ul_ . mapM_ (\p -> li_ $ link False p p.title)
416 $ pagesWithTag tag
417
418-- | page series
419
420data Series = Series
421 { name :: Text
422 , pages :: [Page] } deriving (Generic)
423
424allSeries :: [Series]
425allSeries = [computingSeries]
426
427computingSeries :: Series
428computingSeries = Series "liberatory computing"
429 [ fst theOasisPost
430 , fst unlicensePost
431 , fst timelineSplittingPost
432 , fst queerCybersecPost
433 , fst howIUseComputersPost
434 , fst zoxuliProject ]
435
436renderSeries :: Series -> Zoxuli
437renderSeries series = do
438 h2_ series.name
439 ol_ . mapM_ (\p -> li_ $ link False p p.title)
440 $ series.pages
441
442seriesNav :: Page -> Maybe Zoxuli
443seriesNav page =
444 if null seriesWithPage then Nothing
445 else Just $ mapM_ renderSeriesNav seriesWithPage
446 where seriesWithPage = filter (elem page . (^. #pages)) allSeries
447 renderSeriesNav :: Series -> Zoxuli
448 renderSeriesNav (Series name ps) = span_ $ do
449 let next xs x = lookup x . zip xs $ tail xs
450 maybeLink t = maybe (pure ()) $ \p -> link False p t
451 position = (+ 1) . fromMaybe 1 $ elemIndex page ps
452 b_ "series"; " : "
453 toHtml . show $ position; "/"
454 toHtml . show $ length ps
455 " in "
456 a_ [ href_ $ "/series.html#" <> slugify name ]
457 . toHtml $ name
458 " : "
459 maybeLink "[previous]" $ next (reverse ps) page
460 " "
461 maybeLink "[next]" $ next ps page
462
463-- | project pages
464
465projectWrapper :: Project -> Project
466projectWrapper project =
467 project & _1 % #html %~ (meta <>)
468 where meta = do
469 p_ [class_ "description"] .
470 toHtml $ project ^. _2 % #description
471 toc
472 ul_ $ do
473 li_ $ a_ [ href_ $ project ^. _2 % #repo ] $
474 b_ "📦 SourceHut page"
475 maybe (pure ()) li_ . seriesNav $ fst project
476 li_ $ do
477 b_ "tags"; " : "
478 renderTags $ project ^. _1 % #tags
479
480projectPreview :: Project -> Zoxuli
481projectPreview project = do
482 b_ $ link False (fst project) $ project ^. _1 % #title
483 " - "; toHtml $ project ^. _2 % #description
484
485projectPages :: [Project]
486projectPages = projectWrapper <$> projectPages'
487
488projectPages' :: [Project]
489projectPages' =
490 [ zoxuliProject
491 , swirlmaniaProject
492 , coaltonRaylibProject
493 ]
494
495zoxuliProject :: Project
496zoxuliProject = makeProject "zoxuli"
497 "a lucid static site generator"
498 "https://git.sr.ht/~nebulae/zoxuli"
499 ["web dev", "haskell", "programming"] $ do
500 h2_ "a humble goal"
501 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 ."
502 p_ "this would lead me on an unexpectedly long journey that ends at the website you're on today ."
503 h2_ "static site generators"
504 p_ $ do
505 "i started off by learning about "
506 a_ [href_ "https://wordpress.com/"] "WordPress"
507 " , 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 ."
508 p_ $ do
509 "looking for other options , i discovered "
510 a_ [href_ "https://en.wikipedia.org/wiki/Static_site_generator"] "static site generators"
511 " ( 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 "
512 a_ [href_ "https://jekyllrb.com/"] "Jekyll"
513 " , but the documentation was too advanced for me at the time . i moved on to other projects for a while ."
514 h2_ "a new problem"
515 p_ "a while later , after i had learned more about programming for other reasons , i realized i could now understand the Jekyll documentation !"
516 p_ $ do "except ... now my expectations for my website had changed significantly . now i wanted :"
517 ul_ $ do
518 li_ "excellent accessibility"
519 li_ "post series with navigation"
520 li_ "tables of contents"
521 li_ "tags that work across multiple categories of pages"
522 li_ "backlinks"
523 li_ "footnotes"
524 li_ "breadcrumbs"
525 li_ "control over where & how the aforementioned elements appear"
526 li_ "syntax highlighting"
527 li_ "LaTeX"
528 li_ "semantic markup"
529 li_ "no JavaScript"
530 li_ "broken link checking"
531 li_ "simple & powerful extensibility in a comfortable language"
532 li_ "the ability to write pages in any markup format"
533 li_ "a fast development feedback loop"
534 p_ $ do
535 "i thought , hey , that's a lot of stuff to ask for , but there are "
536 a_ [href_ "https://jamstack.org/generators/"] "hundreds"
537 " ( eor likely thousands ) of SSGs , so surely at least one of them can do all that ?"
538 h2_ "SSG frenzy"
539 p_ $ do
540 "i tried a lot of SSGs . the three that got me closest to all of my goals were "
541 a_ [href_ "https://soupault.app/"] "Soupault"; " , "
542 a_ [href_ "https://bagatto.co/"] "Bagatto"; " , & "
543 a_ [href_ "https://jaspervdj.be/hakyll/"] "Hakyll"
544 " . but none of those got me everything ( "
545 todo "explain their strengths & shortcomings in detail"
546 " ) . there might be another one out there , but i didn't find it ."
547 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 ."
548 h2_ "zoxuli : first attempt"
549 p_ $ do
550 "my first attempt ( "
551 todo "share zoxuli v1"
552 " ) was written in Common Lisp , & was most similar to Bagatto ."
553 p_ $ do
554 "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 "
555 inlineCode ".("; " & "; inlineCode ")."
556 " that would be evaluated when the site was built ."
557 p_ $ do
558 "this meant that - as an example - if one wanted to generate backlinks , one could create a "
559 inlineCode ".(link <args>)."
560 " function that would be used anywhere they needed links in their markup . the function would both render the link HTML ( using "
561 a_ [href_ "https://github.com/ruricolist/spinneret"] "spinneret"
562 " ) that gets inserted back into that position by zoxuli , & also store the link data into a variable . during the second pass , calls to a "
563 inlineCode ".(backlinks)."
564 " function would convert the collected links into backlinks & render them into HTML wherever they are needed ."
565 h2_ "zoxuli : final version"
566 p_ "after giving version one a proper go , these were my issues with it :"
567 ul_ $ do
568 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"
569 li_ "my implementation resulted in slower build times than i had hoped"
570 li_ $ do
571 "around that time , i realized i don't like programming in Lisp nearly as much as Haskell , especially after learning "
572 a_ [href_ "https://www.parsonsmatt.org/2018/05/19/ghcid_for_the_win.html"] "how to use ghcid"
573 " properly"
574 li_ $ do
575 "i also discovered the "
576 a_ [href_ "https://hackage.haskell.org/package/lucid"] "lucid"
577 " library for Haskell that i favored over spinneret for a few reasons"
578 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 ."
579 p_ $ do
580 "i ported this website from Hakyll to zoxuli & i'm quite pleased with the experience . the source code for this website is on the "
581 link True sourcePage "source page"
582 " . "
583
584swirlmaniaProject :: Project
585swirlmaniaProject = makeProject "swirlmania"
586 "a StepMania level processor"
587 "https://git.sr.ht/~nebulae/swirlmania"
588 ["stepmania", "exercise", "rust"] $ do
589 h2_ "what it is"
590 p_ $ do
591 "swirlmania is a CLI "
592 a_ [href_ "https://www.stepmania.com/"] "StepMania"
593 " simfile ( .ssc ) processor with support for generating tech charts without double steps ."
594 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 ."
595 h2_ "why i made it"
596 p_ $ do
597 "i enjoy playing "
598 a_ [href_ "https://projectoutfox.com/"] "Project OutFox"
599 " ( 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 ."
600 p_ $ do
601 "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 "
602 a_ [href_ "https://github.com/phr00t/AutoStepper"] "AutoStepper"
603 " , 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 ."
604
605coaltonRaylibProject :: Project
606coaltonRaylibProject = makeProject "coalton-raylib"
607 "games programming in Coalton"
608 "https://git.sr.ht/~nebulae/coalton-raylib"
609 ["game dev", "coalton", "common lisp", "programming"] $ do
610 h2_ "the problem"
611 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 ."
612 p_ $ do
613 "this is because one must restart the entire program they're working on every time a new change is compiled"
614 footnote "there are ways to smooth this over , but they can add a lot of complexity"
615 " ."
616 h2_ "one possible solution"
617 p_ $ do
618 "as an ML language built on top of Common Lisp , "
619 a_ [href_ "https://coalton-lang.github.io/20211010-introducing-coalton/"] "Coalton"
620 " can provide a statically typed , functional ( with typeclasses ! ) , & highly interactive game programming environment ."
621 p_ $ do
622 "coalton-raylib is an example project i've shared that uses the "
623 a_ [href_ "https://www.raylib.com/"] "raylib"
624 " graphics library ."
625 p_ $ do
626 "i've written the draw loop in Common Lisp , & the data model & update functions in Coalton"
627 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"
628 " . 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 !"
629 h2_ "conclusion"
630 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 ."
631
632-- | post pages
633
634postWrapper :: Post -> Post
635postWrapper post =
636 post & _1 % #html %~ (meta <>)
637 where meta = do
638 toc
639 ul_ $ do
640 li_ $ b_ $ toHtml $ post ^. _2 % #date
641 maybe (pure ()) li_ . seriesNav $ fst post
642 li_ $ do
643 b_ "tags"; " : "
644 renderTags $ post ^. _1 % #tags
645
646postPreview :: Post -> Zoxuli
647postPreview post = do
648 link False (fst post) $ post ^. _1 % #title
649
650postPages :: [Post]
651postPages = reverseChronological $ postWrapper <$> postPages'
652
653postPages' :: [Post]
654postPages' =
655 [ theOasisPost
656 , timelineSplittingPost
657 , compulsorySchoolingPost
658 , howIUseComputersPost
659 , unlicensePost
660 , veganTipsPost
661 , queerCybersecPost
662 , inferiPost
663 , wallOfShardsPost ]
664
665theOasisPost :: Post
666theOasisPost = makePost "the oasis" "2024-11-25"
667 ["virtual reality", "security", "game dev", "programming", "inclusive design", "formal verification"] $ do
668 h2_ "introduction"
669 p_ $ do
670 "for a long time , i've been thinking about how to build a kinder & more radical version of the "
671 a_ [href_ "https://readyplayerone.fandom.com/wiki/OASIS"] "OASIS"
672 " from "
673 a_ [href_ "https://en.wikipedia.org/wiki/Ready_Player_One"] "Ready Player One"
674 " 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 ."
675 h2_ "motivation"
676 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 :"
677 ul_ $ do
678 li_ $ do
679 "unlimited "
680 a_ [href_ "#agency-over-avatar-&-environment"] "creative expression"
681 li_ $ a_ [href_ "https://en.wikipedia.org/wiki/Morphological_freedom"] "morphological freedom"
682 li_ "realistic interaction between people any distance apart"
683 li_ $ do
684 a_ [href_ "#formal-verification"] "formally verified"
685 " "; a_ [href_ "#abuse-protection"] "abuse protection"
686 h2_ "primary values"
687 h3_ "agency over avatar & environment"
688 blockquote_ [cite_ "https://applied-langua.ge/posts/here-is-a-loud-announcement.html#orga51f75c"] $ do
689 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"
690 p_ $ do
691 " — Applied Language , "
692 cite_ $ a_ [href_ "https://applied-langua.ge/posts/here-is-a-loud-announcement.html#orga51f75c"] "Maximalist computing"
693 ul_ $ do
694 li_ $ do
695 "programmable , like "
696 a_ [href_ "https://resonite.com/"] "Resonite"
697 " is using "
698 a_ [href_ "https://wiki.resonite.com/ProtoFlux"] "ProtoFlux"
699 " ; the freedom to modify systems . see "
700 a_ [href_ "https://youtu.be/eS8KeCOJBFA?si=WiUEa41EypVRfGvP"] "Rustybot's video on programming a flying device"
701 " for a demonstration"
702 li_ $ do
703 "introspection to the core ; the ability to inspect any property of the oasis from inside it . this facilitates "
704 a_ [href_ "https://plato.stanford.edu/entries/agency/"] "agency"
705 " , if the fulfillment of one's agency's "
706 a_ [href_ "https://plato.stanford.edu/entries/action/#ConsAim"] "constitutive aim"
707 " is contingent on having accurate models of the world"
708 li_ $ do "no "; a_ [href_ "https://www.deceptive.design/types"] "deceptive design patterns"; " ior advertisements"
709 li_ $ do "no "; a_ [href_ "https://en.wikipedia.org/wiki/Artificial_scarcity"] "artificial scarcity"
710 ul_ $ do
711 li_ $ do link True (fst unlicensePost) "public domain"; " source code"
712 li_ "anticapitalist ( unlike the OASIS )"
713 li_ "no leveling hierarchy that locks features for new people"
714 li_ $ do "no "; a_ [href_ "https://www.defectivebydesign.org/what_is_drm"] "DRM"
715 li_ $ do "no "; a_ [href_ "https://youtu.be/YQ_xWvX1n9g?si=G0hjss5DYLXjdKPe"] "NFTs"; " ior cryptocurrencies"
716 li_ "no limits on changing account metadata like usernames , with the exception of a UUID for persistent blocklists"
717 h3_ "inclusive design"
718 blockquote_ [cite_ "https://100daysofa11y.com/2019/12/03/accommodation-versus-inclusive-design/"] $ do
719 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"
720 p_ $ do
721 " — Amy Carney , "
722 cite_ $ a_ [href_ "https://100daysofa11y.com/2019/12/03/accommodation-versus-inclusive-design/"] "Accommodation versus Inclusive Design"
723 ul_ $ do
724 li_ $ do
725 "create a core protocol like "
726 a_ [href_ "https://en.wikipedia.org/wiki/Secure_Scuttlebutt"] "SSB"
727 " eor "
728 a_ [href_ "https://en.wikipedia.org/wiki/ActivityPub"] "ActivityPub"
729 " to allow for multiple apps built upon it . "
730 a_ [href_ "https://en.wikipedia.org/wiki/Inclusive_design"] "inclusive design"
731 " 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"
732 li_ $ do
733 a_ [href_ "https://iep.utm.edu/qualia/"] "qualia"
734 "-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 "
735 a_ [href_ "https://www.ifwiki.org/Parser-based_interactive_fiction"] "interactive fiction"
736 " , ior more specifically , as a "
737 a_ [href_ "https://en.wikipedia.org/wiki/Multi-user_dungeon"] "MUD"
738 " . pure text can be accessed over a sweeping range of input & output devices , such as "
739 a_ [href_ "https://en.wikipedia.org/wiki/Refreshable_braille_display"] "refreshable braille displays"
740 " . here are few examples of what creation & programming could look like within interactive fiction :"
741 ul_ $ do
742 li_ $ a_ [href_ "https://netjam.org/quoth/"] "Quoth"
743 li_ $ a_ [href_ "https://github.com/seisatsu/DennisMUD"] "DennisMUD"
744 li_ $ a_ [href_ "https://wiki.xxiivv.com/site/paradise.html"] "Paradise"
745 li_ $ a_ [href_ "https://git.sr.ht/~nebulae/nova_conjure"] "NovaConjure"
746 li_ $ do
747 "support many programming paradigms to accommodate varied neurotypes & prevent a "
748 a_ [href_ "https://permacomputing.net/monoculture/"] "monoculture"
749 " . the base language should make the creation of new languages ( spanning the range of each "
750 a_ [href_ "https://madhadron.com/programming/seven_ur_languages.html"] "ur-language"
751 " , & beyond ) simpler , as "
752 a_ [href_ "https://beautifulracket.com/appendix/domain-specific-languages.html"] "Racket"
753 " ior "
754 a_ [href_ "https://wiki.haskell.org/Embedded_domain_specific_language"] "Haskell"
755 " do"
756 ul_ $ do
757 li_ $ do
758 "this could allow esoteric languages with radically different approaches like "
759 a_ [href_ "https://www.dangermouse.net/esoteric/piet/samples.html"] "Piet"
760 " to flourish"
761 li_ $ do
762 link True (fst coaltonRaylibProject) "Coalton"
763 " & "
764 a_ [href_ "https://hazel.org/"] "Hazel"
765 " show that "
766 a_ [href_ "https://en.wikipedia.org/wiki/ML_(programming_language)"] "ML"
767 "-style programming can integrate into a highly dynamic simulation"
768 li_ "thorough documentation for people with any degree of computing knowledge"
769 li_ $ do
770 "provide an accessibility toolkit so people can create new assistive devices within the oasis more easily , & handle "
771 a_ [href_ "https://en.wikipedia.org/wiki/Internationalization_and_localization"] "i18n & l10n"
772 li_ "avoid anthropocentric assumptions to future-proof the possible inclusion of non-human animals , AI agents , aliens , etc."
773 li_ $ do
774 "allow "
775 a_ [href_ "https://pluralpedia.org/w/Plurality"] "plural"
776 " systems to easily switch between profiles to match who is fronting , along with tools for communication between headmates"
777 li_ $ do
778 "runs natively on Linux , "
779 a_ [href_ "https://en.wikipedia.org/wiki/Berkeley_Software_Distribution"] "BSD"
780 " , & others"
781 li_ $ do
782 "see the "
783 a_ [href_ "https://gameaccessibilityguidelines.com/full-list/"] "Game Accessibility Guidelines"
784 " for more ideas in this realm"
785 h3_ "abuse protection"
786 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 ."
787 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 ."
788 ul_ $ do
789 li_ $ do
790 "use fine-grained "
791 a_ [href_ "https://crochet.qteati.me/docs/reference/system/security/why.html"] "capability security"
792 " for "
793 a_ [href_ "https://medium.com/@robotlolita/dependencies-are-bad-but-necessary-806f38f65df4"] "safer dependencies"
794 " while programming in the oasis ( like "
795 a_ [href_ "https://crochet.qteati.me/docs/reference/system/whats-crochet.html"] "Crochet"
796 " 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"
797 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"
798 li_ $ do
799 "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 "
800 link True (fst timelineSplittingPost) "timeline splitting block"
801 " for more on this topic"
802 li_ $ do
803 "distributed/decentralized to counter emergent hierarchy & co-optation by corporations ior the state . the protocol should be ( non-blockchain ) "
804 a_ [href_ "https://en.wikipedia.org/wiki/Peer-to-peer"] "P2P"
805 " by default , with optional "
806 a_ [href_ "https://en.wikipedia.org/wiki/Federation_(information_technology)"] "federation"
807 " for specific instances where it's useful"
808 li_ $ do
809 "forums , git hosting , & any other external infrastructure should avoid regime-compliant software like Discord & GitHub if possible , & have a moderation policy that is "
810 a_ [href_ "https://raddle.me/wiki/defining_our_terms"] "intolerant of bigotry"
811 li_ $ do
812 "multi-factor authentication , including "
813 a_ [href_ "https://en.wikipedia.org/wiki/Universal_2nd_Factor"] "U2F"
814 li_ $ do
815 "accessible over "
816 a_ [href_ "https://www.torproject.org/"] "TOR"
817 " & "
818 a_ [href_ "https://geti2p.net/en/"] "I2P"
819 li_ $ do
820 a_ [href_ "https://en.wikipedia.org/wiki/Homomorphic_encryption#Fully_homomorphic_encryption"] "fully homomorphic encryption"
821 " could allow people to rely on the computational resources of others without necessarily trusting them"
822 li_ $ do
823 "compatible with "
824 a_ [href_ "https://permacomputing.net/salvage_computing/"] "salvage computing"
825 " . if the oasis is to be built upon new hardware , it must wait until the current system of "
826 a_ [href_ "https://youtu.be/vmtaWQxBYFk?si=UotkxTCkwUbPqgQ4"] "exploitative electronics production"
827 " is destroyed , & a kinder means of production has taken its place"
828 h3_ "formal verification"
829 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 ."
830 ul_ $ do
831 li_ $ do
832 "deductive verification using "
833 a_ [href_ "https://en.wikipedia.org/wiki/Dependent_type"] "dependently typed"
834 " programming ( a "
835 a_ [href_ "https://en.wikipedia.org/wiki/Formal_verification"] "formal verification"
836 " approach ) could ensure , using mathematical proofs , that entire sets of bugs cannot occur . this would be used in conjunction with "
837 a_ [href_ "https://en.wikipedia.org/wiki/Secure_by_design"] "secure design"
838 " to prevent exploits in addition to bugs"
839 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 :"
840 ul_ $ do
841 li_ "improve the learning materials . it is uncertain how much this would help , but i am hopeful over a very long time frame"
842 li_ $ do
843 "use "
844 a_ [href_ "https://en.wikipedia.org/wiki/Refinement_type"] "refinement types"
845 " where possible . "
846 a_ [href_ "https://ucsd-progsys.github.io/liquidhaskell/"] "LiquidHaskell"
847 " could be combined with "
848 a_ [href_ "https://wiki.portal.chalmers.se/agda/pmwiki.php"] "Agda"
849 " using "
850 a_ [href_ "https://agda.github.io/agda2hs/"] "agda2hs"
851 " , for instance"
852 li_ $ do
853 a_ [href_ "https://github.com/magmide/magmide"] "Magmide"
854 " 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"
855 li_ $ do
856 "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 "
857 a_ [href_ "https://medium.com/@maiavictor/towards-a-simple-theorem-prover-5005a1e66a6f"] "Cedille"
858 " , eor "
859 a_ [href_ "https://whatisrt.github.io/meta-cedille/2019/06/25/syntactic-metaprogramming-i.html"] "Meta-cedille"
860 " if syntactic metaprogramming were helpful"
861 h2_ "further reading"
862 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 ) :"
863 ul_ $ do
864 li_ $ a_ [href_ "https://en.wikibooks.org/wiki/The_World_of_Peer-to-Peer_(P2P)"] "The World of Peer-to-Peer"
865 li_ $ a_ [href_ "https://ssbc.github.io/scuttlebutt-protocol-guide/"] "the Scuttlebutt Protocol Guide"
866 li_ $ a_ [href_ "https://softwarefoundations.cis.upenn.edu/"] "Software Foundations"
867 li_ $ a_ [href_ "https://plfa.github.io/"] "Programming Language Foundations in Agda"
868 li_ $ a_ [href_ "https://beautifulracket.com/"] "Beautiful Racket"
869 li_ $ a_ [href_ "https://crochet.qteati.me/docs/reference/system/index.html"] "The Crochet System"
870 li_ $ a_ [href_ "https://fuchsia.dev/fuchsia-src/concepts/principles/secure"] "Fuchsia OS security docs"
871 h2_ "conclusion"
872 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 ."
873 p_ $ do
874 "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 "
875 link True contactPage "contact me"
876 " !"
877
878timelineSplittingPost :: Post
879timelineSplittingPost = makePost "timeline splitting block" "2024-11-16"
880 ["game dev", "security", "queer"] $ do
881 h2_ "safety features aren't strong enough"
882 p_ $ do
883 "when i've visited social spaces in "
884 a_ [href_ "https://en.wikipedia.org/wiki/Virtual_reality"] "virtual reality"
885 " , 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 :"
886 ul_ $ do
887 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"
888 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"
889 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"
890 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"
891 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"
892 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."
893 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"
894 li_ "reports i've made haven't resulted in much action , & if they do , it usually takes at least a week"
895 h3_ "trivial fixes"
896 p_ "potential patches for some of the above issues :"
897 ul_ $ do
898 li_ "don't make social consensus necessary to completely remove someone from your environment"
899 li_ "allow hiding & muting your surroundings while using the menu"
900 li_ "ensure it's easy to see the username of anyone you're interacting with"
901 li_ "add an option to share who you've blocked with others , along with your reasons for each block"
902 li_ "allow blocking discreetly & in bulk"
903 li_ "add a shortcut so you can block faster"
904 h2_ "a more potent kind of block"
905 p_ $ do "my experiences have motivated me to think of an entirely different way to implement blocking ."
906 p_ $ do
907 "suppose you're in "
908 link True (fst theOasisPost) "the oasis"
909 " , & 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 ."
910 p_ "should the message be visible to you ?"
911 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 ."
912 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"; " ."
913 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 ."
914 h3_ "timeline divergence"
915 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 ."
916 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 ."
917 p_ $ do
918 "sophisticated tools for merging timelines à la "
919 a_ [href_ "https://git-scm.com/docs/git-merge"] "git"
920 " could prevent people from losing changes when switching timelines ."
921 h3_ "choosing timelines"
922 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 ."
923
924compulsorySchoolingPost :: Post
925compulsorySchoolingPost = makePost "compulsory schooling is abusive" "2024-10-11"
926 ["youth liberation", "philosophy"] $ do
927 h2_ "even if ..."
928 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 ."
929 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 ."
930 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 ."
931 h2_ "the problem"
932 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 ."
933 p_ $ do
934 "if someone did the same thing to "; b_ "all"; " adults"
935 footnote "not entirely hypothetical ; wage slavery approaches a weaker form of this"
936 " , & 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 ."
937 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 ."
938 h2_ "how to fix it"
939 p_ "my take is fairly straightforward :"
940 ul_ $ do
941 li_ "make educational facilities & resources entirely opt-in"
942 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 !"
943 li_ "actually give children agency over the design of those resources , & give them full control over what they get to learn about"
944 li_ "stop conditioning adult staff to act like fucking cops"
945 li_ "be extremely cautious about creating pressure on children to visit any given educational environment"
946 p_ $ do
947 "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 \""
948 a_ [href_ "https://en.wikipedia.org/wiki/Third_place"] "third places"
949 "\" than are currently available ."
950 hr_ []
951 h2_ "an aside on argumentation for youth liberation"
952 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 ."
953 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 ."
954 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 ."
955 p_ $ do
956 "but what they blatantly omit from their arguments is that compulsory schooling is a problem "
957 em_ "because it's abusive to assert ownership over another person , steal their agency , & gaslight them about their personhood"
958 " ."
959 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 ."
960
961queerCybersecPost :: Post
962queerCybersecPost = makePost "queer cybersecurity resources" "2024-07-07"
963 ["security", "privacy", "queer", "guide"] $ do
964 h2_ "introduction"
965 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 !"
966 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 ."
967 h2_ "privacy & security"
968 "these links are rather general in purpose , so you may need to explore them a bit to find what you are looking for :"
969 ul_ $ do
970 li_ $ a_ [href_ "https://gendersec.tacticaltech.org/wiki/index.php/Complete_manual"] "Zen & the art of making tech work for you - Gender & Tech Resources"
971 li_ $ a_ [href_ "https://ssd.eff.org/"] "Surveillance Self-Defense - Electronic Frontier Foundation"
972 li_ $ a_ [href_ "https://www.privacyguides.org/en/"] "Privacy Guides"
973 h2_ "doxing"
974 p_ "these guides go over restorative & preventative strategies for people affected by doxing :"
975 ul_ $ do
976 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"
977 li_ $ a_ [href_ "https://gendersec.tacticaltech.org/wiki/index.php/Self-dox"] "Self-dox - Gender & Tech Resources"
978 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"
979 h2_ "social media"
980 p_ $ do
981 "i'd strongly advise looking into safer alternatives ( such as well moderated instances on the "
982 a_ [href_ "https://www.fediverse.to/"] "fediverse"
983 " ) , 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 :"
984 p_ $ a_ [href_ "https://righttobe.org/guides/how-to-use-social-media-safely/"] "How To Use Social Media Safely - Right To Be"
985
986inferiPost :: Post
987inferiPost = makePost "inferi monologue" "2024-05-20" ["fiction"] $ do
988 p_ $ do
989 "a headcannon of how "
990 a_ [href_ "https://pottermore.fandom.com/wiki/Inferi"] "inferi"
991 " would greet travelers :"
992 blockquote_ $ do
993 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 ."
994 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 ."
995 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"; " ."
996 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 ."
997 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 ."
998 p_ "stop struggling , [REDACTED] ."
999 p_ $ em_ "we already told you , the waters are cozy ."
1000
1001howIUseComputersPost :: Post
1002howIUseComputersPost = makePost "how i use computers" "2024-08-24"
1003 ["qubesOS", "programming", "haskell", "purescript"] $ do
1004 h2_ "introduction"
1005 p_ $ do
1006 "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 "
1007 link True (fst theOasisPost) "my ideal computing environment"
1008 " ."
1009 todo "explain choices in more detail"
1010 h2_ "hardware"
1011 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 ."
1012 p_ $ do
1013 "my primary computer is a Thinkpad T430 running "
1014 a_ [href_ "https://www.qubes-os.org/"] "QubesOS"
1015 " . i chose this laptop because , out of the options that can be flashed with "
1016 a_ [href_ "https://www.coreboot.org/"] "coreboot"
1017 " , it was old enough to be somewhat affordable"
1018 footnote "around 200 USD on Newegg"
1019 " , while still running fast enough for most tasks that don't involve graphics ( & some that do ) ."
1020 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 ."
1021 p_ $ do
1022 "my \"smart\"phone is a Pixel 4a"
1023 footnote "this was also around 200 USD on eBay"
1024 " running CalyxOS"
1025 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 ."
1026 " ."
1027 h2_ "software"
1028 p_ $ do
1029 "i primarily use CalyxOS for taking notes with "
1030 a_ [href_ "https://f-droid.org/packages/com.orgzly/"] "Orgzly"
1031 " , tracking sleep with "
1032 a_ [href_ "https://f-droid.org/packages/hu.vmiklos.plees_tracker/"] "Plees Tracker"
1033 " , web browsing away from home , insecure communications , & listening to audio-based educational materials ."
1034 p_ "i use QubesOS for web browsing , programming , Serious Writing , & other forms of expression ."
1035 p_ $ do
1036 "i chose QubesOS because i find "
1037 a_ [href_ "https://en.wikipedia.org/wiki/Ambient_authority"] "ambient authority"
1038 " horrifying , but i'm not aware of any robust "
1039 a_ [href_ "https://en.wikipedia.org/wiki/Capability-based_security"] "capability-based"
1040 " operating systems that would fill the same need for me ."
1041 p_ $ do
1042 "QubesOS is slow & "
1043 a_ [href_ "https://github.com/QubesOS/qubes-issues/issues/5907"] "doesn't have screen reader support"
1044 " yet , but it does have some great features like configuration using "
1045 a_ [href_ "https://www.qubes-os.org/doc/salt/"] "Salt"
1046 footnote $ do
1047 "ior maybe even Nix-like configuration in the future if "
1048 a_ [href_ "https://spectrum-os.org/"] "Spectrum"
1049 " goes well"
1050 ", Whonix qubes , & offline qubes . here are a few things i've learned that make it more tolerable :"
1051 ul_ $ do
1052 li_ $ do
1053 "install "
1054 a_ [href_ "https://i3wm.org/"] "i3"
1055 ul_ $ do
1056 li_ $ do
1057 "name qubes using two-character strings so they can be searched for more quickly using "
1058 a_ [href_ "https://wiki.archlinux.org/title/Dmenu"] "dmenu"
1059 li_ "make shortcuts for locking the screen & toggling the status bar"
1060 li_ $ do "make a shortcut ( mine is bound to "; kbd_ "Alt"; " + ";kbd_ "i"; " ) for opening a dmenu list of helper scripts & frequently opened programs"
1061 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"
1062 li_ $ do
1063 "dark mode can be enabled in "
1064 a_ [href_ "https://xfce.org/"] "XFCE"
1065 " qubes by "
1066 inlineCode "qvm-run"
1067 "ing the following command in each of them :"
1068 code "bash" "xfconf-query -c xsettings -p /Net/ThemeName -s 'Adwaita-dark'"
1069 li_ $ do
1070 "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 "
1071 a_ [href_ "https://www.borgbackup.org/"] "BorgBackup"
1072 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"
1073 li_ $ do
1074 a_ [href_ "https://wiki.archlinux.org/title/Rofi"] "rofi"
1075 " can be opened inside a qube using "
1076 inlineCode "qvm-run"
1077 " in dom0 scripts , but the rofi flag "
1078 inlineCode "-normal-window"
1079 " must be added to disable "
1080 inlineCode "override_redirect"
1081 " , which allows the program window to appear undecorated & on top in "
1082 a_ [href_ "https://en.wikipedia.org/wiki/X_Window_System"] "X11"
1083 h2_ "programming"
1084 h3_ "language"
1085 p_ $ do
1086 "currently , the languages i find most useful are "
1087 a_ [href_ "https://www.haskell.org/"] "Haskell"
1088 " & "
1089 a_ [href_ "https://www.purescript.org/"] "PureScript"
1090 " ( which is very similar to Haskell , but compiles to JavaScript ) ."
1091 p_ "a few things i like about them are :"
1092 ul_ $ do
1093 li_ "very clean syntax"
1094 li_ $ a_ [href_ "https://en.wikipedia.org/wiki/Pure_function"] "functional purity"
1095 li_ $ a_ [href_ "https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system"] "Hindley-Milner type system"
1096 li_ $ a_ [href_ "https://en.wikipedia.org/wiki/Type_class"] "typeclasses"
1097 li_ $ do
1098 a_ [href_ "https://hoogle.haskell.org/"] "Hoogle"
1099 "/"
1100 a_ [href_ "https://pursuit.purescript.org/"] "Pursuit"
1101 li_ $ do
1102 a_ [href_ "https://github.com/ndmitchell/ghcid"] "ghcid"
1103 "/"
1104 a_ [href_ "https://github.com/kRITZCREEK/pscid"] "pscid"
1105 li_ "high abstraction power"
1106 li_ $ do
1107 "automatically "
1108 a_ [href_ "https://en.wikipedia.org/wiki/Currying"] "curried"
1109 " functions"
1110 li_ $ a_ [href_ "https://en.wikipedia.org/wiki/Lazy_evaluation"] "lazy evaluation"
1111 li_ $ do
1112 a_ [href_ "https://en.wikipedia.org/wiki/Row_polymorphism"] "row polymorphism"
1113 " ( PureScript only )"
1114 li_ $ do
1115 "wonderful libraries like "
1116 a_ [href_ "https://github.com/ajnsit/concur"] "Concur"
1117 " , "
1118 a_ [href_ "https://hackage.haskell.org/package/optics"] "optics"
1119 " & "
1120 a_ [href_ "https://hackage.haskell.org/package/apecs"] "apecs"
1121 p_ $ do
1122 "i'm autistic & get overwhelmed by extraneous detail "; em_ "very"; " easily , so i view many of these as accessibility features"
1123 footnote "however , i have heard that for some people , these languages are unpleasant to work with for the some of the same reasons ."
1124 " , 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 ."
1125 p_ $ do
1126 "for native programs that target embedded devices ior need to be "
1127 a_ [href_ "https://en.wikipedia.org/wiki/Static_build"] "statically built"
1128 " ior "
1129 a_ [href_ "https://en.wikipedia.org/wiki/Cross_compiler"] "cross compiled"
1130 " , "
1131 a_ [href_ "https://www.rust-lang.org/"] "Rust"
1132 " is a nice language that provides a somewhat similar experience to Haskell , while making those tasks much easier ."
1133 p_ $ do
1134 "i've experimented a lot with "
1135 a_ [href_ "https://nixos.org/"] "Nix"
1136 " 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"
1137 footnote $ do
1138 "i've seen many folks point out that the "
1139 a_ [href_ "https://discourse.nixos.org/"] "Nix forum"
1140 " & 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 "
1141 a_ [href_ "https://en.wikipedia.org/wiki/Anduril_Industries"] "Anduril"
1142 " ."
1143 " . i've definitely benefited from Nix before , but those benefits have only barely outweighed the many negatives i've experienced along the way . maybe "
1144 a_ [href_ "https://lix.systems/"] "Lix"
1145 " & "
1146 a_ [href_ "https://auxolotl.org/en/"] "Aux"
1147 " will manage to solve some of those issues ."
1148 h3_ "code editor"
1149 p_ $ do
1150 "the code editor i use most often is "
1151 a_ [href_ "https://helix-editor.com/"] "helix"; " ."
1152 p_ $ do
1153 "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"
1154 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 ."
1155 " . once i was proficient with vim , i moved on to "
1156 a_ [href_ "https://github.com/doomemacs/doomemacs"] "Doom Emacs"
1157 " ."
1158 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 ."
1159 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 ."
1160
1161unlicensePost :: Post
1162unlicensePost = makePost "why i use the Unlicense & CC0" "2024-07-21"
1163 ["anticopyright", "philosophy"] $ do
1164 h2_ "introduction"
1165 p_ $ do
1166 "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"
1167 footnote "it's also not a comprehensive argument , as there are quite a few reasons i dislike \"intellectual property\" that aren't mentioned here ."
1168 " ."
1169 h2_ "\"intellectual property\" relies on death"
1170 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\" ."
1171 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 ."
1172 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 ?"
1173 h2_ "copyleft & copyfarleft"
1174 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 ."
1175 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 ?"
1176 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 ."
1177 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 ."
1178 h2_ "even copyleft causes psychic damage"
1179 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 ."
1180 p_ $ do
1181 "anecdotally , trying to make sense of the rules for using copyleft software"
1182 footnote "which is an instance of trying to navigate the legal system"
1183 " 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 ."
1184 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 ."
1185 h2_ "releasing work into the public domain"
1186 p_ $ do
1187 "regarding anticopyright praxis , my current preference is to use the "
1188 a_ [href_ "https://unlicense.org/"] "Unlicense"
1189 " for code , & "
1190 a_ [href_ "https://creativecommons.org/public-domain/cc0/"] "CC0"
1191 " for everything else ."
1192 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\" ."
1193
1194veganTipsPost :: Post
1195veganTipsPost = makePost "a few vegan tips" "2024-07-03"
1196 ["vegan", "guide"] $ do
1197 h2_ "introduction"
1198 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 ."
1199 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 ."
1200 h2_ "the tips"
1201 ul_ $ do
1202 li_ "be careful with stickers & sticky things . bugs can become trapped on them easily"
1203 li_ $ do "be "; em_ "very"; " distrustful of unfamiliar non-vegans’ assessments of whether things are vegan eor not"
1204 li_ $ do
1205 "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"
1206 footnote "i almost never see bugs trapped in the tub anymore after doing this"
1207 li_ $ do
1208 "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 . "
1209 todo "link to a detailed guide"
1210 li_ "don’t assume that random household items like toilet paper are vegan by default"
1211 li_ $ do
1212 "fireworks are "
1213 a_ [href_ "https://www.animal-ethics.org/how-fireworks-harm-nonhuman-animals/"] "harmful ior deadly"
1214 " to many living things"
1215 li_ "avoid unnecessary loud noises that could distress nearby animals . some music may be an exception , though , if it's not too loud"
1216 li_ "don’t walk when the ground is unlit to avoid crushing bugs"
1217 li_ $ do "reduce ior eliminate reliance on car travel for "; em_ "many"; " reasons"
1218 li_ "recreational fires often burn insects alive & wood smoke can be harmful to animals"
1219 li_ "avoid planting poisonous plants where wild animals might eat them"
1220 h2_ "related writing"
1221 p_ $ do
1222 "if one's interested in more practical advice of this nature , i can recommend the writings of a researcher named "
1223 a_ [href_ "https://briantomasik.com/"] "Brian Tomasik"
1224 " . 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 ."
1225
1226wallOfShardsPost :: Post
1227wallOfShardsPost = makePost "wall of shards" "2024-05-10"
1228 ["fiction"] $ do
1229 h2_ "loading world ..."
1230 p_ $ do
1231 "type "; inlineCode "start"
1232 " to collect a shard ."
1233 code "haskell" "start"
1234 p_ $ em_ "shard count : 2"
1235 h2_ "your lab"
1236 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 ."
1237 code "haskell" "talkTo b6e"
1238 p_ "you break the silence ."
1239 blockquote_ "are you ready to get started ?"
1240 blockquote_ "yeah . what will it feel like , exactly ? like will i even notice you're there ?"
1241 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 ."
1242 blockquote_ "too bad i can't take a nap during it ."
1243 blockquote_ "i know right . well , if you're ready then have a seat & i'll start projecting ."
1244 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 ."
1245 code "haskell" "use Terminal"
1246 p_ $ do
1247 "you swivel over to your terminal & execute "
1248 inlineCode "1ntr0j3ct.hs"; " ."
1249 blockquote_ "you named the script using leetspeak ?"
1250 blockquote_ "yep , it makes words taste better ."
1251 p_ "you get up & lie down on your yoga mat . your vision starts to fade ..."
1252 h2_ "the center"
1253 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 ."
1254 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 ?"
1255 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 ."
1256 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 ."
1257 code "haskell" "go West"
1258 p_ "there is a cliff face to the west . you hover up to the top edge ."
1259 h2_ "eastern plateau ridge"
1260 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 ?"
1261 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 ."
1262 p_ "there's a rectangular slot in the ground close by , but you can't see what's in it from here ."
1263 code "haskell" "examine Slot"
1264 h2_ "slot machine"
1265 p_ "now that you're closer to the slot , you notice a hand-written sign next to it that says :"
1266 blockquote_ "slot machine : enter the slot & slide like a coin to a random location"
1267 p_ "somebody walks over to you & asks what you're doing ."
1268 blockquote_ "hello ! i'm trying to figure out what the deal with this slot thing is ."
1269 blockquote_ "no you're not . i saw you over there trying to vandalize my hand-written sign ."
1270 blockquote_ "you what ? i didn't even touch the sign ."
1271 blockquote_ "then how did all of those purple stains get on it ?"
1272 p_ "you glance at the sign again . it does appear more stained than you remember it . you wonder , aloud :"
1273 blockquote_ "maybe it's from that pool over there ? whatever gravity well is swirling above the pool might have become volatile ."
1274 blockquote_ "that's certainly a possiblity . but it seems much more likely that you hated my handwriting style & wanted to destroy it yourself ."
1275 blockquote_ "you serious ? i didn't even think of the handwriting style until now. it was perfectly serviceable ."
1276 blockquote_ "oh ."
1277 p_ "they gaze into the distance uncomfortably ."
1278 p_ "the grinding sound grows louder , & the crimson glow brighter ."
1279 p_ $ em_ "shard count : 3"
1280 code "haskell" "ask SignPainter . about Sound"
1281 p_ "you ask the sign painter if they know where that sound is coming from ."
1282 blockquote_ "no ."
1283 code "haskell" "ask SignPainter . about CrimsonGlow"
1284 p_ "you ask them if they know what the crimson glow is coming from ."
1285 blockquote_ "no ."
1286 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 ."
1287 p_ "it starts to rain . the droplets are purple , & stains your grey dress ."
1288 code "haskell" "go East"
1289 p_ "you hover back down the cliff face & land on the boardwalk again ."
1290 h2_ "the center"
1291 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 ."
1292 code "haskell" "go West"
1293 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 ."
1294 p_ "but no . that would be a gamble ."
1295 p_ "you don't like leaving things to chance ."
1296 code "haskell" "go North"
1297 p_ "with your mind made up , you hover northward along the boardwalk ."
1298 h2_ "an expanse"
1299 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 ."
1300 p_ "there is a swarm of winged , metal centipedes flying over your head ."
1301 p_ "the grinding sound is loud enough here to put you on edge ."
1302 p_ $ em_ "shard count : 4"
1303 code "haskell" "ask Centipede . about Sound"
1304 p_ "you call out to the centipedes above you ."
1305 blockquote_ "excuse me , would any of you be able to help me answer a quick question ?"
1306 p_ "one of them lands in front of you . they are wearing a really cool sweater with a fractal pattern knitted onto it ."
1307 blockquote_ "i might be able to help ya ! what's ur question ?"
1308 blockquote_ "oh nice ! thank you . do you know what that glass grinding noise in the distance is ?"
1309 blockquote_ "ya mean death ?"
1310 blockquote_ "what ?"
1311 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 !"
1312 p_ "the other centipedes start gliding to the southeast ."
1313 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 ?"
1314 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 ."
1315 blockquote_ "ok , well thanks for the info . i'll keep searching then ."
1316 blockquote_ "be careful ."
1317 p_ "they fly away ."
1318 code "haskell" "save"
1319 p_ $ em_ "serializing timeline ..."
1320 p_ $ em_ "game saved ."
1321 p_ $ em_ $ do
1322 "enter the code "
1323 inlineCode "5nJ0kL3-001"
1324 " to restore the game to this point in time ."
1325 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"