<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title>novov blog</title>
	<link href="https://novov.me/blog/feed.xml" rel="self" />
	<link href="https://novov.me" />
	<updated>2026-02-11T00:00:00+12:00</updated>
	<id>https://novov.me/blog</id>
	<entry>
		<title>Review: Portal: Revolution</title>
		<link href="https://novov.me/blog/posts/portalrevolutionreview" />
		<id>https://novov.me/blog/posts/portalrevolutionreview</id>
		<updated>2026-02-11T00:00:00+12:00</updated>
		<summary>A worthwhile effort, but not really Portal 3.</summary>
		<content type="html">
			&lt;figure class=&#34;&#34;&gt;
			&lt;img alt=&#34;&#34; src=&#34;/images/blog/content/revo.jpg&#34;/&gt;
			&lt;figcaption&gt;This picture certainly looks very pretty, and is a nice refresher from the environs of &lt;em&gt;Portal 2&lt;/em&gt;. From a narrative perspective, it has some flaws though: the idea of Aperture Science&#39;s laboratories being exposed to the elements in such a blatant way seems a bit implausible. 
&lt;/figcaption&gt;
		&lt;/figure&gt;
&lt;p&gt;Unlike many games, the archetypal mod for a Valve game is a full-fledged separate campaign, which is often listed on its own on Steam. Famously, popular Valve titles such as &lt;em&gt;Team Fortress&lt;/em&gt; and &lt;em&gt;Counter-Strike&lt;/em&gt; were initially conceived as mods for &lt;em&gt;Half-Life&lt;/em&gt;. Throughout the late 1990s and 2000s, there was a boom of mods for Valve&#39;s games, but due to the higher barrier to entry presented by modern game development,&lt;sup class=&#34;ref&#34; id=&#34;ref1&#34;&gt;&lt;a href=&#34;#fn1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; and a diminishing amount of support provided by Valve, this trend had largely abated by the release of &lt;em&gt;Portal 2&lt;/em&gt;. &lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;1&#34;&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;p&gt;Even though Valve&#39;s Hammer editor (with a lineage stretching all the way back to &lt;em&gt;Quake&lt;/em&gt;) is still based around the &#34;old way&#34; of doing things in many respects, the additional graphical detail still makes development harder.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Nevertheless, a few major&lt;sup class=&#34;ref&#34; id=&#34;ref2&#34;&gt;&lt;a href=&#34;#fn2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; mods were still released, which I will now go through in a blatant attempt to expound about something I am interested in even though it does not directly fall under the ostensible purpose of the post. To be fair, I will be comparing these (well, mainly &lt;em&gt;Mel&lt;/em&gt;) to &lt;em&gt;Portal: Revolution&lt;/em&gt; a number of times, so it still serves a purpose.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;2&#34;&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;p&gt;&#34;Major&#34; being defined as receiving some news coverage by gaming sites and being listed on Steam as a standalone title, at the time of &lt;em&gt;Revolution&lt;/em&gt;&#39;s release.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;ul class=&#34;wideList&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Thinking With Time Machine&lt;/em&gt;&lt;/strong&gt; was the first and probably the worst &lt;em&gt;Portal 2&lt;/em&gt; mod. It has an interesting &#34;time travel&#34; mechanic, based around recording one&#39;s past actions and replaying them using an iPad-esque device. Its execution is widely considered mediocre though. The hallmark mechanic quickly becomes confusing, the story has a hokey setup that doesn&#39;t deserve a mention, and while it sports an interesting futuristic aesthetic (well, more futuristic than &lt;em&gt;Portal&lt;/em&gt; already is) it for some reason decides to abandon the series convention of using white to indicate a portalable surface, with disastrous results for gameplay intelligibility.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Aperture Tag&lt;/em&gt;&lt;/strong&gt; had a really interesting idea, namely, replacing the famous portal gun with a gun that shoots the orange and blue gels introduced in &lt;em&gt;Portal 2&lt;/em&gt;. Controversially, it was not made available for free, as is considered customary for a &lt;em&gt;Portal&lt;/em&gt; mod. While the titular mechanic is fun and the gameplay decent enough, the graphics and level design lacks a certain polish,&lt;sup class=&#34;ref&#34; id=&#34;ref3&#34;&gt;&lt;a href=&#34;#fn3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; and the story is nothing to write home about either.&lt;/p&gt;
&lt;/li&gt;
&lt;li class=&#34;asideContainer&#34; role=&#34;generic&#34;&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;3&#34;&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;p&gt;Probably a bit more annoying for a &lt;em&gt;Portal 2&lt;/em&gt; lore aficionado like me, who considers the lack of an adequate transition between Old and New Aperture to be an important omission.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Portal Stories: Mel&lt;/em&gt;&lt;/strong&gt; quickly assumed a role as the archetypal &lt;em&gt;Portal 2&lt;/em&gt; mod after its release, one that in my opinion is well-deserved. &lt;em&gt;Mel&lt;/em&gt; fans have created &lt;a href=&#34;https://www.tumblr.com/tagged/Portal%20Stories%3A%20Mel&#34;&gt;fanart&lt;/a&gt; and even &lt;a href=&#34;https://www.reddit.com/r/Portal/comments/igcpt7/i_made_the_portal_stories_mel_portal_gun_as_you/&#34;&gt;actual portal guns&lt;/a&gt;, which I can&#39;t ever see happening for &lt;em&gt;TWTM&lt;/em&gt;. It has a level of polish and execution not seen in its forebears, with many new fancy graphical assets and visually stunning and extremely polished environments. Apart from its set-piece moments, visually many of its levels are equivalent quality-wise to those in &lt;em&gt;Portal 2&lt;/em&gt;, only with a greater abundance of graphical props and more advanced lighting effects.&lt;sup class=&#34;ref&#34; id=&#34;ref4&#34;&gt;&lt;a href=&#34;#fn4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; Although its soundtrack is by the same composer as &lt;em&gt;Tag&lt;/em&gt;&#39;s, it is more compelling. &lt;/p&gt;
&lt;p&gt;The Achilles heel of &lt;em&gt;Mel&lt;/em&gt; is its infamously hard puzzle design: the community members that made it were experienced in solving test chambers, and failed to adequately create a difficulty curve. Although I find them fun, I don&#39;t consider them well-balanced; it doesn&#39;t help that much of the difficulty is based on cheap cube-swapping conundrums. To the team&#39;s credit, they later added easier versions, but when playing through these it is very easy to notice that they are post-facto revisions. &lt;/p&gt;
&lt;p&gt;Unlike its precedents, the story has all the finesse one would expect of a professional game, even if the writing isn&#39;t quite Valve-level. Virgil is an adequate companion with good voice acting, but he lacks the humour or unique personality of GLaDOS or Wheatley. Conversely, AEGIS is a unique antagonist that compellingly introduces a more mechanical and less &#34;quirky funny robot&#34; character into the &lt;em&gt;Portal&lt;/em&gt; universe.&lt;/p&gt;
&lt;/li&gt;
&lt;li class=&#34;asideContainer&#34; role=&#34;generic&#34;&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;4&#34;&gt;&lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;p&gt;To put it another way, if this were &lt;em&gt;Portal 3&lt;/em&gt; this would be percieved as an insipid retread, but in this case it is a testament to the team&#39;s skill.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Portal Reloaded&lt;/em&gt;&lt;/strong&gt; is another take on the concept of time travel, to more interesting effect than &lt;em&gt;TWTM&lt;/em&gt;. Instead of recording one&#39;s actions, one uses a third portal to swap between a version of the test chamber in the past and one in the future. At first, the mechanic is a bit unintuitive, but once you adjust, it creates some entertainingly mind-bending puzzles. While they perhaps are not much easier than &lt;em&gt;Mel&lt;/em&gt; they feel a lot fairer and more memorable. &lt;/p&gt;
&lt;p&gt;While &lt;em&gt;Reloaded&lt;/em&gt;&#39;s visuals aren&#39;t up to the standard of &lt;em&gt;Mel&lt;/em&gt;, they get the job done. Overall it is a bit of a smaller scale mod, which intentionally doesn&#39;t have many story elements beyond the test chambers. Its limited scope means it feels almost like a level pack in mod form, but ironically its core mechanic probably possesses the most potential for a &lt;em&gt;Portal 3&lt;/em&gt; if Valve somehow hypothetically finds a way to make the learning curve easier.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After a lengthy development period, &lt;em&gt;Portal: Revolution&lt;/em&gt; joined these mods at the start of 2024. It was created by Austrian Stefan Heinz and a small team of developers, who laboured away at it for a number of years. Unsurprisingly, some fans have hyped it up, comparing it to a potential &lt;em&gt;Portal 3&lt;/em&gt;, and it does indeed possess polish on the level of &lt;em&gt;Mel&lt;/em&gt;. With these grand claims in mind, I took it upon myself to play it... when it released, and then write an article about it a few years later for some reason.&lt;/p&gt;
&lt;hr /&gt;
&lt;figure class=&#34;sideCaption small&#34;&gt;
			&lt;img alt=&#34;&#34; src=&#34;/images/blog/content/revo2.jpg&#34;/&gt;
			&lt;figcaption&gt;The environment design and additional graphical effects work in tandem to produce great results.
&lt;/figcaption&gt;
		&lt;/figure&gt;
