<?xml version="1.0" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Vale.Rocks Posts</title>
    <description>Long form writings about assorted topics.</description>
    <link>https://vale.rocks/posts</link>
    <atom:link href="https://vale.rocks/posts/feed.xml" rel="self" type="application/rss+xml"/>
    <item>
      <pubDate>Tue, 06 Oct 2026 00:00:00 GMT</pubDate>
      <title>Beauty in DVD Menus</title>
      <link>https://vale.rocks/posts/dvd-menus</link>
      <guid>https://vale.rocks/posts/dvd-menus</guid>
      <description>Understanding of DVD video menus for films and series. The technical details of how menus were implemented and what functions were available for creating menus, a look at the influence of aspect ratios and how menu designs changed and became more ambitious before returning to boring, and specific looks at some of the most memorable DVD menus released.</description>
      <content:encoded><![CDATA[
			
			
			<p>Look at many early <abbr title="Digital Video Disc">DVD</abbr> releases, and you&#8217;ll see interactive menus touted as a selling point. Coming from <abbr title="Video Home System">VHS</abbr> (or LaserDisc), which had no menus to speak of, this was a genuine improvement. That isn&#8217;t to say all <abbr>DVD</abbr>s had interactive menus, however. Many of the earliest releases just entered straight into their content, and the same is true of some cheaper releases.</p>
<p>However, once <abbr>DVD</abbr> became widespread, publishers started to really embrace the capabilities the format afforded them. The format first released in late 1996; however it wasn&#8217;t until the 2000s that they really kicked off. With the medium&#8217;s strengths and foibles known, players widely adopted, and technology ready to handle the task, <abbr>DVD</abbr>s hit their stride. With this came some brilliant and memorable menus.</p>
<h2 id="resolution--aspect-ratio">Resolution & Aspect Ratio</h2>
<p>In <abbr title="National Television System Committee">NTSC</abbr> regions video on <abbr>DVD</abbr> almost always has a resolution of 720 × 480 pixels, while in <abbr title="Phase Alternating Line">PAL</abbr> regions they&#8217;re almost always 720 × 576 pixels. These specific resolutions can be traced back to the <a href="https://en.wikipedia.org/wiki/D-1_(Sony)">D-1</a>, a digital recording video standard which stored uncompressed component video. It was a major leap in real-time, high-quality recording when it released in 1986 and quickly achieved ubiquity. It derived its resolution from the <a href="https://en.wikipedia.org/wiki/Rec._601">Rec. 601/BT.601/<abbr>CCIR</abbr> 601</a> standard from 1982.</p>
<p><a href="https://en.wikipedia.org/wiki/DVD-Video#Video_data">Other resolutions are possible</a>, however are rarely used for having worse quality and generally being a poor trade-off. You may notice that <abbr>NTSC</abbr>&#8217;s resolution of 720 × 480 pixels is a ratio of 3:2 and that <abbr>PAL</abbr>&#8217;s is a resolution of 5:4. The <abbr>DVD</abbr> has metadata tags telling the playback device how to then stretch the video to the desired aspect ratio for correct appearance in viewing. This is the difference between Storage Aspect Ratio (<abbr>SAR</abbr>), which is the ratio on the disc, and Display Aspect Ratio (<abbr>DAR</abbr>) or Pixel Aspect Ratio (<abbr>PAR</abbr>), which is the ratio in presentation.</p>
<p>Due to the transition from 4:3 aspect ratios on home displays to 16:9, there were a lot of fluctuations in <abbr>DVD</abbr> presentation. From widescreen that was forced to fit within a 4:3 area via letterboxing, to pan and scan, to anamorphic widescreen, there was variation in presentation. With <abbr>DVD</abbr> menus, we see exactly the same as was true in the <a href="https://vale.rocks/micros/20260715-0450">transitioning era of broadcast television, where critical information was kept within the 4:3 safe area</a>, while non-critical, flavour imagery was within the 16:9 only area.</p>
<p>Even releases long after most people had migrated to widescreen, 16:9 displays continue to keep everything within this small safe area. It became a major design consideration of <abbr>DVD</abbr> menus that has stuck around even if no longer strictly necessary.</p>
<h2 id="menu-features">Menu Features</h2>
<p><abbr>DVD</abbr> menus can take many forms, though they tend to have a fairly typical set of options. More often than not, a play button, a chapter/scene/episode select, special features or extras, and settings, including subtitle, language, audio, and picture options. At the very simplest, these are displayed in a list with a static image background. At the most decadent, there are full custom animations or acting with diegetic menus and layers of content designed specifically for the <abbr>DVD</abbr> &#8211; oodles of extra content and hidden additions crammed into every nook until the disc can&#8217;t hold anything more.</p>
<p>Being developed in the mid-1990s, <abbr>DVD</abbr>s are fairly simple in terms of technical capabilities. The picture shown by a <abbr>DVD</abbr> is a standard <abbr>MPEG</abbr>-2 video stream. For interactive elements, like menu items which highlight when hovered, or an overlay on the presentation, subpictures are used. Subpictures are 2-bit, meaning they only support four colours at a time. These colours are pulled from a palette, which is a defined set of 16 colours. The transparency can also be altered by adjusting the contrast level. Subtitles are handled by the same means. Interestingly, they&#8217;re graphics too &#8211; not text. Douglas Dixon&#8217;s <a href="https://www.manifest-tech.com/links/dvd_terms.htm"><abbr>DVD</abbr> Authoring Terminology</a> has a nice overview of many of the finer technical details.</p>
<p>Within the <abbr>DVD</abbr> Virtual Machine (<abbr>DVD</abbr> VM), there are sixteen General Parameter Registers (<abbr>GPRM</abbr>s). These are variables which hold 16-bit integers, allowing a tiny bit of memory for some details, such as chosen settings. Beside the <abbr>GPRM</abbr>s are twenty-four System Parameter Registers (<abbr>SPRM</abbr>s), which are read-only and are managed by the <abbr>DVD</abbr> player itself, storing the device-level details. The <abbr>DVD</abbr> VM <a href="https://en.wikibooks.org/wiki/Inside_DVD-Video/Interaction_Machine">Interaction Machine</a>, which allows handling what happens on user interaction, is extremely basic, making the ability for people to make such interesting, expressive, and complex menus very impressive. <abbr>DVD</abbr> games<sup><a id="footnote-ref-1" href="#footnote-1" data-footnote-ref aria-describedby="footnote-label">1</a></sup> particularly exploited all the memory and interaction functionality to the fullest extents possible.</p>
<p>Menus often feature looping clips and audio that don&#8217;t quite seamlessly repeat or have abrupt endings, which are the subject of much nostalgic reminiscing, with many stories online of people waking in early hours of the morning to find a <abbr>DVD</abbr> menu on loop.</p>
<p>Some publishers had a degree of consistency across their <abbr>DVD</abbr> catalogue. One <abbr>DVD</abbr> menu feature ingrained deep into the back of my mind is <a href="https://disney.go.com/disneyvideos/fastplay/home.html">Disney&#8217;s FastPlay</a>. Designed to make their <abbr>DVD</abbr>s more accessible, especially to children potentially unable to manage the remote, it automatically starts playing the disc&#8217;s content without need for viewer interaction. In function, this really means that it often plays trailers before the feature presentation, leading many viewers to avoid it.</p>
<figure class="shorter">
<img src="/assets/posts/dvd-menus/disney-fastplay.avif" alt="A DVD and the logo 'Disney's FastPlay' on a blue background. At the bottom are two buttons, one reading 'FastPlay' and the other reading 'Main Menu'.">
<figcaption>Disney&#8217;s FastPlay screen which would appear upon loading a disc.</figcaption>
</figure><p>FastPlay supporting <abbr>DVD</abbr>s <a href="https://www.youtube.com/watch?v=wjGtXYiOgu4">open with</a> Tinkerbell flying onto the screen while a voiceover states:</p>
<blockquote>
<p>This Disney <abbr>DVD</abbr> is enhanced with Disney&#8217;s FastPlay. Your movie and a selection of bonus features will begin automatically. To bypass FastPlay, select the &#8216;Main Menu&#8217; button at anytime. FastPlay will begin in a moment!</p>
</blockquote>
<p>Debuting at the same time in 2004, many Disney <abbr>DVD</abbr>s often also feature what they call <a href="https://disney.go.com/disneyvideos/fastplay/easyfind.html">EasyFind menus</a>, which provide a consistent set of options with a consistent set of accompanying graphics for ease of use.</p>
<p>More modern <abbr>DVD</abbr> releases often forgo additional special features. Even standards like most setup options and scene/chapter selection are often absent as discs are spat out quickly, crammed into a template. Special features are reserved for the more expensive Blu-ray releases.</p>
<h2 id="memorable-menus">Memorable Menus</h2>
<p>Scooby-Doo 2: Monsters Unleashed had a very fun menu. The main screen showed Scooby Doo and various monsters messing about in an old mining town, and when selecting a menu item, it would play a transition into another place from the film with further animations of Scooby-Doo fooling around. Each section had full custom <abbr>3D</abbr> animations, and two games playable directly on the <abbr>DVD</abbr> player were included on the disc.</p>
<p>The first, <em>Behind-the-Mystery Mystery: The Mystery of the Missing Pants</em>, could be started in a special feature and then required you to navigate through the <abbr>DVD</abbr>&#8217;s menu to find an icon of pants to continue along the story. The next, much more complete game was <em>The Scooby-Doo Monsters Unleashed Challenge</em>, which had you as the player driving around in the Mystery Machine to various locations from the film, navigating through the locations, and collecting clues that would help unravel the mystery.</p>
<figure class="left">
<img src="/assets/posts/dvd-menus/scooby-doo-2-game.avif" alt="A creepy old manor with green walls. A red, grid carpet stretches the floor, and beams of light illuminate specific squares.">
<figcaption>A part of the Monsters Unleashed Challenge where you must pick the correct path across the floor to navigate forward. Stepping on a trapped tile shows a failure clip from the film.</figcaption>
</figure><p>Due to the limitations of <abbr>DVD</abbr>s, the entire game is relatively simple in terms of mechanics; however, it is obvious a lot of effort was put into it to make it feel comprehensive, and it really plays to the strengths of the medium with lots of little clips and sections. One section has the player figuring out the path over a trapped floor, and another involves attacking skeletons in a warehouse while not hitting Scooby, just like Whack-A-Mole.</p>
<p>Scooby-Doo 2 also came with a teaser trailer for another movie with a fantastic <abbr>DVD</abbr> menu: <em>Harry Potter and the Prisoner of Azkaban</em>. After a little opener showing some clips from the film, the Prisoner of Azkaban&#8217;s <abbr>DVD</abbr> placed you on the Knight Bus from the film, zooming through the streets of London while the shrunken head quips. Different menus on the <abbr>DVD</abbr> stayed true to the theme, with the scene selection being themed after The Daily Prophet newspaper.</p>
<p>Shrek 2&#8217;s original menu is memorable primarily for the main Brady Bunch-esque screen. It features the film&#8217;s main characters all quibbling at each other (and particularly with Donkey). The disc is also packed with content, with the ability to view a lot of art, read about the cast and details about the film, listen to music, explore an interactive map, and play multiple games (<em>Far Far Away Idol</em>, <em>Find Puss In Boots</em>, and <em>Save Fiona!</em>), among other things. It is extremely full of things to look through and poke at.</p>
<figure class="shorter">
<img src="/assets/posts/dvd-menus/shrek-2.avif" alt="A bright green background with windows containing various characters for the film representing each menu item. Donkey is in the middle, and most of the characters look displeased with him.">
<figcaption>Shrek 2 <abbr>DVD</abbr> main menu.</figcaption>
</figure><p>The Rocky Horror Picture Show <abbr>DVD</abbr> opens with the iconic lips welcoming you to the <abbr>DVD</abbr>. After which you&#8217;re presented with the main menu, where a disembodied pair of legs wearing heels and fishnets walks in, kicking around one of the menu items, which begins flipped the wrong way around. The extra features are numerous and play into Rocky Horror&#8217;s cult status. Some menu options are accompanied by a large switch which animates when flicked. Throughout much of the menu the lips continue speaking while songs from the film play in the background. The 16:9-only portion of the screen is occupied by red curtains, which slide in and out again when &#8216;Play Movie&#8217; is selected.</p>
<figure class="shorter">
<img src="/assets/posts/dvd-menus/rocky-horror.avif" alt="Red lips to the top left with some legs underneath it. To the right are four menu items: 'Play', 'Chapter Selection', 'Language Selection', and 'Special Features'. Red curtains are on each side of the screen.">
<figcaption>Rocky Horror Picture Show <abbr>DVD</abbr> main menu.</figcaption>
</figure><p>When inserted, Wayne&#8217;s World&#8217;s <abbr>DVD</abbr> menu first shows static before simulating switching through multiple channels and then landing on a channel guide, with plenty of spoof material like fake adverts. In addition to various options like scene selection and subtitle configuration appearing like upcoming television shows across different channels, there are also listings for tonnes of other shows and films which can be scrolled through like a real cable set top box. It is a brilliantly fun interface.</p>
<p>Chitty Chitty Bang Bang has a <abbr>3D</abbr> render of the titular fuel-burning oracle flying through the clouds, with menus superimposed onto it, and Thunderbirds (2004) opens with clips from the film before dropping you into Thunderbird 2&#8217;s cockpit with a variety of controls as you fly around, and a voiceover speaks to you while you&#8217;re presented with all sorts of information. You could even switch which craft you&#8217;re piloting.</p>
<p><abbr>DVD</abbr> releases of Doctor Who following the 2005 revival also had extremely fun interfaces. Many of the <abbr>DVD</abbr> releases of both Classic Who and New Who had <a href="https://doctorwhoworlduk.com/eastereggs">many hidden secrets and additions included</a>. Different releases vary, but many of the earlier ones were set in the Tardis, with menu items presented on and around the console. Some showed the time vortex and time stream, while they began to simplify a bit during the Peter Capaldi era before slipping into more generic menus, as became common throughout the mid-2010s.</p>
<figure class="shorter">
<img src="/assets/posts/dvd-menus/doctor-who-series-7.avif" alt="Left-aligned menu listing special features, with the Tardis in the background, overtaken by vines, while the time stream undulates unstably to the right.">
<figcaption>Doctor Who Series 7 special features menu (disc 1).</figcaption>
</figure><hr>
<p>In modern <abbr>DVD</abbr> releases, we rarely see any menus of note. <abbr>DVD</abbr>s are no longer the dominant format they once were, and companies rarely put effort into their presentation. Despite being a much more capable format from a technical perspective, with high-resolution media, menu layers, everything offered by <a href="https://en.wikipedia.org/wiki/BD-J">Blu-ray Disc Java (BD-J)</a> and more, Blu-rays unfortunately very rarely see impressive menu presentations. Modern <abbr>DVD</abbr>s and Blu-ray menus alike are often little more than an image or video with a generic menu atop it.</p>
<p>It is understandable. Physical media as a whole is less popular with the mass adoption of streaming services; however, it is a shame to see that the creativity and excitement of the media viewing experience provided by menus replaced by the sterile, generic, one-size-fits-all interfaces of online platforms. If curious, there are a great number of <abbr>DVD</abbr> menus to be perused at <a href="https://dvdmoviemenus.com">dvdmoviemenus.com</a>.</p>
<section class="footnotes" data-footnotes>
<h2 id="footnote-label" class="sr-only">Footnotes</h2>
<ol>
<li id="footnote-1">
<p>I speak not of games simply released using the <abbr>DVD</abbr> medium, like console or PC releases, but of actual <abbr>DVD</abbr> games, which were standard <abbr>DVD</abbr> Video discs with games implemented the same as any menu. The most famous of these games is perhaps <a href="https://en.wikipedia.org/wiki/Scene_It%3F">Scene It?</a> <a href="#footnote-ref-1" data-footnote-backref aria-label="Back to reference 1">↩</a></p>
</li>
</ol>
</section>

		]]></content:encoded>
    </item>
    <item>
      <pubDate>Mon, 05 Oct 2026 00:00:00 GMT</pubDate>
      <title>Speaker Rider</title>
      <link>https://vale.rocks/posts/speaker-rider</link>
      <guid>https://vale.rocks/posts/speaker-rider</guid>
      <description>The speaker rider of Declan Chidlow, identifying my expectations when speaking and presenting at events such as conferences and meet-ups. Technical requirements, expectations for conduct, event handling, and diversity in speakers, and accomodations I expect as a speaker myself.</description>
      <content:encoded><![CDATA[
			
			
			<p>A <a href="https://en.wikipedia.org/wiki/Rider_%28theater%29">rider</a> is a term used by performers and production teams for a document listing demands and requests for their performance. Famously, the band Van Halen would include a clause in their rider requesting a bowl of M&M&#8217;s with the brown dragées removed as a way to check that the document had been comprehensively read.</p>
<p>This is my rider for speaking at events, such as conferences and meetups. It is a reasonable set of expectations that, for the most part, is expected by any speaker &#8211; not just myself.</p>
<p>Plenty of speakers have riders, including <a href="https://matthiasott.com/speaker-rider">Matthias Ott</a>, <a href="https://cassidoo.co/rider/">Cassidy Williams</a>, <a href="https://www.mauricecherry.com/speaker-rider">Maurice Cherry</a>, <a href="https://hazelweakly.me/speaker-rider/">Hazel Weakly</a> <a href="https://remysharp.com/rider">Remy Sharp</a>, <a href="https://aeva.online/media/speaker-rider/">æva black</a>, <a href="https://rupumped.github.io/speaker-rider.html">Nicholas S Selby</a>, and <a href="https://third-bit.com/talks/speaking/">Greg Wilson</a>. My rider is partially derived from theirs.</p>
<div class="markdown-alert markdown-alert-important">
<p class="markdown-alert-title"><svg class="octicon octicon-report mr-2" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg>Important</p>
<p>This rider primarily pertains to for-profit events. I may choose to waive or re-evaluate parts based on context, such as ticket prices.</p>
</div>
<h2 id="expectations--culture">Expectations & Culture</h2>
<p>Your event must have a public code of conduct. It should define what is acceptable and what isn&#8217;t, as well as how violations of the code will be enforced. It should be explicit and mustn&#8217;t be buried away somewhere. This is absolutely critical, and lacking one is a deal breaker for me.</p>
<p>The venue must be accessible to people who make use of mobility aids. It is basic human decency not to exclude people because of a disability when alternative arrangements can be made or a solution for their access can be found. I take digital accessibility extremely seriously in my work, and I&#8217;m not willing to compromise on it. Masks should also be accepted and provided, with details on what ill attendees should do.</p>
<p>I expect a reasonable degree of diversity of speakers at any event. Many conferences (especially tech ones) tend to be dominated by able-bodied, white, cisgender men of high socio-economic status from the same collection of countries. Such a lineup is not representative of the wide variety of viewpoints and experiences that should be represented at an event. I don&#8217;t want a token minority to tick a box; I want a varied speaker lineup. Diversity makes communities strong.</p>
<p>Time limits for talks must be enforced. I will honour them, and it is unfair for someone else&#8217;s talk to creep over and into somebody else&#8217;s time. It inconveniences the person whose slot is being disrupted, and it throws off the whole day&#8217;s schedule.</p>
<p>When attending events, I like to make the absolute most of the experience. I wish to be able to feel the vibe of the event, engage in hallway conversations, and meet lots of folks. Some of the greatest value from an event comes not from a speaker&#8217;s talk directly, but from everything surrounding the talk. I expect a free, full pass not just for the day I&#8217;m speaking but for all days of the event.</p>
<p>Promotion such as social media posts about my talk is welcome, and I&#8217;ll promote my talk through my own means too; however, I do not consent to any AI alterations of my image, my presentation, or AI-generated copy beside my presentation. I prefer if AI-generated slides and content are banned event-wide, too. What is the point of having a human give a talk if their content or material is going to be AI generated? It is disrespectful to the audience and disrespectful to speakers who go through the effort to diligently create their work.</p>
<h2 id="logistics">Logistics</h2>
<p>Creating a talk is an extraordinarily time-consuming process. It takes countless hours to research a topic, ensure complete understanding, create slides and demos if needed, tweak them, practise, refine, practise more, tweak more, and work to get it as good as it can be. In addition to that is time travelling to the event and attending it. Given the immense time commitment required to deliver a high-quality presentation, I require a speaker fee for for-profit events.</p>
<p>If significant travel is required for me to speak, then I&#8217;ll require compensation or coverage for that travel. I&#8217;m content flying economy. I&#8217;ll also need some coverage for my lodging. Even if paid for presenting, which I also expect, a talk cannot be a net financial negative for me once lodging and travel are factored in.</p>
<p>As the considerations and details are all so variable, I handle them on a case-by-case basis. Should an event be cancelled, then I expect reimbursement for any out-of-pocket expenses already incurred.</p>
<h2 id="technical-requirements">Technical Requirements</h2>
<p>My bespoke presentation software is browser-based and thus system and device agnostic. Ideally I will present from my own computer, though I am conducive to using a provided alternative device if necessary. An internet connection is optimal &#8211; preferably Ethernet, though WiFi is often acceptable. The web is my focus, so being able to access it is important. I will need to know by what methods I will be connecting to the venue&#8217;s systems (DisplayPort, <abbr title="High-Definition Media Interface">HDMI</abbr>, <abbr>USB</abbr>-C, etc).</p>
<p>My slides are as much part of my voice and presentation when speaking as the diction I choose and stage presence I hold. I&#8217;m content to make minor alterations but am unwilling to reformat my slides into a template or to force a specific style.</p>
<p>I prefer a headset or lavalier/lapel microphone to a fixed microphone or handheld option. I find it important to gesture with my hands or point as necessary. With a clicker and a handheld microphone, one is very limited in dexterity, which is especially an issue if giving a demo which requires cursor manipulation or typing on a keyboard.</p>
<p>I will need to know what type of display my slides will be presented on. This is in large part due to talking about colour and contrast in some situations and some displays, such as projectors, making this difficult. A brief <abbr title="Audio Visual">AV</abbr> test at some point <em>prior</em> to my talk is important for ensuring everything goes smoothly.</p>
<p>If my talk is to be recorded, I wish to know ahead of time. I also wish to know where it will be published. I&#8217;m generally happy to have my work recorded; I just like to be aware. Any recording or publication of a talk I give should not be censored in any way. I retain ownership of my slides and content, providing it under a non-exclusive licensee. I prefer any recording to be freely accessible, though am happy to negotiate if needed.</p>
<hr>
<p>Are you happy with the above and interested in having me speak? Brilliant. Confirm you&#8217;ve read this rider and <a href="https://vale.rocks/contact">send me a message</a> with information about the event. If you&#8217;re located outside of Australia, I&#8217;ll need an official letter of invitation.</p>

		]]></content:encoded>
    </item>
    <item>
      <pubDate>Sat, 12 Sep 2026 00:00:00 GMT</pubDate>
      <title>Examining My Team Fortress Statistics</title>
      <link>https://vale.rocks/posts/team-fortress-stats</link>
      <guid>https://vale.rocks/posts/team-fortress-stats</guid>
      <description>Statistics and data from my time playing Team Fortress 2. Everything that I can easily extract from the API, including my play activity as various classes, in various modes. Kills, damage inflicted, score, and other details with some light commentary where appropriate.</description>
      <content:encoded><![CDATA[
			
			
			<p>Team Fortress 2 is a great game. It is also a deeply unserious one. I&#8217;m not sure how much value can be extracted from the gameplay statistics of an online multiplayer experience where it is not uncommon to killbind for a laugh or to decide not to kill anyone for an entire match and instead chill with the enemy. Team Fortress 2 is a deeply unserious game with a deeply unserious community.</p>
<p>Nevertheless, this page presents my stats for <a href="http://teamfortress.com">Team Fortress 2</a>, Valve&#8217;s 2007 class-based multiplayer first-person shooter, since I first played it on the 28<sup>th</sup> of April 2020. I&#8217;m dubious of the accuracy of these statistics, so they should be taken with a grain of salt. What is tracked is very limited, and omits negative statistics, such as deaths. Though, with objective-based gamemodes, kill-to-death ratios don&#8217;t have much bearing on performance. One could stay alive and kill the enemy team effectively, but that is worthless if the objective is not being completed.</p>
<p>Team Fortress 2 data is all kept and stored on Steam so can be easily accessed. I fetch the data manually on occasion and then use <a href="https://vale.rocks/posts/web-origami">Web Origami</a> to transform it to this readable page. When I last fetched the data is evidenced by the modification data in this post&#8217;s header.</p>
<p>This is a similar process to the one I employ for <a href="https://vale.rocks/posts/halo-stats">Examining My Halo Service Record</a>.</p>
<details>
<summary>Further data details</summary><p>One can easily access their Team Fortress 2 stats at both <code>https://steamcommunity.com/id/USERNAME/stats/TF2</code> and <code>https://steamcommunity.com/id/USERNAME/gcpd/440/</code> (&#8217;440&#8217; is Team Fortress 2&#8217;s Steam game ID). These two pages show slightly different sets of stats, though much of the data overlaps.</p>
<p>The data used for this post is sourced from Steam&#8217;s <abbr>API</abbr>: <code>https://api.steampowered.com/ISteamUserStats/GetUserStatsForGame/v0001/?key=API_KEY&amp;steamid=STEAM_ID&amp;appid=440</code>. The schema for that endpoint can be sourced from <code>https://api.steampowered.com/ISteamUserStats/GetSchemaForGame/v0002/?key=API_KEY&amp;appid=440</code>.</p>
<p>The above presented stats pages and the data sourced from the <abbr>API</abbr> each differ &#8211; in some cases rather significantly. My understanding is that this is due to discrepancies between Steamworks and the Game Coordinator.</p>
</details><h2 id="overall-stats">Overall Stats</h2>
<ul>
<li>Playtime: 200.6 hours</li>
<li>Kills: 7234</li>
<li>Kills per Hour: 36.1</li>
<li>Kill Assists: 4075</li>
<li>Damage Dealt: 2194212</li>
<li>Buildings Destroyed: 1309</li>
<li>Point Captures: 932</li>
<li>Point Defenses: 573</li>
<li>Points Scored: 15926</li>
<li>Dominations: 285</li>
<li>Revenges: 231</li>
</ul>
<h2 id="per-class-stats">Per-Class Stats</h2>
<p>My most played class is Engineer. I have the most kills with Pyro, the most assists with Engineer, have dealt the most damage with Pyro, have scored the most points with Pyro, have got the most captures with Medic, the most defences with Pyro, and have lived the longest life as Engineer.</p>
<h3 id="scout">Scout</h3>
<p>Being a manic movement-mechanic enjoying player, one would think that I&#8217;d be a major fan of Scout. However, his movement is a tad boring compared to the rocket and sticky jumping of Soldier and Demoman, the flare jumping or jetpack boosting of Pyro, blast jump mirroring of the Quickfix, and other movement mechanics. Yes, Scout can double jump (or triple jump with the Atomizer) and do some interesting things with the Force-a-Nature, but the low health makes anything too tricky too risky. I like to be rather goofy when playing TF2, but Scout is too punishing for that play style.</p>
<ul>
<li>Playtime: 8 hours (4.0%)</li>
<li>Kills: 183</li>
<li>Kills per Hour: 22.8</li>
<li>Kill Assists: 96</li>
<li>Damage Dealt: 66234</li>
<li>Damage per Kill: 362</li>
<li>Buildings Destroyed: 32</li>
<li>Point Captures: 31</li>
<li>Point Defenses: 23</li>
<li>Points Scored: 322</li>
<li>Dominations: 2</li>
<li>Revenges: 8</li>
<li>Longest Life: 3 minutes and 13 seconds</li>
<li>Most Kills: 5</li>
<li>Most Kill Assists: 3</li>
<li>Most Damage: 616</li>
<li>Most Buildings Destroyed: 3</li>
<li>Most Captures: 3</li>
<li>Most Defenses: 1</li>
<li>Most Points: 8</li>
<li>Most Dominations: 1</li>
<li>Most Revenges: 1</li>
</ul>
<h3 id="soldier">Soldier</h3>
<p>Soldier feels about as close to a &#8216;default&#8217; class as you can get in TF2. Soldier is easy to play though has a high skill ceiling, as is expected of a TF2 class. I&#8217;ll reach for the class to dish out damage, but only when it is necessary for team composition.</p>
<ul>
<li>Playtime: 28.4 hours (14.1%)</li>
<li>Kills: 1635</li>
<li>Kills per Hour: 57.6</li>
<li>Kill Assists: 559</li>
<li>Damage Dealt: 530796</li>
<li>Damage per Kill: 325</li>
<li>Buildings Destroyed: 355</li>
<li>Point Captures: 195</li>
<li>Point Defenses: 47</li>
<li>Points Scored: 2787</li>
<li>Dominations: 69</li>
<li>Revenges: 29</li>
<li>Longest Life: 5 minutes and 43 seconds</li>
<li>Most Kills: 32</li>
<li>Most Kill Assists: 14</li>
<li>Most Damage: 7677</li>
<li>Most Buildings Destroyed: 8</li>
<li>Most Captures: 6</li>
<li>Most Defenses: 2</li>
<li>Most Points: 59</li>
<li>Most Dominations: 5</li>
<li>Most Revenges: 1</li>
</ul>
<h4 id="mann-vs-machine">Mann vs Machine</h4>
<ul>
<li>Playtime: 37 minutes and 32 seconds</li>
<li>Longest Life: 8 minutes and 18 seconds</li>
<li>Kills: 236 (Best: 46)</li>
<li>Kill Assists: 52 (Best: 16)</li>
<li>Damage Dealt: 48506 (Best: 9778)</li>
<li>Point Defenses: 52 (Best: 13)</li>
<li>Points Scored: 562 (Best: 93)</li>
</ul>
<h3 id="pyro">Pyro</h3>
<p><kbd>W</kbd>+<kbd>M1</kbd> is the ultimate play strategy. Pair it with the Thermal Thruster and you&#8217;re set to be a right pest. It is a shame there is no tracking for &#8216;amount of players air blasted sent plummeting to their doom by me crouched around the corner&#8217;.</p>
<ul>
<li>Playtime: 47.2 hours (23.5%)</li>
<li>Kills: 2674</li>
<li>Kills per Hour: 56.7</li>
<li>Kill Assists: 719</li>
<li>Damage Dealt: 718882</li>
<li>Damage per Kill: 269</li>
<li>Fire Damage: 703646</li>
<li>Buildings Destroyed: 464</li>
<li>Point Captures: 211</li>
<li>Point Defenses: 297</li>
<li>Points Scored: 4469</li>
<li>Dominations: 64</li>
<li>Revenges: 90</li>
<li>Longest Life: 9 minutes and 56 seconds</li>
<li>Most Kills: 8</li>
<li>Most Kill Assists: 4</li>
<li>Most Damage: 1884</li>
<li>Most Buildings Destroyed: 5</li>
<li>Most Captures: 8</li>
<li>Most Defenses: 24</li>
<li>Most Points: 29</li>
<li>Most Dominations: 2</li>
<li>Most Revenges: 3</li>
</ul>
<h4 id="mann-vs-machine-1">Mann vs Machine</h4>
<ul>
<li>Playtime: 8 minutes and 12 seconds</li>
<li>Longest Life: 3 minutes and 49 seconds</li>
<li>Kills: 4 (Best: 2)</li>
<li>Kill Assists: 1 (Best: 1)</li>
<li>Damage Dealt: 3037 (Best: 1315)</li>
<li>Fire Damage: 2787</li>
<li>Points Scored: 27 (Best: 18)</li>
</ul>
<h3 id="demoman">Demoman</h3>
<p>Like Soldier, Demoman is the go-to &#8216;damage dealer&#8217;. I&#8217;m very dynamic in switching weapons with Demoman based on circumstance. The Loch-n-Load is the obvious case for dealing with Engineer&#8217;s buildings due to the increased damage to buildings, while I quite enjoy the Loose Cannon for its fuse control, faster projectile speed, and ability to &#8216;<span style="font-family: fantasy; color: var(--yellow); paint-order: stroke fill; -webkit-text-stroke: 2px var(--black); filter: drop-shadow(0 0 0.25rem var(--magenta));">Donk! 2x</span>&#8217;. I&#8217;m partial to the Scottish Resistance for setting up traps &#8211; particuarly huge minefields with 14 stickies deployed. I don&#8217;t play much Demoknight, as I find TF2&#8217;s melee mechanics to be lacklustre.</p>
<ul>
<li>Playtime: 19.2 hours (9.6%)</li>
<li>Kills: 635</li>
<li>Kills per Hour: 33.1</li>
<li>Kill Assists: 230</li>
<li>Damage Dealt: 229293</li>
<li>Damage per Kill: 361</li>
<li>Buildings Destroyed: 314</li>
<li>Point Captures: 101</li>
<li>Point Defenses: 63</li>
<li>Points Scored: 1386</li>
<li>Dominations: 14</li>
<li>Revenges: 14</li>
<li>Longest Life: 6 minutes and 40 seconds</li>
<li>Most Kills: 18</li>
<li>Most Kill Assists: 10</li>
<li>Most Damage: 4353</li>
<li>Most Buildings Destroyed: 19</li>
<li>Most Captures: 18</li>
<li>Most Defenses: 3</li>
<li>Most Points: 47</li>
<li>Most Dominations: 3</li>
<li>Most Revenges: 1</li>
</ul>
<h4 id="mann-vs-machine-2">Mann vs Machine</h4>
<ul>
<li>Playtime: 1.5 hours</li>
<li>Longest Life: 12 minutes and 27 seconds</li>
<li>Kills: 327 (Best: 47)</li>
<li>Kill Assists: 65 (Best: 13)</li>
<li>Damage Dealt: 128166 (Best: 18619)</li>
<li>Buildings Destroyed: 8 (Best: 3)</li>
<li>Point Defenses: 56 (Best: 13)</li>
<li>Points Scored: 1206 (Best: 139)</li>
</ul>
<h3 id="heavy">Heavy</h3>
<p>I find Heavy to be a slog to play. Heavy is so easily countered by Spy and Sniper but has zero recourse against the latter. Once respawned, it then takes three years to return to the front lines. More than perhaps any other class, without the support of your team Heavy is unviable against anyone who has even the vaguest understanding of the game.</p>
<ul>
<li>Playtime: 1.7 hours (0.8%)</li>
<li>Kills: 40</li>
<li>Kills per Hour: 24.0</li>
<li>Kill Assists: 17</li>
<li>Damage Dealt: 20049</li>
<li>Damage per Kill: 501</li>
<li>Buildings Destroyed: 3</li>
<li>Point Captures: 6</li>
<li>Points Scored: 72</li>
<li>Revenges: 2</li>
<li>Longest Life: 5 minutes and 11 seconds</li>
<li>Most Kills: 4</li>
<li>Most Kill Assists: 2</li>
<li>Most Damage: 3647</li>
<li>Most Buildings Destroyed: 1</li>
<li>Most Captures: 3</li>
<li>Most Points: 8</li>
<li>Most Revenges: 1</li>
</ul>
<h4 id="mann-vs-machine-3">Mann vs Machine</h4>
<ul>
<li>Playtime: 44 seconds</li>
<li>Longest Life: 35 seconds</li>
</ul>
<h3 id="engineer">Engineer</h3>
<p>The snowballing of building up a nest and upgrading buildings is fantastically enjoyable. There is a lovely gameplay loop of staying on your toes and remaining aware of the ever-lurking Spy looking to do you in. Engineer&#8217;s unlockables also make him an extremely varied class. From long-distance repair with the Rescue Ranger, to a Mini-Sentry with the Gunslinger, to manual control with the Wrangler, and projectile destruction with the Short Circuit.</p>
<ul>
<li>Playtime: 53.8 hours (26.8%)</li>
<li>Kills: 1741</li>
<li>Kills per Hour: 32.3</li>
<li>Kill Assists: 1219</li>
<li>Damage Dealt: 531724</li>
<li>Damage per Kill: 305</li>
<li>Buildings Built: 6836</li>
<li>Teleports Provided: 2828</li>
<li>Buildings Destroyed: 53</li>
<li>Point Captures: 43</li>
<li>Point Defenses: 67</li>
<li>Points Scored: 3988</li>
<li>Dominations: 115</li>
<li>Revenges: 50</li>
<li>Longest Life: 12 minutes and 7 seconds</li>
<li>Most Kills: 60</li>
<li>Most Kill Assists: 63</li>
<li>Most Damage: 14099</li>
<li>Most Buildings Built: 24</li>
<li>Most Sentry Kills: 60</li>
<li>Most Teleports: 38</li>
<li>Most Buildings Destroyed: 3</li>
<li>Most Captures: 4</li>
<li>Most Defenses: 3</li>
<li>Most Points: 123</li>
<li>Most Dominations: 13</li>
<li>Most Revenges: 2</li>
</ul>
<h4 id="mann-vs-machine-4">Mann vs Machine</h4>
<ul>
<li>Playtime: 20 minutes and 12 seconds</li>
<li>Longest Life: 3 minutes and 34 seconds</li>
<li>Kills: 72 (Best: 14)</li>
<li>Kill Assists: 27 (Best: 9)</li>
<li>Damage Dealt: 22162 (Best: 7220)</li>
<li>Buildings Built: 34 (Best: 7)</li>
<li>Teleports Provided: 14 (Best: 6)</li>
<li>Point Defenses: 25 (Best: 8)</li>
<li>Points Scored: 278 (Best: 68)</li>
<li>Most Sentry Kills: 20</li>
</ul>
<h3 id="medic">Medic</h3>
<p>I love playing support classes. Medic, especially with the Vaccinator. I love juggling the various damage resistances based on situation and the dynamic gameplay that comes with it, though it does come at the cost of slurs from the enemy team. Also, Battle Medic for the win!</p>
<ul>
<li>Playtime: 36.3 hours (18.1%)</li>
<li>Kills: 179</li>
<li>Kills per Hour: 4.9</li>
<li>Kill Assists: 1195</li>
<li>Damage Dealt: 65395</li>
<li>Damage per Kill: 365</li>
<li>Health Points Healed: 1798857</li>
<li>ÜberCharges: 416</li>
<li>ÜberCharges per Hour: 11.5</li>
<li>Buildings Destroyed: 22</li>
<li>Point Captures: 331</li>
<li>Point Defenses: 63</li>
<li>Points Scored: 2536</li>
<li>Dominations: 20</li>
<li>Revenges: 29</li>
<li>Longest Life: 8 minutes and 32 seconds</li>
<li>Most Kills: 3</li>
<li>Most Kill Assists: 22</li>
<li>Most Damage: 882</li>
<li>Most Healing: 5081</li>
<li>Most ÜberCharges: 6</li>
<li>Most Buildings Destroyed: 2</li>
<li>Most Captures: 19</li>
<li>Most Defenses: 4</li>
<li>Most Points: 38</li>
<li>Most Dominations: 2</li>
<li>Most Revenges: 1</li>
</ul>
<h4 id="mann-vs-machine-5">Mann vs Machine</h4>
<ul>
<li>Playtime: 55 minutes and 10 seconds</li>
<li>Longest Life: 6 minutes and 49 seconds</li>
<li>Kills: 12 (Best: 3)</li>
<li>Kill Assists: 43 (Best: 4)</li>
<li>Damage Dealt: 2887 (Best: 356)</li>
<li>Health Points Healed: 25535 (Best: 2125)</li>
<li>ÜberCharges: 5 (Best: 2)</li>
<li>Buildings Destroyed: 1 (Best: 1)</li>
<li>Point Defenses: 5 (Best: 2)</li>
<li>Points Scored: 237 (Best: 42)</li>
</ul>
<h3 id="sniper">Sniper</h3>
<p>A lot of people play Sniper, but having many Snipers on a team&#8217;s lineup is a detriment. I&#8217;ve never played much Sniper because it is so rare that my doing so would actually add to the team.</p>
<ul>
<li>Playtime: 1.7 hours (0.8%)</li>
<li>Kills: 54</li>
<li>Kills per Hour: 32.6</li>
<li>Kill Assists: 18</li>
<li>Damage Dealt: 11691</li>
<li>Damage per Kill: 217</li>
<li>Headshots: 53</li>
<li>Buildings Destroyed: 10</li>
<li>Point Captures: 2</li>
<li>Point Defenses: 5</li>
<li>Points Scored: 91</li>
<li>Longest Life: 4 minutes and 24 seconds</li>
<li>Most Kills: 20</li>
<li>Most Kill Assists: 3</li>
<li>Most Damage: 3989</li>
<li>Most Headshots: 19</li>
<li>Most Buildings Destroyed: 2</li>
<li>Most Captures: 2</li>
<li>Most Defenses: 1</li>
<li>Most Points: 36</li>
</ul>
<h3 id="spy">Spy</h3>
<p>Like Sniper, the average public server has more than enough people playing Spy. The times where I will opt for Spy are when there are no other Spy players on the team, or when an Engineer&#8217;s nest needs sapping.</p>
<ul>
<li>Playtime: 4.5 hours (2.2%)</li>
<li>Kills: 93</li>
<li>Kills per Hour: 20.8</li>
<li>Kill Assists: 22</li>
<li>Damage Dealt: 20148</li>
<li>Damage per Kill: 217</li>
<li>Backstabs: 80</li>
<li>Health Points Leeched: 1322</li>
<li>Buildings Destroyed: 56</li>
<li>Point Captures: 12</li>
<li>Point Defenses: 8</li>
<li>Points Scored: 275</li>
<li>Dominations: 1</li>
<li>Revenges: 9</li>
<li>Longest Life: 6 minutes and 6 seconds</li>
<li>Most Kills: 3</li>
<li>Most Kill Assists: 4</li>
<li>Most Damage: 775</li>
<li>Most Backstabs: 3</li>
<li>Most Health Leeched: 159</li>
<li>Most Buildings Destroyed: 4</li>
<li>Most Captures: 3</li>
<li>Most Defenses: 2</li>
<li>Most Points: 7</li>
<li>Most Dominations: 1</li>
<li>Most Revenges: 1</li>
</ul>
<h2 id="modes-and-maps">Modes and Maps</h2>
<p>It would appear that not all maps and modes are logged and accounted for in Team Fortress 2&#8217;s tracking.</p>
<h3 id="payload">Payload</h3>
<p>Far and away the game&#8217;s best mode. Payload is a great deal of fun.</p>
<ul>
<li><strong>Total: 85 hours</strong></li>
<li>Badwater Basin: 20.5 hours</li>
<li>Upward: 20 hours</li>
<li>Frontier: 15 hours</li>
<li>Barnblitz: 10.9 hours</li>
<li>Thunder Mountain: 9.2 hours</li>
<li>Gold Rush: 4.9 hours</li>
<li>Hoodoo: 4.5 hours</li>
</ul>
<h3 id="payload-race">Payload Race</h3>
<ul>
<li><strong>Total: 3.1 hours</strong></li>
<li>Hightower: 2.8 hours</li>
<li>Nightfall: 8 minutes and 54 seconds</li>
<li>Pipeline: 7 minutes and 47 seconds</li>
</ul>
<h3 id="control-points">Control Points</h3>
<ul>
<li><strong>Total: 27.8 hours</strong></li>
<li>Dustbowl: 19.6 hours</li>
<li>Mountain Lab: 1.3 hours</li>
<li>Steel: 1.3 hours</li>
<li>Egypt: 58 minutes and 10 seconds</li>
<li>Gorge: 49 minutes and 20 seconds</li>
<li>Foundry: 47 minutes and 48 seconds</li>
<li>Gravel Pit: 47 minutes and 46 seconds</li>
<li>Junction: 44 minutes and 34 seconds</li>
<li>Mann Manor: 22 minutes and 28 seconds</li>
<li>Badlands: 22 minutes and 16 seconds</li>
<li>Gullywash: 12 minutes and 25 seconds</li>
<li>Yukon: 11 minutes and 15 seconds</li>
<li>Well: 9 minutes and 30 seconds</li>
<li>Fastlane: 7 minutes and 54 seconds</li>
<li>Freight: 2 minutes and 50 seconds</li>
<li>Coldfront: 2 minutes and 32 seconds</li>
</ul>
<h3 id="king-of-the-hill">King of the Hill</h3>
<ul>
<li><strong>Total: 9.3 hours</strong></li>
<li>Harvest: 3.3 hours</li>
<li>Sawmill: 1.4 hours</li>
<li>Lakeside: 1.2 hours</li>
<li>Nucleus: 1.1 hours</li>
<li>Kong King: 59 minutes and 4 seconds</li>
<li>Viaduct: 54 minutes and 47 seconds</li>
<li>Badlands: 28 minutes</li>
</ul>
<h3 id="capture-the-flag">Capture the Flag</h3>
<ul>
<li><strong>Total: 5.4 hours</strong></li>
<li><abbr>2F</abbr>ort: 4.6 hours</li>
<li>Turbine: 28 minutes and 32 seconds</li>
<li>Double Cross: 19 minutes and 49 seconds</li>
</ul>
<h3 id="special-delivery">Special Delivery</h3>
<ul>
<li><strong>Total: 7 minutes and 9 seconds</strong></li>
<li>Doomsday: 7 minutes and 9 seconds</li>
</ul>
<style>
@media (min-width: 30rem) {
	article > div ul {
		columns: 2;
		column-gap: 2rem;

		&:has(> li:only-child) {
            columns: 1;
        }

		li {
			break-inside: avoid;
            margin-block-start: 0;
		}
	}
}
</style>

		]]></content:encoded>
    </item>
    <item>
      <pubDate>Fri, 11 Sep 2026 00:00:00 GMT</pubDate>
      <title>CSS Curiosities of the Past</title>
      <link>https://vale.rocks/posts/css-relics</link>
      <guid>https://vale.rocks/posts/css-relics</guid>
      <description>Summary of the various CSS syntaxes, parsing bugs, hacks, bespoke features, and implementations used across browsers and the web to achieve specific goals in the days before browser vendors became more adherent to a single solid specification. Particularly focusing on the non-compliant, bespoke implementations of functionality seen in Microsoft&apos;s Internet Explorer.</description>
      <content:encoded><![CDATA[
			
			
			<p>The ebbs and flows of the web have gotten us to where we stand today. We simply wouldn&#8217;t have the web we do without the journey it has taken us to get here. However, some of the steps it has taken to get here have been interesting to say the least.</p>
<p><abbr>CSS</abbr> is how we style things on the web, but since its inception it has been made, on occasion, to wear a few more hats. It has taken on odd roles and picked up behaviours it probably ought not to have. Such is life.</p>
<p>As I&#8217;ve detailed <a href="https://vale.rocks/posts/html-relics">odd and context-specific <abbr>HTML</abbr></a>, this is a look at <abbr>CSS</abbr> largely outside the specifications. Browser-specific hacks, technology-scoped syntax, and engine-exclusive snippets forged from questionable circumstances, corporate complications, and esoteric implementations.</p>
<h2 id="property-parsing">Property Parsing</h2>
<pre><code class="language-css"><span class="hljs-attribute">width</span>: <span class="hljs-number">300px</span>;
*<span class="hljs-attribute">width</span>: <span class="hljs-number">250px</span>;
_width: <span class="hljs-number">200px</span>;
-<span class="hljs-attribute">width</span>: <span class="hljs-number">200px</span>;
</code></pre><p>Most browsers, correctly, would treat a property prefixed with an asterisk as invalid. However, Internet Explorer 7 and earlier would treat it as valid. It was so famous it garnered the name &#8216;star hack&#8217; for the shape of the asterisk. Likewise, when prefixing a property with an underscore or hyphen, <em>only</em> Internet Explorer 6 would treat it as valid. There were <em>many</em> more similar hacks used, the vast majority of which are best documented at the eponymous <a href="http://browserhacks.com">browserhacks.com</a>. The main gist is that some browsers would incorrectly parse properties, selectors, and values, and that could be used for gain in an era where browser behaviour was rather varied.</p>
<p>Limiting <abbr>CSS</abbr> to apply only in certain browsers with conditional comments in <abbr>CSS</abbr> files, such as could be done in <abbr>HTML</abbr> documents, wasn&#8217;t possible.<sup><a id="footnote-ref-1" href="#footnote-1" data-footnote-ref aria-describedby="footnote-label">1</a></sup> Therefore, this exploitation of questionable parsing of what is and isn&#8217;t valid was commonplace for targeting specific browsers.</p>
<h2 id="important">Important</h2>
<pre><code class="language-css"><span class="hljs-attribute">background</span>: red !interesting;
</code></pre><p>Internet Explorer 7 and earlier would treat almost any textual string prefixed by an exclamation mark as <code>!important</code>. Most commonly, people would make use of this by writing <code>!ie</code> to have a style only override specificity in Internet Explorer. As far as Internet Explorer was concerned, the arbitrary <code>!banana</code> and the specced <code>!important</code> were the same, while other browsers correctly only accepted the latter.</p>
<p>There was another related bug in Internet Explorer 6 and lower where a style declared later in the same block would overwrite an <code>!important</code> value. For example, here the colour would be black rather than white, as it should be:</p>
<pre><code class="language-css"><span class="hljs-attribute">color</span>: white <span class="hljs-meta">!important</span>;
<span class="hljs-attribute">color</span>: black;
</code></pre><h2 id="document-level-browser-detection">Document Level Browser Detection</h2>
<p>There were <a href="https://web.archive.org/web/20071005221259/http://www.javascriptkit.com/dhtmltutors/csshacks2.shtml">so many ways</a> in which you could identify what browser was in use on a document level via <abbr>CSS</abbr>. Some examples include:</p>
<ul>
<li>In Internet Explorer 6 and earlier you could write <code>* html {}</code>.</li>
<li>For only Internet Explorer 7 you could use <code>*:first-child+html {}</code>.</li>
<li>Browsers other than Internet Explorer 7 support <code>html &gt; /**/ body {}</code>.</li>
<li>Early versions of Firefox would apply styles within <code>body:empty {}</code> (even when the body had contents).</li>
</ul>
<p>This approach was often messy to use, as it meant writing multiple descending selectors to try to target elements in specific browsers only.</p>
<h2 id="clearfix">Clearfix</h2>
<pre><code class="language-css"><span class="hljs-selector-class">.clearfix</span> {
	<span class="hljs-attribute">zoom</span>: <span class="hljs-number">1</span>;
}
</code></pre><p>Until version 8, Internet Explorer <a href="https://www.haslayout.net/haslayout.html">had a concept called <code>hasLayout</code></a>. An internal flag, it would designate whether an element was responsible for rendering itself (<code>true</code>) or if a parent element would be responsible for it (<code>false</code>). Naturally, this was an obtuse and confusing system. Some elements, such as <code>&lt;img&gt;</code>, <code>&lt;iframe&gt;</code>, and most things input-related, would intrinsically &#8216;have layout&#8217;. Other elements wouldn&#8217;t have layout, <a href="https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa752723(v=vs.85)#remarks">unless it was specifically given via specific <abbr>CSS</abbr> declarations being present</a>.</p>
<p>An element without layout could encounter weird margin and border behaviours, positioning complications, and general odd rendering and, most importantly, would cause parent containers to collapse when their children were floated. This caused all sorts of problems in an age where floating elements was the de facto way to lay out pages.</p>
<p>The <code>zoom</code> property changes the size at which its target appears. With a value of <code>1</code>, the target appears at its existing size. This may seem useless, but <code>zoom</code> gives an element layout, so it would be used as a simple way to do so without otherwise changing an element&#8217;s visual appearance.</p>
<h2 id="hand-cursor">Hand Cursor</h2>
<pre><code class="language-css"><span class="hljs-attribute">cursor</span>: pointer;
<span class="hljs-attribute">cursor</span>: hand;
</code></pre><p>Prior to Internet Explorer 6, Internet Explorer didn&#8217;t respect the <code>pointer</code> value for the <code>cursor</code> property. Instead, it only supported the non-standard <code>hand</code> value, which provided a pointing hand. Therefore, sites <a href="https://boyet.com/blog/dumb-css-cursor-pointer-or-hand/">would commonly write both values in their <abbr>CSS</abbr></a> with the expectation that <code>cursor: hand</code> would be considered invalid in browsers other than Internet Explorer, thus prompting them to use <code>pointer</code> while Internet Explorer uses <code>hand</code>.</p>
<h2 id="css-expressions"><abbr>CSS</abbr> Expressions</h2>
<pre><code class="language-css"><span class="hljs-attribute">top</span>: <span class="hljs-built_in">expression</span>(<span class="hljs-built_in">eval</span>(document.documentElement.scrollTop));
</code></pre><p>Formally called &#8216;Dynamic Properties&#8217;, <abbr>CSS</abbr> expressions were a way to execute JavaScript in <abbr>CSS</abbr>. It was non-standard behaviour introduced in Internet Explorer 5 to patch up lagging styling capabilities, such as missing support for <code>position: fixed</code> (which the above snippet addresses), or <code>min-width</code> and <code>max-width</code>, among others. This made making layouts rather difficult. <abbr>CSS</abbr> Expressions were hacky and awkward while exposing a lot of complexity. You could go as far as to change what styles were applied based on the time of day using <code>Date()</code>. <abbr>CSS</abbr> expressions were constantly re-evaluated, making them extremely performance taxing. As was noted by Steve Souders on the <a href="https://web.archive.org/web/20080808113459/http://developer.yahoo.net/blog/archives/2007/07/high_performanc_6.html">Yahoo! Developer Network blog</a>:</p>
<blockquote>
<p>The problem with expressions is that they are evaluated more frequently than most people expect. Not only are they evaluated when the page is rendered and resized, but also when the page is scrolled and even when the user moves the mouse over the page.</p>
</blockquote>
<p>Microsoft ended support for them with Internet Explorer 8, as announced in their dramatically titled post &#8216;<a href="https://learn.microsoft.com/en-us/archive/blogs/ie/ending-expressions">Ending Expressions</a>&#8217;.</p>
<h2 id="filters">Filters</h2>
<p>Internet Explorer had a number of iffy behaviours and lagged behind other browsers for many visual effects, even regarding basic properties like <code>opacity</code>. Thus, Microsoft brought in <a href="https://webplatform.github.io/docs/concepts/proprietary_internet_explorer_techniques/#filters:~:text=Filters%20present%20a%20way%20to%20apply%20certain%20visual%20effects%20either%20to%20page%20elements%20or%20to%20the%20page%20as%20a%20whole%2E">bespoke filter functionality</a>. Filters used DirectX-based components of Windows, far away from web platform standards. Internet Explorer first introduced its filter functionality with version 4. The syntax was rather simple, with an example of lowering an element&#8217;s opacity looking like this:</p>
<pre><code class="language-css"><span class="hljs-attribute">filter</span>: <span class="hljs-built_in">alpha</span>(opacity=<span class="hljs-number">50</span>);
</code></pre><p>It was far from perfect but allowed addressing many of Explorer&#8217;s shortcomings. Filters required that an element <a href="#clearfix">had layout</a> and also annoyingly stripped ClearType font anti-aliasing for small text, making it look jagged. Sometimes they&#8217;d cause issues with interactivity, too. In version 5.5 filter syntax became more complex, looking like this:</p>
<pre><code class="language-css"><span class="hljs-attribute">filter</span>: progid:DXImageTransform.Microsoft.<span class="hljs-built_in">Alpha</span>(opacity=<span class="hljs-number">50</span>);
</code></pre><p>Note the presence of <code>DX</code> referring to DirectX. Filters could <a href="https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/ms532847(v=vs.85)#transitions">even be animated</a>. In the last update to filter functionality, Microsoft vendor-prefixed their filter property in version 8 to better comply with <abbr>CSS</abbr> standards. They also made it so that filters would not strip font anti-aliasing, and it became necessary to wrap the value in quotes:</p>
<pre><code class="language-css">-ms-<span class="hljs-attribute">filter</span>: <span class="hljs-string">&quot;progid:DXImageTransform.Microsoft.Alpha(opacity=50)&quot;</span>;
</code></pre><p><code>-ms-filter</code> was finally removed with Internet Explorer 10. This removal extended to Internet Explorer&#8217;s legacy modes too. By version 10&#8217;s release, most popular uses for filters had received support from the browser, such as the <code>opacity</code> property which was added in version 9.</p>
<p>Aside from opacity, two of the other very common uses for Explorer&#8217;s filter capabilities were handling transparent <abbr>PNG</abbr> images and applying gradients. Transparent sections of <abbr>PNG</abbr>s in Internet Explorer 6 and earlier were replaced with a grey background. Even in later versions, <abbr>PNG</abbr>s could encounter issues usually related to gamut. Therefore, people would often load images via <code>AlphaImageLoader</code>:</p>
<pre><code class="language-css"><span class="hljs-attribute">filter</span>: progid:DXImageTransform.Microsoft.<span class="hljs-built_in">AlphaImageLoader</span>(src=<span class="hljs-string">&#x27;image.png&#x27;</span>);
</code></pre><p>Gradients would be applied with <code>filter</code> as an alternative to using background images (<code>linear-gradient()</code> would not receive support until Internet Explorer version 10).</p>
<pre><code class="language-css"><span class="hljs-attribute">filter</span>: progid:DXImageTransform.Microsoft.<span class="hljs-built_in">gradient</span>(startColorstr=<span class="hljs-string">&#x27;red&#x27;</span>, endColorstr=<span class="hljs-string">&#x27;green&#x27;</span>, GradientType=<span class="hljs-number">0</span>);
</code></pre><p>People would often implement simple reusable filters for commonly encountered situations using the aforementioned <a href="#css-expressions"><abbr>CSS</abbr> Expressions</a> functionality.</p>
<h2 id="scrollbars">Scrollbars</h2>
<pre><code class="language-css"><span class="hljs-selector-tag">body</span> {
	scrollbar-face-<span class="hljs-attribute">color</span>: <span class="hljs-number">#333333</span>;
	scrollbar-highlight-<span class="hljs-attribute">color</span>: <span class="hljs-number">#666666</span>;
	scrollbar-<span class="hljs-number">3</span>dlight-<span class="hljs-attribute">color</span>: <span class="hljs-number">#000000</span>;
	scrollbar-darkshadow-<span class="hljs-attribute">color</span>: <span class="hljs-number">#000000</span>;
	scrollbar-shadow-<span class="hljs-attribute">color</span>: <span class="hljs-number">#111111</span>;
	scrollbar-arrow-<span class="hljs-attribute">color</span>: red;
	scrollbar-track-<span class="hljs-attribute">color</span>: <span class="hljs-number">#222222</span>;
}
</code></pre><p>Internet Explorer version 5.5 introduced the ability to customise the appearance of scrollbars.</p>
<figure class="right">
<img src="/assets/posts/css-relics/ie-11-scrollbars.avif" alt="An Internet Explorer 11 windows with dark coloured scrollbars and red arrows.">
<figcaption>The above scrollbar styles applied in Internet Explorer 11.</figcaption>
</figure><p>For the arrow buttons and thumb, <code>face-color</code> set background, <code>highlight-color</code> set the inner left highlight, <code>3dlight-color</code> set the outer right highlight, <code>darkshadow-color</code> set the inner right shadow, <code>shadow-color</code> set the inner right shadow, and <code>arrow-color</code> set the arrow icons themselves. <code>track-color</code> obviously set the scrollbar track. There were even <a href="https://www.yaldex.com/PadFiles/ColoredScrollBarsPad.htm">full applications for generating the styles</a>.</p>
<p>Much like today, styling scrollbars was considered somewhat gaudy and over-the-top, so it was mostly used for minor tweaks in professional contexts. The functionality was of course utilised to its fullest potential by people customising their MySpace profiles.</p>
<h2 id="html-components"><abbr>HTML</abbr> Components</h2>
<pre><code class="language-css"><span class="hljs-selector-class">.item</span> {
	behavior: <span class="hljs-built_in">url</span>(<span class="hljs-string">csshover.htc</span>);
}
</code></pre><p><abbr>HTML</abbr> Components (not to be confused with contemporary <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components">Web Components</a>) were an Internet Explorer exclusive feature added in version 5 and expanded greatly in version 5.5, which allowed attaching scripting logic to <abbr>HTML</abbr> elements via <abbr>CSS</abbr>. Though many languages were supported, JavaScript was almost always used.</p>
<p>Here is an example of a <abbr>HTML</abbr> Component that would be used to add hack-in hover behaviour on elements other than links, which is the only place <code>:hover</code> was supported in Internet Explorer prior to version 7. Note that the language specified is &#8216;JScript&#8217; &#8211; Microsoft&#8217;s diverging implementation of JavaScript which Internet Explorer supported.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">PUBLIC:COMPONENT</span> <span class="hljs-attr">NAME</span>=<span class="hljs-string">&quot;CSSHover&quot;</span>&gt;</span>
	<span class="hljs-tag">&lt;<span class="hljs-name">PUBLIC:ATTACH</span> <span class="hljs-attr">EVENT</span>=<span class="hljs-string">&quot;onmouseover&quot;</span> <span class="hljs-attr">ONEVENT</span>=<span class="hljs-string">&quot;hoverOn()&quot;</span> /&gt;</span>
	<span class="hljs-tag">&lt;<span class="hljs-name">PUBLIC:ATTACH</span> <span class="hljs-attr">EVENT</span>=<span class="hljs-string">&quot;onmouseout&quot;</span> <span class="hljs-attr">ONEVENT</span>=<span class="hljs-string">&quot;hoverOff()&quot;</span> /&gt;</span>

	<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">language</span>=<span class="hljs-string">&quot;JScript&quot;</span>&gt;</span><span class="language-javascript">
		<span class="hljs-comment">// Append a class when the mouse enters</span>
		<span class="hljs-keyword">function</span> <span class="hljs-title function_">hoverOn</span>(<span class="hljs-params"></span>) {
			<span class="hljs-keyword">if</span> (!<span class="hljs-regexp">/\bhovered\b/</span>.<span class="hljs-title function_">test</span>(element.<span class="hljs-property">className</span>)) {
				element.<span class="hljs-property">className</span> += <span class="hljs-string">&quot; hovered&quot;</span>;
			}
		}

		<span class="hljs-comment">// Remove the class when the mouse leaves</span>
		<span class="hljs-keyword">function</span> <span class="hljs-title function_">hoverOff</span>(<span class="hljs-params"></span>) {
			element.<span class="hljs-property">className</span> = element.<span class="hljs-property">className</span>.<span class="hljs-title function_">replace</span>(<span class="hljs-regexp">/\b\s?hovered\b/g</span>, <span class="hljs-string">&quot;&quot;</span>);
		}
	</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">PUBLIC:COMPONENT</span>&gt;</span>
</code></pre><p>A particular popular usage of this functionality was <a href="http://css3pie.com">Progressive Internet Explorer</a>, which ported then-modern <abbr>CSS</abbr> features to Internet Explorer versions 6 through 9. From Internet Explorer 8, <code>behaviour</code> is available as the vendor prefixed <code>-ms-behavior</code>, and <a href="https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/hh801216(v=vs.85)">support was removed in Internet Explorer 10</a>.</p>
<h2 id="box-model-hack">Box Model Hack</h2>
<pre><code class="language-css"><span class="hljs-selector-tag">div</span> {
	<span class="hljs-attribute">width</span>: <span class="hljs-number">400px</span>;
    <span class="hljs-attribute">voice-family</span>: <span class="hljs-string">&quot;\&quot;}\&quot;&quot;</span>;
	<span class="hljs-attribute">voice-family</span>: inherit;
	<span class="hljs-attribute">width</span>: <span class="hljs-number">300px</span>;
}
</code></pre><p>A <a href="https://tantek.com/CSS/Examples/boxmodelhack.html">rather famous hack from Tantek Çelik</a>. The <code>voice-family</code> property was used for specifying which voice family should be used when reading content aloud. The property wasn&#8217;t supported by older browsers of the time, and the value was provided as a string. Due to a parser bug, Internet Explorer 5 would interpret <code>&quot;\&quot;}\&quot;&quot;</code> as the closing of the current <abbr>CSS</abbr> block, leaving the other declarations invalid and allowed to slip past the browser undetected. This was important, as implementations of the <a href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Box_model">box model</a> were differing.</p>
<p>The Windows releases of Internet Explorer caught by the hack &#8211; versions 5 and 5.5 &#8211; handled the box model incorrectly. They would include padding and borders inside the declared width, rather than outside as they should have. Meanwhile, standard-compliant browsers which parsed the <abbr>CSS</abbr> correctly (with the exception of Opera, for which a further snippet would be included) supported the box model and would correctly handle borders and margins as being outside of the element&#8217;s width.</p>
<h2 id="holly-hack">Holly Hack</h2>
<pre><code class="language-css"><span class="hljs-comment">/* Hides from IE5 on Mac \*/</span>
* <span class="hljs-selector-tag">html</span> <span class="hljs-selector-class">.element</span> {
	<span class="hljs-attribute">height</span>: <span class="hljs-number">1%</span>;
}
<span class="hljs-comment">/* End hide from IE5 on Mac */</span>
</code></pre><p>Internet Explorer for Mac used an entirely different engine to Internet Explorer elsewhere. While most platforms used Trident/<abbr>MSHTML</abbr>, Explorer for Mac used Tasman, which had bugs of its own. One of these bugs was that comments with an escape character before closing (<code>\*/</code>) would be mishandled.</p>
<p>The content before the next properly closed comment would be treated as a comment by Internet Explorer for Mac and thus not parsed, but other browsers would handle it properly. In the above snippet a <a href="https://web.archive.org/web/20150324181023/http://www.communitymx.com/content/article.cfm?page=2&amp;cid=C37E0">Holly Hack</a> (named for Holly Bergevin) is paired with <a href="#document-level-browser-detection">a hack browser detection</a> targeting Internet Explorer 6 and earlier so that a fix to unwanted behaviour exclusive to Internet Explorer on Windows would <em>only</em> apply to Internet Explorer on Windows.</p>
<h2 id="double-margin-float">Double Margin Float</h2>
<pre><code class="language-css"><span class="hljs-selector-tag">div</span> {
	<span class="hljs-attribute">float</span>: left;
	<span class="hljs-attribute">margin-left</span>: <span class="hljs-number">5px</span>;
	<span class="hljs-attribute">display</span>: inline;
}
</code></pre><p>Internet Explorer would display the above margin as 5px. However, without a <code>display</code> value of <code>inline</code>, it&#8217;d be rendered as 10px &#8211; not 5px. As explained in Position Is Everything&#8217;s Explorer Exposed article, <a href="https://web.archive.org/web/20080907120231/http://www.positioniseverything.net/explorer/doubled-margin.html">The IE Doubled Float-Margin Bug</a>:</p>
<blockquote>
<p>Why is this happening? Don&#8217;t ask such silly questions! This is IE, remember? Conformance with the specs is only to be hoped for, not expected. The simple fact is it does happen.</p>
</blockquote>
<h2 id="toolbars">Toolbars</h2>
<p>Before the <a href="https://vale.rocks/posts/html-relics#skype-toolbar">Skype Toolbar opt-out meta tag</a> was introduced &#8211; and even as a fallback after it was &#8211; some site owners would stop Skype&#8217;s Toolbar from displaying Skype buttons on their page directly with <abbr>CSS</abbr>:</p>
<pre><code class="language-css"><span class="hljs-selector-tag">span</span><span class="hljs-selector-class">.skype_pnh_container</span> {
	<span class="hljs-attribute">display</span>: none <span class="hljs-meta">!important</span>;
}

<span class="hljs-selector-tag">span</span><span class="hljs-selector-class">.skype_pnh_print_container</span> {
	<span class="hljs-attribute">display</span>: inline <span class="hljs-meta">!important</span>;
}
</code></pre><p>In a very similar case, the <a href="https://web.archive.org/web/20120222191153/http://about.ask.com/apn/toolbar/docs/default/faq/en/chrome/chrome.html">Ask Toolbar</a> would appear at the top of the page and sometimes break pages, leading to developers targeting <code>#apn-null-toolbar</code> and <code>#apn-body-style</code> to remove it. Many other extensions, often installed by applications without users really understanding them, would introduce similar issues that browsers would have to target and remove.</p>
<h2 id="vendor-prefixes">Vendor Prefixes</h2>
<p>Vendor prefixes were mainly used for non-standard or experimental <abbr>CSS</abbr> features so that developers could test new features and give feedback to browser vendors before their implementation or specification is finalised. &#8216;Prefix&#8217; refers to the browser-specific mark preceding the property, pseudo, at-rule, or media feature. <code>-webkit-</code> was used for WebKit and Blink-based browsers, <code>-moz-</code> for Gecko-based browsers, <code>-o-</code> for Presto-based browsers, <code>-khtml-</code> for <abbr>KHTML</abbr> (and kept around for early WebKit versions), and <code>-ms-</code> for <abbr>MSHTML</abbr>/Trident-based browsers, <a href="https://www.w3.org/TR/CSS2/syndata.html#vendor-keyword-history">as well as others</a>.</p>
<p>However, these vendor prefixes would sometimes be prematurely adopted beyond experimenting. Developers would include them in production sites such that removing support for these testing features would break them. As such, browser vendors found themselves having to keep support for these testing implementations.</p>
<p>As a result, browser vendors no longer use vendor prefixes, instead placing features behind flags which must be enabled on each individual browser. Most vendor prefixes are obsolete in the face of non-prefixed implementations. However, some stick around as proper implementations haven&#8217;t been specced. Perhaps most famously, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/-webkit-text-stroke"><code>-webkit-text-stroke</code></a>, which is supported across all major browsers and not just those using WebKit.</p>
<hr>
<p>This article isn&#8217;t comprehensive. These are only the more popular or notable non-standard bits. Many more curious <abbr>CSS</abbr> oddities from time passed linger out there on the web, collecting dust and growing creaky. Even in 2005 Microsoft was <a href="https://learn.microsoft.com/en-us/archive/blogs/ie/call-to-action-the-demise-of-css-hacks-and-broken-pages">trying to get people to stop using many of these hacks</a>. At least (outside of legacy contexts) we don&#8217;t have to fret about the questionable behaviour of Internet Explorer and other stone-age browsers any longer.</p>
<section class="footnotes" data-footnotes>
<h2 id="footnote-label" class="sr-only">Footnotes</h2>
<ol>
<li id="footnote-1">
<p>People would sometimes get around this limitation by wrapping styles in conditional comments where they were imported, using conditional comments to selectively apply classes, or by wrapping inline styles within conditional comments, all within their <abbr>HTML</abbr>. <a href="#footnote-ref-1" data-footnote-backref aria-label="Back to reference 1">↩</a></p>
</li>
</ol>
</section>

		]]></content:encoded>
    </item>
    <item>
      <pubDate>Wed, 09 Sep 2026 00:00:00 GMT</pubDate>
      <title>My HTML Boilerplate</title>
      <link>https://vale.rocks/posts/html-boilerplate</link>
      <guid>https://vale.rocks/posts/html-boilerplate</guid>
      <description>A document outlining and explaining my general structure for HTML pages to use. A slim general markup template that applies to almost all HTML documents on the web and forgoes anything unnecessary. It is a general framework to build upon for individual sites.</description>
      <content:encoded><![CDATA[
			
			
			<p>When <abbr>HTML</abbr> was first created, a document could be very simple indeed. A valid document could look like this:</p>
<!-- prettier-ignore -->
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">TITLE</span>&gt;</span>HTML document<span class="hljs-tag">&lt;/<span class="hljs-name">TITLE</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">H1</span>&gt;</span>Heading<span class="hljs-tag">&lt;/<span class="hljs-name">H1</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">P</span>&gt;</span>This is a paragraph with a <span class="hljs-tag">&lt;<span class="hljs-name">A</span> <span class="hljs-attr">HREF</span>=<span class="hljs-string">&quot;https://example.com/&quot;</span>&gt;</span>link<span class="hljs-tag">&lt;/<span class="hljs-name">A</span>&gt;</span>.
</code></pre><p>It wasn&#8217;t until <abbr>HTML</abbr> 2.0 &#8211; the first formalised standard &#8211; that a proper document structure came into being. A <code>DOCTYPE</code> declaration to explain a document&#8217;s type and to handle compatibility became an expected inclusion, as did head and body sections:</p>
<!-- prettier-ignore -->
<pre><code class="language-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-keyword">HTML</span> <span class="hljs-keyword">PUBLIC</span> <span class="hljs-string">&quot;-//IETF//DTD HTML 2.0//EN&quot;</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">HEAD</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">TITLE</span>&gt;</span>HTML document<span class="hljs-tag">&lt;/<span class="hljs-name">TITLE</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">HEAD</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">BODY</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">H1</span>&gt;</span>Heading<span class="hljs-tag">&lt;/<span class="hljs-name">H1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">P</span>&gt;</span>This is a document.
<span class="hljs-tag">&lt;/<span class="hljs-name">BODY</span>&gt;</span>
</code></pre><p>In the years since <abbr>HTML</abbr> 2.0&#8217;s 1995 debut, the web has changed massively. However, there is a saying in the web standards world: <em>&#8216;Don&#8217;t Break The Web&#8217;</em>. There are some exceptions, but on the whole a website developed at the web&#8217;s inception should work in a modern browser, regardless of how much time has passed. To keep this compatibility, however, risks making changes impossible for fret of breaking existing sites.</p>
<p>One way the web combats this is with certain elements that are expected in <abbr>HTML</abbr> documents. If the element is present, then it uses the new functionality. If not, it simply falls back to the old functionality. Pair that with what different integrations and systems across the web expect, and it means that there is rather a lot of &#8216;boilerplate&#8217; &#8211; code that is repeated across almost every new or maintained site. <abbr>HTML</abbr> boilerplate commonly both opts in to modern functionality and also sets site preferences and details. Assorted things such as how the site should embed on social media, what styles should be loaded, how the browser should theme surrounding the site, and other such details.</p>
<h2 id="boilerplate">Boilerplate</h2>
<p>Much like <a href="https://vale.rocks/posts/css-reset">I maintain my own <abbr>CSS</abbr> reset</a>, which provides me a clean slate for my styles, I maintain my own boilerplate, which I use as a base structure and reference when creating <abbr>HTML</abbr> documents. Much like my <abbr>CSS</abbr> reset, it is very opinionated. Here it is in full:</p>
<pre><code class="language-html"><span class="hljs-meta">&lt;!doctype <span class="hljs-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">&quot;en&quot;</span>&gt;</span>
	<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">&quot;UTF-8&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;viewport&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;width=device-width&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;text-scale&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;scale&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Name of Page | Name of Website<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

		<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;stylesheet&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/styles.css&quot;</span>&gt;</span>

		<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;preload&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;font.woff2&quot;</span> <span class="hljs-attr">as</span>=<span class="hljs-string">&quot;font&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;font/woff2&quot;</span> <span class="hljs-attr">crossorigin</span>&gt;</span>

		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:title&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;Name of Page&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;description&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;Description of this page.&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:description&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;Description of this page for embeds.&quot;</span>&gt;</span>

		<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;icon&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;image/svg+xml&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://example.com/favicon.svg&quot;</span>&gt;</span>

		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:image&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;https://example.com/embed-image.webp&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:image:alt&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;A picture of something.&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:image:type&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;image/webp&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:image:width&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;1200&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:image:height&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;630&quot;</span>&gt;</span>

		<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;canonical&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://example.com/page&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:url&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;https://example.com/page&quot;</span>&gt;</span>

		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:site_name&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;Website Name&quot;</span>&gt;</span>

		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;author&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;A N Other&quot;</span>&gt;</span>

		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;color-scheme&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;light dark&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;theme-color&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;red&quot;</span> <span class="hljs-attr">media</span>=<span class="hljs-string">&quot;(prefers-color-scheme: light)&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;theme-color&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;green&quot;</span> <span class="hljs-attr">media</span>=<span class="hljs-string">&quot;(prefers-color-scheme: dark)&quot;</span>&gt;</span>

		<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;alternate&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;application/rss+xml&quot;</span> <span class="hljs-attr">title</span>=<span class="hljs-string">&quot;RSS feed of posts on Website Name.&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/posts/feed.xml&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;alternate&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;application/feed+json&quot;</span> <span class="hljs-attr">title</span>=<span class="hljs-string">&quot;JSON feed of posts on Website Name.&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/posts/feed.json&quot;</span>&gt;</span>

		<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;search&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;application/opensearchdescription+xml&quot;</span> <span class="hljs-attr">title</span>=<span class="hljs-string">&quot;Website Search&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://example.com/opensearch.xml&quot;</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;manifest&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/app.webmanifest&quot;</span>&gt;</span>
	<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

	<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;main&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">footer</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;footer&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
	<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre><h2 id="breakdown">Breakdown</h2>
<p>It should be noted that there is order to my <abbr>HTML</abbr> boilerplate. The order of the document head in particular has great influence on performance. <a href="https://rviscomi.github.io/capo.js/">Capo.js</a> is a brilliant tool for evaluating the order of elements in a document&#8217;s head from a performance perspective.</p>
<pre><code class="language-html"><span class="hljs-meta">&lt;!doctype <span class="hljs-keyword">html</span>&gt;</span>
</code></pre><p>This is the document type declaration for the living <abbr>HTML</abbr> standard, as introduced in <abbr>HTML</abbr> 5. I always include it to avoid falling into quirks mode.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">&quot;en&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre><p>Opens the <code>html</code> tag which wraps the document and defines the document language using an <a href="https://www.rfc-editor.org/info/rfc5646/"><abbr>RFC</abbr> 5646</a> compliant tag with the <code>lang</code> attribute. The language provided the default for the full page and can be overwritten on a per-element basis. Providing the language is important for automatic translation, typography such as hyphens, and for assistive technologies (especially screen readers).</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">&quot;UTF-8&quot;</span>&gt;</span>
</code></pre><p>The first element I place in the <code>head</code> is always the <code>charset</code> <code>meta</code> tag with a value of <code>UTF-8</code>, which is the only valid encoding as of <abbr>HTML</abbr> 5. It is always top of the <code>head</code>, as it must occur within the first 1024 bytes of a document, and it should be before any elements liable to get mangled.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;viewport&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;width=device-width&quot;</span>&gt;</span>
</code></pre><p>When the first iPhone launched in 2007, it rendered desktop sites with the expectation of the user to zoom in and pan around. Apple introduced the above <code>meta</code> tag for sites that were actually optimised for mobile, and it was eventually picked up more widely across browsers such that now it is supported widely to make a site responsive.</p>
<p>Many people will include <code>initial-scale=1</code>, however, after extensive testing and research, I&#8217;ve identified that <a href="https://vale.rocks/micros/20260902-1350">it isn&#8217;t necessary to include any more</a>. It can be included to change the page&#8217;s presentation if an element horizontally expands beyond the viewport width, but that should never be allowed to happen <a href="https://vale.rocks/micros/20260908-1315">and I advise against it</a>.</p>
<p><code>minimum-scale</code>, <code>maximum-scale</code>, and <code>user-scalable</code> all greatly harm accessibility and should never<sup><a id="footnote-ref-1" href="#footnote-1" data-footnote-ref aria-describedby="footnote-label">1</a></sup> be used. They should generally be stripped from sites whenever noticed.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;text-scale&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;scale&quot;</span>&gt;</span>
</code></pre><p>Makes text <a href="https://matuzo.at/blog/2026/text-scaling-meta-tag">scale in accordance with the system setting</a>. If this tag is present, then a page&#8217;s styles must expect it and be written accordingly. This is especially important to avoid accessibility pitfalls with content scaling.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Name of Page | Name of Website<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
</code></pre><p>The title of the page. It is a required value which is shown on many surfaces. It is used as the name of the page when bookmarked, the name of the tab in search engines, and anywhere else a name for the page is needed. I&#8217;ll generally show the page title followed by the site&#8217;s title.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;stylesheet&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/styles.css&quot;</span>&gt;</span>
</code></pre><p>Whatever styles must be imported can be imported here. Styles should generally be imported in the page head rather than using the <code>@import</code> <abbr>CSS</abbr> at-rule within a stylesheet to avoid a waterfall, where the stylesheet must first be fetched to then fetch additional stylesheets.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;preload&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;font.woff2&quot;</span> <span class="hljs-attr">as</span>=<span class="hljs-string">&quot;font&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;font/woff2&quot;</span> <span class="hljs-attr">crossorigin</span>&gt;</span>
</code></pre><p>Complex variable fonts can be rather large in size, even after subletting and other optimisations, so I preload fonts that I know will be used on the page. Even if a font is located on the same-origin, <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preload#cors-enabled_fetches">the <code>crossorigin</code> attribute is still necessary</a>. I always serve fonts as <abbr title="Web Open Font Format">WOFF</abbr>2, as it is the most performant widely supported font format.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:title&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;Name of Page&quot;</span>&gt;</span>
</code></pre><p>The <code>og:title</code> is used for embeds, such as those seen on social media. It is one of the many metadata values of <a href="https://ogp.me">the Open Graph protocol</a>. While I&#8217;ll typically include the site name at the end of the <code>&lt;title&gt;</code> element, I leave it absent in the <code>og:title</code>. In the majority of cases embeds will show the domain or <code>og:site_name</code> next to the title, rendering it a duplicate.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;description&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;Description of this page.&quot;</span>&gt;</span>
</code></pre><p>I mainly treat this meta description field as an exercise in search engine optimisation. Previously major search engines would expose the description to users on search pages, however they mostly fetch directly from the document itself now.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:description&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;Description of this page for embeds.&quot;</span>&gt;</span>
</code></pre><p>The <code>og:description</code> is sometimes shown in embeds. If absent, embeds usually forgo a description or fall back to the meta description. I like to write short, often quippy content here that strikes intrigue and fits in social media or chat feeds.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;icon&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;image/svg+xml&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://example.com/favicon.svg&quot;</span>&gt;</span>
</code></pre><p>A favicon is an important bit of branding for all websites &#8211; especially when it comes to identifying tabs when you have many open. I serve favicons as <abbr>SVG</abbr>s, as they&#8217;re <a href="https://caniuse.com/link-icon-svg">well supported</a>, can be made to dynamically adapt to light/dark mode, look good at all sizes, and remove the need for maintaining a set of raster favicons in different sizes.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:image&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;https://example.com/embed-image.webp&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:image:alt&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;A picture of something.&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:image:type&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;image/webp&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:image:width&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;1200&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:image:height&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;630&quot;</span>&gt;</span>
</code></pre><p>The image defined in the <code>og:image</code> is often shown in a site&#8217;s embed on the likes of social media or chat platforms. It is advantageous to include on almost every site, as it adds context and usually increases an embed&#8217;s size for better presence. Support for alt text on embedded images is middling, so it shouldn&#8217;t be relied upon. Some sites support it, some ignore it, and some support it in odd ways. I make the effort to include it but keep it brief. 1200px by 630px is a widely supported size, and WebP is the best supported of the modern image formats I&#8217;ve tested.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;canonical&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://example.com/page&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:url&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;https://example.com/page&quot;</span>&gt;</span>
</code></pre><p>A canonical link to the authoritative version of the page is important for indicating what should be considered the source of truth. This is especially important if content is duplicated.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">&quot;og:site_name&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;Website Name&quot;</span>&gt;</span>
</code></pre><p>The name of the website to be shown in embeds. As aforementioned, some embeds will show this name near the page&#8217;s title.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;author&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;A N Other&quot;</span>&gt;</span>
</code></pre><p>The <code>author</code> tag obviously indicates the author of a page. It isn&#8217;t strictly necessary but is useful for developers to identify who is responsible for a page.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;color-scheme&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;light dark&quot;</span>&gt;</span>
</code></pre><p>Setting the <code>color-scheme</code> meta tag with a content attribute value of <code>light dark</code> tells the browser that a site supports both light and dark modes. Having it defined in the head prevents a Flash of Unstyled Content (<abbr>FOUC</abbr>), such as a screen of bright white when the site and browser are set to dark mode.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;theme-color&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;red&quot;</span> <span class="hljs-attr">media</span>=<span class="hljs-string">&quot;(prefers-color-scheme: light)&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;theme-color&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;green&quot;</span> <span class="hljs-attr">media</span>=<span class="hljs-string">&quot;(prefers-color-scheme: dark)&quot;</span>&gt;</span>
</code></pre><p>Used for theming the browser chrome of sites installed as progressive web apps (<abbr>PWA</abbr>s) and for theming the browser chrome in Chrome for Android (but only in light mode). Some other browsers also interpret these values in various ways. I use the media attribute to set the colour independently for both light and dark modes.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;alternate&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;application/rss+xml&quot;</span> <span class="hljs-attr">title</span>=<span class="hljs-string">&quot;RSS feed of posts on Website Name.&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/posts/feed.xml&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;alternate&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;application/feed+json&quot;</span> <span class="hljs-attr">title</span>=<span class="hljs-string">&quot;JSON feed of posts on Website Name.&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/posts/feed.json&quot;</span>&gt;</span>
</code></pre><p>If a site has syndication feeds, then including these in the head <a href="https://piccalil.li/blog/a-quick-guide-to-creating-syndication-feeds/#auto-discovery">permits autodiscovery of them</a>.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;search&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;application/opensearchdescription+xml&quot;</span> <span class="hljs-attr">title</span>=<span class="hljs-string">&quot;Website Search&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://example.com/opensearch.xml&quot;</span>&gt;</span>
</code></pre><p>If a site has integrated search functionality, then establishing an <a href="https://github.com/dewitt/opensearch/blob/master/opensearch-1-1-draft-6.md">opensearch.xml</a> file and referencing it from your document head exposes it to browsers so they can provide a rich searching experience. The exact experience differs by browser, but in many cases it allows searching with a site via the browser&#8217;s own address bar and also provides a simple way to add a search engine.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;manifest&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/app.webmanifest&quot;</span>&gt;</span>
</code></pre><p>I&#8217;m a progressive web app evangelist. I love them, and many sites benefit from being <abbr>PWA</abbr>s, even if a site is not a typical &#8216;app&#8217;. I&#8217;ll <a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Manifest">define a manifest</a> for most sites even if the only benefit is that the presentation is nicer if people add the site to their homescreen. This declaration helps browsers discover the manifest.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;main&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">footer</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;footer&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
</code></pre><p>This defines any site&#8217;s general <code>body</code> structure. The <code>header</code> holds a navigation element for general site navigation. The <code>main</code> holds the primary page content and has an <code>id</code> attribute to provide an anchor, which is important for &#8216;skip to&#8217; links. The <code>footer</code> holds information about the current site and page. Like <code>main</code>, I give it an <code>id</code> for anchoring purposes. I don&#8217;t get any more detailed with my <abbr>HTML</abbr> body boilerplate, as there is so much variance depending on the site.</p>
<hr>
<p>This is just boilerplate. It is a template for what I&#8217;ll include on roughly every site, with some light alterations. Every site is sure to deviate from this depending on its requirements, but this is a reasonable foundation.</p>
<p>If a page is expected to be cited academically, then you&#8217;d consider including Google Scholar&#8217;s <code>citation_*</code> meta tags and <a href="https://www.dublincore.org/specifications/dublin-core/">Dublin Core</a>&#8217;s <code>dc</code> meta tags. If a page represents an article, then you&#8217;d include the tags from the Open Graph Protocol&#8217;s <a href="https://ogp.me/#type_article">article namespace</a> and perhaps tags pertaining to a publishing system. A video, audio, book, or other content type would similarly be marked up differently. Many sites will also benefit from <a href="https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data"><code>JSON-LD</code> structured data</a>. It all depends on the particular page and what is needed.</p>
<p>For a larger boilerplate that outlines some more optional inclusions, I recommend Manuel Matuzović&#8217;s brilliant article, <a href="https://matuzo.at/blog/2026/html-boilerplate">My <abbr>HTML</abbr> boilerplate in 2026</a>.</p>
<section class="footnotes" data-footnotes>
<h2 id="footnote-label" class="sr-only">Footnotes</h2>
<ol>
<li id="footnote-1">
<p>There are cases where they can be used, but you&#8217;ll know those extremely rare cases when you come to them. Take great and extreme care. <a href="#footnote-ref-1" data-footnote-backref aria-label="Back to reference 1">↩</a></p>
</li>
</ol>
</section>

		]]></content:encoded>
    </item>
    <item>
      <pubDate>Tue, 08 Sep 2026 00:00:00 GMT</pubDate>
      <title>Antiquated HTML Snippets and Artefacts</title>
      <link>https://vale.rocks/posts/html-relics</link>
      <guid>https://vale.rocks/posts/html-relics</guid>
      <description>Overviews of the very many snippets of HTML that were once commonly included on websites to address specific cases with certain technologies, browsers, operating systems, or extensions. Fragments dating back to the days of Internet Explorer and Netscape, to more modern bits that are nonetheless obsolete.</description>
      <content:encoded><![CDATA[
			
			
			<p>With ever-changing devices, browsers, operating systems, form factors, specifications, personal preferences, tooling, and corporate interests, the web is in a constant state of flux. As a result, so is the <abbr>HTML</abbr> we write. For every line of the <abbr>HTML</abbr> specification itself that has changed since the language&#8217;s inception, there are many more bits of <abbr>HTML</abbr> that have seen what I&#8217;ll call &#8216;environmental&#8217; changes. Adaptations to differing browsers, extensions, integrations, and systems which we find <abbr>HTML</abbr> existing in.</p>
<p>This article doesn&#8217;t cover <a href="https://www.htmhell.dev/adventcalendar/2025/22/">once-specced but now obsolete bits of <abbr>HTML</abbr></a> but instead looks at all the snippets that have wormed their way into websites as result of, or in combat against, third-party integrations, browser competition, vendor extensions, and platform-specific hacks. The bits of <abbr>HTML</abbr> that were included for reasons, and which have been forgotten for present irrelevance. The snippets that live on only in the markup of sites from bygone eras and in the minds of those who fought during the browser wars.</p>
<h2 id="x-ua-compatible">X-UA-Compatible</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">&quot;X-UA-Compatible&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;IE=edge&quot;</span>&gt;</span>
</code></pre><p>In an age where browsers changed quickly and version-specific behaviours weren&#8217;t unheard of, it was deemed necessary to signal compatibility with specific versions of browsers with the <code>X-UA-Compatible</code> meta tag. Here the content attribute reads <code>IE=edge</code>, meaning that the target is the highest supported document mode in Internet Explorer (IE).</p>
<p>As <a href="https://learn.microsoft.com/en-us/openspecs/ie_standards/ms-iedoco/380e2488-f5eb-4457-a07a-0cb1b6e4b4b5">outlined in the documentation</a>, there are other values than <code>edge</code>. One can also supply a value of <code>5</code> through <code>11</code> to correspond with the associated Internet Explorer version, or <code>EmulateIE7</code> through <code>EmulateIE11</code> to enter into that version&#8217;s mode, but only if a valid <code>DOCTYPE</code> is declared, otherwise falling back to quirks mode.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">&quot;X-UA-Compatible&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;chrome=1&quot;</span>&gt;</span>
</code></pre><p>Before Chrome took over the market, Google released an Internet Explorer plugin called <a href="https://en.wikipedia.org/wiki/Google_Chrome_Frame">Google Chrome Frame</a>. Installable in Internet Explorer versions 6 through 9, it rendered websites in Chrome&#8217;s modified WebKit engine rather than Internet Explorer&#8217;s Trident engine if they had the tag set.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">&quot;X-UA-Compatible&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;requiresActiveX=true&quot;</span>&gt;</span>
</code></pre><p><code>requiresActiveX</code> was used to prompt Internet Explorer 10 to switch to desktop mode if in Metro mode, which didn&#8217;t support plugins.</p>
<h2 id="icbm-coordinate"><abbr>ICBM</abbr> Coordinate</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;ICBM&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;-31.9548, 115.8602&quot;</span>&gt;</span>
</code></pre><p><abbr>ICBM</abbr> (an abbreviation of &#8216;intercontinental ballistic missile&#8217;) is hacker slang for one&#8217;s geographical location that dates back to Usenet days. The meta tag was used for identifying the location of a website&#8217;s subject and was referenced by the service <a href="https://web.archive.org/web/20060701025123/http://geourl.org/">GeoURL</a> for plotting sites on the globe and helping people find sites of geographical proximity.</p>
<h2 id="conditional-comments">Conditional Comments</h2>
<pre><code class="language-html"><span class="hljs-comment">&lt;!--[if gte IE 6]&gt;
	&lt;p&gt;Only shown in Internet Explorer 6 and higher.&lt;/p&gt;
&lt;![endif]--&gt;</span>
</code></pre><p>In an era where browsers changed regularly and the vicious browser wars were in full force, it was sometimes important to target a specific browser or version of one. Microsoft handled this in Internet Explorer with <a href="https://www.haslayout.net/condcom.html">specially formatted comments</a> as seen in the snippet. These conditional comments, or &#8216;condcoms&#8217; for short, could be written and refined using a number of operators:</p>
<table>
<thead>
<tr>
<th align="center">Operator</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>IE</code></td>
<td align="left">Denotes Internet Explorer. Can also include a version, such as <code>IE 7</code>.</td>
</tr>
<tr>
<td align="center"><code>lt</code></td>
<td align="left">Less than.</td>
</tr>
<tr>
<td align="center"><code>lte</code></td>
<td align="left">Less than or equal.</td>
</tr>
<tr>
<td align="center"><code>gt</code></td>
<td align="left">Greater than.</td>
</tr>
<tr>
<td align="center"><code>gte</code></td>
<td align="left">Greater than or equal.</td>
</tr>
<tr>
<td align="center"><code>!</code></td>
<td align="left"><abbr>NOT</abbr>.</td>
</tr>
<tr>
<td align="center"><code>&amp;</code></td>
<td align="left"><abbr>AND</abbr>.</td>
</tr>
<tr>
<td align="center"><code>|</code></td>
<td align="left">OR.</td>
</tr>
<tr>
<td align="center"><code>()</code></td>
<td align="left">Subexpression operator.</td>
</tr>
<tr>
<td align="center"><code>true</code></td>
<td align="left">Always evaluates to true.</td>
</tr>
<tr>
<td align="center"><code>false</code></td>
<td align="left">Always evaluates to false.</td>
</tr>
</tbody></table>
<pre><code class="language-html"><span class="hljs-comment">&lt;!--&amp;{navigator.appName == &#x27;Netscape&#x27;};
	&lt;p&gt;Only shown in Netscape.&lt;/p&gt;
--&gt;</span>

<span class="hljs-comment">&lt;!--&amp;{navigator.platform == &#x27;win95&#x27;};
    &lt;p&gt;Only shown in Netscape on Windows 95.&lt;/p&gt;
--&gt;</span>
</code></pre><p>Netscape <a href="https://www.masswerk.at/nowgobang/2019/object-handle-event#:~:text=A%20special%20use%20case%20were%20conditional%20comments">had its own way of handling conditional comments</a> using JavaScript entities immediately following an opening comment tag. If evaluated to <code>true</code>, the comment would be included. If <code>false</code>, it&#8217;d just be a comment. Browsers other than Netscape would always treat it as just a comment.</p>
<h2 id="microsoft-smart-tags">Microsoft Smart Tags</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;MSSmartTagsPreventParsing&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;TRUE&quot;</span>&gt;</span>
</code></pre><p><a href="https://web.archive.org/web/20010625111031/http://www.microsoft.com/windows/ie/preview/smarttags/default.asp">Smart Tags</a> was a system Microsoft experimented with in beta versions of Internet Explorer 6 which would automatically inject hyperlinks into pages.<sup><a id="footnote-ref-1" href="#footnote-1" data-footnote-ref aria-describedby="footnote-label">1</a></sup> An example given by Microsoft was that &#8216;a Smart Tag might detect the names of major companies on the Web and tag them, allowing you to access stock quotes and company information.&#8217;. Site owners were outraged, and the <code>MSSmartTagsPreventParsing</code> meta tag was introduced to allow opting out. The feature didn&#8217;t make it into a full release of Internet Explorer, though was implemented in Microsoft Word.</p>
<h2 id="pics"><abbr>PICS</abbr></h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
	<span class="hljs-attr">http-equiv</span>=<span class="hljs-string">&quot;PICS-Label&quot;</span>
	<span class="hljs-attr">content</span>=<span class="hljs-string">&#x27;
 (PICS-1.1 &quot;http://www.gcf.org/v2.5&quot;
    labels on &quot;1994.11.05T08:15-0500&quot;
           until &quot;1995.12.31T23:59-0000&quot;
           for &quot;http://w3.org/PICS/Overview.html&quot;
    ratings (suds 0.5 density 0 color/hue 1))
&#x27;</span>
&gt;</span>
</code></pre><p>In the mid-90s the World Wide Web Consortium (W3C) attempted to establish a set of technical specifications for labelling internet content, called <a href="https://www.w3.org/PICS/">Platform for Internet Content Selection (<abbr>PICS</abbr>)</a>. <abbr>PICS</abbr> was incorporated into many filtering products, as well as Internet Explorer as of version 3. The shown meta tag could be included on a page to label it.</p>
<p>Rather unsurprisingly, many site owners just lied and miscategorised their sites. More still just never added the tags. The <a href="https://www.w3.org/2007/powder/">Protocol for Web Description Resources (<abbr>POWDER</abbr>)</a> succeeded <abbr>PICS</abbr> but was also unsuccessful in its intentions. <abbr>PICS</abbr> was more or less completely dropped by 2003.</p>
<h2 id="interpage-transitions">Interpage Transitions</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">&quot;Page-Enter&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;revealTrans(Duration=2.0,Transition=12)&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">&quot;Page-Exit&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;revealTrans(Duration=2.0,Transition=12)&quot;</span>&gt;</span>
</code></pre><p>Much like slide deck applications such as Microsoft PowerPoint or Apple Keynote have the ability to set transitions, Internet Explorer from version 4 to version 8 <a href="https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/ms532847(v=vs.85)#interpage-transitions">supported the above tags for transition style effects</a>. This feature wouldn&#8217;t officially reach the web platform until the adoption of the <a href="https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API">View Transition <abbr>API</abbr></a>. Web developer Bramus has ported Internet Explorer&#8217;s <a href="https://page-transitions.style">transitions to the new View Transition <abbr>API</abbr></a>.</p>
<h2 id="frame-buster">Frame Buster</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">&quot;Window-target&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;_top&quot;</span>&gt;</span>
</code></pre><p>Starting in Netscape Navigator in the mid-90s and then working its way over to Internet Explorer and other browsers, this non-standard meta tag would cause a page to break free of the parent page and open as a standalone browser window if it was loaded in a frame. It was popularly used by people to stop their pages from being embedded in frames on other sites. The <code>_top</code> <code>Window-target</code> specifies that a page should load in a <em>top</em> level window. In the modern age people use security headers to prevent pages from being embedded.</p>
<h2 id="baidu-page-transcoding">Baidu Page Transcoding</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;applicable-device&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;pc,mobile&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">&quot;Cache-Control&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;no-siteapp,no-transform&quot;</span>&gt;</span>
</code></pre><p>The Baidu Browser (<ruby>百<rt>bǎi</rt>度<rt>dù</rt>浏<rt>liú</rt>览<rt>lǎn</rt>器<rt>qì</rt></ruby>) included a page &#8216;transcoding&#8217; feature on mobile which was immensely unpopular. Websites would be routed through <code>transcoder.baidu.com</code> and modified. Layouts would be restructured, styles stripped, images compressed, branding removed, and adverts on the site would be removed while Baidu Union (<ruby>百<rt>bǎi</rt>度<rt>dù</rt>联<rt>lián</rt>盟<rt>méng</rt></ruby>) adverts would be injected. It <a href="https://zzz.buzz/zh/2017/04/10/baidu-mobile-seo-and-baidu-siteapp/">heavily disrupted sites</a>. One of these tags would be added to sites from 2012 through to 2018 to opt out of this transcoding taking place.</p>
<h2 id="skype-toolbar">Skype Toolbar</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;skype_toolbar&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;skype_toolbar_parser_compatible&quot;</span>&gt;</span>
</code></pre><p>There was an add-on for Internet Explorer, Chrome, and Firefox called &#8216;Skype Toolbar&#8217; (later &#8216;Skype Click to Call&#8217;). Available from the mid-2000s until the mid-2010s, it was automatically installed alongside Skype and would attempt to detect phone numbers on pages and show a clickable icon. This icon allowed calling a number via Skype, adding it to one&#8217;s Skype address book, and assorted other Skype-related functionality. In inserting an icon, it would often cause page breakages, so developers would include the above tag to disable it on their sites.</p>
<p>The extension was also extremely unstable in Firefox, to the extent that <a href="https://blog.mozilla.org/addons/2011/01/20/blocking-the-skype-toolbar-in-firefox/">Mozilla explicitly blocked it</a> in 2011.</p>
<h2 id="image-toolbar">Image Toolbar</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">&quot;imagetoolbar&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;no&quot;</span>&gt;</span>
</code></pre><p>Internet Explorer 6 added an Image Toolbar, which would appear over images and show buttons for actions such as saving or sharing an image. Developers naturally hated this intrusion on their site and could disable the functionality with the above meta tag.</p>
<h2 id="cleartype">ClearType</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">&quot;cleartype&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;on&quot;</span>&gt;</span>
</code></pre><p>ClearType is Microsoft&#8217;s system <a href="https://learn.microsoft.com/en-us/typography/cleartype/">for improving the legibility of typography</a>. This tag could be included on pages to make typography look better on low-resolution devices, namely those running Pocket Internet Explorer / Internet Explorer Mobile.</p>
<h2 id="ajax-crawling"><abbr>AJAX</abbr> Crawling</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;fragment&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;!&quot;</span>&gt;</span>
</code></pre><p>Google previously didn&#8217;t run JavaScript when crawling pages, so sites which had <abbr>AJAX</abbr>-based content would not be indexed. This meta tag told Google&#8217;s crawler to request a page with the <code>_escaped_fragment_</code> query parameter, which was expected to return a <abbr>HTML</abbr> version of the page&#8217;s contents. Google began recommending this approach in 2009 and <a href="https://web.archive.org/web/20180707074702/https://webmasters.googleblog.com/2015/10/deprecating-our-ajax-crawling-scheme.html">stopped advising it in 2015</a>.</p>
<h2 id="directory">Directory</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;robots&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;noodp, noydir&quot;</span>&gt;</span>
</code></pre><p>Web directories used to be immensely popular as a way for people to find content on the internet. Two of the most popular were Yahoo Directory and DMoz (named for the <abbr>URL</abbr> <code>directory.mozilla.org</code>). The directories would sometimes write their own titles and descriptions for sites, which would be used by some search engines. To signal to search engines that they should use the metadata provided on the page and not the metadata from the directories, developers would include the above meta tag. Both directories are defunct now, making this snippet irrelevant.</p>
<h2 id="web-app-name">Web App Name</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;application-name&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;App Title&quot;</span>&gt;</span>
</code></pre><p><code>application-name</code> was used by various web app implementations across various browsers before Progressive Web Apps (<abbr>PWA</abbr>s) became established. If missing, systems usually fell back to <code>&lt;title&gt;</code>.</p>
<h2 id="internet-explorer-pinned-sites">Internet Explorer Pinned Sites</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-tooltip&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;Visit our site!&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-starturl&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;./&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-window&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;width=1024;height=768&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-navbutton-color&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;#FF3300&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-task&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;name=Blog;action-uri=/blog;icon-uri=/favicon.ico&quot;</span>&gt;</span>
</code></pre><p>Internet Explorer 9 and higher on Windows 7 had a function to <a href="https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/samples/gg491738(v=vs.85)">pin sites to the taskbar</a>. When pinned, sites could expose some site features on an operating system and browser level, almost like a modern progressive web app. <code>msapplication-tooltip</code> was text shown when hovering a site&#8217;s icon, <code>msapplication-starturl</code> set the root <abbr>URL</abbr> of the pinned site, <code>msapplication-window</code> set the initial size of the pinned site&#8217;s window when opened (minimum width of 800px and height of 600px), <code>msapplication-navbutton-color</code> set a custom colour for the browser chrome&#8217;s back and forward navigation buttons, and <a href="https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/samples/gg491725(v=vs.85)#using-msapplication-task"><code>msapplication-task</code></a> was used to define quick actions which could be accessed by secondary clicking a pinned site in the taskbar. For example, a quick link to a blog page.</p>
<h2 id="microsoft-web-apps">Microsoft Web Apps</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-TileColor&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;#FF3300&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-TileImage&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;/mstile-144x144.png&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-square70x70logo&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;/images/small-tile.png&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-square150x150logo&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;/images/medium-tile.png&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-wide310x150logo&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;/images/wide-tile.png&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-square310x310logo&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;/images/large-tile.png&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-config&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;/browserconfig.xml&quot;</span>&gt;</span>
</code></pre><p>Very similar to the previously mentioned Pinned Site functionality, these values were used for presentation. <code>msapplication-TileColor</code>, <code>msapplication-TileImage</code>, and the various <code>msapplication-square*</code> and <code>msapplication-wide*</code> attribute carrying tags were used for setting the theming of the tiles across the assorted versions of Windows, including the desktop UI, Metro UI, and Windows Mobile.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-badge&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;frequency=360;polling-uri=https://contoso.com/BadgeUpdate.aspx&quot;</span>&gt;</span>
</code></pre><p><code>msapplication-badge</code> was used <a href="https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/samples/jj152137(v=vs.85)">to define a web address to be polled for notifications</a> which would display on a site&#8217;s Live Tile.</p>
<h2 id="chrome-pinned-sites">Chrome Pinned Sites</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;application-url&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;https://vale.rocks&quot;</span>&gt;</span>
</code></pre><p>Google Chrome had some pinned web app functionality which would use <code>application-url</code> for the start <abbr>URL</abbr>.</p>
<h2 id="safari-pinned-sites">Safari Pinned Sites</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;mask-icon&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;icon.svg&quot;</span> <span class="hljs-attr">color</span>=<span class="hljs-string">&quot;green&quot;</span>&gt;</span>
</code></pre><p>Pinned Sites/Tabs in Safari allowed &#8216;users to keep their favorite websites open, running, and easily accessible.&#8217;. An <abbr>SVG</abbr> icon for the Pinned Tab could be declared alongside a colour which the icon would use.</p>
<h2 id="crx-less-web-apps"><abbr>CRX</abbr>-less Web Apps</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;chrome-application-definition&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;application_definition.json&quot;</span>&gt;</span>
</code></pre><p><a href="https://web.archive.org/web/20120303234427/http://code.google.com/intl/en-US/chrome/apps/docs/no_crx.html"><abbr>CRX</abbr>-less Web Apps</a> were applications in Google Chrome which allowed using an online manifest to describe a hosted app. The above meta tag would link to a <abbr>JSON</abbr> file with the manifest:</p>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
	<span class="hljs-attr">&quot;name&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Application&quot;</span><span class="hljs-punctuation">,</span>
	<span class="hljs-attr">&quot;description&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Description describing the app.&quot;</span><span class="hljs-punctuation">,</span>
	<span class="hljs-attr">&quot;launch_url&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;index.html&quot;</span><span class="hljs-punctuation">,</span>
	<span class="hljs-attr">&quot;launch_container&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;panel&quot;</span><span class="hljs-punctuation">,</span>
	<span class="hljs-attr">&quot;icons&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
		<span class="hljs-attr">&quot;128&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;128.png&quot;</span>
	<span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
	<span class="hljs-attr">&quot;permissions&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">&quot;notifications&quot;</span><span class="hljs-punctuation">]</span>
<span class="hljs-punctuation">}</span>
</code></pre><p>These <abbr>CRX</abbr>-less apps could be distributed on the Chrome Web Store with just the <abbr>JSON</abbr> manifest and an icon, with no need for the full <code>.crx</code> format Chrome uses for extensions. This type of app was later renamed to &#8216;Chrome Apps&#8217;, which are <a href="https://developer.chrome.com/docs/apps/overview">being phased out</a>.</p>
<h2 id="ios-web-apps">iOS Web Apps</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;apple-touch-icon&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/custom_icon.png&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;apple-touch-startup-image&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/splash.png&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;apple-mobile-web-app-title&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;App Name&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;apple-mobile-web-app-capable&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;yes&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;apple-mobile-web-app-status-bar-style&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;black-translucent&quot;</span>&gt;</span>
</code></pre><p>To allow site owners to customise the experience of their websites when added to a user&#8217;s homescreen on iOS, Apple <a href="https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html">introduced the above meta tags</a>. The icon, startup image, and title are self-explanatory, while <code>apple-mobile-web-app-capable</code> disabled the browser chrome, and <code>apple-mobile-web-app-status-bar-style</code> allowed setting the operating system status bar to one of three possible values:</p>
<ul>
<li><code>default</code> - White background with black text and icons.</li>
<li><code>black</code> - Black background with black text and icons.</li>
<li><code>black-translucent</code> - Background colour sourced from the webpage background colour with white text and icons.</li>
</ul>
<p>These meta tags are now rendered obsolete by modern <abbr>PWA</abbr> definitions.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;apple-touch-fullscreen&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;yes&quot;</span>&gt;</span>
</code></pre><p><code>apple-touch-fullscreen</code> was used in some early demos for iOS 2, however, Apple&#8217;s documentation only reflects <code>apple-mobile-web-app-capable</code>. Due to its presence in those early demos, <code>apple-touch-fullscreen</code> was popularised before the feature released, seemingly prompting Apple to make it an alias of <code>apple-mobile-web-app-capable</code>.</p>
<h2 id="uc-browser-and-qq-browser">UC Browser and QQ Browser</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;screen-orientation&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;portrait&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;x5-orientation&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;portrait&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;full-screen&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;yes&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;x5-fullscreen&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;true&quot;</span>&gt;</span>
</code></pre><p>UC Browser and QQ Browser were particularly popular browsers in Asia through the early to mid-2010s due to their heavy data savings and optimisation for cheap devices. UC Browser would use <code>screen-orientation</code> to force a specific display orientation and <code>full-screen</code> to hide the browser&#8217;s chrome. QQ Browser would do the same, though with <code>x5-orientation</code> and <code>x5-fullscreen</code>. &#8216;X5&#8217; in those meta names refer to Tencent&#8217;s X5 browser engine. The meta tags are no longer needed due to the standard fullscreen and orientation <abbr>API</abbr>s and popularisation of more capable browsers.</p>
<h2 id="pda-optimised"><abbr>PDA</abbr> Optimised</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;HandheldFriendly&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;true&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;MobileOptimized&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;320&quot;</span>&gt;</span>
</code></pre><p>Before the proliferation of <code>&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width&quot;&gt;</code> for making sites cleanly scale to small screens, these tags were widely used for mobile content. <code>HandheldFriendly</code> was created for <a href="https://getoutofmyhead.dev/handheld-friendly">AvantGo</a> and then <a href="https://web.archive.org/web/20150306230553/https://developer.blackberry.com/playbook/html5/documentation/handheldfriendly.html">spread to the Blackberry Browser</a>, while <code>MobileOptimized</code> was a <a href="https://learn.microsoft.com/en-us/previous-versions/bb431690(v=msdn.10)">Microsoft concoction</a> for old versions of <a href="https://vale.rocks/posts/pda-browsers#windows-mobile">Windows Mobile</a>.</p>
<h2 id="internet-explorer-tap-highlight">Internet Explorer Tap Highlight</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;msapplication-tap-highlight&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;no&quot;</span>&gt;</span>
</code></pre><p>This snippet stops links from highlighting when tapped in Internet Explorer 11. It was similar to <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/-webkit-tap-highlight-color"><code>-webkit-tap-highlight-color</code></a>, though unlike that property it was a boolean and didn&#8217;t allow changing the colour.</p>
<h2 id="revisit-after">Revisit-After</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;revisit-after&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;7 days&quot;</span>&gt;</span>
</code></pre><p>A website called <a href="http://vancouver-webpages.com">Vancouver Webpages</a> ran a niche regional search system called &#8216;searchBC&#8217; (the BC standing for &#8216;British Columbia&#8217;) which used the tag to know how often it should re-scrape a site. However, this was the only known use of the tag. There is no evidence that it has ever been used by any major search engine, <a href="https://developers.google.com/search/blog/2007/12/answering-more-popular-picks-meta-tags#revisit-after-sitemap-lastmod-and-changefreq">including Google</a>. Despite this, it somehow caught on like some sort of <abbr>SEO</abbr> myth and was perpetuated across the web.</p>
<h2 id="page-prerendering">Page Prerendering</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;prerender&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://example.com&quot;</span>&gt;</span>
</code></pre><p>Only fully supported in Chrome between versions 13 and 62 and never specced, this would fetch and process a page so it would be ready when users navigate to it. The functionality was replaced by the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API">Speculation Rules <abbr>API</abbr></a>.</p>
<h2 id="accelerated-mobile-pages-version">Accelerated Mobile Pages Version</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;amphtml&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://example.com/amp.html&quot;</span>&gt;</span>
</code></pre><p>Accelerated Mobile Pages (<abbr>AMP</abbr>) were restructured versions of pages optimised for faster content loading. This tag was used to link to an <abbr>AMP</abbr> version of a page, however, Accelerated Mobile Pages are no longer widely used, and Google no longer pushes for them, making the tag unneeded.</p>
<h2 id="safari-footer-landmark">Safari Footer Landmark</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">footer</span> <span class="hljs-attr">role</span>=<span class="hljs-string">&quot;contentinfo&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
</code></pre><p>Prior to Safari 13, the <code>contentinfo</code> landmark role <a href="https://trac.webkit.org/changeset/242051/webkit/">wasn&#8217;t exposed properly to VoiceOver</a> which was a significant accessibility problem. To address this, the <code>role</code> would be explicitly set on the page footer by developers.</p>
<h2 id="internet-explorer-reading-view">Internet Explorer Reading View</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;IE_RM_OFF&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;true&quot;</span>&gt;</span>
</code></pre><p>Starting with Internet Explorer 9, &#8216;Reading View&#8217; was introduced. By pressing a button which would appear in the browser chrome, you could get a simplified version of a page suited for reading. Pages could opt out of having this button shown by including the aforementioned meta tag.</p>
<h2 id="frontpage">FrontPage</h2>
<pre><code class="language-html"><span class="hljs-comment">&lt;!--webbot bot=&quot;Timestamp&quot; s-type=&quot;EDITED&quot; s-format=&quot;%B %d, %Y&quot; startspan --&gt;</span>
<span class="hljs-comment">&lt;!--webbot bot=&quot;Timestamp&quot; i-checksum=&quot;54321&quot; endspan --&gt;</span>

<span class="hljs-comment">&lt;!--webbot bot=&quot;TableOfContents&quot; s-component-title=&quot;Site Map&quot; s-starting-point=&quot;index.htm&quot; s-heading-level=&quot;3&quot; startspan --&gt;</span>
<span class="hljs-comment">&lt;!--webbot bot=&quot;TableOfContents&quot; endspan --&gt;</span>

<span class="hljs-comment">&lt;!--webbot bot=&quot;HitCounter&quot; u-custom i-digits=&quot;6&quot; startspan --&gt;</span>
<span class="hljs-comment">&lt;!--webbot bot=&quot;HitCounter&quot; endspan --&gt;</span>

<span class="hljs-comment">&lt;!--webbot bot=&quot;PurpleText&quot; preview=&quot;<span class="hljs-doctag">TODO:</span> Replace product prices before launching sale page.&quot; startspan --&gt;</span>
<span class="hljs-comment">&lt;!--webbot bot=&quot;PurpleText&quot; endspan --&gt;</span>
</code></pre><p>Microsoft FrontPage was a <abbr title="What You See Is What You Get">WYSIWYG</abbr> website creation tool. Among other code, it would inject <a href="https://www.neusob.de/projekt/workshop/webbot.htm">WebBot Components</a>, such as those seen above. They were marked up as comments, so they wouldn&#8217;t appear on a page directly, but they were processed by FrontPage Server Extensions (<abbr>FPSE</abbr>) and used in FrontPage&#8217;s editor. Many of these WebBot Components existed, and developers could create their own using the FrontPage Software Developer&#8217;s Kit.</p>
<h2 id="really-simple-discovery">Really Simple Discovery</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;EditURI&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://example.com/xmlrpc.php?rsd&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;application/rsd+xml&quot;</span> <span class="hljs-attr">title</span>=<span class="hljs-string">&quot;RSD&quot;</span>&gt;</span>
</code></pre><p><a href="https://cyber.harvard.edu/blogs/gems/tech/rsd.html">Really Simple Discovery (<abbr>RSD</abbr>)</a> was a system for exposing services for managing a blog to clients. The link in the head would direct clients to an <abbr>XML</abbr> document which would include endpoints to which tools such as Windows Live Writer, BlogJet, or MarsEdit could connect. It was implemented across platforms, including WordPress, Blogger, LiveJournal, TypePad, and MediaWiki. Modern publishing systems have generally deprecated it.</p>
<h2 id="pingbacks">Pingbacks</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;pingback&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://example.com/xmlrpc.php&quot;</span>&gt;</span>
</code></pre><p>Pingbacks were a system where sites would alert other sites when they linked to them. The site receiving the &#8216;ping&#8217; would check that a link was actually present on the site sending the ping, then make a note on the page saying something to the effect of &#8216;[Website] linked to this page&#8217;. They functioned somewhat similarly to how <a href="https://indieweb.org/Webmention">WebMentions</a> do.</p>
<p>Unfortunately, pingbacks rather quickly became an avenue for spam and <abbr>SEO</abbr>-gaming, so fell out of fashion. Vulnerabilities allowing sites to be tied up in <abbr title="Distributed Denial of Service">DDoS</abbr> attacks also became widely exploited.</p>
<h2 id="share-partners">Share Partners</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;image_src&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://example.com/post/image.png&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;audio_src&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://example.com/post/audio.mp4&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;video_src&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://example.com/post/video.mp4&quot;</span>&gt;</span>
</code></pre><p>Before Facebook created <a href="https://ogp.me">Open Graph</a>, they had a &#8216;Share Partners&#8217; system for defining metadata to be used in embeds. Many additional sites adopted it as an ad hoc standard and implemented the tags. For example, <a href="https://web.archive.org/web/20120511044923/https://about.digg.com/thumbnails">Digg</a>.</p>
<p><code>rel=&quot;image_src&quot;</code> would be referenced for an image to embed, <code>rel=&quot;audio_src&quot;</code> would be referenced for audio to embed, and likewise <code> rel=&quot;video_src&quot;</code> for video. There were <a href="https://web.archive.org/web/20061114042416/https://www.facebook.com/share_partners.php">a number of these meta tags</a> which were supported to varying degrees.</p>
<h2 id="twitter-embeds">Twitter Embeds</h2>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;twitter:card&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;summary&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;twitter:site&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;@account&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;twitter:creator&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;@writer_account&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;twitter:url&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;https://example.com/posts/hello-world&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;twitter:title&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;Title&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;twitter:description&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;Page description&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;twitter:image&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;https://example.com/hello-world-embed-image.png&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;twitter:image:alt&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;Alternative text for the image.&quot;</span>&gt;</span>
</code></pre><p>These meta tags (and some other, less frequently used ones) were used on Twitter when generating link embeds. However, the documentation and card validator are no longer accessible (previously at <code>https://dev.twitter.com/cards/getting-started</code> and <code>https://cards-dev.twitter.com/validator</code> respectively). X falls back to the widely respected Open Graph meta tags, making the Twitter-specific declarations largely useless. They should be removed in favour of Open Graph tags. Further, they should be removed because X is an awful site with poor moderation that is owned by a man who publicly performed a Nazi Sieg Heil salute and has directly contributed to the rise of fascism in the United States of America and globally, among other horrors.</p>
<pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;twitter:dnt&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;on&quot;</span>&gt;</span>
</code></pre><p>Twitter also had a Do Not Track meta tag for opting out of tracking when using Twitter for Websites widgets. Again, the documentation (previously at <code>https://dev.twitter.com/web/overview/privacy</code>) is now inaccessible, and it seems the tag is no longer respected.</p>
<hr>
<p>This article isn&#8217;t comprehensive. These are only the more popular or notable non-standard bits. There are so many more obscure bits drifting through the shatters of cyberspace. For the curious mind, some more meta tags are listed &#8211; albeit without associated detail &#8211; on <a href="https://wiki.whatwg.org/wiki/MetaExtensions">the WhatWG Wiki</a>. There are also a very wide variety of similar <a href="https://vale.rocks/posts/css-relics"><abbr>CSS</abbr> relics from browser releases of years past</a>.</p>
<section class="footnotes" data-footnotes>
<h2 id="footnote-label" class="sr-only">Footnotes</h2>
<ol>
<li id="footnote-1">
<p>Google tried something very similar in late-2024 with a feature called &#8216;<a href="https://web.archive.org/web/20241121124222/https://support.google.com/websearch/thread/308719098/page-annotation-in-google-app-browser-for-ios?hl=en">Page Annotations</a>&#8217; in their Google app on iOS. It was hated and ultimately discontinued in March 2025. <a href="#footnote-ref-1" data-footnote-backref aria-label="Back to reference 1">↩</a></p>
</li>
</ol>
</section>

		]]></content:encoded>
    </item>
    <item>
      <pubDate>Sat, 05 Sep 2026 00:00:00 GMT</pubDate>
      <title>Examining My Halo Service Record</title>
      <link>https://vale.rocks/posts/halo-stats</link>
      <guid>https://vale.rocks/posts/halo-stats</guid>
      <description>Statistics and data from my playing of the video games in the Halo series. My data extracted from Halo Waypoint combined with some light analysis. Covering the games in the Master Chief Collection and Halo Infinite. Kills, deaths, and how they all happened.</description>
      <content:encoded><![CDATA[
			
			
			<p>I am not what one would call the greatest player of Halo to ever grace this planet. If you can believe it, I am rather mediocre. I have moments of greatness, but I&#8217;m also very much a casual player. Halo is a game I can pick up and play for leisure without too much effort or consideration. That said, I love data. I love diving into data and picking out interesting little details &#8211; all the tiny little bits that you don&#8217;t really notice otherwise.</p>
<p>Bungie must have been data fiends too, because their website, <a href="https://www.halopedia.org/Bungie.net">bungie.net</a>, used to be a haven for player stats. Hooking directly into Xbox Live, bungie.net was a brilliant hub of Halo stats and content. You could even see <a href="https://bnetarchive.haloman30.com/Stats/halo3/heatmapstatsed76.html">things like heatmaps</a> showing where a player killed or got killed. Even details such as what weapons you were best with. Unfortunately, 343 Industries didn&#8217;t keep the same level of detail when they took over the franchise. Some details are made accessible on Halo Waypoint, but they&#8217;re a bit lacklustre, and not all tracked details are exposed.</p>
<p>This page shows all my Halo stats, sourced from my <a href="https://www.halowaypoint.com/players/outervale/service-records">Service Records on Halo Waypoint</a>. The stats are not fetched automatically, as Halo Studios or Microsoft are liable to change authentication or the returned data, causing a surprise breakage. I instead fetch them manually when I feel the data has grown stale. Using the <a href="https://vale.rocks/posts/web-origami">ever-wonderful Web Origami dialect of JavaScript</a> which I built this site upon, I then transform the data to populate this post. You can see when I last updated the data by referencing the modification date in the header.</p>
<p>This is a similar process to the one I employ for <a href="https://vale.rocks/posts/team-fortress-stats">Examining My Team Fortress Statistics</a>.</p>
<details>
<summary>Further data details</summary><p>I load up the Halo Waypoint site in my browser, authenticate, and download my Service Records directly. My Halo Infinite Service Record comes from <code>https://halostats.svc.halowaypoint.com/hi/players/xuid(2535432479962354)/Matchmade/servicerecord?</code>. My Halo MCC Service Record comes from <code>https://mccapi.svc.halowaypoint.com/hmcc/users/gt(OuterVale)/service-record</code> with the campaign data coming from <code>https://mccapi.svc.halowaypoint.com/hmcc/users/gt(OuterVale)/service-record/{GAME}/campaign</code>. In the latter I substitute <code>{GAME}</code> for the game: &#8216;h1&#8217;, &#8216;h2&#8217;, &#8216;h3&#8217;, &#8216;odst&#8217;, &#8216;reach&#8217;, or &#8216;h4&#8217;.</p>
<p>I then save my acquired data in my website&#8217;s Git repository. I have scripts to map campaign level numbers to the actual names corresponding to the levels, to map medal IDs to the actual medal data, and a script to convert the timestamps to actual human-readable duration values with reasonable degrees of detail.</p>
</details><h2 id="halo-the-master-chief-collection">Halo: The Master Chief Collection</h2>
<p>The Master Chief Collection (MCC) has my stats for Halo: CE through Halo 4. I did not play the original Xbox and Xbox 360 releases of these games when their servers were still available, so no stats exist from those releases.</p>
<p>My MCC stats are particularly poor. If ever you&#8217;ve tried to play an old online game with a die-hard community, you know the struggle. The people still playing these old Halo games online are really good. Many have been playing since the games originally released and know them intricately. Meanwhile, I&#8217;ve only played for 2 days and 8 hours, and that is across all of the games in the collection. They&#8217;re fun games that are great to jump into, but I won&#8217;t kid that I don&#8217;t get decimated.</p>
<h3 id="multiplayer">Multiplayer</h3>
<ul>
<li>Games Played: 84</li>
<li>Wins: 37</li>
<li>Losses: 47</li>
<li>Kills: 455</li>
<li>Deaths: 1016</li>
<li>Assists: 342</li>
<li>Average <abbr title="Kill-Death-Assist">KDA</abbr>: -5.32</li>
</ul>
<h3 id="campaigns">Campaigns</h3>
<ul>
<li>Mission Kills: 8550</li>
<li>Mission Deaths: 127</li>
</ul>
<details>
<summary>Individual campaign level stats</summary><h3>Halo: Combat Evolved</h3><h4>The Pillar of Autumn</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Normal</li>
	<li>Best Time (Single Player) (Easy): 1 hour and 40 minutes</li>
	<li>Best Score (Co-op) (Normal): 3900</li>
	<li>Best Time (Co-op) (Normal): 16 minutes and 39 seconds</li>
</ul>
<h4>Halo</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Normal</li>
	<li>Best Score (Single Player) (Easy): 611</li>
	<li>Best Time (Single Player) (Easy): 40 minutes and 45 seconds</li>
	<li>Best Score (Co-op) (Normal): 3660</li>
	<li>Best Time (Co-op) (Normal): 31 minutes and 21 seconds</li>
</ul>
<h4>Truth and Reconciliation</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1526</li>
	<li>Best Time (Single Player) (Easy): 37 minutes and 43 seconds</li>
</ul>
<h4>The Silent Cartographer</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1055</li>
	<li>Best Time (Single Player) (Easy): 38 minutes and 12 seconds</li>
</ul>
<h4>Assault on the Control Room</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1724</li>
	<li>Best Time (Single Player) (Easy): 1 hour and 5 minutes</li>
</ul>
<h4>343 Guilty Spark</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 827</li>
	<li>Best Time (Single Player) (Easy): 23 minutes and 42 seconds</li>
</ul>
<h4>The Library</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2256</li>
	<li>Best Time (Single Player) (Easy): 45 minutes and 36 seconds</li>
</ul>
<h4>Two Betrayals</h4>
<ul>
	<li>Highest Difficulty (Single Player): None</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
</ul>
<h4>Keyes</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2459</li>
	<li>Best Time (Single Player) (Easy): 25 minutes and 49 seconds</li>
</ul>
<h4>The Maw</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1032</li>
	<li>Best Time (Single Player) (Easy): 30 minutes and 52 seconds</li>
</ul>
<h3>Halo 2</h3><h4>The Heretic</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1504</li>
	<li>Best Time (Single Player) (Easy): 17 minutes and 36 seconds</li>
</ul>
<h4>The Armory</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 961</li>
	<li>Best Time (Single Player) (Easy): 30 minutes and 5 seconds</li>
</ul>
<h4>Cairo Station</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 3469</li>
	<li>Best Time (Single Player) (Easy): 19 minutes and 23 seconds</li>
</ul>
<h4>Outskirts</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1294</li>
	<li>Best Time (Single Player) (Easy): 22 minutes and 8 seconds</li>
</ul>
<h4>Metropolis</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 705</li>
	<li>Best Time (Single Player) (Easy): 54 minutes and 7 seconds</li>
</ul>
<h4>The Arbiter</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1745</li>
	<li>Best Time (Single Player) (Easy): 27 minutes and 39 seconds</li>
</ul>
<h4>Oracle</h4>
<ul>
	<li>Highest Difficulty (Single Player): None</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
</ul>
<h4>Delta Halo</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 490</li>
	<li>Best Time (Single Player) (Easy): 29 minutes and 17 seconds</li>
</ul>
<h4>Regret</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1499</li>
	<li>Best Time (Single Player) (Easy): 24 minutes and 46 seconds</li>
</ul>
<h4>Sacred Icon</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2084</li>
	<li>Best Time (Single Player) (Easy): 44 minutes and 25 seconds</li>
</ul>
<h4>Quarantine Zone</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1932</li>
	<li>Best Time (Single Player) (Easy): 15 minutes and 16 seconds</li>
</ul>
<h4>Gravemind</h4>
<ul>
	<li>Highest Difficulty (Single Player): None</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
</ul>
<h4>Uprising</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 3317</li>
	<li>Best Time (Single Player) (Easy): 20 minutes and 53 seconds</li>
</ul>
<h3>Halo 3</h3><h4>Sierra 117</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1330</li>
	<li>Best Time (Single Player) (Easy): 18 minutes and 53 seconds</li>
</ul>
<h4>Crowsnest</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1466</li>
	<li>Best Time (Single Player) (Easy): 34 minutes and 21 seconds</li>
</ul>
<h4>Tsavo Highway</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2605</li>
	<li>Best Time (Single Player) (Easy): 20 minutes and 3 seconds</li>
</ul>
<h4>The Storm</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2188</li>
	<li>Best Time (Single Player) (Easy): 22 minutes and 29 seconds</li>
</ul>
<h4>Floodgate</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2607</li>
	<li>Best Time (Single Player) (Easy): 15 minutes and 13 seconds</li>
</ul>
<h4>The Ark</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2918</li>
	<li>Best Time (Single Player) (Easy): 44 minutes and 39 seconds</li>
</ul>
<h4>The Covenant</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 3572</li>
	<li>Best Time (Single Player) (Easy): 39 minutes and 49 seconds</li>
</ul>
<h4>Cortana</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1843</li>
	<li>Best Time (Single Player) (Easy): 28 minutes and 35 seconds</li>
</ul>
<h4>Halo</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 3068</li>
	<li>Best Time (Single Player) (Easy): 21 minutes and 3 seconds</li>
</ul>
<h3>Halo 3: <abbr>ODST</abbr></h3><h4>Prepare to Drop</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 755</li>
	<li>Best Time (Single Player) (Easy): 14 minutes and 5 seconds</li>
</ul>
<h4>Mombasa Streets</h4>
<ul>
	<li>Highest Difficulty (Single Player): None</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
</ul>
<h4>Tayari Plaza</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2860</li>
	<li>Best Time (Single Player) (Easy): 16 minutes and 42 seconds</li>
</ul>
<h4>Uplift Reserve</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2732</li>
	<li>Best Time (Single Player) (Easy): 14 minutes and 17 seconds</li>
</ul>
<h4>Kizingo Boulevard</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2108</li>
	<li>Best Time (Single Player) (Easy): 13 minutes and 53 seconds</li>
</ul>
<h4><abbr>ONI</abbr> Alpha Site</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1207</li>
	<li>Best Time (Single Player) (Easy): 19 minutes and 42 seconds</li>
</ul>
<h4><abbr>NMPD</abbr> HQ</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1826</li>
	<li>Best Time (Single Player) (Easy): 4 minutes and 12 seconds</li>
</ul>
<h4>Kikowani Station</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 9096</li>
	<li>Best Time (Single Player) (Easy): 23 minutes and 21 seconds</li>
</ul>
<h3>Halo: Reach</h3><h4>Noble Actual</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 694</li>
	<li>Best Time (Single Player) (Easy): 19 minutes and 49 seconds</li>
</ul>
<h4>Winter Contingency</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2037</li>
	<li>Best Time (Single Player) (Easy): 21 minutes and 54 seconds</li>
</ul>
<h4><abbr>ONI</abbr>: Sword Base</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 903</li>
	<li>Best Time (Single Player) (Easy): 27 minutes and 31 seconds</li>
</ul>
<h4>Nightfall</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2250</li>
	<li>Best Time (Single Player) (Easy): 23 minutes and 7 seconds</li>
</ul>
<h4>Tip of the Spear</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2475</li>
	<li>Best Time (Single Player) (Easy): 31 minutes and 12 seconds</li>
</ul>
<h4>Long Night of Solace</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2230</li>
	<li>Best Time (Single Player) (Easy): 26 minutes and 23 seconds</li>
</ul>
<h4>Exodus</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 3166</li>
	<li>Best Time (Single Player) (Easy): 25 minutes and 34 seconds</li>
</ul>
<h4>New Alexandria</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2358</li>
	<li>Best Time (Single Player) (Easy): 24 minutes and 9 seconds</li>
</ul>
<h4>The Package</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 4391</li>
	<li>Best Time (Single Player) (Easy): 29 minutes and 38 seconds</li>
</ul>
<h4>The Pillar of Autumn</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
</ul>
<h4>Lone Wolf</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 387</li>
	<li>Best Time (Single Player) (Easy): 4 minutes and 41 seconds</li>
</ul>
<h3>Halo 4</h3><h4>Dawn</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2279</li>
	<li>Best Time (Single Player) (Easy): 17 minutes and 37 seconds</li>
</ul>
<h4>Requiem</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1636</li>
	<li>Best Time (Single Player) (Easy): 28 minutes and 38 seconds</li>
</ul>
<h4>Forerunner</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 1765</li>
	<li>Best Time (Single Player) (Easy): 39 minutes and 38 seconds</li>
</ul>
<h4>Infinity</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 6806</li>
	<li>Best Time (Single Player) (Easy): 44 minutes and 40 seconds</li>
</ul>
<h4>Reclaimer</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 2789</li>
	<li>Best Time (Single Player) (Easy): 52 minutes and 44 seconds</li>
</ul>
<h4>Shutdown</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 3463</li>
	<li>Best Time (Single Player) (Easy): 36 minutes and 6 seconds</li>
</ul>
<h4>Composer</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 6125</li>
	<li>Best Time (Single Player) (Easy): 27 minutes and 49 seconds</li>
</ul>
<h4>Midnight</h4>
<ul>
	<li>Highest Difficulty (Single Player): Easy</li>
	<li>Highest Difficulty (Co-op): Not Played</li>
	<li>Best Score (Single Player) (Easy): 6046</li>
	<li>Best Time (Single Player) (Easy): 32 minutes and 10 seconds</li>
</ul>
</details><h2 id="halo-infinite">Halo Infinite</h2>
<p>Unlike MCC, I&#8217;m not quite as poorly matched in Halo Infinite on account of it being a newer game that is much more accessible and has a far greater active player population. It is also an extremely solid online game with the best gameplay of the series &#8211; or at least it has grown into being one following its lacklustre 2021 launch.</p>
<figure class="right shorter">
<img src="/assets/posts/halo-stats/infinite-spartan.avif" alt="An almost insectoid-looking Spartan holding a pistol. The helmet exposes a brain-like plate with a colourful holographic accent which is also seen on shoulder plates. The rest of the armour plating is dark and worn with accents of green.">
<figcaption>My multiplayer Spartan holding an Mk50 Sidekick. Applied is the Rakshasa armour core with the Abundant Growth coating, Mimir helmet, Unity visor, Tactor Augmentor shoulder pads, and Trapmaster&#8217;s Map armour effect.</figcaption>
</figure><p>It should be noted that the majority of my play time in Halo Infinite is primarily with network ping in excess of 300ms and with a controller with stick drift (I have <a href="https://vale.rocks/micros/20260808-0411">tried to fix it</a> to no avail). I usually connect to the Sydney servers, which are some <abbr>3300KM</abbr> away from my Xbox. On a handful of occasions I&#8217;ve been absolutely destroyed by Australian Halo YouTuber <a href="https://www.youtube.com/@mintblitz">Mint Blitz</a>.</p>
<p>I&#8217;ve completed 637 matches in my 4 days and 9 hours of playtime since I first played the game in February of 2023. Of those matches, I&#8217;ve won 328 of them, lost 299 of them, and tied in 10 of them. That is a 51.49% win rate overall.</p>
<h3 id="core-stats">Core Stats</h3>
<p>These are the totals across all game types (including Firefight, which massively inflates figures).</p>
<ul>
<li>Score: 8952</li>
<li>Personal Score: 877483</li>
<li>Rounds Won: 352 (51.31%)</li>
<li>Rounds Lost: 324 (47.23%)</li>
<li>Rounds Tied: 10 (1.46%)</li>
<li>Win/Loss Ratio: 1.10</li>
<li>Kills: 14779</li>
<li>Deaths: 6960</li>
<li>Assists: 4102</li>
<li>Kill-to-death Ratio: 2.12</li>
<li>Average <abbr title="Kill-Death-Assist">KDA</abbr>: 14.42</li>
<li>Suicides: 116 (1.67%)</li>
<li>Betrayals: 19 <em>(sorry!)</em></li>
<li>Grenade Kills: 140 (0.95%)</li>
<li>Headshot Kills: 461 (3.12%)</li>
<li>Melee Kills: 986 (6.67%)</li>
<li>Power Weapon Kills: 1498 (10.14%)</li>
<li>Shots Fired: 255457</li>
<li>Shots Hit (Accuracy): 85016 (33.28%)</li>
<li>Damage Dealt: 3216329</li>
<li>Damage Taken: 1834199</li>
<li>Damage Ratio: 1.75</li>
<li>Callout Assists: 2</li>
<li>Vehicles Destroyed: 163</li>
<li>Driver Assists: 70</li>
<li>Vehicle Hijacks: 27</li>
<li><abbr title="Electro Magnetic Pulse">EMP</abbr> Assists: 7</li>
<li>Max Killing Spree: 10</li>
<li>Spawns: 7432</li>
<li>Objectives Completed: 351</li>
</ul>
<p>For exclusively player versus player interactions, excluding Firefight:</p>
<ul>
<li>Kills: 4863</li>
<li>Deaths: 6315</li>
<li>Assists: 1832</li>
<li>Kill-to-death Ratio: 0.77</li>
</ul>
<h3 id="medals">Medals</h3>
<h4>Spree</h4>
<ul>
	<li><span class="medal" style="background-position:-64px -0px;"></span> <strong>Killing Spree</strong> ×405<br>Kill 5 enemies without dying.</li>
	<li><span class="medal" style="background-position:-128px -0px;"></span> <strong>Killing Frenzy</strong> ×272<br>Kill 10 enemies without dying.</li>
	<li><span class="medal" style="background-position:-192px -0px;"></span> <strong>Running Riot</strong> ×221<br>Kill 15 enemies without dying.</li>
	<li><span class="medal" style="background-position:-256px -0px;"></span> <strong>Rampage</strong> ×168<br>Kill 20 enemies without dying.</li>
	<li><span class="medal" style="background-position:-320px -0px;"></span> <strong>Nightmare</strong> ×136<br>Kill 25 enemies without dying.</li>
	<li><span class="medal" style="background-position:-0px -0px;"></span> <strong>Killjoy</strong> ×124<br>End an enemy&#8217;s killing spree.</li>
	<li><span class="medal" style="background-position:-384px -0px;"></span> <strong>Boogeyman</strong> ×113<br>Kill 30 enemies without dying.</li>
	<li><span class="medal" style="background-position:-448px -0px;"></span> <strong>Grim Reaper</strong> ×98<br>Kill 35 enemies without dying.</li>
	<li><span class="medal" style="background-position:-512px -0px;"></span> <strong>Demon</strong> ×71<br>Kill 40 enemies without dying.</li>
	<li><span class="medal" style="background-position:-128px -640px;"></span> <strong>Driving Spree</strong> ×4<br>Earn 5 Driver Assists without dying.</li>
	<li><span class="medal" style="background-position:-192px -640px;"></span> <strong>Death Cabbie</strong> ×2<br>Earn 10 Driver Assists without dying.</li>
	<li><span class="medal" style="background-position:-256px -640px;"></span> <strong>Immortal Chauffeur</strong> ×1<br>Earn 15 Driver Assists without dying.</li>
</ul>
<h4>Mode</h4>
<ul>
	<li><span class="medal" style="background-position:-576px -0px;"></span> <strong>Steaktacular</strong> ×51<br>Win a game by dominating the enemy team.</li>
	<li><span class="medal" style="background-position:-896px -192px;"></span> <strong>Hill Guardian</strong> ×22<br>Occupy the Hill for 30 seconds without leaving in King of the Hill.</li>
	<li><span class="medal" style="background-position:-640px -0px;"></span> <strong>Flawless Victory</strong> ×9<br>Win every round of a game with 3+ rounds.</li>
	<li><span class="medal" style="background-position:-960px -0px;"></span> <strong>Stopped Short</strong> ×6<br>Kill an enemy flag carrier who is about to score.</li>
	<li><span class="medal" style="background-position:-64px -64px;"></span> <strong>Goal Line Stand</strong> ×4<br>Return a flag near the enemy flag stand.</li>
	<li><span class="medal" style="background-position:-448px -64px;"></span> <strong>Extermination</strong> ×4<br>Wipe an enemy team with at least an Overkill in Elimination or Attrition.</li>
	<li><span class="medal" style="background-position:-704px -0px;"></span> <strong>Perfection</strong> ×3<br>Win a game with 15+ kills and no deaths.</li>
	<li><span class="medal" style="background-position:-832px -192px;"></span> <strong>Always Rotating</strong> ×2<br>Capture all zones in a single life.</li>
	<li><span class="medal" style="background-position:-960px -192px;"></span> <strong>Clock Stop</strong> ×1<br>Stop the enemy from scoring their final points by capturing a zone in Strongholds.</li>
</ul>
<h4>Multikill</h4>
<ul>
	<li><span class="medal" style="background-position:-0px -256px;"></span> <strong>Double Kill</strong> ×1874<br>Kill 2 enemies in quick succession.</li>
	<li><span class="medal" style="background-position:-64px -256px;"></span> <strong>Triple Kill</strong> ×623<br>Kill 3 enemies in quick succession.</li>
	<li><span class="medal" style="background-position:-128px -256px;"></span> <strong>Overkill</strong> ×283<br>Kill 4 enemies in quick succession.</li>
	<li><span class="medal" style="background-position:-192px -256px;"></span> <strong>Killtacular</strong> ×135<br>Kill 5 enemies in quick succession.</li>
	<li><span class="medal" style="background-position:-256px -256px;"></span> <strong>Killtrocity</strong> ×69<br>Kill 6 enemies in quick succession.</li>
	<li><span class="medal" style="background-position:-320px -256px;"></span> <strong>Killamanjaro</strong> ×41<br>Kill 7 enemies in quick succession.</li>
	<li><span class="medal" style="background-position:-384px -256px;"></span> <strong>Killtastrophe</strong> ×30<br>Kill 8 enemies in quick succession.</li>
	<li><span class="medal" style="background-position:-448px -256px;"></span> <strong>Killpocalypse</strong> ×20<br>Kill 9 enemies in quick succession.</li>
	<li><span class="medal" style="background-position:-512px -256px;"></span> <strong>Killionaire</strong> ×15<br>Kill 10 enemies in quick succession.</li>
</ul>
<h4>Proficiency</h4>
<ul>
	<li><span class="medal" style="background-position:-320px -320px;"></span> <strong>Boxer</strong> ×84<br>Kill 5 enemies with melee in a game.</li>
	<li><span class="medal" style="background-position:-256px -320px;"></span> <strong>Bomber</strong> ×60<br>Kill 5 enemies with launchers in a game.</li>
	<li><span class="medal" style="background-position:-384px -320px;"></span> <strong>Warrior</strong> ×47<br>Kill 5 enemies with melee weapons in a game.</li>
	<li><span class="medal" style="background-position:-768px -256px;"></span> <strong>Wingman</strong> ×41<br>Earn 10 Kill Assists in a game.</li>
	<li><span class="medal" style="background-position:-64px -320px;"></span> <strong>Rifleman</strong> ×32<br>Kill 5 enemies with assault rifles in a game.</li>
	<li><span class="medal" style="background-position:-448px -320px;"></span> <strong>Gunslinger</strong> ×32<br>Kill 5 enemies with pistols in a game.</li>
	<li><span class="medal" style="background-position:-576px -320px;"></span> <strong>Breacher</strong> ×28<br>Kill 5 enemies with <abbr>SMG</abbr> weapons in a game.</li>
	<li><span class="medal" style="background-position:-704px -320px;"></span> <strong>Marksman</strong> ×24<br>Kill 5 enemies with tactical rifles in a game.</li>
	<li><span class="medal" style="background-position:-192px -320px;"></span> <strong>Grenadier</strong> ×21<br>Kill 5 enemies with grenades in a game.</li>
	<li><span class="medal" style="background-position:-640px -320px;"></span> <strong>Sharpshooter</strong> ×16<br>Kill 5 enemies with sniper rifles in a game.</li>
	<li><span class="medal" style="background-position:-512px -320px;"></span> <strong>Scattergunner</strong> ×15<br>Kill 5 enemies with shotguns in a game.</li>
	<li><span class="medal" style="background-position:-960px -256px;"></span> <strong>Driver</strong> ×7<br>Kill 5 enemies with ground vehicles in a game.</li>
	<li><span class="medal" style="background-position:-832px -256px;"></span> <strong>Wheelman</strong> ×5<br>Earn 5 Driver Assists in a game.</li>
	<li><span class="medal" style="background-position:-768px -320px;"></span> <strong>Tanker</strong> ×5<br>Kill 5 enemies with siege vehicles in a game.</li>
	<li><span class="medal" style="background-position:-896px -256px;"></span> <strong>Gunner</strong> ×2<br>Kill 5 enemies with mounted turrets in a game.</li>
	<li><span class="medal" style="background-position:-128px -320px;"></span> <strong>Heavy</strong> ×2<br>Kill 5 enemies with detached turrets in a game.</li>
	<li><span class="medal" style="background-position:-704px -256px;"></span> <strong>Saboteur</strong> ×1<br>Destroy 5 enemy vehicles in a game.</li>
	<li><span class="medal" style="background-position:-0px -320px;"></span> <strong>Pilot</strong> ×1<br>Kill 5 enemies with aircraft in a game.</li>
	<li><span class="medal" style="background-position:-832px -320px;"></span> <strong>Bodyguard</strong> ×1<br>Save 5 allies by killing their attacker in a game.</li>
</ul>
<h4>Skill</h4>
<ul>
	<li><span class="medal" style="background-position:-256px -384px;"></span> <strong>Back Smack</strong> ×441<br>Kill an enemy by hitting them from behind with melee.</li>
	<li><span class="medal" style="background-position:-320px -384px;"></span> <strong>Splatter</strong> ×265<br>Kill an enemy by hitting them with a vehicle.</li>
	<li><span class="medal" style="background-position:-64px -384px;"></span> <strong>Cluster Luck</strong> ×198<br>Kill 2+ enemies with a single grenade.</li>
	<li><span class="medal" style="background-position:-640px -384px;"></span> <strong>Odin&#8217;s Raven</strong> ×176<br>Detect 3+ enemies with a single Threat Sensor.</li>
	<li><span class="medal" style="background-position:-576px -384px;"></span> <strong>Kong</strong> ×119<br>Kill an enemy by throwing a Fusion Coil.</li>
	<li><span class="medal" style="background-position:-384px -384px;"></span> <strong>Reversal</strong> ×104<br>Kill an enemy who attacked you first.</li>
	<li><span class="medal" style="background-position:-704px -448px;"></span> <strong>Grand Slam</strong> ×78<br>Kill 2+ enemies with a single Gravity Hammer swing.</li>
	<li><span class="medal" style="background-position:-128px -384px;"></span> <strong>Stick</strong> ×74<br>Kill an enemy by sticking them with a Plasma or Spike Grenade.</li>
	<li><span class="medal" style="background-position:-448px -384px;"></span> <strong>Snipe</strong> ×64<br>Headshot an enemy with a Power sniper rifle.</li>
	<li><span class="medal" style="background-position:-448px -448px;"></span> <strong>No Scope</strong> ×56<br>Kill an enemy with a Power sniper rifle without zooming.</li>
	<li><span class="medal" style="background-position:-512px -448px;"></span> <strong>Whiplash</strong> ×48<br>Kill a grappling enemy.</li>
	<li><span class="medal" style="background-position:-0px -384px;"></span> <strong>Harpoon</strong> ×37<br>Grapple a distant enemy.</li>
	<li><span class="medal" style="background-position:-960px -384px;"></span> <strong>Bank Shot</strong> ×27<br>Kill an enemy with a ricochet.</li>
	<li><span class="medal" style="background-position:-704px -384px;"></span> <strong>Tag &amp; Bag</strong> ×15<br>Kill 2+ enemies while revealing them with the Threat Sensor.</li>
	<li><span class="medal" style="background-position:-512px -384px;"></span> <strong>Guardian Angel</strong> ×15<br>Save an ally&#8217;s life from far away.</li>
	<li><span class="medal" style="background-position:-896px -384px;"></span> <strong>Bulltrue</strong> ×14<br>Save yourself or an ally by interrupting an enemy&#8217;s Energy Sword lunge.</li>
	<li><span class="medal" style="background-position:-64px -448px;"></span> <strong>Perfect</strong> ×13<br>Kill an enemy with a precision weapon with peak efficiency.</li>
	<li><span class="medal" style="background-position:-640px -448px;"></span> <strong>Boom Block</strong> ×12<br>Block an incoming projectile by deploying a Drop Wall.</li>
	<li><span class="medal" style="background-position:-0px -512px;"></span> <strong>Sneak King</strong> ×11<br>Kill a camouflaged enemy by hitting them from behind with melee.</li>
	<li><span class="medal" style="background-position:-320px -512px;"></span> <strong>Ninja</strong> ×8<br>Kill an enemy by leaping over them and hitting them from behind with melee.</li>
	<li><span class="medal" style="background-position:-576px -448px;"></span> <strong>Windshield Wiper</strong> ×7<br>Kill an enemy attempting to hijack a vehicle.</li>
	<li><span class="medal" style="background-position:-896px -576px;"></span> <strong>Counter-snipe</strong> ×7<br>Headshot an enemy while you both are zoomed with Power sniper rifles.</li>
	<li><span class="medal" style="background-position:-192px -384px;"></span> <strong>Chain Reaction</strong> ×5<br>Kill an enemy with a shock chain.</li>
	<li><span class="medal" style="background-position:-960px -320px;"></span> <strong>Dogfight</strong> ×3<br>Destroy an enemy aircraft while in one yourself.</li>
	<li><span class="medal" style="background-position:-832px -384px;"></span> <strong>Pancake</strong> ×3<br>Kill an enemy by flattening them with the Repulsor.</li>
	<li><span class="medal" style="background-position:-256px -512px;"></span> <strong>Quigley</strong> ×3<br>Kill 2+ enemies with a single S7 Sniper round.</li>
	<li><span class="medal" style="background-position:-256px -448px;"></span> <strong>Fire &amp; Forget</strong> ×3<br>Kill an enemy with an M41 <abbr>SPNK</abbr>r from far away.</li>
	<li><span class="medal" style="background-position:-192px -448px;"></span> <strong>Hail Mary</strong> ×2<br>Kill an enemy with a grenade from far away.</li>
	<li><span class="medal" style="background-position:-128px -448px;"></span> <strong>Mind the Gap</strong> ×1<br>Kill an enemy by sending them to their doom with the Repulsor.</li>
	<li><span class="medal" style="background-position:-192px -512px;"></span> <strong>Remote Detonation</strong> ×1<br>Kill an enemy by shooting a grenade.</li>
	<li><span class="medal" style="background-position:-768px -384px;"></span> <strong>Rideshare</strong> ×1<br>Deliver the objective carrier to the objective after driving a great distance.</li>
	<li><span class="medal" style="background-position:-896px -320px;"></span> <strong>Skyjack</strong> ×1<br>Hijack an enemy aircraft.</li>
	<li><span class="medal" style="background-position:-896px -448px;"></span> <strong>Autopilot Engaged</strong> ×1<br>Kill the enemy driver of a moving vehicle with a Power sniper rifle.</li>
	<li><span class="medal" style="background-position:-320px -448px;"></span> <strong>Ballista</strong> ×1<br>Kill an enemy with a Skewer from far away.</li>
</ul>
<h4>Style</h4>
<ul>
	<li><span class="medal" style="background-position:-576px -512px;"></span> <strong>From the Grave</strong> ×127<br>Kill an enemy after you die.</li>
	<li><span class="medal" style="background-position:-768px -512px;"></span> <strong>Last Shot</strong> ×125<br>Kill an enemy with your magazine&#8217;s last round.</li>
	<li><span class="medal" style="background-position:-384px -576px;"></span> <strong>Yard Sale</strong> ×78<br>Kill an enemy who had a Power weapon and a full inventory.</li>
	<li><span class="medal" style="background-position:-128px -576px;"></span> <strong>Grapple-jack</strong> ×13<br>Grapple to and hijack an enemy vehicle.</li>
	<li><span class="medal" style="background-position:-576px -576px;"></span> <strong>360</strong> ×12<br>Kill an enemy by shooting them moments after spinning around.</li>
	<li><span class="medal" style="background-position:-320px -576px;"></span> <strong>Off the Rack</strong> ×5<br>Kill an enemy with a weapon moments after retrieving it from its spawn location.</li>
	<li><span class="medal" style="background-position:-704px -512px;"></span> <strong>Quick Draw</strong> ×4<br>Kill an enemy with a pistol moments after switching to it.</li>
	<li><span class="medal" style="background-position:-960px -512px;"></span> <strong>Ramming Speed</strong> ×4<br>Destroy an enemy vehicle by hitting it with your own.</li>
	<li><span class="medal" style="background-position:-448px -512px;"></span> <strong>Mount Up</strong> ×2<br>Assemble a fully-loaded vehicle of 2+ allies after honking the horn.</li>
	<li><span class="medal" style="background-position:-512px -512px;"></span> <strong>Reclaimer</strong> ×2<br>Hijack an enemy vehicle that was once yours.</li>
	<li><span class="medal" style="background-position:-320px -640px;"></span> <strong>Blind Fire</strong> ×2<br>Kill a distant enemy by shooting them from inside a Shroud Screen.</li>
	<li><span class="medal" style="background-position:-832px -576px;"></span> <strong>Fastball</strong> ×1<br>Kill an enemy with the impact from a thrown grenade.</li>
</ul><h3 id="capture-the-flag">Capture the Flag</h3>
<p>My favourite of Halo&#8217;s game types. The goal is to capture the enemy flag and return it to your base. I very much play the objective and will throw away lives trying to get one up.</p>
<ul>
<li>Flag Steals: 203</li>
<li>Flag Grabs: 156</li>
<li>Flag Captures: 81</li>
<li>Flag Capture Assists: 48</li>
<li>Flag Steal-to-Capture Conversion: 39.9%</li>
<li>Flag Carriers Killed: 109</li>
<li>Flag Returners Killed: 15</li>
<li>Flag Returns: 95</li>
<li>Flag Secures: 148</li>
<li>Kills as Flag Carrier: 6</li>
<li>Kills as Flag Returner: 18</li>
<li>Time as Flag Carrier: 41 minutes and 17 seconds</li>
</ul>
<h3 id="attrition">Attrition</h3>
<p>Slayer, but each team has a limited number of lives, and players can be revived. I usually feel like too much of a burden to my team.</p>
<ul>
<li>Allies Revived: 132</li>
<li>Elimination Assists: 12</li>
<li>Eliminations: 19</li>
<li>Enemy Revives Denied: 0</li>
<li>Executions: 0</li>
<li>Kills as Last Player Standing: 1</li>
<li>Last Players Standing Killed: 1</li>
<li>Rounds Survived: 9</li>
<li>Times Revived by Ally: 171</li>
</ul>
<h3 id="infection">Infection</h3>
<p>A group of survivors try to survive against zombies. Once slain, survivors join the zombie team to hunt down more survivors. I find this mode very stressful, so don&#8217;t play it often.</p>
<ul>
<li>Alphas Killed: 3</li>
<li>Spartans Infected: 5</li>
<li>Spartans Infected as Alpha: 3</li>
<li>Kills as Last Spartan Standing: 0</li>
<li>Last Spartans Standing Infected: 0</li>
<li>Rounds as Alpha: 1</li>
<li>Rounds as Last Spartan Standing: 0</li>
<li>Rounds Finished as Infected: 7</li>
<li>Rounds Survived as Spartan: 0</li>
<li>Rounds Survived as Last Spartan Standing: 0</li>
<li>Time as Last Spartan Standing: 0 seconds</li>
<li>Infected Killed: 4</li>
</ul>
<h3 id="oddball">Oddball</h3>
<p>Must hold onto a skull (the titular Oddball) to collect points, while stopping the enemy team from doing the same. Very much dependent on team members being helpful due to being unable to use weapons while holding the ball. Unfortunately, they are often not.</p>
<ul>
<li>Kills as Skull Carrier: 4</li>
<li>Longest Time as Skull Carrier: 53 seconds</li>
<li>Skull Carriers Killed: 4</li>
<li>Skull Grabs: 2</li>
<li>Time as Skull Carrier: 2 minutes and 15 seconds</li>
<li>Skull Scoring Ticks: 132</li>
</ul>
<h3 id="total-control">Total Control</h3>
<p>Teams must capture and control all designated areas on a map while preventing the enemy team from doing the same.</p>
<ul>
<li>Zone Captures: 208</li>
<li>Zone Defensive Kills: 40</li>
<li>Zone Offensive Kills: 76</li>
<li>Zone Secures: 33</li>
<li>Total Zone Occupation Time: 49 minutes and 52 seconds</li>
<li>Zone Scoring Ticks: 386</li>
</ul>
<h3 id="stockpile">Stockpile</h3>
<p>Two teams fighting for Power Seeds, which are located in neutral territory and must be collected and deposited at your base. I&#8217;m not much a fan of this gametype.</p>
<ul>
<li>Kills as Power Seed Carrier: 0</li>
<li>Power Seed Carriers Killed: 1</li>
<li>Power Seeds Deposited: 0</li>
<li>Power Seeds Stolen: 0</li>
<li>Time as Power Seed Carrier: 0 seconds</li>
<li>Time as Power Seed Driver: 0 seconds</li>
</ul>
<h3 id="firefight">Firefight</h3>
<p>Multiplayer or single-player wave defence against computer-driven enemies.</p>
<ul>
<li>Kills: 9564</li>
<li>Deaths: 245</li>
<li>Assists: 2150</li>
<li>Grunt Kills: 4147 (43.36%)</li>
<li>Jackal Kills: 2567 (26.84%)</li>
<li>Elite Kills: 454 (4.75%)</li>
<li>Brute Kills: 1164 (12.17%)</li>
<li>Hunter Kills: 30 (0.31%)</li>
<li>Skimmer Kills: 1059 (11.07%)</li>
<li>Boss Kills: 143 (1.50%)</li>
</ul>
<style>
@media (min-width: 30rem) {
	article > div ul {
		columns: 2;
		column-gap: 2rem;

		&:has(> li:only-child) {
            columns: 1;
        }

		li {
			break-inside: avoid;
            margin-block-start: 0;
		}
	}
}

.medal {
	display: inline-block;
	block-size: 4rem;
	aspect-ratio: 1;
	vertical-align: middle;
	background-image: url(/assets/posts/halo-stats/infinite-medals.avif);
	background-size: 1024px auto;
}
</style>

		]]></content:encoded>
    </item>
    <item>
      <pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate>
      <title>The Curiosity That Is Minecraft: Pi Edition</title>
      <link>https://vale.rocks/posts/minecraft-pi-edition</link>
      <guid>https://vale.rocks/posts/minecraft-pi-edition</guid>
      <description>The history and details of an obscure Minecraft version that was exclusively available on the Raspberry Pi. Based on the mobile Pocket Edition for phones but with some unique functionality. Namely, a native API for interacting with the game. Primarily created to serve as an educational tool.</description>
      <content:encoded><![CDATA[
			
			
			<p><em>Minecraft: Pi Edition</em> is a modified port of the game Minecraft to the Raspberry Pi, a hobbyist single-board computer. It is a bit of an oddity, because it differs greatly from other editions of Minecraft, is completely free, saw only fleeting support from Minecraft&#8217;s developer Mojang, and is obscure, despite being a port of the best-selling game of all time.</p>
<figure class="shorter pixelated">
<img src="/assets/posts/minecraft-pi-edition/mc-pi-edition-small-house.avif" alt="A small Minecraft house made of wood. It has a planter out the front with a cyan rose in it. To the right is a patch of wheat. I'm holding an iron sword.">
<figcaption>
A small house built in Pi Edition. Note the cyan rose, which was exclusive to old versions of Pocket Edition, as the colour red caused bad image ghosting on the Xperia Play.
</figcaption>
</figure><h2 id="history">History</h2>
<p>Minecraft was originally developed in Java for desktop operating systems. As the game grew in popularity, demand grew for it to appear on more platforms. In August 2011 the first port of the game, <em>Minecraft: Pocket Edition</em> (MC:PE), released on the Xperia Play. In October the game came to wider Android, and in November it came to iOS.</p>
<p>To run on mobile phones of the time, the Pocket Edition was written in C++, rather than Java, and was severely cut down and optimised. For context, the most recent flagship Samsung phone at the time of MC:PE&#8217;s release was the Samsung Galaxy S II, and the most recent iPhone was the iPhone 4s. The Pocket Edition was far behind the Java Edition in features, something that hasn&#8217;t changed years on, with many parity issues <a href="https://minecraft.wiki/w/Parity_issue_list">remaining unaddressed</a>, even now that Minecraft Bedrock Edition, which evolved from Pocket Edition, is the main and predominant version of the game.</p>
<p>In November 2012, <a href="https://web.archive.org/web/20200716231638/https://www.mojang.com/2012/11/minecraft-is-coming-to-the-raspberry-pi/">Mojang announced Minecraft was coming to the Raspberry Pi</a> with development being led by <a href="https://minecraft.wiki/w/Aron_Nieminen">Aron Nieminen</a> and <a href="https://minecraft.wiki/w/Daniel_Frisk">Daniel Frisk</a>.</p>
<p>On December 20<sup>th</sup>, Mojang accidentally published the announcement blog post on the Minecraft: Pi Edition blog before quickly retracting it. However, when they <a href="https://web.archive.org/web/20170124210204/http://pi.minecraft.net/">published the announcement blog post officially</a> upon release of the game, the post retained the initial, incorrect publish date.</p>
<p>On December 26<sup>th</sup>, the game leaked online after it was accidentally uploaded unencrypted on Mojang&#8217;s repository, before being encrypted shortly thereafter. Daniel <a href="https://web.archive.org/web/20200716160833/https://twitter.com/danfrisk/status/283682787033247744">said of the leak</a>, &#8216;I don&#8217;t mind if people use the leaked build, but be aware that it&#8217;s pre-alpha quality.&#8217;. The leaked version identified itself as &#8216;0.1.0 alpha&#8217; and was based upon Pocket Edition v0.5.0 alpha.</p>
<p>Minecraft: Pi Edition released officially on February 11<sup>th</sup>, 2013. This initial version, v0.1.1 alpha, was the only version released. In January 2016, it was stated by then Mojang Developer Tommaso Checchi <a href="https://www.reddit.com/r/MCPE/comments/42g9cr/comment/cza7seq/">in a thread on Reddit regarding the status of the Pi Edition</a> that:</p>
<blockquote>
<p>It ded :(</p>
<p>The original team has stopped supporting it and starting with 0.9 <abbr>MCPE</abbr> became a lot more ambitious technically, which also means that it became a lot harder to strip down to run on a Raspberry Pi. Actually, we finished removing all Pi related code to reduce complexity in 2015.</p>
<p>Maybe someday we&#8217;ll revisit it but I wouldn&#8217;t hold my breath :P</p>
</blockquote>
<p>In September 2014 Raspbian (now called &#8216;Raspberry Pi OS&#8217;) was updated to include Minecraft Pi. It remained pre-installed until August 2021, when the operating system updated to using Debian Bullseye as a base and <a href="https://downloads.raspberrypi.org/raspios_full_armhf/release_notes.txt#:~:ext=Minecraft%20removed%20from%20Recommended%20Software">Minecraft Pi became incompatible</a>.</p>
<h2 id="functionality">Functionality</h2>
<p>The Pi Edition is not a &#8216;game&#8217; in the same way that other versions of Minecraft are. It is designed to be hacked upon via its <abbr title="Applications Programming Interface">API</abbr>, so out of the box there are a number of changes from Pocket Edition v0.6.1 alpha (on which Minecraft: Pi Edition is based). These are:</p>
<ol>
<li>Survival mode is stripped. You cannot join survival mode servers or set your own game mode to survival.</li>
<li>The player is always called &#8216;StevePi&#8217;.</li>
<li>Signs are always blank and cannot be edited.</li>
<li>There is no audio (though a mute button still appears in the menu).</li>
<li>The interface uses the Xperia Play design, rather than the standard touch interface.</li>
<li>You can&#8217;t select a world&#8217;s seed or name. All worlds have the name &#8216;world&#8217;.</li>
<li>The world is always visible via <abbr title="Local Area Network">LAN</abbr>.</li>
<li>Mobs are disabled.</li>
<li>Chests, Crafting Tables, Furnaces, <abbr>TNT</abbr>, and the Nether Reactor Core are all non-functional.</li>
<li>Fancy graphics are disabled.</li>
<li>The bow doesn&#8217;t function. It can be drawn, but it doesn&#8217;t shoot arrows and will remain drawn until switched from.</li>
<li>Saplings and wheat seeds do not grow unless bone meal is applied.</li>
<li>Fire doesn&#8217;t spread and is also invisible.</li>
<li>Coordinates are shown in the top left corner.</li>
<li>You can sneak, which was otherwise exclusive to the Xperia Play version of Pocket Edition until v0.12.1.</li>
</ol>
<p>Most of these features remain in the game, just patched out. Some of these changes can be attributed to performance considerations. At the time of Pi Edition&#8217;s release, the most recent Raspberry Pi was the Raspberry Pi 1 Model A &#8211; a cheaper variant of the original Raspberry Pi with only <abbr>256MB</abbr> of memory (even less than the iPhone 4). The Pi Edition has bespoke <abbr title="Graphics Processing Unit">GPU</abbr> code which explains some visual differences. It is because of this that screenshots of Pi Edition will appear blank, unless using a workaround such as <a href="https://github.com/AndrewFromMelbourne/raspi2png">raspi2png</a>.</p>
<p>Only &#8216;Old&#8217;-style worlds can be generated. They&#8217;re 256 blocks wide on the X and Z axes, and 128 blocks high on the Z axis. Rainforest, Swampland, Seasonal Forest, Forest, Savannah, Shrubland, Taiga, Desert, Plains, Ice Desert, and Tundra biomes are all present in the game. However, the Savannah and Shrubland have no special generation and the Ice Desert does not generate naturally. Due to the small world size it is uncommon to have much, if any, variation of biomes within a world. The files for worlds themselves are located at <code>~/.minecraft/games/com.mojang/minecraftWorlds</code>. They can be modified by the same means that are used to modify worlds in old versions of Pocket Edition.</p>
<h2 id="api"><abbr>API</abbr></h2>
<p>Most of Pi Edition&#8217;s changes from Pocket Edition can be attributed to Pi Edition&#8217;s focus on hacking and experimenting. The edition was very much designed for people to dip their toes into development and to be used in educational contexts. There is a full <abbr>API</abbr> for interacting with Pi Edition with libraries for Python and Java bundled. The protocol specification is documented in a text file within the edition&#8217;s files. Curiously, despite the intent for users to hack on Pi Edition, debug symbols are stripped. This is particularly odd, as they weren&#8217;t stripped from Bedrock Edition until release version 1.13.0.</p>
<p>People have done all sorts of things using the <abbr>API</abbr>. Many of these efforts can be seen on the <a href="https://www.minecraftforum.net/forums/minecraft-editions/minecraft-pi-edition">Minecraft: Pi Edition board</a> of the Minecraft Forum. Some usages of the <abbr>API</abbr> I find most interesting are Dav Stott&#8217;s <a href="https://davstott.me.uk/index.php/2013/07/28/raspberry-pi-drawing-maps-inside-minecraft/">Ordnance Survey map viewer</a> and the <a href="https://www.stuffaboutcode.com/minecraft/">various experiments by Martin O&#8217;Hanlon</a>. Zhuowei Zhang <a href="https://github.com/zhuowei/RaspberryJuice">created a Bukkit plugin called RaspberryJuice</a>, which implements the Pi Edition <abbr>API</abbr> on Java Edition, allowing scripts to be used across editions.</p>
<h2 id="textures">Textures</h2>
<p>Minecraft: Pi Edition stores textures as <abbr>PNG</abbr> files within the <code>data/images/</code> directory. In Raspberry Pi OS, this directory is located within <code>/opt/minecraft-pi/</code>, making the full path <code>/opt/minecraft-pi/data/images/</code>. Many textures are stored in spritesheets.</p>
<figure class="right pixelated">
<img src="/assets/posts/minecraft-pi-edition/mc-pi-edition-main-menu.avif" alt="A simple menu with a tiled dirt texture background. There are two buttons: 'Start Game' and 'Join Game'. In the bottom left is the RakNet logo, while in the bottom right is text that reads '©Mojang AB'. Front and centre is the logo 'Minecraft: Pi Edition' with the version number.">
<figcaption>Pi Edition&#8217;s main menu.</figcaption>
</figure><p>There are many textures which are carried across from Pocket Edition but which are unused. The relevant textures to modify are:</p>
<ul>
<li><code>terrain.png</code> - All block textures.</li>
<li><code>particles.png</code> - Particles, such as water droplets and potion effects.</li>
<li><code>mob/</code> - Contains the textures for mobs. <code>char.png</code> is the player skin.</li>
<li><code>art/kz.png</code> - All paintings. Named &#8216;kz&#8217; for <a href="http://zetterstrand.com">Kristoffer Zetterstrand</a>, who made the paintings.</li>
<li><code>font/default8.png</code> - The font used for the interface.</li>
<li><code>environment/clouds.png</code> - Clouds. Note that they&#8217;re only visible if you manually enable Fancy Graphics.</li>
<li><code>gui/gui.png</code> - The buttons used in the menu and the in-game hotbar. The rest of the buttons are unused.</li>
<li><code>gui/touch_gui</code> - Most unused, with the exception of the mute and third-person toggle buttons.</li>
<li><code>gui/items.png</code> - All item textures.</li>
<li><code>gui/icons.png</code> - The crosshair, health, armour, and breath interface elements. With the exception of the crosshair, these icons are unused due to being survival dependent.</li>
<li><code>gui/pi_title.png</code> - The logo used on the main menu.</li>
<li><code>gui/default_world.png</code> - Thumbnail used in the interface for all worlds.</li>
<li><code>gui/gui_blocks.png</code> - Unlike Java Edition and newer versions of Bedrock Edition, Pi Edition does not automatically generate the display of blocks within the user&#8217;s inventory. Instead, it uses a pre-generated spritesheet containing <abbr>3D</abbr> representations of the blocks.</li>
<li><code>gui/background.png</code> & <code>gui/bg32.png</code> - Tiled for the menu backgrounds.</li>
<li><code>gui/cursor.png</code> - Mouse pointer.</li>
<li><code>gui/logo/</code> - Logos of RakNet, the C++ networking library used by Pi Edition. Appears in the bottom left corner of the main menu.</li>
</ul>
<p>As they are just <abbr>PNG</abbr> files and not at all bespoke, they can be easily modified with image manipulation tools. Just ensure they&#8217;re saved as 32-bit <abbr>PNG</abbr>s, as otherwise they&#8217;ll appear corrupted.</p>
<hr>
<p>Minecraft: Pi Edition has largely fallen into irrelevance in the many years since it released. With it no longer being supported on the modern releases of the very devices it was built for, it is firmly a footnote of the past. It can still be found on and downloaded from the Minecraft website; however, the original Pi-specific website that was at <code>pi.minecraft.net</code> is gone.</p>
<p>Outside of official support, a continuation and modernisation of Pi Edition titled <em><a href="https://gitea.thebrokenrail.com/minecraft-pi-reborn/minecraft-pi-reborn">Minecraft: Pi Edition: Reborn</a></em>, or <em><abbr>MCPI</abbr>-Reborn</em>, has been under development in various forms for years. It brings more modern features and assorted fixes, in addition to patching back in functionality, such as survival mode, that sits latent in Pi Edition&#8217;s codebase. The source code for many versions of the Legacy Console Editions and the Pocket Edition &#8211; including the version upon which Pi Edition is based &#8211; leaked in March 2026 and has been referenced by the modding community to make their mods even more impressive.</p>

		]]></content:encoded>
    </item>
    <item>
      <pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate>
      <title>A Complete History of Stoat</title>
      <link>https://vale.rocks/posts/stoat-history</link>
      <guid>https://vale.rocks/posts/stoat-history</guid>
      <description>An in-depth history of the Stoat chat platform. From its precursor Riot, through to all the additions and changes the platform has seen and received as it has grown. Details from when it was once Revolt to the change into Stoat and details of all the bumps and successes along the way.</description>
      <content:encoded><![CDATA[
			
			
			<p>In 2019 three students in their mid-teens &#8211; Paul Makles (Insert), <a href="https://renevinter.xyz">Rene Vinter (Nizune)</a>, and <a href="https://fatalerrorcoded.eu">Martin Löffler (FatalErrorCoded)</a> &#8211; established Riot (stylised <abbr>RIOT</abbr>), an online chat platform targeting gaming communities. Funded by donations on Patreon, Riot operated at a small scale and ultimately ceased development in mid-2019.</p>
<figure class="shorter long">
<img src="/assets/posts/stoat-history/riot-landing-page.avif" alt="A purple landing page with multiple sections showcasing Riot's capabilities. It touts being open-source, has the tagline 'Let's riot together', and one section shows off gaming communities.">
<figcaption>Riot landing page.</figcaption>
</figure><p>Throughout 2020, the team worked on a new project: Revolt. Starting afresh with the lessons learned from Riot, rather than building upon it. Riot had been developed in <abbr>ECMAS</abbr>cript, while Rust was chosen for Revolt&#8217;s back-end as a result of Makles wishing to use the opportunity to learn the language. The name &#8216;Revolt&#8217; was originally just the name of the <abbr>API</abbr> server in development for the project, but it ended up sticking and becoming the name of the project as a whole. Work on Revolt began in late 2019 and continued through 2020.</p>
<p>The back-end was established with a collection of services:</p>
<ul>
<li>January, for proxying images and generating embeds.</li>
<li>Autumn, a file server.</li>
<li>Delta, for the <abbr title="Representational State Transfer">REST</abbr> <abbr>API</abbr>.</li>
<li>Bonfire, for WebSocket events.</li>
<li>Vortex, for voice communication.</li>
</ul>
<p>A web client called Revite (now referred to as &#8216;For Legacy Web&#8217;) was created, which was also installable on mobile devices as a <abbr title="Progressive Web App">PWA</abbr> and on desktop operating systems via an <a href="https://www.electronjs.org">Electron wrapper</a>. In January of 2021 the project went live in a closed beta state and in August officially launched in an open beta.</p>
<figure class="left">
<img src="/assets/posts/stoat-history/revolt-pre-servers.avif" alt="A rather barren chat interface showing a 'Testers' group selected from a list of conversations. A member list is shown to the right with a large chat pane in the centre and a message bar down the bottom. The top right corner shows the current user, and underneath it are tabs for 'Home', 'Friends', 'Saved Messages', and 'Developer'.">
<figcaption>A screenshot of Revite from April 2021, prior to the addition of servers.</figcaption>
</figure><p>Initially being without servers at all, only group chats and direct messages, servers were eventually added, and in mid-June 2021, Makles created the first proper server on the platform: Revolt Testers. This server replaced the &#8216;Testers&#8217; group chat (pictured) and was later rebranded to the &#8216;Revolt Lounge&#8217;.</p>
<p>Revolt&#8217;s first &#8216;influx&#8217; &#8211; the name given to mass inpourings of new users &#8211; occurred in September of 2021 when the platform found itself <a href="https://news.ycombinator.com/item?id=28434012">on the front page of Hacker News</a>, reaching 642 upvotes. Nobody from the team posted or was aware of this post until a great deal of users began to show up. Message acknowledgements had to be disabled to prevent the platform from going offline. As result of Hacker News&#8217; reach, Revolt saw secondary exposure from additional sources such as <a href="https://lobste.rs/s/9tlgop/revolt_new_foss_self_hostable_discord">Lobste.rs</a> and <a href="https://gigazine.net/gsc_news/en/20210919-revolt/">Gigazine</a>. <a href="https://itsfoss.com/revolt/">It&#8217;s <abbr>FOSS</abbr></a> published a particularly popular article which appeared on Google News.</p>
<figure class="right">
<img src="/assets/posts/stoat-history/revite-2021.avif" alt="A more populated interface, showing many more conversations, in-chat messages from bots, and a newly introduced server list to the far left of the page.">
<figcaption>A screenshot of Revite taken by Insert in June 2021.</figcaption>
</figure><p>In very late 2021, the Discover service launched, providing an easy first-party way for people to explore Revolt. Via Discover, users can join servers, invite bots to servers they moderate, and apply themes to Revite.</p>
<p>In May of 2022, a <a href="https://stoat.chat/updates/architecture-overhaul">comprehensive rearchitecturing</a> of Revolt&#8217;s back-end was completed, following the effort&#8217;s beginnings in late January. This greatly improved the reliability and resilience of the platform, while greatly improving both the developer and user experiences. Of particular note was a greatly improved permission system, allowing for private channels in servers and greater control of user permissions by server administrators. A rudimentary <abbr>GIF</abbr> sharing service developed by Revolt and called Gifbox launched in August, though was not well supported after launch and eventually stopped working in mid-2024.</p>
<p>In October of 2022, internet influencer and self-proclaimed misogynist facing multiple international charges for rape, human trafficking, and child abuse material Andrew Tate launched &#8216;The Real World&#8217;. A successor to his previous platform &#8216;Hustler&#8217;s University&#8217;, The Real World is equally as slimy. Part of the &#8216;manosphere&#8217;, the paid platform instructs users on how to make money by hustling with cryptocurrencies and such.</p>
<p>In November it was discovered by a user in the Revolt Lounge that The Real World was completely built atop of Revolt. Paul Makles looked into it and confirmed that not only was it violating Revolt&#8217;s AGPLv3 licence, but that he&#8217;d been contacted by them prior to launch in an attempt to hire him onto the team. I gained access to the platform myself via a contact and can confirm first-hand that it was a modified version of Revite. The <abbr>API</abbr> responses from the back-end made explicit reference to Revolt, too.</p>
<p>The Real World was hacked in May 2024, and almost a million user details were exposed, not due to a vulnerability in Revolt, but because they failed to configure their databases correctly. This was followed in November by another breach in which even more data was leaked and where the hackers flooded chats with <abbr>LGBTQ</abbr>+ emojis. Humorously, this November intrusion happened while Andrew Tate was actively live streaming. Unfortunately, with lack of resources to legally tackle The Real World&#8217;s licence violation, the platform has remained active.</p>
<p>In February 2023, in-app reporting functionality was launched on Revolt as part of a significant push for user safety. This introduced the ability for users to report content to Revolt to be moderated on a platform level, something that had previously been managed across servers by the user-run bot <a href="https://automod.vale.rocks">AutoMod</a>. Alongside this came a major update to <a href="https://github.com/stoatchat/rust-authifier">Authifier</a>, changing its name from &#8216;rAuth&#8217; and becoming a more capable system to prevent spam and abuse of the service. Vinter officially departed from Revolt in early 2023, and Löffler&#8217;s contributions slowed around the same time, later ceasing entirely.</p>
<p>The first major user milestone was reached in June of 2023, when the platform <a href="https://stoat.chat/updates/100k-users">hit 100,000 registered users</a>. This occurred two days following <a href="https://stoat.chat/updates/evolving-usernames">the launch of discriminators</a>, four-digit tags prefixed by an octothorpe which are present at the end of usernames to allow multiple accounts to have the same username and to dissuade a black market of rare username sales. Discord had <a href="https://discord.com/blog/usernames/">announced their intent to remove discriminators</a> the previous month and was rolling the new system out at this time.</p>
<p>In October, the platform&#8217;s first official native application &#8211; Revolt For Android &#8211; <a href="https://stoat.chat/updates/revolt-on-the-go">was teased</a>. Following in December came the <a href="https://stoat.chat/updates/refreshing-revolt-web">beta release of Revolt For Web</a>, a new web and desktop client following Google&#8217;s Material 3 design language intended to replace Revite.</p>
<p>Publicly visible changes were low in early 2024 as lots of work was done behind the scenes. This changed with the short-lived but informative &#8216;Month in Revolt&#8217; series. The <a href="https://stoat.chat/updates/month-in-revolt-may-2024">May entry</a> documented continued work on the Android app, voice and video calling, and an improved developer website. The voice and video work involved replacing Vortex &#8211; the previous voice service whose long-needed 2.0 release had entered a development hell following the departure of Martin Löffler &#8211; with a new <a href="https://livekit.com">LiveKit</a>-based implementation which would also be able to facilitate video sharing.</p>
<p>The <a href="https://stoat.chat/updates/month-in-revolt-july-2024">July entry</a> (June was skipped) detailed improvements to the beta web client (specifically in regard to message formatting and settings), some development on a native iOS client, and various changes to the back-end, including conclusion of an architectural overhaul. The <a href="https://stoat.chat/updates/month-in-revolt-august-2024">final of the monthly updates</a>, which released in August, noted more mobile client improvements and work on moderation systems, though development of the new web client stalled due to Paul Makles&#8217; unavailability.</p>
<p>In October of 2024, Revolt reached another major milestone: half-a-million registered users. This came following a ban of Discord in Russia by the Roskomnadzor &#8211; the agency concerned with monitoring and controlling media and communications within Russia. The following day, Discord was banned in Turkey too. The huge number of Russian and Turkish speaking users necessitated that Revolt fast-track the onboarding of more moderators to handle the event. October also saw features such as pinned messages and webhooks begin to roll out. A private beta for the native Android app also occurred from mid-2024.</p>
<p>In early 2025 the Revolt landing page was overhauled alongside tweaks to the wordmark and brand palette. The native Android app also launched into a long-awaited early access state on the Google Play Store, replacing the <abbr title="Trust Web Activity">TWA</abbr> version that was previously available. It also ended up on the <a href="https://news.ycombinator.com/item?id=43277918">front page of Hacker News again</a>.</p>
<figure class="shorter">
<img src="/assets/posts/stoat-history/revolt-landing-page-early-2025.avif" alt="A gradient-heavy landing page with a dark blue background. Large text reads 'Find your community', followed by 'Revolt is the chat app that's truly built with you in mind.'. A download button is prominent, with a skewed screenshot of Revite's interface visible behind it.">
<figcaption>The Revolt website in early 2025.</figcaption>
</figure><p>As a result of a cease and desist notice regarding the name &#8216;Revolt&#8217;, the platform changed its name to &#8216;Stoat&#8217; after the species of mustelid. Stoat did not publicly divulge the sender of the cease and desist on the grounds of wishing to avoid harming negotiations. Temporary brand resources for the new name were hastily created, and the rebrand <a href="https://web.archive.org/web/20260210034916/https://stoat.chat/updates/long-live-stoat">took place at the beginning of October, 2025</a>. Alongside changes to the brand, the new Stoat For Web client was officially launched and made the default client, replacing Revite. The new LiveKit-based voice system also launched; however, it wasn&#8217;t initially usable due to issues running it in a production deployment.</p>
<p>On the 9<sup>th</sup> of February, 2026, <a href="https://discord.com/press-releases/discord-launches-teen-by-default-settings-globally">Discord announced global age-verification measures</a>. Unhappy users, citing the invasion of privacy, their disdain for Discord&#8217;s chosen age-verification service&#8217;s ties to American surveillance firm Palantir, and existing grievances with Discord&#8217;s increasing profit-over-product mentality, moved to Stoat in droves. The resulting influx was intense for the team to handle and very strenuous on Stoat&#8217;s infrastructure. The drastic sudden increase in email activity saw the platform incorrectly added to spam lists, which caused sign-up delays.</p>
<p>A <a href="https://vale.rocks/portfolio/stoat#icon">new logo and mascot designed by myself</a> went live on February 12<sup>th</sup>, as <a href="https://bsky.app/profile/stoat.chat/post/3memon3azgk22">announced on Bluesky</a>, and by February 19<sup>th</sup>, <a href="https://www.reddit.com/r/stoatchat/comments/1r8tfnb/stoat_user_count_and_other_assorted_figures_over/">Stoat had reached 1,120,000 users</a>, and the platform continued to grow aggressively. Continued press coverage from the likes of <a href="https://www.techradar.com/computing/social-media/so-many-discord-users-are-flocking-to-this-alternative-platform-its-making-stoat-crash">TechRadar</a>, <a href="https://www.youtube.com/watch?v=kWcuSvv6v90&amp;">Switch and Click</a>, <a href="https://www.youtube.com/watch?v=bzosJNHD8jI">Linus Tech Tips</a>, <a href="https://www.youtube.com/watch?v=kpjcmXbmMVM&amp;t=1882s">Gamers Nexus</a>, and <a href="https://www.windowscentral.com/software-apps/discord-alternative-search-10000-percent-stoat">Windows Central</a>, among others, attracted more and more people.</p>
<p>The biggest events of the following months were the introduction of push notifications, which <a href="https://bsky.app/profile/stoat.chat/post/3mmn7m7gwzg2m">came to Stoat For Android in May</a>; the <a href="https://stoat.chat/updates/introducing-gifbox">launch of a completely overhauled Gifbox</a> sharing nothing but the name and idea of the original, following the shutdown of Tenor&#8217;s <abbr>API</abbr>; and then <a href="https://stoat.chat/release-notes/93eb1f4ec77444ca9fb13617e0e6c0b1">video streaming in mid-July</a>. Video streaming had been hotly anticipated and was already implemented and available to people self-hosting, but this update saw the experience polished and the feature made widely available. The status page was also moved to <a href="https://stoatstatus.com">stoatstatus.com</a>.</p>
<p>In mid-August of 2026, <a href="https://agenciabrasil.ebc.com.br/en/geral/noticia/2026-08/brazil-orders-discord-suspend-live-streams-country">Discord was ordered by Brazil to suspend video streaming within the country</a> following abuse of the service. As with previous restrictions of Discord&#8217;s service availability, this triggered an influx. A mass number of Brazilian users joined the platform, making use of the recently launched video-streaming functionality. An extra production node within the United States of America had been established to improve performance of the service outside of Europe on August 9<sup>th</sup>, but the unexpected influx saw it removed on the 22<sup>nd</sup> due to the great associated costs.</p>
<figure class="shorter">
<img src="/assets/posts/stoat-history/stoat-for-web-august-2026.avif" alt="A Material 3-styled client with a purple tint. Left to right is a server list, a list of channels in the current server 'AutoMod', a chat pane showing a rules channel, and then a list of users. Buttons to create a server, open Discover, open settings, go home, pin messages, and search messages can all be seen.">
<figcaption>A screenshot of Stoat For Web in August 2026.</figcaption>
</figure><p>It was during late August that Stoat reached another milestone: one-and-a-half million users. It was also during August that the official Stoat server on platform, which had previously been called the &#8216;Revolt Lounge&#8217;, <a href="https://vale.rocks/micros/20260821-1025">switched to allowing topical discussion only</a> rather than allowing all discussion. This was done to avoid centralisation of users in one server and to promote users dispersing across the platform. This brings us to Stoat as it stands as of this article&#8217;s publication.</p>

		]]></content:encoded>
    </item>
    <item>
      <pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate>
      <title>The AT Protocol Harkens An Old Web Ethos</title>
      <link>https://vale.rocks/posts/atproto-ethos</link>
      <guid>https://vale.rocks/posts/atproto-ethos</guid>
      <description>Love for the beauty of the AT Protocol and the older web principles it revitalises with open, public data. The opportunity for integrations and automations as seen of the web from roughly the mid-2000s through to the mid-2010s.</description>
      <content:encoded><![CDATA[
			
			
			<p>Web3, the &#8216;era&#8217; of the web supposedly ushering in blockchain technologies and other such fluff, has undoubtedly been a bust. Perhaps not for the bank accounts of manipulators, but a bust in general. Blockchain has very few legitimate applications, <abbr title="Non-Fungible Token">NFT</abbr>s went down like the Hindenburg, and cryptocurrencies have remained a niche with strong ties to crime and corruption.</p>
<p>The hype-driven sham of Web3 followed Web 2.0, which did have substance. With adjacent names such as the &#8216;participative web&#8217; or the &#8216;social web&#8217;, it really gained popularity as a concept in the mid-2000s alongside the establishment of proper social applications like Flickr, Facebook, Last.fm, Twitter, del.icio.us, MySpace, and Foursquare. Part of the beauty of these applications was their rather open <abbr title="Application Programming Interface">API</abbr>s. They made the web feel so alive. Fetching activity from social media and displaying it on articles, people showing their location check-ins on their sites, social bookmarking, the proliferation of <abbr>RSS</abbr> feeds, more interactive capabilities, content discovery via tagging, and so on and so forth all became core parts of what made the web the web.</p>
<p>People feeding data through <a href="https://en.wikipedia.org/wiki/Yahoo_Pipes">Yahoo! Pipes</a> to create automations and mashups of data, <a href="https://www.protopage.com">Protopipe</a> to create rich custom web dashboards, content aggregators like StumbleUpon, Digg, and Reddit linking out to web curios, and people just hacking together with the data exposed and at their disposal directly. The web felt alive with data flowing freely and platforms largely ungated.</p>
<p>Then, slowly but surely, everything started to close and tighten. Websites became platforms and began to optimise obsessively for keeping people engaged. External integrations or outgoing links became hazards, threatening to reduce time-on-page. Access to data through any means other than the platform&#8217;s desired gateways became a threat. The <abbr>API</abbr>s became more restricted, then got dropped altogether. Integrations switched off, and the hedges surrounding the gardens grew thicker and taller.</p>
<p>However, there remains hope for this era and ethos of the web, and the AT Protocol is what is bringing it back into vogue.</p>
<h2 id="the-at-protocol">The AT Protocol</h2>
<p>The &#8216;Authenticated Transfer Protocol&#8217;, or AT Proto for short, is a very simple system at its core. A user signs up on a Personal Data Server (<abbr>PDS</abbr>) on which they&#8217;re given a data repository. This data repository can hold data in the form of records, which are housed within collections. Each user can be identified via a Decentralised Identifier (<abbr>DID</abbr>). The records that are held can take the form of <abbr>JSON</abbr> or blobs, for content such as images or video.</p>
<figure>
<svg viewBox="0 0 800 500" role="img">
    <desc>A diagram showing records nested in collections nested in a data repository nested in a Personal Data Server.</desc> 
    <defs>
        <rect id="pds" width="760" height="460" fill="light-dark(var(--white), var(--grey))" stroke="var(--bright_blue)" stroke-width="2" />
        <rect id="repo" width="340" height="390" fill="oklch(from var(--blue) l c h / calc(alpha - 0.9))" stroke="var(--blue)" stroke-width="2" />
        <rect id="collection" width="310" height="145" fill="oklch(from var(--green) l c h / calc(alpha - 0.85))" stroke="var(--green)"
            stroke-width="2" />
        <rect id="record" width="290" height="30" fill="light-dark(var(--bright_white), var(--dark_grey))" stroke="var(--yellow)" stroke-width="2" />
    </defs>
    <!-- Outer Container -->
    <use href="#pds" x="20" y="20" />
    <!-- User 1 Repository -->
    <use href="#repo" x="40" y="70" />
    <use href="#collection" x="55" y="135" />
    <use href="#record" x="65" y="195" />
    <use href="#record" x="65" y="235" />
    <use href="#collection" x="55" y="295" />
    <use href="#record" x="65" y="355" />
    <use href="#record" x="65" y="395" />
    <!-- User 2 Repository -->
    <use href="#repo" x="420" y="70" />
    <use href="#collection" x="435" y="135" />
    <use href="#record" x="445" y="195" />
    <use href="#record" x="445" y="235" />
    <use href="#collection" x="435" y="295" />
    <use href="#record" x="445" y="355" />
    <use href="#record" x="445" y="395" />
    <!-- Titles Group -->
    <g font-weight="600">
        <text x="40" y="50">Personal Data Server</text>
        <text x="55" y="100">Data Repository</text>
        <text x="65" y="160">Collection</text>
        <text x="65" y="320">Collection</text>
        <text x="435" y="100">Data Repository</text>
        <text x="445" y="160">Collection</text>
        <text x="445" y="320">Collection</text>
    </g>
    <!-- Subtitles & Records Group -->
    <g font-family="monospace" font-size="0.8rem">
        <text x="55" y="120">@vale.rocks (did:plc:7qg&#8230;)</text>
        <text x="65" y="180">app.bsky.feed.post</text>
        <text x="75" y="215">Record: &quot;The AT Protocol Harkens&#8230;&quot;</text>
        <text x="75" y="255">Record: &quot;Atmosphere apps are&#8230;&quot;</text>
        <text x="65" y="340">site.standard.document</text>
        <text x="75" y="375">Record:&apos;Web Platform Wishlist&apos;</text>
        <text x="75" y="415">Record:&apos;Overview of Digital&#8230;&apos;</text>
        <text x="435" y="120">@jaydip.me (did:plc:dl6&#8230;)</text>
        <text x="445" y="180">app.bsky.feed.post</text>
        <text x="455" y="215">Record: &quot;wanna see forums but&#8230;&quot;</text>
        <text x="455" y="255">Record: &quot;no adobe tools were used&quot;</text>
        <text x="445" y="340">app.bsky.graph.follow</text>
        <text x="455" y="375">Record: Follow @vale.rocks</text>
        <text x="455" y="415">Record: Follow @goose.art</text>
    </g>
</svg>
<figcaption>A simple diagram of how records, collections, data repositories, and Personal Data Servers fit together.</figcaption>
</figure><p><abbr>JSON</abbr> records conform to lexicons, which are schemas that keep data consistently structured and formatted. In addition to the unique <abbr>DID</abbr> each user has, they also have a handle, which is defined via a <abbr title="Domain Name System">DNS</abbr> record. My handle is <code>@vale.rocks</code>. I&#8217;ve deliberately kept this explanation simple (though not inaccurate) for the sake of brevity, so you should read Dan Abramov&#8217;s <a href="https://overreacted.io/open-social/">Open Social</a> if you&#8217;re interested in further detail.</p>
<p>As an example, here is the record for my Bluesky profile, which is stored under the collection <code>app.bsky.actor.profile</code>:</p>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;uri&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;at://did:plc:7qg6mz2xtzozxkgbcvf4pdnu/app.bsky.actor.profile/self&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;cid&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;bafyreiavinef6pltfb4bxml7mbbq3gf53buben4fwxgaa7af2nxefa7zqa&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;value&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;$type&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;app.bsky.actor.profile&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;avatar&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
      <span class="hljs-attr">&quot;ref&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
        <span class="hljs-attr">&quot;$link&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;bafkreiav5vj6xi33c7pcr2wtl3bqxsynlgd7rwdpvetnik75nte4ms5xzy&quot;</span>
      <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
      <span class="hljs-attr">&quot;size&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">812706</span><span class="hljs-punctuation">,</span>
      <span class="hljs-attr">&quot;$type&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;blob&quot;</span><span class="hljs-punctuation">,</span>
      <span class="hljs-attr">&quot;mimeType&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;image/png&quot;</span>
    <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;banner&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
      <span class="hljs-attr">&quot;ref&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
        <span class="hljs-attr">&quot;$link&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;bafkreicca3ksn3adp6ixeorlppum5rccani2qjuchs24yq5uilx3z67eyq&quot;</span>
      <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
      <span class="hljs-attr">&quot;size&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">941911</span><span class="hljs-punctuation">,</span>
      <span class="hljs-attr">&quot;$type&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;blob&quot;</span><span class="hljs-punctuation">,</span>
      <span class="hljs-attr">&quot;mimeType&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;image/jpeg&quot;</span>
    <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;description&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Front-end developer, designer, writer, and avid user of the superpowered information superhighway.\n\n✧ https://vale.rocks\n✧ https://fedi.vale.rocks/vale&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;displayName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Vale&quot;</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre><p>This record isn&#8217;t hidden away anywhere. It is public. It exists on the AT Protocol at <code>at://did:plc:7qg6mz2xtzozxkgbcvf4pdnu/app.bsky.actor.profile/self</code>. Bluesky pulls from this record if you <a href="https://bsky.app/profile/vale.rocks">view my profile</a>, and you can view the record for yourself via online AT Proto viewers such as <a href="https://atproto.at/uri/at://did:plc:7qg6mz2xtzozxkgbcvf4pdnu/app.bsky.actor.profile/self">Taproot</a> or <a href="https://pdsls.dev/at://did:plc:7qg6mz2xtzozxkgbcvf4pdnu/app.bsky.actor.profile/self"><abbr>PDS</abbr>ls</a>.</p>
<p>This is the beauty of the AT Protocol: your data is under your control. It exists in your data repository on the <abbr>PDS</abbr> you select, and unless the data is explicitly made private, it is public. Even data held within &#8216;Atproto Spaces&#8217;, which is the system for private data, is still stored in repositories on your <abbr>PDS</abbr> and remains completely under your control. At any time you can manage records yourself or move to another <abbr>PDS</abbr> without everything breaking.</p>
<p>The most popular and well-known AT Protocol application is Bluesky. The AT Protocol stems from Bluesky, which was formed as a research group within Twitter as part of research into decentralising Twitter. However, Elon Musk&#8217;s acquisition of Twitter and rebranding of it into &#8216;X&#8217; saw Bluesky sever ties with Twitter and entirely become its own thing. While I think that Bluesky is flawed, like Twitter before it, the AT Protocol is solid.<sup><a id="footnote-ref-1" href="#footnote-1" data-footnote-ref aria-describedby="footnote-label">1</a></sup></p>
<h2 id="an-open-atmosphere">An Open Atmosphere</h2>
<p>I spoke to the open nature of Web 2.0. Of such a variety of open systems which people used to the greatest extents they could. Of people creating a social internet with integrations and dynamic data which could be wielded and transformed to create a living ecosystem across the web.</p>
<p>The Atmosphere, which is the name given to the ecosystem surrounding the AT Protocol, makes this aged reality a present one once again. <em>Your</em> data is openly accessible to <em>you</em>. I can access the records for my posts on Bluesky, for my <a href="https://tangled.org/vale.rocks">code on Tangled</a>, for my <a href="https://atstore.fyi/profile/vale.rocks">reviews on at-store</a>, for my <a href="https://keytrace.dev/@vale.rocks">identity verification on Keytrace</a>, for my <a href="https://sifa.id/p/vale.rocks">professional identity on Sifa</a>, for the <a href="https://npmx.dev/profile/vale.rocks">npm packages I&#8217;ve liked on npmx</a>, or anything else I&#8217;ve done across the protocol. In fact, I do access these records regularly. I&#8217;ve got all sorts of automations that tie into Atmosphere, including <a href="https://vale.rocks/posts/the-implementation-of-this-site#at-protocol-integration">integrations here on Vale.Rocks</a>.</p>
<p>When a new app launches and I log in with my account on the Atmosphere, I&#8217;m greeted not by a blank slate but by an interface pre-populated by all my existing records. I don&#8217;t manage separate account details on every single Atmosphere using service. I update it once, and everything reads that changed record, though in most cases I&#8217;m given the affordance to change it on a per-service basis if I so choose.</p>
<p>On people&#8217;s personal websites I can leave comments using my account on the AT Protocol, and increasingly I&#8217;ve seen people fetching data from their records across the Atmosphere. People publishing articles with <a href="https://standard.site">Standard.site</a> records on platforms such as <a href="https://leaflet.pub">Leaflet</a>, <a href="https://pckt.blog">pckt</a>, and <a href="https://offprint.app">offprint</a> and then displaying them on their own site, or showing the bookmarks they&#8217;ve saved with one of many bookmarking solutions, or just creating their own site entirely with something like <a href="https://blento.app">Blento</a>. It is all of the creativity and dynamic integrations of liberal Web 2.0 <abbr>API</abbr>s, but with more data, presented in a way that is standardised and easy to access while being under the complete control of the user without some company able to lock it away.</p>
<p>The AT Protocol puts your data in your hands while making it open and accessible and easy to integrate and manipulate. I can&#8217;t help but feel that it captures what the World Wide Web once was. In a climate where the web is only becoming more and more locked down in favour of protecting corporate interests and preventing scraping for artificial intelligence, it feels blissful to see a return to owning data and brandishing it without restraint.</p>
<section class="footnotes" data-footnotes>
<h2 id="footnote-label" class="sr-only">Footnotes</h2>
<ol>
<li id="footnote-1">
<p>I&#8217;m not sure microblogging can be done &#8216;right&#8217; in a social sense. The format itself promotes short, rash responses prone to degradation of context, <a href="https://vale.rocks/micros/20260819-0423">which I&#8217;ve bemoaned before</a>. However, Bluesky&#8217;s moderation is also a bit shaky, as is <a href="https://techcrunch.com/2025/10/05/waffles-eat-bluesky/">how they handle public relations</a>. Thankfully the AT Protocol doesn&#8217;t depend on them. They have the biggest <abbr>PDS</abbr>, and the <a href="https://atproto.com/blog/plc-directory-org">Public Ledger of Credentials is centralised</a>. However they&#8217;re working to change this, and <code>did:web</code> doesn&#8217;t rely upon Bluesky. <a href="#footnote-ref-1" data-footnote-backref aria-label="Back to reference 1">↩</a></p>
</li>
</ol>
</section>

		]]></content:encoded>
    </item>
  </channel>
</rss>