&lt;p&gt;Visually, &lt;em&gt;Revolution&lt;/em&gt; is stunning. It introduces higher resolution textures, which are by-and-large suitable replacements for the originals. Large portions of the environment are exposed to the outside world in a way &lt;em&gt;Portal 2&lt;/em&gt; is not, utilising cascaded shadow maps for realistic outdoors illumination. Foliage is now slightly reflective, and volumetric lighting is used in select places to create convincing rays of light. Some assets are replaced with higher-resolution replicas, which are by and large suitable replacements. A number of other subtle improvements are made, aided by an upgrade from DirectX 9 to 11 and OpenGL to Vulkan. &lt;/p&gt;
&lt;p&gt;This is not just the result of improved technology, but also impeccable map design, with stunning vistas, overgrown ruins teeming with a wide variety of fauna, and the technological labyrinths one expects from Aperture Science. Unlike &lt;em&gt;Mel&lt;/em&gt;, it does introduce a few new visual themes: an &#34;under construction&#34; transitory style between Old and New Apertures, and proper test chambers in behind-the-scenes areas.&lt;sup class=&#34;ref&#34; id=&#34;ref5&#34;&gt;&lt;a href=&#34;#fn5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; While these help keep things fresh and add to the feeling that you&#39;ve doing something new and cool and interesting within Aperture (in a way &lt;em&gt;Mel&lt;/em&gt;&#39;s charming-but-rather-unsurprising environments sometimes don&#39;t) they&#39;ve not a total shift like Old Aperture in &lt;em&gt;Portal 2&lt;/em&gt;. One of the high points is &lt;span class=&#34;spoiler&#34;&gt;&lt;svg alt=&#34;&#34; class=&#34;icon&#34;&gt;&lt;use xlink:href=&#34;/images/icons/closed.svg#body&#34;&gt;&lt;/use&gt;&lt;/svg&gt;the Spire&lt;/span&gt;, whose sterile nature thematically fits as a contrast to the dilapidated landscape around it. Throughout the game, the outdoors chambers progress from daylight, then sunset, and finally the nighttime, which is executed nicely to create an effect of progression.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;5&#34;&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;p&gt;Although these are visually attractive, the actual convincingness from a lore perspective is questionable at times. I&#39;ll excuse it though.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Unlike &lt;em&gt;Mel&lt;/em&gt;, which boasts a wide array of set pieces, including the spiderlike AEGIS, an underground train introduction, and a panoply of explosions, &lt;em&gt;Revolution&lt;/em&gt; is more restrained. Cores often lurk behind panels, with their animatics being minimal when they appear, and the amount of custom models is on the lower side. It basically attempts to have the minimum amount of set pieces one can while still feeling like a full-fledged campaign and not a &lt;em&gt;Reloaded&lt;/em&gt;-esque affair. This is an admitted decision to save developer time: &lt;em&gt;Revolution&lt;/em&gt; was pushed out on a very strict deadline. To their credit, it is an often successful one, at times being unnoticeable, and during the latter portions of the game it fits nicely with the game&#39;s themes. Still, it can occasionally rob the world of a certain &lt;em&gt;joie de vivre&lt;/em&gt; and soul.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;Portal Revolution&lt;/em&gt;&#39;s story is probably its weakest link, but can be still compelling and interesting. The dialogue is decent enough and largely carries the mod forwards, with some funny moments, even if it doesn&#39;t come close to reaching &lt;em&gt;Portal 2&lt;/em&gt; (not that such a thing would realistically be achievable for a small team), and the premise is a bit generic at first and takes a while to come into its own. This ends up being a disappointment compared to its more unique forbears: in &lt;em&gt;Mel&lt;/em&gt;, the protagonist begins in the 50s, and is shunted into the future after a scientific fuckup, but in &lt;em&gt;Revolution&lt;/em&gt;, they just wake up and do some tests. &lt;/p&gt;
&lt;p&gt;In general, portions of the early game can come off as a bit uninspired at times; just like in &lt;em&gt;Portal 2&lt;/em&gt;, there are surprise test chambers where you are flung into the behind-the-scenes areas, and jokes are often retreads of Valve&#39;s material. Some find the introductory core character, Stirling, to be grating at first, and I can see why, but there is more to the writing than him; as the game progresses, some interesting concepts and unique thematic elements are explored.  Ultimately though, the story is still very much a flawed product; to explain its pros and cons in more depth, I&#39;ll have to do some comparison with &lt;em&gt;Portal 2&lt;/em&gt; and &lt;em&gt;Mel&lt;/em&gt;, and unfortunately delve into lots of spoilers. &lt;/p&gt;
&lt;details class=&#34;blockspoiler&#34;&gt;
&lt;summary&gt;&lt;svg alt=&#34;&#34; class=&#34;icon closed&#34;&gt;&lt;use xlink:href=&#34;/images/icons/closed.svg#body&#34;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;svg alt=&#34;&#34; class=&#34;icon open&#34;&gt;&lt;use xlink:href=&#34;/images/icons/open.svg#body&#34;&gt;&lt;/use&gt;&lt;/svg&gt;Lengthy expounding about &lt;em&gt;Portal: Revolution&lt;/em&gt;&#39;s plot, including many spoilers&lt;/summary&gt;
&lt;p&gt;Around 25 percent of the way through the game, the player just randomly falls down a lift. In the developer commentary, this is explained as a way to communicate the difficulty of the journey and break things up, but in game it feels insufficiently justified. The same feeling permeates the game&#39;s first half. At its worst, in &lt;em&gt;Revolution&lt;/em&gt;-land, stuff just kinda happens because the writer dictates it. &lt;/p&gt;
&lt;p&gt;Although the player has the stated goal of reaching the Spire (with a very beautiful visual setpiece), the actual journey there sometimes feels a bit like a tour through (admittedly very pretty) environments and (admittedly very fun) puzzles with the ultimate objective being a very thin pretext. In &lt;em&gt;Portal 1&lt;/em&gt;, the clean manicured chambers slowly become more disturbing as you realise what is going on. In &lt;em&gt;Portal 2&lt;/em&gt;, the chambers start off dilapidated with Aperture abandoned for eons, but then GLaDOS fixes them and Wheatley smashes them together. To a lesser degree, &lt;em&gt;Mel&lt;/em&gt; suffers from the same flaw, but even there you try to go through the shrubbery to avoid AEGIS, and the goo is rising beneath you all the time, adding pressure and momentum to the narrative. In &lt;em&gt;Revolution&lt;/em&gt;, it can sometimes feel like the locations are arbitrary and not influenced by player action or the wider plot.&lt;/p&gt;
&lt;p&gt;This lack of depth also extends to the characterisation. Stirling is charming at times, but he doesn&#39;t have the same magnetism or connection to the world around him as his cohorts. His dialogue sells the fact that he sees Aperture as a workspace quite well, but we often don&#39;t get a sense of him being a cleaning robot; there&#39;s space to incorporate this idea into the dialogue more without being excessive. Fortunately, in the second half of the game, things start to show promise of becoming more meaningful. The player reaches the Spire, which has a unique environment and adds interesting elements to Aperture&#39;s lore. Then they unfold into an abandoned expanse, which feels more desolate than any in &lt;em&gt;Portal 2&lt;/em&gt;. Exploring these ruins leads to Conly, who has a great personality and superb voice acting by Sarah Jacklin.&lt;sup class=&#34;ref&#34; id=&#34;ref6&#34;&gt;&lt;a href=&#34;#fn6&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; As the player ferries Conly back up to the Enrichment Centre&#39;s upper reaches, one gets enveloped in dread and loss, as there is a neat tonal shift to darker and more depressing environs.&lt;sup class=&#34;ref&#34; id=&#34;ref7&#34;&gt;&lt;a href=&#34;#fn7&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; &lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;6&#34;&gt;&lt;span class=&#34;number&#34;&gt;6&lt;/span&gt;&lt;p&gt;Why she hasn&#39;t got heaps of roles is beyond me. Though perhaps I&#39;m just biased towards my Antipodean cohorts.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;7&#34;&gt;&lt;span class=&#34;number&#34;&gt;7&lt;/span&gt;&lt;p&gt;Though the interspersion of test chambers and behind-the-scenes sections seems rather contrived at times.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;But this quality progression is abruptly broken by Stirling&#39;s heel turn, which is not really sufficiently explained or justified. It may make sense in line with his ultimate motivations, but the game doesn&#39;t really sell that fact, and it really forgets to make him into much of a compelling villain at all. Going back to the point I made outside this big spoiler disclosure thingamajig, it also feels like he isn&#39;t sufficiently distinct from Wheatley in &lt;em&gt;Portal 2&lt;/em&gt;. The funniest villain line he has, where the player character is standing on a precipice and he suggests various ways of getting rid of her... well, Wheatley does the same thing in &lt;em&gt;Portal 2&lt;/em&gt;, though the creativity of the new scenarios keeps things entertaining at least. The least funny line he has, where he makes a kinda problematic jab about brain damage, is &lt;em&gt;also&lt;/em&gt; a retread of &lt;em&gt;Portal 2&lt;/em&gt;, but that game is at least capable of getting away with it due to vastly superior writing.&lt;sup class=&#34;ref&#34; id=&#34;ref8&#34;&gt;&lt;a href=&#34;#fn8&#34;&gt;8&lt;/a&gt;&lt;/sup&gt; Even his plot arc, where he is your eager helper and guide, then loses you in an dilapidated and revelation-laden underground area, betrays you at the ninth hour when you re-emerge, and finally is very insecure towards both you and his superior... is pretty much the same as &lt;em&gt;Portal 2&lt;/em&gt;. Though Heinz claims the last one was unintentional, and I don&#39;t think he&#39;s lying, a lack of intentionality doesn&#39;t make the player not feel like they&#39;ve done it all before. It is really a testament to other aspects of the mod that these flaws don&#39;t totally ruin the whole enchilada.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;8&#34;&gt;&lt;span class=&#34;number&#34;&gt;8&lt;/span&gt;&lt;p&gt;&lt;s&gt;I&#39;ve had a concussion once, I can give GLaDOS a pass.&lt;/s&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;The most controversial part of &lt;em&gt;Revolution&lt;/em&gt; is the ending. Personally, I&#39;m in the boat that doesn&#39;t &lt;em&gt;hate&lt;/em&gt; the concept. The actual execution, however, leaves something to be desired. Firstly, in part due to the aforementioned deadlines that Heinz and his team set for themselves, it is very sudden; one is punted out of the final test chamber into the boss fight with barely any buildup. By contrast, &lt;em&gt;Portal 2&lt;/em&gt; has you trying to run away from Wheatley while he cack-handedly attempts to kill you to often amusing effect, and in &lt;em&gt;Mel&lt;/em&gt; you run around under AEGIS&#39;s nose disabling all its security measures. &lt;/p&gt;
&lt;p&gt;The other issue is how the ending is contextualised as part of the narrative arc as a whole. Whilst I&#39;m not a stickler for everyone-hugs-each-other-and-the-universe-is-saved affairs, the way this particular ending is implemented means that it doesn&#39;t feel like a rewarding conclusion. To pull off an ambivalent-to-bad ending without it feeling like a slap in the face, the story needs to lead up to in a natural way to prevent it feeling jarring; while some of the more depressing vibes during Conly&#39;s ascent do pull things in the right emotional direction, they are ultimately insufficient. While I appreciate Stefan&#39;s goal of trying something tonally different, I can&#39;t really say he succeeds at it.&lt;/p&gt;
&lt;/details&gt;
&lt;hr /&gt;
&lt;p&gt;Conversely, &lt;em&gt;Revolution&lt;/em&gt;&#39;s puzzles are probably the strongest part of the game. Extant mechanics, such as hard light bridges, cubes, and tractor beams, used in ingenious ways. Unlike &lt;em&gt;Mel&lt;/em&gt;, the puzzles also form a coherent difficulty curve, where introductory chambers introduce or re-acquaint players with a mechanic, and then later expand upon things and combine them for more difficult results. If anything, they are too easy, but apart from a few outliers, solving them rarely feels unsatisfying.&lt;/p&gt;
&lt;p&gt;The most interesting puzzles in the mod involve the new mechanics, which are creative and entertaining. After playing &lt;em&gt;Portal 2&lt;/em&gt; I struggled to see what additions Valve could make in a future entry, but these could be used to great effect. There are tubes that suck objects from one portion of a test chamber to another, power switches that can enable and disable both hindrances and helpful elements, and paired cubes that act as laser portals, with one end of a laser entering one cube and issuing from the other. They bring diverse possibilities, and appropriately the chambers use them in a variety of ways. But they are ultimately are somewhat under-utilised: for instance, and I am far from the only person to make this critique, the cubes only make a short appearance in the last ten or so chambers.&lt;sup class=&#34;ref&#34; id=&#34;ref9&#34;&gt;&lt;a href=&#34;#fn9&#34;&gt;9&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;9&#34;&gt;&lt;span class=&#34;number&#34;&gt;9&lt;/span&gt;&lt;p&gt;To be fair, a similar critique could be made about the gels in &lt;em&gt;Portal 2&lt;/em&gt;, though to a lesser extent.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;hr /&gt;
&lt;p&gt;Compared to &lt;em&gt;Mel&lt;/em&gt;, &lt;em&gt;Reloaded&lt;/em&gt;, and &lt;em&gt;Portal 2&lt;/em&gt;, &lt;em&gt;Revolution&lt;/em&gt;&#39;s music is sparser, sharing some similarity with the sounds of the first &lt;em&gt;Portal&lt;/em&gt; game. Quite often, diegetic sound effects take the centre stage instead of the instruments, and tracks often feel like they&#39;ve just composed of one synth and not much else.  It&#39;s a nice touch, and there are some neat moments where a swell of music seamlessly phases in at just the right time. Unlike &lt;em&gt;Mel&lt;/em&gt; and like &lt;em&gt;Portal 2&lt;/em&gt;, many of these tracks within test chambers are dynamic as well: when you kill a turret or make a fling, the music reacts to you progressing in the test. These two changes mean that compared to &lt;em&gt;Mel&lt;/em&gt;, the aural environment of the mod feels more reactive and less constant.  &lt;em&gt;Mel&lt;/em&gt;&#39;s music is nice to listen to outside of the game, but can feel a bit repetitive in test chambers; I have no such qualms with Revolution.&lt;/p&gt;
&lt;p&gt;However, sometimes this music is &lt;em&gt;too&lt;/em&gt; sparse. The tracks&#39; simplicity comes off as fine-tuned minimalism in many places, but a few are left wanting for more aural complexity. Especially outside of tests, the game can stretch into overlong periods of silence, with some areas lacking any music at all (again, this is a consequence of the mod&#39;s expeditious release). While not every moment needs music, a few areas &lt;span class=&#34;spoiler&#34;&gt;&lt;svg alt=&#34;&#34; class=&#34;icon&#34;&gt;&lt;use xlink:href=&#34;/images/icons/closed.svg#body&#34;&gt;&lt;/use&gt;&lt;/svg&gt;such as entering the Spire or just after the Spire fails and you are teleported to Old Aperture&lt;/span&gt; felt they deserved more musical acknowledgement than they got. &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I feel like equating &lt;em&gt;Revolution&lt;/em&gt; to &lt;em&gt;Portal 3&lt;/em&gt; is doing it a disservice. Unlike &lt;a href=&#34;https://www.youtube.com/watch?v=IPXeNcxneS0&#34;&gt;some people&lt;/a&gt;,&lt;sup class=&#34;ref&#34; id=&#34;ref10&#34;&gt;&lt;a href=&#34;#fn10&#34;&gt;10&lt;/a&gt;&lt;/sup&gt; I like many things about the mod, but I acknowledge that it has flaws as well. Ultimately, comparing it to a new title puts it on a pedestal, creating a vision of a Valve-like holistic product which perfectly solves fans&#39; &lt;em&gt;Portal&lt;/em&gt; fix, creating unrealistic expectations that can&#39;t be met, and sandpapering over the actual development process.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;10&#34;&gt;&lt;span class=&#34;number&#34;&gt;10&lt;/span&gt;&lt;p&gt;Also... a bit of a rant, but &lt;em&gt;Revolution&lt;/em&gt; &lt;strong&gt;does&lt;/strong&gt; take into account the Borealis, sorry. Like if you are going to complain about the game not taking into Portal lore, at least get your details right... still a very interesting video overall, even if I absolutely disagree about &lt;em&gt;Revolution&lt;/em&gt; or about &lt;em&gt;Mel&lt;/em&gt;&#39;s excessive cube-swapping being a good thing.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;article id=&#34;rating&#34;&gt;&lt;img class=&#34;star&#34; src=&#34;/images/blog/star.jpg&#34; /&gt;&lt;span&gt;&lt;b&gt;
3.9&lt;/b&gt; out of 5 Novov Affirmation Points&lt;/span&gt;&lt;/article&gt;
&lt;ul id=&#34;footnotes&#34;&gt;
&lt;li id=&#34;fn1&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref1&#34;&gt;1&lt;/a&gt;
&lt;p&gt;Even though Valve&#39;s Hammer editor (with a lineage stretching all the way back to &lt;em&gt;Quake&lt;/em&gt;) is still based around the &#34;old way&#34; of doing things in many respects, the additional graphical detail still makes development harder.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref2&#34;&gt;2&lt;/a&gt;
&lt;p&gt;&#34;Major&#34; being defined as receiving some news coverage by gaming sites and being listed on Steam as a standalone title, at the time of &lt;em&gt;Revolution&lt;/em&gt;&#39;s release.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref3&#34;&gt;3&lt;/a&gt;
&lt;p&gt;Probably a bit more annoying for a &lt;em&gt;Portal 2&lt;/em&gt; lore aficionado like me, who considers the lack of an adequate transition between Old and New Aperture to be an important omission.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn4&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref4&#34;&gt;4&lt;/a&gt;
&lt;p&gt;To put it another way, if this were &lt;em&gt;Portal 3&lt;/em&gt; this would be percieved as an insipid retread, but in this case it is a testament to the team&#39;s skill.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn5&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref5&#34;&gt;5&lt;/a&gt;
&lt;p&gt;Although these are visually attractive, the actual convincingness from a lore perspective is questionable at times. I&#39;ll excuse it though.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn6&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref6&#34;&gt;6&lt;/a&gt;
&lt;p&gt;Why she hasn&#39;t got heaps of roles is beyond me. Though perhaps I&#39;m just biased towards my Antipodean cohorts.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn7&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref7&#34;&gt;7&lt;/a&gt;
&lt;p&gt;Though the interspersion of test chambers and behind-the-scenes sections seems rather contrived at times.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn8&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref8&#34;&gt;8&lt;/a&gt;
&lt;p&gt;&lt;s&gt;I&#39;ve had a concussion once, I can give GLaDOS a pass.&lt;/s&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn9&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref9&#34;&gt;9&lt;/a&gt;
&lt;p&gt;To be fair, a similar critique could be made about the gels in &lt;em&gt;Portal 2&lt;/em&gt;, though to a lesser extent.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn10&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref10&#34;&gt;10&lt;/a&gt;
&lt;p&gt;Also... a bit of a rant, but &lt;em&gt;Revolution&lt;/em&gt; &lt;strong&gt;does&lt;/strong&gt; take into account the Borealis, sorry. Like if you are going to complain about the game not taking into Portal lore, at least get your details right... still a very interesting video overall, even if I absolutely disagree about &lt;em&gt;Revolution&lt;/em&gt; or about &lt;em&gt;Mel&lt;/em&gt;&#39;s excessive cube-swapping being a good thing.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
		</content>
		<author>
			<name>novov</name>
			<email>anon185441@gmail.com</email>
		</author>
	</entry>
	
	<entry>
		<title>Behind Homepage</title>
		<link href="https://novov.me/blog/posts/behindhomepage" />
		<id>https://novov.me/blog/posts/behindhomepage</id>
		<updated>2024-12-20T00:00:00+12:00</updated>
		<summary>The story of developing the Homepage plugin for Obsidian.</summary>
		<content type="html">
			&lt;p&gt;I&#39;m the developer of the Homepage plugin for the Obsidian notetaking app. One of the most popular plugins within the community repository, it adds the ability to designate certain notes, workspaces, canvases, etc. to open on startup or otherwise perform actions when opening a vault. &lt;/p&gt;
&lt;p&gt;This may appear to be a simple and painless affair, but there&#39;s a surprising amount of complexity involved. For experienced developers, much of this will not come as a surprise, but for those who are learning the ropes of plugin development, or are otherwise interested, I hope this is somewhat informative.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id=&#34;origins&#34;&gt;&lt;a href=&#34;#origins&#34;&gt;Origins&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I initially started using Obsidian as a replacement to my &lt;a href=&#34;https://tiddlywiki.com&#34;&gt;TiddlyWiki&lt;/a&gt; file. While TiddlyWiki is great in many respects, its single-file structure is hard to use in certain circumstances and not very portable. To work around this, I used the official &lt;a href=&#34;https://tiddlywiki.com/static/TiddlyDesktop.html&#34;&gt;TiddlyDesktop&lt;/a&gt; app, but it launches on a wiki chooser every time, making quick notetaking rather difficult. As I continued using my wiki, I found myself gravitating towards plain text files for quick notes unrelated to bigger interlinked documents. With Obsidian, these could be transformed to Markdown with just a few quick edits, and co-exist with the rest of my notes. And if I was the midst of coding in my text editor, I could still start a note in the same app and then add it to my Obsidian vault when done.&lt;/p&gt;
&lt;p&gt;However,  there was one dealbreaker with Obsidian. TiddlyWiki &lt;a href=&#34;https://tiddlywiki.com/static/Configuring%2520startup%2520tiddlers.html&#34;&gt;can start&lt;/a&gt; on a designated &#39;tiddler&#39;;&lt;sup class=&#34;ref&#34; id=&#34;ref1&#34;&gt;&lt;a href=&#34;#fn1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; I had made a custom-built &#39;Home&#39; tiddler with a set of quick links, and this became a core part of my workflow.&lt;sup class=&#34;ref&#34; id=&#34;ref2&#34;&gt;&lt;a href=&#34;#fn2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; But Obsidian has no inbuilt mechanism for this, meaning that I had to wade through whatever I was last doing every time I opened it. Fortunately, Obsidian had an then-incipient plugin system. Since I already knew how to program, it was very easy to start a new plugin using the official template. Although it took me a while to get up to speed with the API (and figure how to avoid loading the homepage when the plugin is installed), the first version ended up being very simple:&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;1&#34;&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;p&gt;Equivalent to a wiki page or note.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;2&#34;&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;p&gt;In addition to the sidebar, which has a more comprehensive listing of different tiddlers/notes in both Obsidian and TiddlyWiki.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted typescript&#34;&gt;&lt;span class=&#34;k&#34;&gt;export&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Homepage&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;extends&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Plugin&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;settings&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;HomepageSettings&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;async&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;await&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;loadSettings&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addSettingTab&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;HomepageSettingTab&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addCommand&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;open-homepage&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Open Homepage&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;callback&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;this.openHomepage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;workspace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;activeLeaf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//only do on startup, not plugin activation&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;workspace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onLayoutReady&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;openHomepage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//continued...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It was rudimentary and its logic was really simple. It went something like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clear all existing notes&lt;/li&gt;
&lt;li&gt;Open the specified homepage note&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It was the proverbial Model T of plugins - the only option was to change what note was the homepage. After it flew past the submission process, I expected that it would get around 3 users. After all, there were already quite a few plugins, and nobody had developed something similar. Instead, its user base grew many times bigger than I would have ever expected.&lt;/p&gt;
&lt;p&gt;Naïvely, I didn&#39;t consider that many of them would have lots of different needs and demands that didn&#39;t fit within that model, and before long, I found myself adding features that I initially rejected: Daily Notes support, &#34;Use when opening normally&#34;, and retaining notes in the sidebar, among others. Hubris and myopia are powerful things.&lt;/p&gt;
&lt;p&gt;Those additional users and extra bells and whistles are nice for bragging rights, but with them the plugin also grew massively in lines of code, complexity, and features. I learned a lot, but gained a lot of extra responsibility as well. &lt;/p&gt;
&lt;h4 id=&#34;side_note_dataview_in_homepage&#34;&gt;&lt;a href=&#34;#side_note_dataview_in_homepage&#34;&gt;Side Note: Dataview in Homepage&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;My TiddlyWiki homepage also had several other special properties - the time of the latest edit made to the wiki, and the total number of tiddlers that existed in the wiki. In TiddlyWiki, this is accomplished like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted text&#34;&gt;&amp;lt;b&amp;gt;Last updated on &amp;lt;$list filter=&amp;quot;[!is[system]!has[draft.of]!sort[modified]limit[1]]&amp;quot;&amp;gt; &amp;lt;$view field=&amp;quot;modified&amp;quot; format=&amp;quot;date&amp;quot; template=&amp;quot;DDth MMM YYYY at hh12:0mmam&amp;quot;/&amp;gt; &amp;lt;/$list&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;
&amp;lt;b&amp;gt;&amp;lt;$count filter=&amp;quot;[!is[system]]&amp;quot; /&amp;gt; pages on this wiki&amp;lt;/b&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Although I considered creating a plugin to implement a system of magic words similar to TiddlyWiki&#39;s &lt;a href=&#34;https://tiddlywiki.com/static/Widgets.html&#34;&gt;widgets&lt;/a&gt;, I realised that it was very easy to write something equivalent with &lt;a href=&#34;https://blacksmithgu.github.io/obsidian-dataview/&#34;&gt;Dataview&lt;/a&gt;&#39;s built-in JavaScript capabilities:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted js&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;all&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;dv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;lastmod&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sort&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;toFormat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;dd LLL yyyy &amp;#39;at&amp;#39; h:mma&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;dv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;paragraph&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&amp;lt;div class=&amp;quot;nv-subtitle&amp;quot;&amp;gt;Last updated on &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;lastmod&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;&amp;lt;br/&amp;gt;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt; pages in this vault&amp;lt;/div&amp;gt;`&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Homepage and Dataview are a popular combination nowadays, with many flashy and photogenic homepages far beyond what I ever imagined. Although they were intended to be used together from the very start, I later added an extra setting to ensure that Dataview statistics are always refreshed (depending on your use case, the original refresh rate may be sufficient).&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id=&#34;optimisation&#34;&gt;&lt;a href=&#34;#optimisation&#34;&gt;Optimisation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Although nothing Homepage does is particularly intensive, it has a very high performance bar: users shouldn&#39;t have to wait to interact with their homepage. Opening a file may be quick, but when wrapped in Obsidian&#39;s panes and models it can take a little longer. And it&#39;s always prudent to avoid useless and repetitive work.&lt;/p&gt;
&lt;p&gt;The primary path for Homepage - the original method of clearing extant notes, and opening a new note - is designed to be simple, and to involve little intensive work. Although there&#39;s a lot more conditionals and steps that there initially were, the path from the initial &lt;code&gt;HomepagePlugin.onload()&lt;/code&gt; to the actual opening of the vault should be as straightforwards as possible. Ideally, anything extra is gated behind a sole condition which then leads to the implementation, and any additional processing is only done then.&lt;/p&gt;
&lt;p&gt;Obsidian&#39;s core functions are closed-source, but they can still be introspected via the Chromium developer tools. For many plugins, this isn&#39;t necessary, and you can stick to the intended model of being handed the API as a mysterious black box, where all the difficult stuff is out of sight and out of mind. But for Homepage, it has been very helpful.&lt;sup class=&#34;ref&#34; id=&#34;ref3&#34;&gt;&lt;a href=&#34;#fn3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;3&#34;&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;p&gt;Of course, one should keep in mind that internal APIs are internal for a reason, and that their performance characteristics are subject to change with little notice.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;As an example, let&#39;s look at the code that closes all other tabs when &#34;Replace all open notes&#34; is selected. We want to close all tabs on a certain list of known tab types, as Obsidian has tabs like the file browser we want to retain.&lt;sup class=&#34;ref&#34; id=&#34;ref4&#34;&gt;&lt;a href=&#34;#fn4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; This seems simple: there is the function &lt;code&gt;app.workspace.detachLeavesOfType&lt;/code&gt;, so we run through the types of leaves we want to close:&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;4&#34;&gt;&lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;p&gt;i.e. &#34;markdown&#34;, &#34;image&#34;, &#34;pdf&#34;, etc. Additionally, a few third-party plugins&#39; tabs had undisclosed side effects, and Obsidian has certain tabs like release notes that needed to be treated separately.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted ts&#34;&gt;&lt;span class=&#34;nx&#34;&gt;CLOSED_LEAVES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;forEach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;workspace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;detachLeavesOfType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What isn&#39;t apparent from the public-facing API is that Obsidian keeps a list of all the open leaves, but it doesn&#39;t track them by type. Usually, the user opens and closes tabs a lot more than they do something that requires tabs of a certain type, so tracking tabs by type is suboptimal. Instead, Obsidian simply does this:&lt;sup class=&#34;ref&#34; id=&#34;ref5&#34;&gt;&lt;a href=&#34;#fn5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;5&#34;&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;p&gt;This isn&#39;t the exact code used, of course, as that is proprietary.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted ts&#34;&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getLeavesOfType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewType&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;WorkspaceLeaf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaves&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[];&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;iterateAllLeaves&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;view&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getViewType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaves&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;push&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaves&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;detachLeavesOfType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewType&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;WorkspaceLeaf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;of&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getLeavesOfType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;detach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Obviously, we don&#39;t want to be iterating through the whole set of leaves multiple times, as it&#39;s an expensive operation. Instead, we can simply call &lt;code&gt;iterateAllLeaves&lt;/code&gt; directly, as it&#39;s also a publicly exposed function.&lt;sup class=&#34;ref&#34; id=&#34;ref6&#34;&gt;&lt;a href=&#34;#fn6&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;  In the callback, we check whether each leaf has a type we want to get rid of once:&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;6&#34;&gt;&lt;span class=&#34;number&#34;&gt;6&lt;/span&gt;&lt;p&gt;Many Obsidian plugins, Homepage included, do use some private APIs. But it&#39;s still good to avoid them where possible.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted ts&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaves&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[];&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;workspace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;iterateAllLeaves&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;CLOSED_LEAVES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;contains&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;view&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getViewType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaves&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;push&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;leaves&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;forEach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;l&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;l&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;detach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In fact, &lt;code&gt;iterateAllLeaves&lt;/code&gt; just calls a few other internal functions to iterate over different parts of the window. If we narrow it down to &lt;code&gt;iterateRootLeaves&lt;/code&gt;, this also ignores the side panels containing the file browser and its cohorts. The tradeoff is that we can&#39;t pick what tab types to close, but the few special tab types can be handled separately.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted ts&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaves&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[];&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;workspace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;iterateAllLeaves&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;l&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaves&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;push&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;l&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;leaves&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;forEach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;l&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;l&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;detach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But it still isn&#39;t ideal. We&#39;ve closing each tab separately, so the visual state is wastefully updated after each modification.&lt;sup class=&#34;ref&#34; id=&#34;ref7&#34;&gt;&lt;a href=&#34;#fn7&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; Instead, the &lt;a href=&#34;https://docs.obsidian.md/Reference/TypeScript+API/Workspace/changeLayout&#34;&gt;changeLayout&lt;/a&gt; function modifies it in one fell swoop. When looking at the code for the popular built-in &lt;a href=&#34;https://help.obsidian.md/Plugins/Workspaces&#34;&gt;Workspaces&lt;/a&gt; plugin, which is proven to work without many hitches, we can see it is used there too. &lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;7&#34;&gt;&lt;span class=&#34;number&#34;&gt;7&lt;/span&gt;&lt;p&gt;Plus the user sees each tab flicker out of existence, which is far from a seamless experience.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;hr /&gt;
&lt;h3 id=&#34;development_and_testing&#34;&gt;&lt;a href=&#34;#development_and_testing&#34;&gt;Development and testing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Most plugins perform their work after the vault is loaded in response to user action, so much of the API is predicated on giving Obsidian time to set up. Homepage acts differently - while it can be manually triggered by user action, it is usually automatically launched on startup. If Obsidian is still loading, Homepage can break in difficult to reproduce ways without carefully considered and tested code.&lt;/p&gt;
&lt;p&gt;The main method of testing Obsidian plugins to use an off-the-shelf JavaScript testing framework and mock Obsidian&#39;s proprietary application code. But for Homepage, which depends on behaviour of Obsidian functions which may not work predictably while the vault is still loading, this does not work. Additionally, while many other plugins have complex logic which can easily be extricated from  parts that interface with Obsidian, Homepage performs almost all its actions by putting together core Obsidian functionality. Therefore, Homepage uses a custom test runner that runs inside the Obsidian vault instead.&lt;sup class=&#34;ref&#34; id=&#34;ref8&#34;&gt;&lt;a href=&#34;#fn8&#34;&gt;8&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;8&#34;&gt;&lt;span class=&#34;number&#34;&gt;8&lt;/span&gt;&lt;p&gt;This could be considered similar to something like &lt;a href=&#34;https://playwright.dev&#34;&gt;Playwright&lt;/a&gt;. In Obsidian-land this is fairly unique AFAIK; I&#39;m not aware of any other plugin which does this.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;While Obsidian can launch vaults in an automated fashion, it can only do this for &lt;em&gt;known&lt;/em&gt; vaults (as of this writing). Therefore, the test vault must be opened manually once. Then the rest is automated via an augmented version of the plugin, which automatically runs through different test scenarios after the vault is initialised. It handles basic testing functionality, like failing on errors,  built in methods for assertion accessible from each test function, etc. The testing cycle runs like so:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The build script builds the plugin using &lt;a href=&#34;https://esbuild.github.io&#34;&gt;ESBuild&lt;/a&gt;, substituting the usual &lt;code&gt;HomepagePlugin&lt;/code&gt; for its &lt;code&gt;HomepageTestPlugin&lt;/code&gt; subclass.  &lt;/li&gt;
&lt;li&gt;It sends a &lt;a href=&#34;https://help.obsidian.md/Extending+Obsidian/Obsidian+URI&#34;&gt;custom URI&lt;/a&gt; to Obsidian, telling any previous test instances to quit. Then it uses another URI launching a vault with the newly built augmented plugin.&lt;/li&gt;
&lt;li&gt;The build script terminates, and logic is handed off to the plugin, which downloads the latest versions of other plugins which the tests interact with. It then runs the tests and displays their results.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each test suite is its own class, which are all loaded into &lt;code&gt;HomepageTestPlugin&lt;/code&gt;. A basic test looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted ts&#34;&gt;&lt;span class=&#34;k&#34;&gt;async&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;replaceAll&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;HomepageTestPlugin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;await&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;workspace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;openLinkText&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Note A&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;homepage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;manualOpenMode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ReplaceAll&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;homepage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;homepage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;workspace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getActiveFile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaves&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;workspace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getLeavesOfType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;markdown&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;assert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Home.md&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaves&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;leaves&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, Homepage incorporates a few additional functions which are included in non-production builds which are designed to be easily accessed in the console for debugging. With ESBuild, these are automatically excluded from production builds:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted ts&#34;&gt;&lt;span class=&#34;kr&#34;&gt;declare&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;DEV&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;boolean&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;DEV&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;./dev&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul class=&#34;wideList&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;homepage.ensurePlugins&lt;/code&gt;: Obsidian doesn&#39;t have a public API to add and manipulate other installed plugins - which makes sense, as it&#39;d be really easy to use for nefarious purposes. However, a user&#39;s particular plugin setup often needs to be emulated to reproduce issues they are experiencing. This function uses a reverse-engineered extension of the Obsidian API to download (and optionally enable) a list of plugins.&lt;sup class=&#34;ref&#34; id=&#34;ref9&#34;&gt;&lt;a href=&#34;#fn9&#34;&gt;9&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li class=&#34;asideContainer&#34; role=&#34;generic&#34;&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;9&#34;&gt;&lt;span class=&#34;number&#34;&gt;9&lt;/span&gt;&lt;p&gt;The test suite initially used its own logic in the build script to directly download and install the plugins, but now also uses this function for consistency with Obsidian&#39;s logic.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;homepage.loadDebugInfo&lt;/code&gt;: This is associated with a  &lt;code&gt;Copy debug info&lt;/code&gt; button in Homepage&#39;s settings and a command.  Unlike Obsidian&#39;s native debug info command, this info is intentionally structured as JSON so it can be loaded into the function, which installs and loads the appropriate plugins, and modifies all Homepage settings and relevant core Obsidian settings.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id=&#34;user_experience&#34;&gt;&lt;a href=&#34;#user_experience&#34;&gt;User experience&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the most challenging parts of making Homepage isn&#39;t making features work, or deciding how to implement things, but designing how users interact with the plugin. Although the core workflow is very simple, the user interaction for complex settings needs to be intuitive.&lt;/p&gt;
&lt;p&gt;A hallmark feature of Homepage 3.0&lt;sup class=&#34;ref&#34; id=&#34;ref10&#34;&gt;&lt;a href=&#34;#fn10&#34;&gt;10&lt;/a&gt;&lt;/sup&gt; was supposed to be the ability to create and switch between arbitrary number of homepages. Any of these homepages could be set as a desktop or mobile homepage, and possibly as a homepage to be opened up on startup, or to be opened via commands or buttons (with the user being able to create an arbitrary amount of them, instead of just one). The feature for a manual opening mode would be obviated: instead, the user would just create a whole new homepage.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;10&#34;&gt;&lt;span class=&#34;number&#34;&gt;10&lt;/span&gt;&lt;p&gt;Initially revived for Homepage 4.0 as well.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;This would open up a whole new set of use cases for the plugin, and plenty of people who don&#39;t want something set automatically on startup would find it useful. In fact, the data model for Homepage 3.0 and later is designed around this, and it is used for having a separate mobile homepage:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted js&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;homepages&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Main Homepage&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Home&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;openOnStartup&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Mobile Homepage&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Mobile Home&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;openOnStartup&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But the main reason why the feature hasn&#39;t been implemented is the difficulty of designing an intuitive user workflow for it. Having an interface that is intuitive, easy to understand, and has no extraneous details is more important than complicating it for a feature that a good portion of users won&#39;t care about or use. &lt;/p&gt;
&lt;p&gt;Right now, making sure that the homepage doesn&#39;t close all other tabs when opening it from a command is as simple as setting a &#34;manual opening mode&#34;. Making it the responsibility of separate homepages is easy to code - most of the work has already been done - but makes for a more annoying user interface. Every time the user wants to change another unrelated setting, they now have to change it for two homepages. I could create a default homepage that all the others inherit from, but that&#39;s more added complexity that users have to wrap their heads around. Sometimes simple is better. &lt;/p&gt;
&lt;p&gt;One of my favourite pieces of user interface for Homepage is the command box. The add button is intentionally in line with the commands, signifying that it&#39;s in the place of where an added command is going to go. The inline nature of the different command pills nicely indicates how the commands are run in order one after another, while being more compact than simply dedicating a row to each command. Plus subjectively I think it looks pretty.&lt;/p&gt;
&lt;p&gt;A challenge was making it support additional options in version 4.0. In versions beforehand, the commands UI looks like this: &lt;/p&gt;
&lt;figure class=&#34;small sideCaption light&#34;&gt;
			&lt;img alt=&#34;&#34; src=&#34;/images/blog/content/commandselect.png&#34;/&gt;
			&lt;figcaption&gt;The commands UI, as introduced in version 3.0.
&lt;/figcaption&gt;
		&lt;/figure&gt;
&lt;p&gt;4.0 added the ability to set certain commands as only activating during startup or when opening the homepage manually. This was intended to serve some of the same purposes as creating arbitrary homepages - people might want to use commands at certain times but not others. Initially, I considered making this option a dropdown on a separate line, in slightly smaller text:&lt;/p&gt;
&lt;figure class=&#34;small sideCaption light&#34;&gt;
			&lt;img alt=&#34;&#34; src=&#34;/images/blog/content/commandrevised1.png&#34;/&gt;
			&lt;figcaption&gt;Although these mockups were made in Affinity Designer post-facto, each layout was actually tested.
&lt;/figcaption&gt;
		&lt;/figure&gt;
&lt;p&gt;But in practice, these dropdowns are &lt;em&gt;extremely&lt;/em&gt; small and hard to target. If they were bigger, they wouldn&#39;t be subordinate to the main titles, and if you made the whole thing bigger, it would take up too much space. Plus, this removes the visual conveyance of the commands being in sequential order - the user is now reading the dropdown and buttons on the bottom, then going back to the top, then back down, and so forth.&lt;/p&gt;
&lt;p&gt;My next solution was to add icons for the different states. I also gave the non-default settings an accent colour to help them stand out, and to convey that something is &#34;active&#34; that isn&#39;t the normal setting. It looked like this:&lt;/p&gt;
&lt;figure class=&#34;small sideCaption light&#34;&gt;
			&lt;img alt=&#34;&#34; src=&#34;/images/blog/content/commandrevised2.png&#34;/&gt;
			&lt;figcaption&gt;It wouldn&#39;t be unreasonable to assume that ⏻ means that the command is executed when closing your vault.
&lt;/figcaption&gt;
		&lt;/figure&gt;
&lt;p&gt;This is definitely more compact and less obtrusive. But even after testing a lot of icons, it&#39;s difficult to tell what they mean, and the small size means they&#39;ve difficult to notice. While it&#39;s a fairly advanced feature, so a size smaller than the default Obsidian UI elements is acceptable, this is too far in that direction. Eventually, I went with this:&lt;/p&gt;
&lt;figure class=&#34;small sideCaption light&#34;&gt;
			&lt;img alt=&#34;&#34; src=&#34;/images/blog/content/commandrevised3.png&#34;/&gt;
			&lt;figcaption&gt;The final commands UI in version 4.0 and later.
&lt;/figcaption&gt;
		&lt;/figure&gt;
&lt;p&gt;At first, I considered this somewhat non-ideal: the button changes size, and using text is almost cheating! But the button needs to be non-intrusive for the majority of users which aren&#39;t interested in an advanced feature, but distinct and descriptive for those who are using it. So having it change size is kind of a necessary evil, &lt;a href=&#34;https://blog.panic.com/clear/&#34;&gt;and there&#39;s precedent for using text in this way.&lt;/a&gt; The icons almost stayed in, but in such a compact UI I found they were additional visual noise, so they were dropped at the last minute.&lt;sup class=&#34;ref&#34; id=&#34;ref11&#34;&gt;&lt;a href=&#34;#fn11&#34;&gt;11&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;11&#34;&gt;&lt;span class=&#34;number&#34;&gt;11&lt;/span&gt;&lt;p&gt;But they still exist commented out.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;hr /&gt;
&lt;ul id=&#34;footnotes&#34;&gt;
&lt;li id=&#34;fn1&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref1&#34;&gt;1&lt;/a&gt;
&lt;p&gt;Equivalent to a wiki page or note.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref2&#34;&gt;2&lt;/a&gt;
&lt;p&gt;In addition to the sidebar, which has a more comprehensive listing of different tiddlers/notes in both Obsidian and TiddlyWiki.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref3&#34;&gt;3&lt;/a&gt;
&lt;p&gt;Of course, one should keep in mind that internal APIs are internal for a reason, and that their performance characteristics are subject to change with little notice.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn4&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref4&#34;&gt;4&lt;/a&gt;
&lt;p&gt;i.e. &#34;markdown&#34;, &#34;image&#34;, &#34;pdf&#34;, etc. Additionally, a few third-party plugins&#39; tabs had undisclosed side effects, and Obsidian has certain tabs like release notes that needed to be treated separately.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn5&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref5&#34;&gt;5&lt;/a&gt;
&lt;p&gt;This isn&#39;t the exact code used, of course, as that is proprietary.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn6&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref6&#34;&gt;6&lt;/a&gt;
&lt;p&gt;Many Obsidian plugins, Homepage included, do use some private APIs. But it&#39;s still good to avoid them where possible.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn7&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref7&#34;&gt;7&lt;/a&gt;
&lt;p&gt;Plus the user sees each tab flicker out of existence, which is far from a seamless experience.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn8&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref8&#34;&gt;8&lt;/a&gt;
&lt;p&gt;This could be considered similar to something like &lt;a href=&#34;https://playwright.dev&#34;&gt;Playwright&lt;/a&gt;. In Obsidian-land this is fairly unique AFAIK; I&#39;m not aware of any other plugin which does this.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn9&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref9&#34;&gt;9&lt;/a&gt;
&lt;p&gt;The test suite initially used its own logic in the build script to directly download and install the plugins, but now also uses this function for consistency with Obsidian&#39;s logic.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn10&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref10&#34;&gt;10&lt;/a&gt;
&lt;p&gt;Initially revived for Homepage 4.0 as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn11&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref11&#34;&gt;11&lt;/a&gt;
&lt;p&gt;But they still exist commented out.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
		</content>
		<author>
			<name>novov</name>
			<email>anon185441@gmail.com</email>
		</author>
	</entry>
	
	<entry>
		<title>Unicode is Worth It</title>
		<link href="https://novov.me/blog/posts/unicodeisworthit" />
		<id>https://novov.me/blog/posts/unicodeisworthit</id>
		<updated>2023-10-27T00:00:00+12:00</updated>
		<summary>My thoughts on a colourful cast of characters.</summary>
		<content type="html">
			&lt;p&gt;In computing, one guideline has came to define how text is encoded: &lt;a href=&#34;https://home.unicode.org&#34;&gt;the Unicode Standard&lt;/a&gt;. The vast majority of letters you see on the screen - on a website, Word document, or in the file system - uses the &lt;a href=&#34;https://en.wikipedia.org/wiki/UTF-8&#34;&gt;UTF-8&lt;/a&gt; encoding of it. &lt;/p&gt;
&lt;p&gt;Being a nearly universal standard, it receives plenty of criticism. In fact, I was being a little misleading with the title, since I am not above criticising it myself. Plenty of Chinese, Korean, and Japanese computing experts have sharply condemned &lt;a href=&#34;https://en.wikipedia.org/wiki/Han_unification&#34;&gt;Han unification&lt;/a&gt;, and for the most part I agree with them. And as plenty of developers know, Unicode&#39;s complex historical context has lead to a design that is at times inelegant and inconsistent: Ω is not the same as Ω.&lt;sup class=&#34;ref&#34; id=&#34;ref1&#34;&gt;&lt;a href=&#34;#fn1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; Sometimes, people even advocate doing away with it entirely, and reverting back to multiple encodings. For instance, from an &lt;a href=&#34;https://web.archive.org/web/20211226171536/http://www.gnu.org/software/moe/manual/moe_manual.html&#34;&gt;old version&lt;/a&gt; of the GNU &lt;code&gt;moe&lt;/code&gt; manual:&lt;/p&gt;
&lt;aside class=&#34;long&#34;&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;1&#34;&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;p&gt;As another example, &lt;a href=&#34;https://www.unicode.org/history/unicode88.pdf&#34;&gt;the original Unicode specification&lt;/a&gt; was based around the idea that every currently used character in the world could fit into a set of 65,536 different codepoints. Anyone who has sufficient experience with Chinese &lt;em&gt;hanzi&lt;/em&gt; or Japanese &lt;em&gt;kanji&lt;/em&gt; would know that this was hubristic. Although commonly used characters can fit under that amount, plenty of place names and surnames - and even some words - use rarer characters. The set of these is far too large to fit in that amount, so the Unicode Consortium eventually relented and developed &lt;a href=&#34;https://en.wikipedia.org/wiki/UTF-16&#34;&gt;surrogate pairs&lt;/a&gt; to encode a much larger set of characters. The original set became the &lt;a href=&#34;https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane&#34;&gt;Basic Multilingual Plane&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;blockquote&gt;
&lt;p&gt;Replacing all the 8-bit character sets with Unicode is like trying to simplify transportation by standardizing on the same kind of (excessively) large vehicle. I.e., forcing everybody to use a vehicle as large as the largest vehicle anybody may need. Just like owning a normal car may be orders of magnitude cheaper than owning a four-engined airliner, text tools using an 8-bit character set may be orders of magnitude more efficient than those using Unicode. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Or &lt;a href=&#34;https://hn.algolia.com/?dateRange=all&amp;amp;page=0&amp;amp;prefix=true&amp;amp;query=author%3AWalterBright%20unicode&amp;amp;sort=byDate&amp;amp;type=comment&#34;&gt;comments&lt;/a&gt; by the creator of the D language, Walter Bright:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The imposing is inflicted by the Unicode standard on everyone in the world who have no use for never ending new invented encodings for the same thing... What should give pause in advocacy for the tarpit of Unicode is its unimplementability. That&#39;s a giant red flag that something went horribly wrong.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a position I strenuously disagree with - a universal character set and encodings that use it are good things.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Core to many of these claims is the idea that &lt;strong&gt;different languages should use specialised encodings&lt;/strong&gt;. Unicode, according to these critics, has accreted unfathomable complexity in service of an impossible goal. And indeed Unicode is complex - but replacing it with multiple encodings would just hand most of the complexity off to a different source. Most OSes handle strings at a fundamental level. Instead of string facilities in operating systems and programming languages having to handle the minutiae of Unicode, they&#39;ll have to handle the complexities of different encodings. Imagine that instead of one kind of string in UTF-16 (Windows)/UTF-8 (most Unix), there’s now around 10, all of which have to interact with core OS services. And all of them operate on their own standards, instead of the singular body of Unicode standards.&lt;/p&gt;
&lt;p&gt;Even then, this is assuming that different developers even &lt;em&gt;bother&lt;/em&gt; to implement it. In our current Unicode world, many still don&#39;t handle complex writing systems such as Arabic &lt;a href=&#34;https://notarabic.com&#34;&gt;very well&lt;/a&gt; - a fact that is commonly pointed out by detractors of Unicode to admonish its complexity. Let&#39;s look at the below Arabic text:&lt;/p&gt;
&lt;p class=&#39;highlight&#39; lang=&#39;ar&#39;&gt;
نيوزيلندا
&lt;/p&gt;

&lt;p&gt;This is legible to your average Arabic speaker. Unfortunately, it isn&#39;t when incorrectly rendered as something like:&lt;/p&gt;
&lt;p class=&#39;highlight&#39; lang=&#39;ar&#39;&gt;
ن ي و ز ي ل ن​ د ​​​​ا
&lt;/p&gt;

&lt;p&gt;It&#39;s easy to blame Unicode, but developers wouldn&#39;t have the impetus to handle different languages at all without it. Unicode at least forces compatibility with &lt;em&gt;some form&lt;/em&gt; of text, and badly-rendered text is better than no text at all. Given the dynamics at play, the latter would be inevitable with the hypothetical Unicode-replacement.&lt;sup class=&#34;ref&#34; id=&#34;ref2&#34;&gt;&lt;a href=&#34;#fn2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; Currently, a person can transmit Arabic that was badly rendered by one system to another one that competently renders it. But if they can&#39;t enter their native language in the first place, then - to use a technical term - they are stuffed. &lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;2&#34;&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;p&gt;Purely hypothetical, since Unicode has already gained so much adoption that realistically it is incredibly unlikely to be replaced. Which makes this article kind of grandstandy and in a certain sense pointless, but I digress.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Unicode&#39;s rules also provide a guideline for correct implementation of rendering these languages: there are always inherent difficulties with rendering scripts that are more complex than simply letters side by side, and it makes more sense to account for that in a basal manner. Since developers have to build a non-zero implementation of Unicode features for many things English speakers use and expect, such as emoji, there&#39;s an incentive for developers to handle global languages properly. With many different encodings, many simply wouldn&#39;t bother.&lt;/p&gt;
&lt;p&gt;There&#39;s also the issue of mixing different languages. Due to the Western world&#39;s preeminent position in the global cultural sphere, a lot of colloquial speech in different languages freely combines various writing systems. Anecdotally, I&#39;m in communities with non-English speakers, and many of them casually mix English and their native language. Even if they don’t, a lot interact with multiple scripts for, say, speaking Czech at work but playing in English on Steam. And this mixing occurs in more formal contexts as well, such as official names, English translations, abbreviations, or technical terms. For instance, a good portion of corporate Chinese, Japanese, Cyrillic, or Arabic text is interspersed with English brand names:&lt;/p&gt;
&lt;p class=&#39;highlight&#39; lang=&#39;ja&#39;&gt;
ニンテンドー3DSシリーズおよびWii Uの「ニンテンドーeショップ」 
&lt;/p&gt;

&lt;p&gt;Sure, one could switch between encodings for this - but it&#39;s a lot of rigmarole for a task that is far more common than the majority of English speakers would expect.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;People will also say that &lt;strong&gt;multi-byte characters are bad and should be avoided&lt;/strong&gt;. This is a very tempting claim to make, as a lot of string handling in low-level programming languages would suddenly become a whole lot easier. Before Unicode became popular, the assumption was generally that a variant of &lt;a href=&#34;https://en.wikipedia.org/wiki/ASCII&#34;&gt;ASCII&lt;/a&gt; would be used, where each character would neatly fit in a byte. Much of Unicode&#39;s complexity comes from the fact that to store many different characters, it has to encode most characters in two or more bytes.&lt;sup class=&#34;ref&#34; id=&#34;ref3&#34;&gt;&lt;a href=&#34;#fn3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; So if this was avoided, it would greatly simplify things... except, not really. Although this would work for English and the ASCII character set, languages such as Chinese and Japanese have heaps of characters - a conservative estimate would be &lt;em&gt;at least&lt;/em&gt; 200,000 for the former, which is more than is able to fit in a byte, or even two bytes. Systems that maintain the ideal of one byte simply don&#39;t work in many places; this might have been easy to ignore in a pre-Unicode era, but in an increasingly globalised world, it&#39;s not.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;3&#34;&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;p&gt;Except for ASCII characters in UTF-8, of course.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Despite what some people say, supporting non-Latin scripts isn&#39;t a nice-to-have. It&#39;s very easy in an English-speaking world to dismiss the importance of other languages. But Mandarin Chinese is the second most popular language in the world, and has almost a million people who are native speakers. These people deserve to not only have basic operating system support for naming files, writing documents, and reading web content efficiently, but also be supported in applications that perform more specialised tasks. Even if you&#39;ve building a tool for an obscure language or niche hobby, or cutting corners and trying to get your product ready to market ASAP, you&#39;ll never know who ends up using it. &lt;/p&gt;
&lt;p&gt;In the early days of Unicode, multi-byte encoding was also criticised for being inefficient at storing text. Initially, most Unicode software used the &lt;a href=&#34;https://en.wikipedia.org/wiki/UTF-16&#34;&gt;UTF-16&lt;/a&gt; encoding, which stores every character in either 16 or 32 bits. But most implementations nowadays use UTF-8, which preserves single-byte encoding for ASCII characters; this also has the advantage of some backwards capability with programs that assume that a byte is coterminous with a character. Only scripts used by other languages, such as the aforementioned Chinese and Japanese, are relegated to higher amounts of bytes. Some people still criticise this as prioritising Western languages, but the amount of these characters is so great that many would still take up multiple bytes even if they were given first priority. And I believe these languages being segregated into their own second-class encodings with limited support would be far more deleterious than the additional bytes.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Another complaint is that &lt;strong&gt;Unicode has a whole bunch of useless characters&lt;/strong&gt;. Typical examples given include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Emoji&lt;/strong&gt;: 😖😵‍💫😳😱&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mathematical lettering&lt;/strong&gt; &lt;span alt=&#34;which is often used online for decoration&#34;&gt;𝑤ℎ𝑖𝑐ℎ 𝑖𝑠 𝑜𝑓𝑡𝑒𝑛 𝑢𝑠𝑒𝑑 𝑜𝑛𝑙𝑖𝑛𝑒 𝑓𝑜𝑟 𝑑𝑒𝑐𝑜𝑟𝑎𝑡𝑖𝑜𝑛&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enclosed characters&lt;/strong&gt; &lt;span alt=&#34;like this&#34;&gt;🅻ⓘ⒦🅴 🅃⒣🄸Ⓢ&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Due to the vast amount of Unicode characters - mostly Chinese, but plenty exist from other languages as well - any encoding that stores them all must be able to have a maximum length of at least 32 bits. But while the amount of characters cannot comfortably fit into a smaller size, 32 bits still leaves heaps of empty space. So most of the extraneous symbols are, to be quite frank, harmless. If you don&#39;t like them, you could almost pretend that they don&#39;t exist.&lt;sup class=&#34;ref&#34; id=&#34;ref4&#34;&gt;&lt;a href=&#34;#fn4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; But in fact, they can often be helpful: while people often consider 𝕏 𝖃 and 𝐗 to be useless decoration and an inappropriate usage of Unicode, they often have very distinct uses in mathematical equations.&lt;sup class=&#34;ref&#34; id=&#34;ref5&#34;&gt;&lt;a href=&#34;#fn5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; If other characters deserve encodings due to their semantic meaning, these do as well, and their codepoints have plenty of practical applications, such as screen readers or contexts without rich text.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;4&#34;&gt;&lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;p&gt;By doing this, you assume all responsibility for modifying system files to remove the fonts that display these characters. The unimaginative reader would state that this is not possible on closed-down platforms like iOS, but a true ideologue would choose their platforms based on whether this is possible, or at the very least wait for an opportune security vulnerability.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;5&#34;&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;p&gt;In fact, using them as decoration can be actively harmful as screen readers don&#39;t speak them properly. Apologies for being a spoilsport. And a hypocrite too, I guess.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;What &lt;em&gt;is&lt;/em&gt; undeniably a negative is that Unicode has multiple encodings for the same symbol. But despite it causing issues now, it was initially a very useful feature. For Unicode to gain wide adoption, it needed to be a lossless conversion target; i.e. it needed to have everything that previous encodings had. While the result may not be optimal in the present, I think it goes without saying that the alternative of Unicode &lt;em&gt;and&lt;/em&gt; several other individual encodings would be even worse.&lt;/p&gt;
&lt;p&gt;Similarly, the vast amount of characters leads some to claim that &lt;strong&gt;nobody can possibly implement all of Unicode&lt;/strong&gt;. But this is beside the point. Nobody could implement all of the internet cabling that spans the globe. Nobody could implement a lot of things as a single unit, but our collective force allows the world to work cohesively regardless. The same is true here: plenty of Unicode libraries exist, and just like other complex aspects of programming, people can build on the shoulders of the metaphorical giants. On the user-facing end, most modern applications allow fallback fonts. If the user needs certain characters, they simply obtain a font that includes them. If they don&#39;t, then it&#39;s no skin off their back. In many cases, the OS doesn&#39;t even need to know about these characters, so new glyphs can be added and used with minimal pain. Unicode may have a lot of complexities, but this in particular is elegant and simple. &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;It&#39;s easy to forget with Unicode&#39;s predominance that there was once a time before it. We&#39;ve tried living in a world without Unicode; but even in that time, humans still communicated in a vast arrays of characters and scripts. The multifarious encodings only made that more difficult; hence Unicode being created in the first place. Unicode is only making sense of the world that already existed, banishing encoding conversion errors to a relic of the past and making global communication easier. It is just a reification, an actualisation in a sense, of the hundreds of years of human history that already exists.&lt;/p&gt;
&lt;h3 id=&#34;further_reading&#34;&gt;&lt;a href=&#34;#further_reading&#34;&gt;Further reading&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Niki Tonsky&#39;s &lt;a href=&#34;https://tonsky.me/blog/unicode/&#34;&gt;The Absolute Minimum Every Software Developer Must Know About Unicode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Commentary on &lt;a href=&#34;https://baturin.org/blog/life-before-unicode/&#34;&gt;life before Unicode&lt;/a&gt; by Daniil Baturin&lt;/li&gt;
&lt;li&gt;A &lt;a href=&#34;https://hachyderm.io/@rygorous@mastodon.gamedev.place/110872853293266595&#34;&gt;discussion&lt;/a&gt; on Mastodon about some actual shortcomings of Unicode&lt;/li&gt;
&lt;/ul&gt;
&lt;ul id=&#34;footnotes&#34;&gt;
&lt;li id=&#34;fn1&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref1&#34;&gt;1&lt;/a&gt;
&lt;p&gt;As another example, &lt;a href=&#34;https://www.unicode.org/history/unicode88.pdf&#34;&gt;the original Unicode specification&lt;/a&gt; was based around the idea that every currently used character in the world could fit into a set of 65,536 different codepoints. Anyone who has sufficient experience with Chinese &lt;em&gt;hanzi&lt;/em&gt; or Japanese &lt;em&gt;kanji&lt;/em&gt; would know that this was hubristic. Although commonly used characters can fit under that amount, plenty of place names and surnames - and even some words - use rarer characters. The set of these is far too large to fit in that amount, so the Unicode Consortium eventually relented and developed &lt;a href=&#34;https://en.wikipedia.org/wiki/UTF-16&#34;&gt;surrogate pairs&lt;/a&gt; to encode a much larger set of characters. The original set became the &lt;a href=&#34;https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane&#34;&gt;Basic Multilingual Plane&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref2&#34;&gt;2&lt;/a&gt;
&lt;p&gt;Purely hypothetical, since Unicode has already gained so much adoption that realistically it is incredibly unlikely to be replaced. Which makes this article kind of grandstandy and in a certain sense pointless, but I digress.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref3&#34;&gt;3&lt;/a&gt;
&lt;p&gt;Except for ASCII characters in UTF-8, of course.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn4&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref4&#34;&gt;4&lt;/a&gt;
&lt;p&gt;By doing this, you assume all responsibility for modifying system files to remove the fonts that display these characters. The unimaginative reader would state that this is not possible on closed-down platforms like iOS, but a true ideologue would choose their platforms based on whether this is possible, or at the very least wait for an opportune security vulnerability.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn5&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref5&#34;&gt;5&lt;/a&gt;
&lt;p&gt;In fact, using them as decoration can be actively harmful as screen readers don&#39;t speak them properly. Apologies for being a spoilsport. And a hypocrite too, I guess.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
		</content>
		<author>
			<name>novov</name>
			<email>anon185441@gmail.com</email>
		</author>
	</entry>
	
	<entry>
		<title>Review: Cassette Beasts</title>
		<link href="https://novov.me/blog/posts/cassettebeastsreview" />
		<id>https://novov.me/blog/posts/cassettebeastsreview</id>
		<updated>2023-08-01T00:00:00+12:00</updated>
		<summary>A lot more than a ripoff.</summary>
		<content type="html">
			&lt;figure &gt;
			&lt;img alt=&#34;&#34; src=&#34;/images/blog/content/cassettebeasts.jpg&#34;/&gt;
			&lt;figcaption&gt;I didn&#39;t get the opportunity in this review to write about it, but the game also features a cool cassette-based battle UI.
&lt;/figcaption&gt;
		&lt;/figure&gt;
&lt;p&gt;For a long time, I&#39;ve been following the open-source &lt;a href=&#34;https://godotengine.org&#34;&gt;Godot Engine&lt;/a&gt; with keen interest. Although I&#39;ve never released any games myself, I agree with their vision of an open software-based game creation toolkit and am keen to see it succeed. So when two-person indie team Bytten Studio released &lt;em&gt;Cassette Beasts&lt;/em&gt; using it I decided to check it out.&lt;sup class=&#34;ref&#34; id=&#34;ref1&#34;&gt;&lt;a href=&#34;#fn1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; I had some experience with their previous game &lt;em&gt;Lenna&#39;s Inception&lt;/em&gt; - which I liked, but ultimately couldn&#39;t finish due to bugs in its Java-based runtime and procedural generation system. Thankfully, they ditched both of those for &lt;em&gt;Cassette Beasts&lt;/em&gt;, allowing me to play it to completion.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;1&#34;&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;p&gt;Cassette Beasts is the first Godot game to release across multiple console platforms and PC, or so I am told.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Most indie monster-catching games tend to be quite similar aesthetically to Pokémon - not that it&#39;s their fault. The billion-dollar franchise casts a long shadow over any potential competitors, and any customers will always have their nostalgia as a nigh-intractable benchmark.  &lt;em&gt;Cassette Beasts&lt;/em&gt; makes great pains judiciously distinguishing itself to alleviate this. Unlike many of its cohorts, its setting is pretty unique: adults (as opposed to children) are plucked out of multifarious timelines and universes and brought to the mysterious island of New Wirral. Although there are the requisite 128 different monsters to collect, they aesthetically take a rather different direction from &lt;em&gt;Pokémon&lt;/em&gt;; many being a melding of man-made and biological artifices almost reminiscent of the fauna of &lt;em&gt;Mother 3&lt;/em&gt;. Players are supposed to &#34;record&#34; these using cassettes, and transform into them in battle to do direct combat. This is a very cool thematic choice, albeit it is a bit weird at times; thankfully the game nicely handwaves it away rather than trying to make unsatisfying excuses. &lt;/p&gt;
&lt;p&gt;Still, it leaves a lot of questions. What if a player character transforms outside of battle? How long is a transformation maintained? Can they get stuck? Do the Traffikrabs and Salamaguses (Salamagi?) in the wild ever encounter a transformed human and get confused? Perhaps I am overthinking this, but there is still a whole lot of story potential left unexplored.&lt;sup class=&#34;ref&#34; id=&#34;ref2&#34;&gt;&lt;a href=&#34;#fn2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; The same can&#39;t be said of New Wirral: the game gives a satisfying and interesting, if a bit clichéd on a certain level, response to the mysteries of the island&#39;s existence. And as a whole, it contains a whole lot of narrative meat and mature heft which doesn&#39;t exist in many monster-catching titles.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;2&#34;&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;p&gt;Except, perhaps, in fanfic if that&#39;s your jam.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;hr /&gt;
&lt;p&gt;The gameplay also contains a number of welcome innovations. Types are similar to the classic &lt;em&gt;Pokémon&lt;/em&gt; formula, but different attacks apply status effects based on you and your opponent&#39;s types. This results in satisfying strategic ploys: if you choose the wrong combination, many available moves will end up giving your opponent a positive effect, so you&#39;ll either need to discard a turn switching to another monster, or factor the buff your enemy receives into your planning. Moves can also be swapped and changed, creating even more tactical variations, at the cost of making overpowered builds a tad too easy. Each member of your two-person team also has an AP meter: they accumulate a certain amount of AP per turn, and can either use it all immediately, or use a less expensive move and save the remaining AP for later moves. This creates immensely rewarding dynamics, and is honestly one of the best battle systems I&#39;ve seen in an RPG; combined with the aforementioned type-based attacks, it lends a large amount of depth to the game. A really neat mechanic that also enhances this is the &#34;fusion meter&#34;; when filled, you can combine your monster with your partner&#39;s for the duration of the battle.&lt;sup class=&#34;ref&#34; id=&#34;ref3&#34;&gt;&lt;a href=&#34;#fn3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; This fills up your AP really fast, letting you use really powerful moves each turn, and doubles your statistics. However, it leaves you more vulnerable as well, as enemies can all focus on a singular target and you are limited to one move a turn to fight back. &lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;3&#34;&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;p&gt;This is similar to some &lt;em&gt;Pokémon&lt;/em&gt; fangames, though it&#39;s only possible in battle, which will disappoint many people. Given the game has quite a few mechanics already, perhaps that&#39;s for the best though.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Unfortunately, all these mechanics become more of a burden when traversing areas with under-levelled beasts, which is a frustrating experience: they still try to approach you, yet are very easily beatable, their battle animations are long and repetitive, but the only item that lets you avoid battles is a consumable (there is a level scaling option, but it affects the rest of the game as well). And while the game is harder than the unconfronting easiness of &lt;em&gt;Pokémon&lt;/em&gt;, it still feels a bit unchallenging at times, and I ended up wishing I had chosen a more difficult AI setting from the get-go.&lt;/p&gt;
&lt;p&gt;Your party is (usually) made up of a customisable player character and a partner. Different partners are encountered throughout the game, and each has a unique quest associated with them, in addition to a few independent quests that spawn in the overworld. Compared to some RPGs, the quantity of non-story quests can sometimes be a bit threadbare, but the game was made by a small team, so it&#39;s understandable. As you fight alongside your partner and rest at campfires with them, you increase a relationship meter,&lt;sup class=&#34;ref&#34; id=&#34;ref4&#34;&gt;&lt;a href=&#34;#fn4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; progressing the narrative and granting additional gameplay powers, eventually even having the option of forming a romantic relationship. &lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;4&#34;&gt;&lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;p&gt;There&#39;s a lot of meters in the game, isn&#39;t there?&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;This adds a necessary element of narrative dimensionality that helps give purpose to the whole conceit of capturing hundreds of disparate creatures, and all the partners are well-written and distinct. My only qualm with them is that there could be a bit more late-game dialogue - again which is the side effect of an indie team. This all factors into the overarching plot, centered around the player attempting to leave New Wirral (albeit they still have the option of beating &lt;s&gt;Gym Leaders&lt;/s&gt; Rangers as a side quest). Unsurprisingly, it doesn&#39;t end up being a cakewalk, and many diversions and entertaining scenarios play out along the way, as is requisite for a good RPG story. I don&#39;t want to spoil too much, but there are some really interesting and unique monsters and setpieces that you encounter. &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;New Wirral is a rather small island; its meagre size is successfully compensated for by a tightly packed environment. There are no wide open expanses here: instead, every corner is packed with multiple chests, buildings, or points of interest, and the game&#39;s environments are punctuated with a large array of biomes to explore. Of course, these include monsters to capture, alongside &#34;rogue fusions&#34; of several different varieties for more challenging fights. The overworld also has full physics simulation, which is a rather odd decision by the developers. This choice has both upsides and downsides: it produces some neat puzzles and makes walking and jumping around that little bit more fun, but occasionally doing a task that would be straightforward in a more traditional RPG overworld environment requires a bit of finagling or guessing to arrive at the intended solution. &lt;/p&gt;
&lt;p&gt;As the player makes their away across the island, they utilise their fancy physics by unlocking different abilities (e.g. swimming or electromagnetism), which allow them to reach previously inaccessible locales. Some are optional, while others are required to progress; unfortunately a few of the latter are difficult to obtain naturally until coming across the right rumour from a townsperson. Overall though, it grants a nice sense of progression usually only obtained in other titles by levelling up: flying halfway across the island in the late game with previously impossible obstacles beneath really reminds me of how far I&#39;ve came.&lt;/p&gt;
&lt;p&gt;The visuals of the overworld employ an interesting style - although the characters and monsters are two-dimensional, they inhabit a three-dimensional world. For the most part this works very well and is excellently done; however, the limited size of its pixel art means that its character sprites can often lack the instant appeal of those seen in more recent &lt;em&gt;Pokémon&lt;/em&gt; games. For non-player characters, the game successfully compensates for this by featuring portraiture by &lt;a href=&#34;https://samibriggs.carrd.co&#34;&gt;Sami Briggs&lt;/a&gt; which excellently fleshes out their vibe and personality. This is obviously not possible for the player character - I had a bit of trouble coming up with an appealing one at first, and it took me quite a few tries before I found something I liked. &lt;/p&gt;
&lt;p&gt;Conversely, the ambient soundtrack, by Joel Baylis, the brother of one of the developers, hits all the right notes. It&#39;s further enhanced by vocals by singer Shelly Bailey, which play when you&#39;ve in important fights or inside buildings. There&#39;s only one other title that I&#39;ve played which uses this technique: magical school RPG &lt;a href=&#34;https://en.wikipedia.org/wiki/Ikenfell&#34;&gt;&lt;em&gt;Ikenfell&lt;/em&gt;&lt;/a&gt;,&lt;sup class=&#34;ref&#34; id=&#34;ref5&#34;&gt;&lt;a href=&#34;#fn5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; but I find it to be immensely entertaining (and a welcome reprieve from the blandness of many video game soundtracks) and wish many more games would have it. It does result in minor fights being sonically repetitive; a few more in the mix would help liven things up, but it can always be disabled and it&#39;s still better than not having it. &lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;5&#34;&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;p&gt;&lt;em&gt;Ikenfell&lt;/em&gt; is also really good in other aspects - you should check it out as well.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;hr /&gt;
&lt;p&gt;All these physics simulations and pretty visuals have an impact on the performance however, which can be a bit suboptimal at times, though it&#39;s never so bad that it impairs enjoying the game. As the player sees more of New Wirral, they experience a noticeable (yet again, hardly game-breaking) slowdown. And once they have explored all of the map,&lt;sup class=&#34;ref&#34; id=&#34;ref6&#34;&gt;&lt;a href=&#34;#fn6&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; a journey across it will inevitably be obstructed by a short intermission in the form of a loading screen. Fortunately, this can be alleviated by turning down the graphical settings, but I feel a computer with my specs should be more than powerful enough to run a game of this intensity without doing so, so it&#39;s still a little disappointing. &lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;6&#34;&gt;&lt;span class=&#34;number&#34;&gt;6&lt;/span&gt;&lt;p&gt;Which nets the requisite achievement, of course.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Console players might be in for a more difficult time, though: the game had showstopping slowdowns, bugs, and glitches on Nintendo Switch on launch, and while this has been improved upon in the 1.2 patch, it still isn&#39;t perfect. Apparently, it runs on the 3.0 branch of Godot, and while this may initially seem like a bad omen for the engine&#39;s console potential, both general performance optimisations and console-specific improvements are supposed to be present in 4.0.&lt;sup class=&#34;ref&#34; id=&#34;ref7&#34;&gt;&lt;a href=&#34;#fn7&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; &lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;7&#34;&gt;&lt;span class=&#34;number&#34;&gt;7&lt;/span&gt;&lt;p&gt;Though it is unlikely that &lt;em&gt;Cassette Beasts&lt;/em&gt; in particular will make the upgrade, as it is reputedly quite difficult, and there is already a veritable array of user mods based around the 3.0 version&#39;s API.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Inevitably, the Rangers have a variety of post-game busywork that needs doing, and much of it is doled out as quests that devolve into needless grinding. While some players have found this fun, needless to say I am not one of them. This is a rather disappointing design decision, since there are a number of bosses and encounters only accessible after doing a whole lot of it. Another post-game disappointment that I imagine many players will be put off by is the lack of player-vs-player combat, even if it&#39;s not something I personally care about. The developers have promised this will be added in an update though, and their track record has so far been great: a free patch has already added eight new monsters and a minor new location. In the meantime, I still recommend anyone interested in monster-catching games checks this out. It&#39;s a great showcase for Godot&#39;s capabilities, and although there&#39;s no chance it&#39;ll dethrone &lt;em&gt;Pokémon&lt;/em&gt; in people&#39;s hearts and minds, the developers make no pretences of doing so - there&#39;s plenty of room for both in the world.&lt;/p&gt;
&lt;article class=&#34;best&#34; id=&#34;rating&#34;&gt;&lt;img class=&#34;star&#34; src=&#34;/images/blog/superstar.jpg&#34; /&gt;&lt;span&gt;&lt;b&gt;
4.6&lt;/b&gt; out of 5 Novov Affirmation Points&lt;br /&gt;
Star Get! Novov really likes this!&lt;/span&gt;&lt;/article&gt;
&lt;ul id=&#34;footnotes&#34;&gt;
&lt;li id=&#34;fn1&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref1&#34;&gt;1&lt;/a&gt;
&lt;p&gt;Cassette Beasts is the first Godot game to release across multiple console platforms and PC, or so I am told.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref2&#34;&gt;2&lt;/a&gt;
&lt;p&gt;Except, perhaps, in fanfic if that&#39;s your jam.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref3&#34;&gt;3&lt;/a&gt;
&lt;p&gt;This is similar to some &lt;em&gt;Pokémon&lt;/em&gt; fangames, though it&#39;s only possible in battle, which will disappoint many people. Given the game has quite a few mechanics already, perhaps that&#39;s for the best though.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn4&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref4&#34;&gt;4&lt;/a&gt;
&lt;p&gt;There&#39;s a lot of meters in the game, isn&#39;t there?&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn5&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref5&#34;&gt;5&lt;/a&gt;
&lt;p&gt;&lt;em&gt;Ikenfell&lt;/em&gt; is also really good in other aspects - you should check it out as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn6&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref6&#34;&gt;6&lt;/a&gt;
&lt;p&gt;Which nets the requisite achievement, of course.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn7&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref7&#34;&gt;7&lt;/a&gt;
&lt;p&gt;Though it is unlikely that &lt;em&gt;Cassette Beasts&lt;/em&gt; in particular will make the upgrade, as it is reputedly quite difficult, and there is already a veritable array of user mods based around the 3.0 version&#39;s API.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
		</content>
		<author>
			<name>novov</name>
			<email>anon185441@gmail.com</email>
		</author>
	</entry>
	
	<entry>
		<title>Mixed Memories</title>
		<link href="https://novov.me/blog/posts/mixedmemories" />
		<id>https://novov.me/blog/posts/mixedmemories</id>
		<updated>2023-07-09T00:00:00+12:00</updated>
		<summary>Why do macOS programs show different amounts of used memory?</summary>
		<content type="html">
			&lt;p&gt;For most Mac users, determining the amount of memory used is pretty simple. You go into Activity Monitor and have a look at the Memory tab. &lt;/p&gt;
&lt;figure class=&#34;small&#34;&gt;
			&lt;img alt=&#34;&#34; src=&#34;/images/blog/content/activitymonitor.jpg&#34;/&gt;
			&lt;figcaption&gt;Activity Monitor even gives us different subcategories of memory usage, which is nice. But as we will see soon, very simplified.
&lt;/figcaption&gt;
		&lt;/figure&gt;
&lt;p&gt;The more technically inclined might go one step further, and use something like &lt;a href=&#34;https://bjango.com/mac/istatmenus/&#34;&gt;iStat Menus&lt;/a&gt; or &lt;a href=&#34;https://github.com/dylanaraps/neofetch&#34;&gt;&lt;code&gt;neofetch&lt;/code&gt;&lt;/a&gt;. I&#39;m too cheap to buy a license for the former, so let&#39;s have a look at the latter.&lt;/p&gt;
&lt;figure class=&#34;light&#34;&gt;
			&lt;img alt=&#34;&#34; src=&#34;/images/blog/content/neofetch.png&#34;/&gt;
			&lt;figcaption&gt;Looks like memory to me.
&lt;/figcaption&gt;
		&lt;/figure&gt;
&lt;hr /&gt;
&lt;p&gt;But they&#39;ll quickly notice a small problem: the amount of used memory can sometimes be different.&lt;sup class=&#34;ref&#34; id=&#34;ref1&#34;&gt;&lt;a href=&#34;#fn1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; And while in this case, one is in mebibytes and the other in megabytes,&lt;sup class=&#34;ref&#34; id=&#34;ref2&#34;&gt;&lt;a href=&#34;#fn2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; the difference still doesn&#39;t line up when you do the conversion. So let&#39;s go one step lower and query the amount of memory by compiling a little executable in a trendy programming language such as &lt;a href=&#34;https://www.rust-lang.org&#34;&gt;Rust&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&#34;long&#34;&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;1&#34;&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;p&gt;This has actually been &lt;a href=&#34;https://github.com/dylanaraps/neofetch/pull/1752&#34;&gt;rectified&lt;/a&gt; in the Neofetch codebase, but a new version hasn&#39;t been released for quite a while.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;2&#34;&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;p&gt;Some people define storage sizes in terms of 1024-byte multiples, while others use a system based on 1000 bytes. Usually, this tends to depend on whether they have an incentive to show a higher number of KBs, GBs, MBs, and such. To stop confusion, standards bodies have redefined 1024-byte units as &lt;em&gt;mebibytes&lt;/em&gt; (MiB), &lt;em&gt;kibibytes&lt;/em&gt; (KiB), &lt;em&gt;gibibytes&lt;/em&gt; (GiB), etc - though many manufacturers still don&#39;t adhere to such a distinction.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted rust&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sysinfo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SystemExt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;print!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;{mem_used} bytes / {mem} bytes&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_used&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;used_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;total_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted text&#34;&gt;Compiling test_crate v0.0.1 (file path redacted)
    Finished dev [unoptimized + debuginfo] target(s) in 0.26s
    Running `target/debug/test_crate`
15674580992 bytes / 17179869184 bytes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, that isn&#39;t helpful. Let&#39;s actually have a look at going on here. Unfortunately, Activity Monitor isn&#39;t open source,&lt;sup class=&#34;ref&#34; id=&#34;ref3&#34;&gt;&lt;a href=&#34;#fn3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; but we &lt;em&gt;can&lt;/em&gt; have a look at the internals of the &lt;code&gt;neofetch&lt;/code&gt; source code and the &lt;code&gt;sysinfo&lt;/code&gt; crate I used. I&#39;m going to start with the former.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;3&#34;&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;p&gt;Shocker!&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;At its core, Neofetch is a &lt;a href=&#34;https://github.com/dylanaraps/neofetch/blob/60d07dee6b76769d8c487a40639fb7b5a1a7bc85/neofetch&#34;&gt;one-file Bash script&lt;/a&gt; that handles all its functionality for a variety of (largely Unix-like, but also Windows) operating systems. It is divided into different functions, each of which is used to obtain the appropriate statistics for the respective category. We want the &lt;code&gt;get_memory()&lt;/code&gt; function. It&#39;s divided into cases for different operating systems, so we&#39;ll grab the section of code that gets the macOS info.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted rust&#34;&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Mac OS X&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;macOS&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;iPhone OS&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_total&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;$(($(sysctl -n hw.memsize) / 1024 / 1024))&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_wired&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;$(vm_stat | awk &amp;#39;/ wired/ { print $4 }&amp;#39;)&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_active&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;$(vm_stat | awk &amp;#39;/ active/ { printf $3 }&amp;#39;)&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_compressed&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;$(vm_stat | awk &amp;#39;/ occupied/ { printf $5 }&amp;#39;)&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_compressed&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;${mem_compressed:-0}&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_used&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;$(((${mem_wired//.} + ${mem_active//.} + ${mem_compressed//.}) * 4 / 1024))&amp;quot;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As one can see, in typical Unix fashion, it calls a number of small utilities to gather the amount of used memory and total memory. In this function, they are &lt;code&gt;sysctl&lt;/code&gt;, which is a command-line tool that allows querying system statistics, and &lt;code&gt;vm_stat&lt;/code&gt;, which lists off various Mach kernel&lt;sup class=&#34;ref&#34; id=&#34;ref4&#34;&gt;&lt;a href=&#34;#fn4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; memory statistics. &lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;4&#34;&gt;&lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Mach_%28kernel%29&#34;&gt;Mach&lt;/a&gt; is the name of the kernel that was eventually developed into the XNU kernel behind macOS. One of the key tasks behind a kernel like it is to allocate and manage memory.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;First, it grabs the total memory and divides it twice to convert it into mebibytes. It then pulls together &lt;em&gt;wired memory&lt;/em&gt;, &lt;em&gt;active memory&lt;/em&gt;, and &lt;em&gt;compressed memory&lt;/em&gt; to compute the used memory. Since the figures it uses are in pages, it then uses the page size&lt;sup class=&#34;ref&#34; id=&#34;ref5&#34;&gt;&lt;a href=&#34;#fn5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; to convert these pages into bytes, and then divides it as it did with the total memory.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;5&#34;&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;p&gt;Memory is divided up into units called &lt;em&gt;pages&lt;/em&gt; internally by the operating system.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Now, let&#39;s look at the Rust &lt;code&gt;sysinfo&lt;/code&gt;  crate I used earlier:&lt;/p&gt;
&lt;p&gt;Much of the library is composed of OS-specific code that lives in its respective folder. In our case, that&#39;s &lt;code&gt;src/apple&lt;/code&gt;, for macOS and iOS code. In particular, we want the functions under &lt;code&gt;SystemExt&lt;/code&gt;, so we&#39;ll grab &lt;a href=&#34;https://github.com/GuillaumeGomez/sysinfo/blob/master/src/apple/system.rs&#34;&gt;&lt;code&gt;src/apple/system.rs&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;highlighted rust&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// get ram info&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_total&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_sys_value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CTL_HW&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;HW_MEMSIZE&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size_of&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_total&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c_void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mib&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u32&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;HOST_VM_INFO64_COUNT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stat&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;zeroed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm_statistics64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host_statistics64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;HOST_VM_INFO64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stat&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm_statistics64&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;KERN_SUCCESS&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// From the apple documentation:&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// /*&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//  * NB: speculative pages are already accounted for in &amp;quot;free_count&amp;quot;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//  * so &amp;quot;speculative_count&amp;quot; is the number of &amp;quot;free&amp;quot; pages that are&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//  * used to hold data that was read speculatively from disk but&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//  * haven&amp;#39;t actually been used by anyone so far.&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//  */&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_available&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;free_count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;saturating_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;inactive_count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;saturating_mul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;page_size_kb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_free&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;free_count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;saturating_sub&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;speculative_count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;saturating_mul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;page_size_kb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Further down, the used memory is computed by subtracting &lt;code&gt;mem_free&lt;/code&gt; from &lt;code&gt;mem_total&lt;/code&gt;. Makes sense, I guess. As for the calculations themselves, they are obtained via macOS system calls, which is more efficient than launching a number of Unix command-line processes. The total memory is retreived using the same system call as Neofetch (&lt;code&gt;hw.memsize&lt;/code&gt;), but it uses the system function &lt;code&gt;sysctlbyname&lt;/code&gt; directly, rather than the intermediary &lt;code&gt;sysctl&lt;/code&gt; terminal utility. Obtaining the free memory is done with the &lt;code&gt;host_statistics64&lt;/code&gt; function, which is what &lt;code&gt;vm_stat&lt;/code&gt; uses &lt;a href=&#34;https://github.com/apple-oss-distributions/system_cmds/blob/system_cmds-951.60.2/vm_stat.tproj/vm_stat.c&#34;&gt;underneath the hood&lt;/a&gt; as well. However, what it does with those values is different than Neofetch: the crate obtains the system&#39;s internal count of free pages, and then (&lt;a href=&#34;https://en.wikipedia.org/wiki/Saturation_arithmetic&#34;&gt;saturatedly&lt;/a&gt;) subtracts speculative pages from them. &lt;/p&gt;
&lt;p&gt;Speculative pages hold data grabbed ahead of time that the kernel thinks currently running processes &lt;em&gt;might&lt;/em&gt; need later. But as the comment in the code says, they aren&#39;t used by anyone yet, and they&#39;ve also pretty easily evicted if the memory is needed for more important uses, so they aren&#39;t really &#34;used&#34; in a way that causes problems. In other words, the Rust &lt;code&gt;sysinfo&lt;/code&gt; crate&#39;s quite a bit stricter in its definition of what counts as &#34;free&#34; memory: any page that is occupied so far, even if it&#39;s not actually used by a program yet, is considered &#34;used&#34;. The line between free and used memory is blurrier and more subjective than it may initially appear. So let&#39;s clear few things up.&lt;/p&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Memory size&lt;/strong&gt;, as you probably know if you&#39;ve reading this, is the amount of memory (to be specific, RAM, or short-term data, as opposed to files on disk) a computer can store. It can be obtained via &lt;code&gt;sysctl -n hw.memsize&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Page size&lt;/strong&gt; is how big a page is in bytes. On Intel Macs, it&#39;s 4096 bytes (4 KiB); Apple silicon Macs are four times larger at 16 KiB. It can be obtained via &lt;code&gt;sysctl -n hw.pagesize&lt;/code&gt; or the top line of &lt;code&gt;vm_stat&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;!-----&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Free memory&lt;/strong&gt; in technical terms is memory that is being used for absolutely nothing.&lt;sup class=&#34;ref&#34; id=&#34;ref6&#34;&gt;&lt;a href=&#34;#fn6&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; It can be obtained by &lt;code&gt;vmstat&lt;/code&gt;&#39;s &#34;Pages free&#34;&lt;sup class=&#34;ref&#34; id=&#34;ref7&#34;&gt;&lt;a href=&#34;#fn7&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; section or &lt;code&gt;sysctl -n vm.page_free_count&lt;/code&gt; (like &lt;code&gt;sysinfo&lt;/code&gt;, these counts exclude speculative memory).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Speculative memory&lt;/strong&gt; is, as stated above, memory that the kernel thinks currently obtained processes may need later, but can be easily evicted for more space. It can be obtained by &lt;code&gt;vmstat&lt;/code&gt;&#39;s &#34;Pages speculative&#34; section, or &lt;code&gt;sysctl -n vm.page_speculative_count&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wired memory&lt;/strong&gt; is memory that is used by the kernel to run essential system processes. It is essentially occupied by the kernel and cannot be freed. It can be obtained by &lt;code&gt;vmstat&lt;/code&gt;&#39;s &#34;Pages wired down&#34; section, or &#34;Wired memory&#34; under Activity Monitor&#39;s Memory tab.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Active memory&lt;/strong&gt; is memory that is being used right now. As in, right this moment, while you&#39;ve reading this. It can be obtained by &lt;code&gt;vmstat&lt;/code&gt;&#39;s &#34;Pages active&#34; section.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inactive memory&lt;/strong&gt; is memory that isn&#39;t used right now, but could be needed, and again can be evicted for more space if necessary. It can be obtained by &lt;code&gt;vmstat&lt;/code&gt;&#39;s &#34;Pages inactive&#34; section.&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Compressed memory&lt;/strong&gt; is inactive memory that is compressed to save RAM space. It can be obtained by &lt;code&gt;vmstat&lt;/code&gt;&#39;s &#34;Pages occupied by compressor&#34; section, or &#34;Compressed&#34; under Activity Monitor&#39;s Memory tab.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;6&#34;&gt;&lt;span class=&#34;number&#34;&gt;6&lt;/span&gt;&lt;p&gt;&amp;lt;insert tumbleweed gif&amp;gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;7&#34;&gt;&lt;span class=&#34;number&#34;&gt;7&lt;/span&gt;&lt;p&gt;The numbers in &lt;code&gt;vm_stat&lt;/code&gt; are the amount of pages, while numbers obtained by &lt;code&gt;sysctl&lt;/code&gt; are usually either bytes or pages.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;!-----&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Anonymous memory&lt;/strong&gt; is memory that isn&#39;t connected to a file on the file system (i.e. is manually allocated by applications). It can be obtained using &lt;code&gt;vmstat&lt;/code&gt;&#39;s &#34;Anonymous pages&#34; section, and is roughly equivalent to &lt;code&gt;sysctl -n vm.page_pageable_internal_count&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File-backed memory&lt;/strong&gt; is the opposite of anonymous memory: memory that &lt;em&gt;is&lt;/em&gt; connected to a file. It can be obtained by &lt;code&gt;vmstat&lt;/code&gt;&#39;s &#34;File-backed pages&#34; section, or &#34;Cached Files&#34; under Activity Monitor&#39;s Memory tab.&lt;/li&gt;
&lt;/ul&gt;
&lt;!-----&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Purgeable memory&lt;/strong&gt; is memory that is designated by app developers as being safely freeable if the OS requires more space (and recreated again later when needed). It can be obtained via &lt;code&gt;vmstat&lt;/code&gt;&#39;s &#34;Pages purgeable&#34; section.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pageable memory&lt;/strong&gt; is memory that can be paged to disk (swap) if the OS runs out of space and no other memory can be freed. In systems with sufficient memory, paging is very rare, but the classfication is still used internally. It can be obtained via &lt;code&gt;sysctl -n vm.page_pageable_internal_count&lt;/code&gt; and &lt;code&gt;sysctl -n vm.page_pageable_external_count&lt;/code&gt;. Swap is available as &#34;Swap Used&#34; under Activity Monitor.&lt;/li&gt;
&lt;/ul&gt;
&lt;!-----&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Application memory&lt;/strong&gt; is a high-level construct used by Activity Monitor that approximates core memory used by apps. Although the formula isn&#39;t publicly available, it appears to be anonymous memory that isn&#39;t purgeable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The issue is obvious: different sources calculate the memory different ways. Neofetch adds wired, active, and compressed memory. The Rust &lt;code&gt;sysinfo&lt;/code&gt; crate gives everything that is not strictly free. And Activity Monitor, although its&#39; method isn&#39;t publicly available, seems to add application memory, wired memory, and compressed memory. As for which one is the most accurate, it depends on what you mean really. Perhaps &lt;code&gt;sysinfo&lt;/code&gt; is the most strictly accurate, but it&#39;s very unhelpful for day-to-day usage.&lt;/p&gt;
&lt;ul id=&#34;footnotes&#34;&gt;
&lt;li id=&#34;fn1&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref1&#34;&gt;1&lt;/a&gt;
&lt;p&gt;This has actually been &lt;a href=&#34;https://github.com/dylanaraps/neofetch/pull/1752&#34;&gt;rectified&lt;/a&gt; in the Neofetch codebase, but a new version hasn&#39;t been released for quite a while.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref2&#34;&gt;2&lt;/a&gt;
&lt;p&gt;Some people define storage sizes in terms of 1024-byte multiples, while others use a system based on 1000 bytes. Usually, this tends to depend on whether they have an incentive to show a higher number of KBs, GBs, MBs, and such. To stop confusion, standards bodies have redefined 1024-byte units as &lt;em&gt;mebibytes&lt;/em&gt; (MiB), &lt;em&gt;kibibytes&lt;/em&gt; (KiB), &lt;em&gt;gibibytes&lt;/em&gt; (GiB), etc - though many manufacturers still don&#39;t adhere to such a distinction.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref3&#34;&gt;3&lt;/a&gt;
&lt;p&gt;Shocker!&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn4&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref4&#34;&gt;4&lt;/a&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Mach_%28kernel%29&#34;&gt;Mach&lt;/a&gt; is the name of the kernel that was eventually developed into the XNU kernel behind macOS. One of the key tasks behind a kernel like it is to allocate and manage memory.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn5&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref5&#34;&gt;5&lt;/a&gt;
&lt;p&gt;Memory is divided up into units called &lt;em&gt;pages&lt;/em&gt; internally by the operating system.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn6&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref6&#34;&gt;6&lt;/a&gt;
&lt;p&gt;&amp;lt;insert tumbleweed gif&amp;gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn7&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref7&#34;&gt;7&lt;/a&gt;
&lt;p&gt;The numbers in &lt;code&gt;vm_stat&lt;/code&gt; are the amount of pages, while numbers obtained by &lt;code&gt;sysctl&lt;/code&gt; are usually either bytes or pages.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
		</content>
		<author>
			<name>novov</name>
			<email>anon185441@gmail.com</email>
		</author>
	</entry>
	
	<entry>
		<title>Review: Omori</title>
		<link href="https://novov.me/blog/posts/omorireview" />
		<id>https://novov.me/blog/posts/omorireview</id>
		<updated>2021-06-14T00:00:00+12:00</updated>
		<summary>Extremely entertaining and a great exploration of mental health.</summary>
		<content type="html">
			&lt;figure &gt;
			&lt;img alt=&#34;&#34; src=&#34;/images/blog/content/omori.jpg&#34;/&gt;
			&lt;figcaption&gt;The battle system in this game is heaps of fun.
&lt;/figcaption&gt;
		&lt;/figure&gt;
&lt;p&gt;&lt;span class=&#34;warning&#34;&gt;This blog post deals with mental health issues.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;When I was a little boy, I sometimes wondered: why do people get depressed? I was quite naïve sometimes.&lt;/p&gt;
&lt;p&gt;Slowly, things changed though. As I grew older and (arguably) wiser, I slowly but surely succumbed murky depths of mental illness myself. It started off slowly, but soon right became wrong and left became right, Thoughts and reality started to blur together. Voices started echoing in my head, telling me everything I was doing was wrong - not just incorrect, but morally depraved. I&#39;d never make anything of myself, and I&#39;d be a failure for the rest of my life. I&#39;d always be an awful person, and I&#39;d never make anything of myself.&lt;/p&gt;
&lt;p&gt;I tried to hold things in for as long as I could, to not disappoint both myself and my family. To tell everyone who doubted me that they were wrong. Eventually, though, the symptoms became too much for others as well, and I had to confine myself to my house...&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;In 2014, &lt;em&gt;Omori&lt;/em&gt; was launched on Kickstarter. It was initially planned for a release date in 2015, so plenty of eager backers forked over their cold, hard, cash. Soon, it became apparent that wouldn&#39;t happen. News of engine troubles and changes in creative direction spread over social media, and &lt;a href=&#34;https://www.reddit.com/r/shittykickstarters/comments/aopi6i/&#34;&gt;many people didn&#39;t think it would release at all.&lt;/a&gt;&lt;sup class=&#34;ref&#34; id=&#34;ref1&#34;&gt;&lt;a href=&#34;#fn1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; But to a lot of people&#39;s shock, it did eventually come out - in 2020, when many people were far more concerned with the minor issue of the coronavirus.&lt;sup class=&#34;ref&#34; id=&#34;ref2&#34;&gt;&lt;a href=&#34;#fn2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; Personally, I&#39;d say the wait was well worth it.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;1&#34;&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;p&gt;Kickstarter has gained a bit of a reputation as a grifters&#39; paradise - a not undeserved one, given the profusion of blatant scams on the platform. But from my experience, video game failures on the platform tend to be less often scams and more often people who just don&#39;t understand the amount of work involved.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;2&#34;&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;p&gt;Or 5G, if you&#39;ve an idiot.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;It&#39;s a psychological horror role-playing game about the titular child Omori. Living in a rather miserable white room, he often takes a trip to the colourful dream-like world outside. There, he plays with his friends Aubrey, Kel, Hero, and Basil, going on adventures and doing things that kids do. But at the start of the game, Basil has just gone missing.&lt;/p&gt;
&lt;p&gt;Actually, let&#39;s start again. &lt;em&gt;Omori&lt;/em&gt; is a psychological horror role-playing game about... Never mind. You &lt;em&gt;could&lt;/em&gt; spoil yourself by, say reading the game&#39;s &lt;a href=&#34;https://en.wikipedia.org/wiki/Omori_(video_game)&#34;&gt;Wikipedia article&lt;/a&gt;&lt;sup class=&#34;ref&#34; id=&#34;ref3&#34;&gt;&lt;a href=&#34;#fn3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, but I would highly recommend you don&#39;t. Anyway, onto the game. While certain parts can be dark, this is balanced with a softer exterior; overall, the game takes plenty of cues from your &lt;em&gt;EarthBound&lt;/em&gt;s and &lt;em&gt;Undertale&lt;/em&gt;s. An aura of juvenile wonder permeates many of the environments, in a way that feels a little familiar from my childhood. But just like real life, we all grow up; one has to confront the darker recesses of the world eventually. It&#39;s just a question of how and when.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;3&#34;&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;p&gt;Disclaimer: I wrote significant parts of said article.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;hr /&gt;
&lt;p&gt;Unlike the events depicted in &lt;em&gt;Omori&lt;/em&gt;, I decided long ago that I wouldn&#39;t be stuck in my house for almost four years. Instead, I largely remained stuck in my house for a year. Big improvement. Though the game&#39;s plot differs from my experience in a lot of ways, many things in the game were familiar to me. Feeling like an outcast; a dreg of society. Having to hide fucked-up things that happened to me from other people.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Regardless of what ends up happening to them, the cast of &lt;em&gt;Omori&lt;/em&gt; are largely empathetic and well-written. Both the main gang and side characters deal with their own issues that often tie into the central narrative fulcrum in a unique way. A specific highlight is a certain cetacean who pops up just before one of the game&#39;s dramatic moments. His depiction - a concoction of hilarity and zaniness - just oozes creativity. &lt;/p&gt;
&lt;p&gt;As a role-playing game, the battle system is a largely turn-based affair. I&#39;m a huge fan of classic turn-based JRPGs, and disagree with them often being maligned by modern gamers. Although it doesn&#39;t have the strategic chops to compete with the best of them, the combat is fun and challenging enough. But the real draw is its unique mechanics: status effects involve dealing with a triadic system of emotions. You have &lt;strong&gt;Happy&lt;/strong&gt;, which pulls your turn forward, but at the cost of accuracy. &lt;strong&gt;Angry&lt;/strong&gt; raises your attack but makes you more vulnerable as well. And &lt;strong&gt;Sad&lt;/strong&gt; raises defence but puts you at the back of the turn list. Both enemies and party members can have these emotions applied to them by choice or not, and each one has another that it&#39;s strong or weak against. It&#39;s a fun twist that shakes things up, although it can be underused in later parts of the game. Your party&#39;s damage also accumulates, allowing you to deal powerful &#34;follow-ups&#34; that interact with a friend. Often they&#39;ve &lt;em&gt;too&lt;/em&gt; powerful and make things a little too easy: I was able to complete the game under-leveled. Despite that, they can still be really fun to use against enemies. &lt;/p&gt;
&lt;p&gt;Speaking of the enemies, they&#39;ve depicted in a hand-illustrated style that exudes charm and creativity. In fact, the whole game&#39;s art is simply amazing - there&#39;s no other way to describe it. It&#39;s able to hone in on the requisite playfulness when required, and make things properly scary for the more spoilery parts of the game. A lot of neat artistic touches and narrative elements attain another layer of meaning as you progress, and things reveal themselves in hindsight. Unlike the &lt;a href=&#34;/blog/posts/cometruereview.html&#34;&gt;film I reviewed in April&lt;/a&gt;, it doesn&#39;t feel hackneyed in the moment either.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Scary stories used to absolutely horrify me as a kid. When making my many requisite trips to the library as a kid, the &lt;em&gt;Goosebumps&lt;/em&gt; books were a no-go; I always sticked to the safety of known entities. Growing older, the fear of the unknown became replaced by a fear of the known. These days, I can read and watch metric craploads of horror content and hardly break a sweat. I&#39;m still not a &lt;em&gt;huge&lt;/em&gt; horror fan, but I find what I&#39;ve been through in real life much more scary. Going crazy is a lot more tangible and horrifying than your monster &lt;em&gt;du jour&lt;/em&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;As a game that primarily deals with a fear of the known, &lt;em&gt;Omori&lt;/em&gt; resonates with me a lot. Although it&#39;s a bit of an overused trope in indie circles, depicting this kind of stuff is no mean feat. Everyone deals with mental illness differently, and one person&#39;s &#34;realistic&#34; might be the next&#39;s &#34;playing into harmful stereotypes in an exceedingly problematic way&#34;. While a certain knife initially made me turn my head, I found things were ultimately portrayed respectfully and realistically. The game juggles with heaps of issues in a way that is honestly pretty impressive for something made in RPG Maker.&lt;sup class=&#34;ref&#34; id=&#34;ref4&#34;&gt;&lt;a href=&#34;#fn4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; I actually forgot it was made in that engine sometimes; the level of thought and flair would be great for even a Unity title.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;4&#34;&gt;&lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;p&gt;As someone who&#39;s really into programming, I used to be of the attitude that people should just use &lt;em&gt;proper&lt;/em&gt; game engines. However, such an attitude locks out a lot of creatives with imaginative and original ideas. In my opinion, it&#39;s really the result that matters; tools are ultimately incidental.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;This amount of care is also invested into a veritable array of side-quests. Most of it is the usual fare, allowing the dedicated player to level up their party that much more and discover tidbits of hidden story content. For instance, you can find humorous quips on signs to put in a &#34;Joke Book&#34;; collecting them all provides an optional quest. But being the un-dedicated player I am, I mostly looked stuff up on the wiki afterwards. If there&#39;s one complaint I have, it&#39;s that the inscrutability and haphazardness sometimes also applies to the primary gameplay route, making it a bit frustrating to progress at times. If you&#39;ve more easily scared than I and make a certain decision early on, you can even be locked into a certain narrative choice. But as someone who can be frustrated about getting the wrong ending, that moment is an exception to the rules. This isn&#39;t one of those games where you need to be watching every step so you get ending 45 instead of ending 46, and the important decisions are usually clear enough.&lt;/p&gt;
&lt;p&gt;In &lt;em&gt;Omori&lt;/em&gt;&#39;s final act, the results of whatever decision you make come back to haunt you for great or ill. Its ending is a real shock, something that ties all the narrative points and thematic beats of the game into something spectacular. In fact, it&#39;s easily one of the best endings I&#39;ve experienced in a video game. Again, I won&#39;t delve into the details, since you should really be &lt;a href=&#34;https://store.steampowered.com/app/1150690/OMORI/&#34;&gt;just playing the game&lt;/a&gt;.&lt;sup class=&#34;ref&#34; id=&#34;ref5&#34;&gt;&lt;a href=&#34;#fn5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; Yes, I&#39;m saying that again - there&#39;s some things you just can&#39;t hide from. Some people can learn to deal with their issues; some cannot. But they&#39;ll always be there.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;5&#34;&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;p&gt;Don&#39;t get ahead of someone when crossing the river in the raft.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;article class=&#34;best&#34; id=&#34;rating&#34;&gt;&lt;img class=&#34;star&#34; src=&#34;/images/blog/superstar.jpg&#34; /&gt;&lt;span&gt;&lt;b&gt;
4.8&lt;/b&gt; out of 5 Novov Affirmation Points&lt;br /&gt;
Star Get! Novov really likes this!&lt;/span&gt;&lt;/article&gt;
&lt;ul id=&#34;footnotes&#34;&gt;
&lt;li id=&#34;fn1&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref1&#34;&gt;1&lt;/a&gt;
&lt;p&gt;Kickstarter has gained a bit of a reputation as a grifters&#39; paradise - a not undeserved one, given the profusion of blatant scams on the platform. But from my experience, video game failures on the platform tend to be less often scams and more often people who just don&#39;t understand the amount of work involved.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref2&#34;&gt;2&lt;/a&gt;
&lt;p&gt;Or 5G, if you&#39;ve an idiot.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref3&#34;&gt;3&lt;/a&gt;
&lt;p&gt;Disclaimer: I wrote significant parts of said article.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn4&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref4&#34;&gt;4&lt;/a&gt;
&lt;p&gt;As someone who&#39;s really into programming, I used to be of the attitude that people should just use &lt;em&gt;proper&lt;/em&gt; game engines. However, such an attitude locks out a lot of creatives with imaginative and original ideas. In my opinion, it&#39;s really the result that matters; tools are ultimately incidental.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn5&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref5&#34;&gt;5&lt;/a&gt;
&lt;p&gt;Don&#39;t get ahead of someone when crossing the river in the raft.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
		</content>
		<author>
			<name>novov</name>
			<email>anon185441@gmail.com</email>
		</author>
	</entry>
	
	<entry>
		<title>Review: Come True</title>
		<link href="https://novov.me/blog/posts/cometruereview" />
		<id>https://novov.me/blog/posts/cometruereview</id>
		<updated>2021-04-03T00:00:00+12:00</updated>
		<summary>For some reason, I'm now doing film reviews. This one is... a mixed bag.</summary>
		<content type="html">
			&lt;figure &gt;
			&lt;img alt=&#34;&#34; src=&#34;/images/blog/content/cometrue.jpg&#34;/&gt;
			&lt;figcaption&gt;Unfortunately, Sarah (Julia Sarah Stone) might be frustrated at some of this movie&#39;s inconsistent plot points.
&lt;/figcaption&gt;
		&lt;/figure&gt;
&lt;p&gt;When I started this blog, I was envisioning some in-depth essays about computing and stuff.&lt;sup class=&#34;ref&#34; id=&#34;ref1&#34;&gt;&lt;a href=&#34;#fn1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; So far, this hasn&#39;t panned out, and unfortunately (or fortunately, depending on your tastes) I feel lazy enough to keep it that way, at least for now. Sorry.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;1&#34;&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;p&gt;I still have a list of around 10 ideas for posts that I tell myself I&#39;ll get around to eventually... or so I tell myself.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Instead, I&#39;m taking a sharp right turn and reviewing a horror movie. Well, horror with sci-fi elements. I&#39;ve been a fan of director &lt;a href=&#34;https://twitter.com/realpilotpriest&#34;&gt;Anthony Scott Burns&lt;/a&gt;&#39; music and oeuvre of short films for a long time. Burns takes a lot of inspiration from the oft-vaunted horror greats - a fact that he makes sure to mention on social media - but also manages to put his own unique spin on things. His second entry into feature films&lt;sup class=&#34;ref&#34; id=&#34;ref2&#34;&gt;&lt;a href=&#34;#fn2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; is his take on one of the classic thematic staples: dreams. As Burns says...&lt;sup class=&#34;ref&#34; id=&#34;ref3&#34;&gt;&lt;a href=&#34;#fn3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;2&#34;&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;p&gt;Although Burns had previously directed &lt;em&gt;Our House&lt;/em&gt;, he feels that the final result didn&#39;t comport with his creative vision. Again, this is something which he&#39;s not afraid to share.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;3&#34;&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;p&gt;&lt;span class=&#34;duprefs&#34;&gt;and &lt;a href=&#34;#ref3b&#34;&gt;3b&lt;/a&gt;&lt;/span&gt;
&lt;a href=&#34;https://www.vulture.com/2021/03/come-true-sees-straight-into-your-nightmares.html&#34;&gt;&lt;em&gt;Come True&lt;/em&gt; Sees Straight Into Your Nightmares&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;blockquote&gt;
&lt;p&gt;Dreams are highly intriguing. It’s where we work out our issues, who we are, what we fear.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;We all have dreams, but &lt;em&gt;Come True&lt;/em&gt;&#39;s main character, 18-year-old Sarah (Julia Sarah Stone) has rather horrifying ones, constantly waking up in the middle of the night. This is exacerbated by an unspecified feud with her mother,&lt;sup class=&#34;ref&#34; id=&#34;ref4&#34;&gt;&lt;a href=&#34;#fn4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; forcing her to sleep in parks, classrooms, and playgrounds. When she sees the notice for a sleep study, it seems like it is just what she needs. She&#39;ll have somewhere to sleep, and all she&#39;ll have to do is ask a few questions. Well, that&#39;s what it seems like at least.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;4&#34;&gt;&lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;p&gt;Burns is somewhat light on the narrative, a detail which I&#39;ll touch on more later.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;It&#39;s an enticing premise, and Burns knows how to make the opening acts of the film compelling. Although he is rather light on the plot detail - fair enough, given its unimportance - you still end up keenly sympathising with Sarah&#39;s situation. In a way, this choice is an ominous sign of things to come later in the film. In horror, there are always clues to problems lurking around the corner, and this is no exception. &lt;/p&gt;
&lt;p&gt;Unfortunately, the nightmare sequences aren&#39;t very interesting. Although they can be legitimately frightening and suspenseful at times, too often they are overlong and of increasingly distant relevance to the film&#39;s plot - that is, until the very end, where they bounce back into relevance like a boomerang. Until then, they are some of the least interesting aspects of the film. The same can be said about some of the non-oneiric scenes: often you see Burns leave the camera rolling a little bit too long.&lt;/p&gt;
&lt;p&gt;Nevertheless, Burns manages to set the film&#39;s tone with gusto. The dream-like atmosphere is complemented by long, partially-lit hallways, churning rows of cathode-ray monitors and control panels, and ominously lit scientists monitoring our protagonist. Apparently, Burns himself did the VFX in addition to the cinematography and direction, but were I not informed of that, I wouldn&#39;t have noticed a thing. Backing the score is the appropriately ethereal sound of synth-pop duo Electric Youth, working alongside solo artist Pilotpriest (aka Anthony Scott Burns as well). It&#39;s great stuff, and their reprise of &#34;Modern Fears&#34; stands out in particular. All these elements unite to comprise a somewhat disconnected and dreamy take on the 80s retro sci-fi vibe &lt;i&gt;du jour&lt;/i&gt;, clearly inspired by films such as &lt;i&gt;Alien&lt;/i&gt; and &lt;i&gt;Altered States&lt;/i&gt;. However, Burns pulls it off exceedingly well  - particularly impressive given his name is on the credits more times than in a Hideo Kojima game.&lt;/p&gt;
&lt;p&gt;As the film progresses, things start to go a little more pear-shaped. The chief researcher is an appropriately wisened old guy, but a particular nerdy young scientist, Jeremy (Landon Liboiron) takes a perverse interest in Sarah, breaking rules and scientific ethics for her. Through him, we discover that the study is investigating the technology to peer into dreams, and appropriately unsettling things are starting to occur. At first, Jeremy&#39;s role is an excellent subversion of misogynistic writing, but a certain later scene feels voyeuristic and seems to reinforce those same tired old tropes. In the second half of the film, he shows up much more prominently. Again, this is a hint that Burns has left about what&#39;s coming, and I&#39;m talking about the film&#39;s quality as well...&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;The last portion of the film - i.e. the final one or two acts,&lt;sup class=&#34;ref&#34; id=&#34;ref5&#34;&gt;&lt;a href=&#34;#fn5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; is easily the worst half, and I don&#39;t say that lightly. Progressively, the plot gets choppier and more thematically dissonant. The pacing gets a lot worse, and the story seems to lead nowhere. Certain details stretch plausibility, and characters vanish from the film. Some of this can be explained by a detail later in the film, but given the viewer doesn&#39;t know that yet, it just seems like bad writing. Although I&#39;m not big on the cruciality of screenwriting, this quote&lt;sup class=&#34;ref&#34; id=&#34;ref3b&#34;&gt;&lt;a href=&#34;#fn3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; from Burns explains a lot:&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;5&#34;&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;p&gt;All of the acts are names after Jungian psychological concepts, which also feature heavily in the film. This feels a bit tired, and although most viewers wouldn&#39;t notice or care, outdated to me given the discrediting of much of Jung&#39;s ideas.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;3&#34;&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;p&gt;&lt;span class=&#34;duprefs&#34;&gt;and &lt;a href=&#34;#ref3b&#34;&gt;3b&lt;/a&gt;&lt;/span&gt;
&lt;a href=&#34;https://www.vulture.com/2021/03/come-true-sees-straight-into-your-nightmares.html&#34;&gt;&lt;em&gt;Come True&lt;/em&gt; Sees Straight Into Your Nightmares&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;blockquote&gt;
&lt;p&gt;For me, making movies is more about resting on emotion than a perfect screenplay.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is all of in service of an ending which feels both unrewarding and cliché. It&#39;s very controversial online, and though I personally didn&#39;t like it, it&#39;s at least interesting. Ideally, I&#39;d create something new from whole cloth, but I&#39;d at least change the way which the final twist is revealed, which reads like an internet meme. I wouldn&#39;t be surprised if Burns was inspired by an insipid Reddit joke; if he was, props to him for at least making a good three-quarters of a film out of it.&lt;/p&gt;
&lt;p&gt;Still, despite the disappointing conclusion, Burns shows a lot of potential, reminding me why I liked his previous work. His use of atmosphere and tone is marvellous, and given the mixed opinions online, you might even like the ending. It&#39;s a movie of highs and lows, one that&#39;s worth watching despite its flaws. No matter what happens, I&#39;d like to see what he creates next.&lt;sup class=&#34;ref&#34; id=&#34;ref6&#34;&gt;&lt;a href=&#34;#fn6&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;6&#34;&gt;&lt;span class=&#34;number&#34;&gt;6&lt;/span&gt;&lt;p&gt;Hopefully he doesn&#39;t promote Joe Rogan again though.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;article id=&#34;rating&#34;&gt;&lt;img class=&#34;star&#34; src=&#34;/images/blog/star.jpg&#34; /&gt;&lt;span&gt;&lt;b&gt;
3.83&lt;/b&gt; out of 5 Novov Affirmation Points&lt;/span&gt;&lt;/article&gt;
&lt;ul id=&#34;footnotes&#34;&gt;
&lt;li id=&#34;fn1&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref1&#34;&gt;1&lt;/a&gt;
&lt;p&gt;I still have a list of around 10 ideas for posts that I tell myself I&#39;ll get around to eventually... or so I tell myself.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref2&#34;&gt;2&lt;/a&gt;
&lt;p&gt;Although Burns had previously directed &lt;em&gt;Our House&lt;/em&gt;, he feels that the final result didn&#39;t comport with his creative vision. Again, this is something which he&#39;s not afraid to share.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref3&#34;&gt;3&lt;/a&gt;
&lt;p&gt;&lt;span class=&#34;duprefs&#34;&gt;and &lt;a href=&#34;#ref3b&#34;&gt;3b&lt;/a&gt;&lt;/span&gt;
&lt;a href=&#34;https://www.vulture.com/2021/03/come-true-sees-straight-into-your-nightmares.html&#34;&gt;&lt;em&gt;Come True&lt;/em&gt; Sees Straight Into Your Nightmares&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn4&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref4&#34;&gt;4&lt;/a&gt;
&lt;p&gt;Burns is somewhat light on the narrative, a detail which I&#39;ll touch on more later.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn5&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref5&#34;&gt;5&lt;/a&gt;
&lt;p&gt;All of the acts are names after Jungian psychological concepts, which also feature heavily in the film. This feels a bit tired, and although most viewers wouldn&#39;t notice or care, outdated to me given the discrediting of much of Jung&#39;s ideas.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn6&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref6&#34;&gt;6&lt;/a&gt;
&lt;p&gt;Hopefully he doesn&#39;t promote Joe Rogan again though.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
		</content>
		<author>
			<name>novov</name>
			<email>anon185441@gmail.com</email>
		</author>
	</entry>
	
	<entry>
		<title>Confessions</title>
		<link href="https://novov.me/blog/posts/confessions" />
		<id>https://novov.me/blog/posts/confessions</id>
		<updated>2021-02-14T00:00:00+12:00</updated>
		<summary>Unfortunately, by that I don't mean the revealing kind... Well, kind of.</summary>
		<content type="html">
			&lt;p&gt;In the later 1800s, the &lt;a href=&#34;https://en.wikipedia.org/wiki/Confession_album&#34;&gt;&lt;em&gt;confession album&lt;/em&gt;&lt;/a&gt; was a popular fixture in British culture. The name had nothing to do with people&#39;s deepest, darkest secrets, though the &#34;confessions&#34; within were of a somewhat personal and revealing nature. It gained prominence for about fifty years, before falling (well, mostly) out of fashion.&lt;/p&gt;
&lt;p&gt;Like so many cultural elements of years bygone, today the confession album has fallen out largely out of usage. It only really survives in two forms: the &lt;a href=&#34;https://en.wikipedia.org/wiki/Proust_Questionnaire&#34;&gt;Proust Questionnaire&lt;/a&gt; used for interviews with the famous and distinguished, and in the Netherlands and Germany, books for little kids. &lt;/p&gt;
&lt;p&gt;But I see no reason for it to stay that way - self-reflection is a quality just as valuable in adults as well, and celebrities are in the greater scheme of things no more important than the common man. Plus, it&#39;s a great way of discovering what kind of person someone is - or at least what kind of person the want to be or think they are.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I&#39;ve taken the liberty of assembling my own list of questions here, with my answers.&lt;sup class=&#34;ref&#34; id=&#34;ref1&#34;&gt;&lt;a href=&#34;#fn1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; Feel free to use it, so long as you provide attribution.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;1&#34;&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;p&gt;Based partially on the Proust Questionnaire, partially on one &lt;a href=&#34;https://www.marxists.org/archive/marx/works/1865/04/01.htm&#34;&gt;Karl Marx&lt;/a&gt; answered, and a few questions of my own.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Favourite virtue&lt;/td&gt;
&lt;td&gt;Selflessness, honesty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chief purpose in life&lt;/td&gt;
&lt;td&gt;To make the world a better place, to enjoy life, to create&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Greatest challenge in life&lt;/td&gt;
&lt;td&gt;To define oneself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Personal idea of happiness&lt;/td&gt;
&lt;td&gt;A nice book next to a fireplace; lack of worries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Personal idea of misery&lt;/td&gt;
&lt;td&gt;Losing your sense of self&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vice you excuse most&lt;/td&gt;
&lt;td&gt;Pride&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vice you hate most&lt;/td&gt;
&lt;td&gt;Selfishness, dishonesty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Principal personal vice&lt;/td&gt;
&lt;td&gt;Pride&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Principal aversion&lt;/td&gt;
&lt;td&gt;Excess&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best test of character&lt;/td&gt;
&lt;td&gt;How someone treats those in need, or that society looks down upon&lt;sup class=&#34;ref&#34; id=&#34;ref2&#34;&gt;&lt;a href=&#34;#fn2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Favourite visual artist&lt;/td&gt;
&lt;td&gt;Albrecht Durer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Favourite medium of art&lt;/td&gt;
&lt;td&gt;Illustration, 2D animation, electronic music&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Favourite hero&lt;sup class=&#34;ref&#34; id=&#34;ref3&#34;&gt;&lt;a href=&#34;#fn3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/td&gt;
&lt;td&gt;Stanislav Petrov&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Favourite colour&lt;/td&gt;
&lt;td&gt;Green&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Favourite food&lt;/td&gt;
&lt;td&gt;Anything sweet, sausage rolls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Favourite flower&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Metrosideros_excelsa&#34;&gt;Pohutukawa&lt;/a&gt;, hibiscus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Favourite ice cream flavour&lt;/td&gt;
&lt;td&gt;Cookies and cream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Favourite potato chip flavour&lt;/td&gt;
&lt;td&gt;Chicken (reasonably common in New Zealand)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Favourite motto&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;/heraldry.html&#34;&gt;&lt;em&gt;Lucem porta in tenebris&lt;/em&gt;&lt;/a&gt;, &lt;a href=&#34;https://www.biblegateway.com/passage/?search=John+8%3A32&#34;&gt;John 8:32&lt;/a&gt;&lt;sup class=&#34;ref&#34; id=&#34;ref4&#34;&gt;&lt;a href=&#34;#fn4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Favourite academic discipline&lt;/td&gt;
&lt;td&gt;Psychology, computer science, history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Favourite mammal&lt;/td&gt;
&lt;td&gt;Cat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dream home&lt;/td&gt;
&lt;td&gt;A wooden hut in the woods, with nobody else around for miles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trolley problem&lt;sup class=&#34;ref&#34; id=&#34;ref5&#34;&gt;&lt;a href=&#34;#fn5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/td&gt;
&lt;td&gt;Pull the lever&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cat or dog person&lt;/td&gt;
&lt;td&gt;Cat, but I like both&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weirdness or blandness&lt;/td&gt;
&lt;td&gt;Weirdness&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;2&#34;&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;p&gt;Of course, excluding people who have done legitimately done horrible things, like serial killers. You could argue that morals are societal, but that&#39;s beyond the scope of this.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;3&#34;&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;p&gt;This can be either real or fictional - or both.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;4&#34;&gt;&lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;p&gt;I&#39;m not a Christian; I just like the quote&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;5&#34;&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Trolley_problem&#34;&gt;https://en.wikipedia.org/wiki/Trolley_problem&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;ul id=&#34;footnotes&#34;&gt;
&lt;li id=&#34;fn1&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref1&#34;&gt;1&lt;/a&gt;
&lt;p&gt;Based partially on the Proust Questionnaire, partially on one &lt;a href=&#34;https://www.marxists.org/archive/marx/works/1865/04/01.htm&#34;&gt;Karl Marx&lt;/a&gt; answered, and a few questions of my own.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref2&#34;&gt;2&lt;/a&gt;
&lt;p&gt;Of course, excluding people who have done legitimately done horrible things, like serial killers. You could argue that morals are societal, but that&#39;s beyond the scope of this.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref3&#34;&gt;3&lt;/a&gt;
&lt;p&gt;This can be either real or fictional - or both.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn4&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref4&#34;&gt;4&lt;/a&gt;
&lt;p&gt;I&#39;m not a Christian; I just like the quote&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn5&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref5&#34;&gt;5&lt;/a&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Trolley_problem&#34;&gt;https://en.wikipedia.org/wiki/Trolley_problem&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
		</content>
		<author>
			<name>novov</name>
			<email>anon185441@gmail.com</email>
		</author>
	</entry>
	
	<entry>
		<title>Twenty Years</title>
		<link href="https://novov.me/blog/posts/twentyyears" />
		<id>https://novov.me/blog/posts/twentyyears</id>
		<updated>2021-01-15T00:00:00+12:00</updated>
		<summary>Wikipedia celebrates its twentieth anniversary.</summary>
		<content type="html">
			&lt;p&gt;&lt;img alt=&#34;The Wikipedia article for &amp;quot;Anniversary&amp;quot;, with a characteristic template notice about uncited words.&#34; src=&#34;/images/blog/content/anniversary.jpg&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Twenty years ago, online encyclopedia Wikipedia was born with surprisingly little fanfare. Starting as an offshoot of the more conventional expert-contributor website &lt;a href=&#34;https://en.wikipedia.org/wiki/Nupedia&#34;&gt;Nupedia&lt;/a&gt;, it was conceived as little more than a flash-in-the-pan experiment. Nobody would have predicted then that it would turn into one of the web&#39;s most essential reference works, a veritable repository of information both informative and interesting - but occasionally inaccurate. &lt;sup&gt;[&lt;a href=&#34;https://en.wikipedia.org/wiki/Wikipedia:Citation_needed&#34;&gt;&lt;em&gt;citation needed&lt;/em&gt;&lt;/a&gt;]&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;And although it has problems with power-tripping admins and over-zealous editors, I&#39;m happy that it&#39;s there. The community is a testament to the power of the common man without the all too frequent handicap represented by the profit motive, and I hope it stays that way for many years to come. Here&#39;s to twenty more!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I&#39;ve been editing on Wikipedia for a much measlier six years, and have been an active editor for about three, first as User:Axisixa and now as &lt;a href=&#34;https://en.wikipedia.org/wiki/User:Mir_Novov&#34;&gt;User:Mir Novov&lt;/a&gt;. Although most of my changes&lt;sup class=&#34;ref&#34; id=&#34;ref1&#34;&gt;&lt;a href=&#34;#fn1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; have been spelling corrections there and adding citations here - typical for an Wikipedia editor - I have got to create a few articles as well:&lt;sup class=&#34;ref&#34; id=&#34;ref2&#34;&gt;&lt;a href=&#34;#fn2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;1&#34;&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;p&gt;Around 1100 in total, which is actually pretty small for an active editor of my vintage.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;2&#34;&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;p&gt;Note that you don&#39;t &#34;own&#34; Wikipedia articles that you create. In accord with the wiki ethos, all articles are released into the ether as a public good free for anyone to modify.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/ToaruOS&#34;&gt;ToaruOS&lt;/a&gt; - an hobby operating system. Not bad, states the facts but little else, partially due to lack of sources.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Simon_Stålenhag&#34;&gt;Simon Stålenhag&lt;/a&gt; - an illustrator focusing on retrofuturistic artwork. Appears in my &lt;a href=&#34;/liked/art/&#34;&gt;Art I like&lt;/a&gt; page, so this is partially out of personal bias, though I&#39;ve made sure to make it neutral, as is &lt;a href=&#34;https://en.wikipedia.org/wiki/Wikipedia:Neutral_point_of_view&#34;&gt;standard Wikipedia practice&lt;/a&gt;. Melds together his personal life and artwork into one section, which is a bad decision.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/OneShot&#34;&gt;OneShot&lt;/a&gt; - an metafictional video game. My favourite out of all the articles I helped create; although it could be improved some more, this is largely due to improper sourcing and bad writing skills.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/IAmA&#34;&gt;IAmA&lt;/a&gt; - a content split from the Reddit article, in particular, the section on its &lt;span class=&#34;nowrap&#34;&gt;I Am A...&lt;/span&gt;/Ask Me Anything subreddit. The content was largely written by others, and it needed to go since it was getting unwieldy. Could probably be transmuted into a more general &#34;ask me anything&#34; article, as the format is very popular outside of Reddit.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;More than any donations,&lt;sup class=&#34;ref&#34; id=&#34;ref3&#34;&gt;&lt;a href=&#34;#fn3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; Wikipedia needs more editors. Maybe you could add information definitions to &lt;a href=&#34;https://en.wiktionary.org/&#34;&gt;Wiktionary&lt;/a&gt; or free media to &lt;a href=&#34;https://commons.wikimedia.org&#34;&gt;Commons&lt;/a&gt; or &lt;a href=&#34;https://en.wikisource.org/&#34;&gt;Wikisource&lt;/a&gt; if that&#39;s more your jam, but unfortunately, they have a far smaller reach. Ignoring that, I found that the &lt;a href=&#34;https://en.wikipedia.org/wiki/Help:Introduction&#34;&gt;&lt;strong&gt;official introduction&lt;/strong&gt;&lt;/a&gt; helped me quite a bit when I started.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;3&#34;&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;p&gt;Cup of coffee etc etc. The &lt;a href=&#34;http://archive.org/web/&#34;&gt;Internet Archive&lt;/a&gt; needs your money more.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Even though I started using the web from a young age, I&#39;m still amazed by the stuff that Wikipedia offers - check out my &lt;a href=&#34;/linkroll/&#34;&gt;linkroll&lt;/a&gt; for some cool things out there.  If you decide to become an editor, you&#39;d be contributing to an ever-growing mass of digital information accessible to anyone in the world (with internet). I know it sounds quite cheesy, but I find that quite powerful. Knowledge deserves to be free. &lt;/p&gt;
&lt;ul id=&#34;footnotes&#34;&gt;
&lt;li id=&#34;fn1&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref1&#34;&gt;1&lt;/a&gt;
&lt;p&gt;Around 1100 in total, which is actually pretty small for an active editor of my vintage.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref2&#34;&gt;2&lt;/a&gt;
&lt;p&gt;Note that you don&#39;t &#34;own&#34; Wikipedia articles that you create. In accord with the wiki ethos, all articles are released into the ether as a public good free for anyone to modify.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref3&#34;&gt;3&lt;/a&gt;
&lt;p&gt;Cup of coffee etc etc. The &lt;a href=&#34;http://archive.org/web/&#34;&gt;Internet Archive&lt;/a&gt; needs your money more.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
		</content>
		<author>
			<name>novov</name>
			<email>anon185441@gmail.com</email>
		</author>
	</entry>
	
	<entry>
		<title>Gone in a Flash</title>
		<link href="https://novov.me/blog/posts/goneinaflash" />
		<id>https://novov.me/blog/posts/goneinaflash</id>
		<updated>2021-01-02T00:00:00+12:00</updated>
		<summary>Adobe Flash is dead, and that's both a good and a bad thing.</summary>
		<content type="html">
			&lt;figure class=&#34;light&#34;&gt;
			&lt;img alt=&#34;&#34; src=&#34;/images/blog/content/flash.jpg&#34;/&gt;
			&lt;figcaption&gt;The notice on Adobe&#39;s website.
&lt;/figcaption&gt;
		&lt;/figure&gt;
&lt;p&gt;On 1 January 2021, Adobe Flash was discontinued. In fact, Adobe went so far as to say that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Adobe strongly recommends all users immediately uninstall Flash Player to help protect their systems.  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you&#39;ve reading this, you should do the same - Flash has more holes than a block of Swiss cheese. I already uninstalled Flash with the advent of Safari 14 - which doesn&#39;t support it. This has been a long time coming. &lt;/p&gt;
&lt;p&gt;Flash, although initially a simple tool for animations, soon had grown into a more complex one supplementing every facet of web design. This came with consequences: a bevy of security issues, high usage requirements, and frequent crashes for any system that dared run it. A crowd of naysayers quickly developed around the technology, especially as open standards like HTML, JavaScript, and CSS became more advanced. &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Chief among them was Apple&#39;s polarising and sometimes problematic CEO Steve Jobs, who decided to exclude Flash from the iPhone. In his manifesto &lt;a href=&#34;https://web.archive.org/web/20200430094807/https://www.apple.com/hotnews/thoughts-on-flash/&#34;&gt;&lt;em&gt;Thoughts on Flash&lt;/em&gt;&lt;/a&gt;, he listed his problems with it. It wouldn&#39;t run quickly on the power-efficient iPhone OS (now iOS). It was proprietary. It was unreliable. And it was insecure.&lt;sup class=&#34;ref&#34; id=&#34;ref1&#34;&gt;&lt;a href=&#34;#fn1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;1&#34;&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;p&gt;To be fair, Jobs probably had additional ulterior motives in that Flash was competition to the App Store.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;At the time, his piece received both &lt;a href=&#34;https://news.ycombinator.com/item?id=1304310&#34;&gt;support and strong criticism&lt;/a&gt;. Many viewed the Flash-less iPhone as handicapped, and Apple as wanting to stifle innovation. But the fact that Flash never took hold on the rival Android operating system proved its critics right. And with the corporate mothership now behind the rising sentiment, Flash begun to fall.&lt;/p&gt;
&lt;p&gt;According to the &lt;a href=&#34;https://twitter.com/ratten_matthias/status/1341974889859665920&#34;&gt;internet consensus&lt;/a&gt;, Flash is a nostalgic part of the web that was mercilessly snuffed out. I too have plenty of nostalgia for the software: I grew up using it to play weird online games, interact with stuff, and... design kitchen layouts. Yes, the last one is true.&lt;sup class=&#34;ref&#34; id=&#34;ref2&#34;&gt;&lt;a href=&#34;#fn2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; I&#39;m still convinced that the web is better off without it though. In addition to its many intractable problems, it&#39;s basically one company&#39;s toehold into the open web. Great emulation software like &lt;a href=&#34;https://ruffle.rs&#34;&gt;Ruffle&lt;/a&gt; and &lt;a href=&#34;https://github.com/swf2js/swf2js&#34;&gt;swf2js&lt;/a&gt; exists to carry its torch.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;2&#34;&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;p&gt;As a kid, I used to spend hours on the websites of cabinet makers and car manufacturers designing the ideal versions of their products. They get you while you&#39;re young.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Nevertheless, I see where its supporters are coming from. Flash represents a time where the web was free for all. When everyone had their own site instead of being funnelled through mega-corporations. When netizens were more than commodities. When going online elicited wonder instead of frustration and alienation. But Flash just happened to die at an ominous time. And although my early web experience was more satisfying, in some ways it was never more than an ideal - remember AOL?&lt;/p&gt;
&lt;p&gt;The Flash design tools were also great for quick content creation.&lt;sup class=&#34;ref&#34; id=&#34;ref3&#34;&gt;&lt;a href=&#34;#fn3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; The art of creating an early HTML page or spinning up an SWF has not been quite replicated - although there are projects out there trying to do it. Web design is now inaccessible to the beginner, an impenetrable stack composed of a million different technologies.&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;3&#34;&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;p&gt;Or so I&#39;m told.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;hr /&gt;
&lt;p&gt;And although Flash is gone, what replaced it has issues in itself. The HTML/CSS/JS stack has become what it sought to destroy. Although ostensibly free, it is controlled by one company in practice: Google has dominance over both Chrome and search to such a degree that a newcomer couldn&#39;t hope to compete.&lt;sup class=&#34;ref&#34; id=&#34;ref4&#34;&gt;&lt;a href=&#34;#fn4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;aside&gt;
&lt;div class=&#34;asideRef&#34; data-id-ref=&#34;4&#34;&gt;&lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;p&gt;Think of the last time there&#39;s been innovation in the web search arena. Google&#39;s monopoly means there&#39;s no incentive, and their control of search essentially means they gatekeep the web.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;ul id=&#34;footnotes&#34;&gt;
&lt;li id=&#34;fn1&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref1&#34;&gt;1&lt;/a&gt;
&lt;p&gt;To be fair, Jobs probably had additional ulterior motives in that Flash was competition to the App Store.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref2&#34;&gt;2&lt;/a&gt;
&lt;p&gt;As a kid, I used to spend hours on the websites of cabinet makers and car manufacturers designing the ideal versions of their products. They get you while you&#39;re young.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref3&#34;&gt;3&lt;/a&gt;
&lt;p&gt;Or so I&#39;m told.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn4&#34;&gt;
&lt;a class=&#34;backref&#34; href=&#34;#ref4&#34;&gt;4&lt;/a&gt;
&lt;p&gt;Think of the last time there&#39;s been innovation in the web search arena. Google&#39;s monopoly means there&#39;s no incentive, and their control of search essentially means they gatekeep the web.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
		</content>
		<author>
			<name>novov</name>
			<email>anon185441@gmail.com</email>
		</author>
	</entry>
	</feed>