<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[What the Flax]]></title><description><![CDATA[Hacks, Writing, Miscellaneous projects]]></description><link>https://ghost.flax.wtf/</link><image><url>https://ghost.flax.wtf/favicon.png</url><title>What the Flax</title><link>https://ghost.flax.wtf/</link></image><generator>Ghost 3.40</generator><lastBuildDate>Sat, 18 Apr 2026 09:50:46 GMT</lastBuildDate><atom:link href="https://ghost.flax.wtf/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[It doesn't know what it doesn't know]]></title><description><![CDATA[<p>In my continuing exploration of the general capabilities of LLM AI, I keep finding a particularly vexing failure mode: confident bullshit. </p><p>I recently put a smart clock in my kid's room, so that he would know when it was an appropriate time to wake me up on the weekends.  Since</p>]]></description><link>https://ghost.flax.wtf/it-doesnt-know-what-it-doesnt-know/</link><guid isPermaLink="false">699ccb0a81b9b7639fb1709e</guid><category><![CDATA[Programming]]></category><category><![CDATA[AI]]></category><dc:creator><![CDATA[steveship]]></dc:creator><pubDate>Mon, 23 Feb 2026 22:17:29 GMT</pubDate><media:content url="https://ghost.flax.wtf/content/images/2026/02/3_AI_hats.png" medium="image"/><content:encoded><![CDATA[<img src="https://ghost.flax.wtf/content/images/2026/02/3_AI_hats.png" alt="It doesn't know what it doesn't know"><p>In my continuing exploration of the general capabilities of LLM AI, I keep finding a particularly vexing failure mode: confident bullshit. </p><p>I recently put a smart clock in my kid's room, so that he would know when it was an appropriate time to wake me up on the weekends.  Since it was a smart clock, I decided I'd try to make a Google Home routine that would use Gemini to find the day's school lunch menu offering and announce it, so that he could decide whether or not to have me make his lunch.</p><p>First failure mode: silence.  The routine threw an error, and absolutely nothing was announced by the smart device.   So I started playing with Gemini directly.</p><p>Since I wanted this to be generalizable, I pointed Gemini to the school district page which links to the current month's menu.  I asked Gemini to find the relevant menu and tell me what today's choice was.  It was able to navigate the page, find the right menu, and apparently access the menu PDF.  But it answered a different random meal choice every time.  I tried many ways of prompting to help it ("find the white square marked with today's day-of-the-month, report the text in that square", etc).  None of it really helped.  It chooses a random entree somewhere in the document.</p><p>So I asked Gemini how I can prompt it to answer more correctly.  At this time, for the first time, it says that PDFs are difficult to parse and that the text in the document near the right day-of-month, might not be nearby in the rendered document.  Okay.  So I ask it to render the PDF, then use visual reasoning to answer the questions.  It still fails, still giving random day's menu choices.</p><p>I download the PDF myself.  Take a screenshot of the rendered page, and save it as PNG.  Upload the PNG and ask Gemini what is for lunch today?  Boom.  No problems.  Ask it for the rest of the week, no problems.  Ask it which days a picky child that doesn't like things to have sauces might want school lunch.  Boom.  No problems.  So it's clearly able to answer these questions when using visual reasoning.</p><p>I upload the PDF itself to Gemini, ask it to render then use visual reasoning to answer the questions.  Perfect, no notes.</p><p>But, if I ask it to find the PDF from the menus page, render it, then use visual reasoning, it won't.  It claims to, but answers randomly again.</p><p>When it's wrong, it's not just wrong; it's confidently wrong.  It's wrong structured the same way as when it's right.  It was even able to identify parsing the PDF directly as a problem (when asked, woulda been nice to volunteer that)!  But it won't follow the instructions to answer visually based on a document it has downloaded.  Perhaps that's one level of indirection too far.</p><p>It has all the capabilities necessary to accomplish the task I set it.  But it won't put them together on its own.  I tried the thinking model too, it failed as well.</p><p>How could I trust this to develop <em>good</em> code?  Not just code that compiles.  Not just code that passes tests (that in all honesty, it probably wrote itself).  How can I have any confidence that it will solve the right problems with the right tools, instead of just claiming to have?</p><p>When I had Gemini help me write my GADDAG implementation, it did something similar.  When trying to USE the GADDAG to find words that fit a board constraint, it completely missed the point of the GADDAG and used it as a plain ol' trie.  I rewrote the crucial code to take advantage of the reversed prefix data.  Had I trusted AI, my game's computer opponent would be needlessly inefficient, AND take longer to initialize.</p>]]></content:encoded></item><item><title><![CDATA[In Mourning]]></title><description><![CDATA[<p>I'm observing my own reactions to the unceasing onslaught of AI.  While there are yet people who resist AI, many of them mischaracterize it as evil.  It's not evil.  It's banal.  Perhaps Arendt would disagree that there's a difference.</p><p>I tried some LLM coding assistants, apparently before they were "good</p>]]></description><link>https://ghost.flax.wtf/in-mourning/</link><guid isPermaLink="false">6996b20e26bd6875f6baca55</guid><dc:creator><![CDATA[steveship]]></dc:creator><pubDate>Thu, 19 Feb 2026 07:13:10 GMT</pubDate><content:encoded><![CDATA[<p>I'm observing my own reactions to the unceasing onslaught of AI.  While there are yet people who resist AI, many of them mischaracterize it as evil.  It's not evil.  It's banal.  Perhaps Arendt would disagree that there's a difference.</p><p>I tried some LLM coding assistants, apparently before they were "good enough".  They did not impress me.  But I see article after article of breathless hype.  I see people I respect completely won over.  And yet.  When I try again, I see the limitations.  I see the externalized work transforming from deep understanding to wrangling code-gacha machines.  I see the extreme waste inherent in outsourcing thought to these inefficient colossi.</p><p>But it doesn't matter.  The fact is that they do work "good enough".  Not good enough for me, mind you.  Good enough for shitposts.  Good enough for right now. Good enough for fitting right into the corporate practices of shiny facade over deeply broken systems.</p><p>I love systems.  I love systemic thinking.  And THAT is what AI is killing.  Killing thought, killing understanding.  Killing the act of mulling something over, letting it stew in the back of your head until something anneals and snaps into a lower energy fit that makes it all make more sense.</p><p>Nothing makes sense anymore.  We live in the Library of Babel.  Everything is available to be generated on demand.  And it's all slop.  The infinitesmal fraction of works that is actually meaningful is buried, drowned.   And no one cares.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://ghost.flax.wtf/content/images/2026/02/ai_truck_fixed-2.png" class="kg-image" alt srcset="https://ghost.flax.wtf/content/images/size/w600/2026/02/ai_truck_fixed-2.png 600w, https://ghost.flax.wtf/content/images/2026/02/ai_truck_fixed-2.png 610w"><figcaption>Gemini fucked this up 8 times before I took the least bad one and manually edited it.</figcaption></figure><p>I'm in mourning that the career of solving problems by understanding and modeling, encoding that in a system and simulation, then building tools that enrich and empower... is gone.  What's left is endless automated regurgitations of things that came before.  It's supplicating at the altar of AI for something entertaining, something pretty.  Something right now.</p><p>But I still need to eat.  My <em>family</em> needs food and shelter.  So I'll try to find a job.  A career in software development may be impossible now, but maybe a job isn't.  Almost every job I've had before was a soul-crushing experience of giving genuine effort for paltry rewards.  Making someone else richer at my own expense so that I could afford to continue the cycle.  And it used to be okay.  I was relatively well-paid.  Not enough to leave the working class, but enough to live comfortably in the approximately 40% of time that remained my own.</p><p>I do not see that continuing.  I honestly don't know how I'm going to make it work.  Maybe I'll end up doing the computer equivalent of flipping burgers.  Maybe my skill isn't a skill anymore.</p><p>It happened to textiles, and we got affordable clothes.</p><p>It happened to carpenters and to anyone who built with their hands.</p><p>The advent of the home microwave led to frozen tv dinners, and the ability for just about anyone to have something resembling any sort of cuisine at home.</p><p>Fast fashion, particle-board furniture, dollar-store quality _stuff_, and microwaved food.  That's our present, and that's our future.</p><p>We'll have bland generated-on-demand TV.  We'll have a million Roblox games.  We'll be able to match-3 of anything on our locked down iPhones.</p><p>The worst part though is that in order to use these banality machines, we have to pay for the privilege.  The means of production have been stolen from us.  We, the developers who once created worlds with our minds, who sculpted abstractions into tools, must now rent the privilege of producing slop.  How long until trying to produce something unapproved isn't stopped at the App stores, but at the IDE, at the prompt.  Imagine producing meshtastic, or ICE-block, or bittorrent, or Annas-archive in the near future.  I'm sorry Dave, I'm afraid I can't do that.</p>]]></content:encoded></item><item><title><![CDATA[Avoiding Work (on the main thread)]]></title><description><![CDATA[<figure class="kg-card kg-image-card"><img src="https://ghost.flax.wtf/content/images/2025/12/gaddags.jpg" class="kg-image" alt="Brad Pitt as Pikey Mickey asking &quot;D'ye like GADDAGS?&quot;" srcset="https://ghost.flax.wtf/content/images/size/w600/2025/12/gaddags.jpg 600w, https://ghost.flax.wtf/content/images/2025/12/gaddags.jpg 686w"></figure><p>I'm working on a CPU opponent for <a href="https://markmywordsgame.com">Mark My Words</a> because I believe it's a very fun game that a lot of people will like, but it can be difficult to find an opponent.</p><p>Since the game is similar to Scrabble in many ways, I did some research on algorithmic</p>]]></description><link>https://ghost.flax.wtf/avoiding-work/</link><guid isPermaLink="false">69433d1fcb73d85774ade16b</guid><category><![CDATA[Programming]]></category><dc:creator><![CDATA[steveship]]></dc:creator><pubDate>Thu, 18 Dec 2025 00:51:03 GMT</pubDate><media:content url="https://ghost.flax.wtf/content/images/2025/12/gaddags-1.jpg" medium="image"/><content:encoded><![CDATA[<figure class="kg-card kg-image-card"><img src="https://ghost.flax.wtf/content/images/2025/12/gaddags.jpg" class="kg-image" alt="Avoiding Work (on the main thread)" srcset="https://ghost.flax.wtf/content/images/size/w600/2025/12/gaddags.jpg 600w, https://ghost.flax.wtf/content/images/2025/12/gaddags.jpg 686w"></figure><img src="https://ghost.flax.wtf/content/images/2025/12/gaddags-1.jpg" alt="Avoiding Work (on the main thread)"><p>I'm working on a CPU opponent for <a href="https://markmywordsgame.com">Mark My Words</a> because I believe it's a very fun game that a lot of people will like, but it can be difficult to find an opponent.</p><p>Since the game is similar to Scrabble in many ways, I did some research on algorithmic strategies for Scrabble, hoping to adapt them to my game.  One of the interesting things I learned about is a <a href="https://en.wikipedia.org/wiki/GADDAG">GADDAG</a>, which is a specialized Trie that makes it easy to look up words starting anywhere in the word.  I already was using a Trie for an experimental feature, so I figured I'd replace it on my way to a CPU opponent.</p><p>While GADDAGs enable quick lookup during the game, this comes at the cost of significantly more precomputing.  When I did a naive replacement, I noticed that the game became unresponsive for a few seconds while initializing the dictionary.  Immediately, I thought "This is a perfect time to bust out an Isolate and do this work on another thread."  And it was!  But, when I went to test in the web build, I discovered that Isolates are not supported on web!</p><p>I looked into it and discovered that <a href="https://docs.flutter.dev/perf/isolates#web-platforms-and-compute">compute</a> addresses this.  Sort of.  It runs stuff in an Isolate in supported platforms, but still on the main thread on web.  I'm back to functional, but unresponsive.</p><p>I've got PLENTY of javascript/typescript experience, so this immediately made me think of somehow turning this initialization process into an async process.  But it's not like a http request where there's a lot of waiting around doing nothing.  All this work still has to be done locally.  But, it doesn't have to be done all at once.  All we're really doing in the initialization is adding every word in the wordlist to the GADDAG.  The order doesn't matter, it's even idempotent.  This is completely parallelizable!  But the event loop is still single-threaded, so not really.</p><p>So I built a poor-man's multithreading for this task.  Chunk the wordlist (I arbitrarily chose 500 word chunks), then for each chunk create a Future.delayed which adds all those words to the GADDAG.  Use Future.wait to gather all these (even though they are Future&lt;void&gt;) so we don't exit early and <a href="https://en.wikipedia.org/wiki/Bob%27s_your_uncle">Bob's-your-uncle</a>.</p><p>This seems to work very well in practice.  I did not notice any unresponsiveness even when I know that the dictionary loading process is ongoing.</p><p>While I was at it, I refactored the dictionary population to go through a Riverpod provider, and used <a href="https://pub.dev/packages/cross_cache">cross_cache</a> to cache the raw Uint8List I get from the Firebase Storage bucket I keep my dictionary wordlists in.  So now I keep a local disk/indexeddb cache, as well as an in-memory cache of each of the dictionaries loaded during the app session.  This means I can avoid:</p><ol><li>The expensive dictionary initialization - if I've already done that this session</li><li>The Firebase read and download - if the user has already done that once for the dictionary in question.</li><li>A lot of work searching for words that fit the board, using the GADDAG.</li></ol><p>Wonderful, but there's still a lot of work to get to a functioning CPU opponent.</p>]]></content:encoded></item><item><title><![CDATA[But what's it good for?]]></title><description><![CDATA[<p>I was in my teens when the Internet first started gaining ground among normies.  I remember being at my cousins' house and they were showing off their new AOL connection.  I remember being unimpressed.  I didn't see the point then, because AOL was among the least compelling things you can</p>]]></description><link>https://ghost.flax.wtf/but-what-is-it-good-for/</link><guid isPermaLink="false">690694a2b7e06902fafaf35e</guid><category><![CDATA[Programming]]></category><category><![CDATA[Musings]]></category><dc:creator><![CDATA[steveship]]></dc:creator><pubDate>Sat, 01 Nov 2025 23:16:11 GMT</pubDate><content:encoded><![CDATA[<p>I was in my teens when the Internet first started gaining ground among normies.  I remember being at my cousins' house and they were showing off their new AOL connection.  I remember being unimpressed.  I didn't see the point then, because AOL was among the least compelling things you can do with an internet connection.  Why would I want to talk to strangers?</p><p>I feel like I'm missing the point of LLM/AI the exact same way.  Why would I want to chat with an LLM instead of using a search engine and getting facts straight from the source?  Why would I want to let the average of all of StackOverflow anywhere near my codebase? Why do people love The Machine that Lies to You?</p><p>The marketing/intuition around the Internet in those early days was that it would connect everyone to each other, facilitating human contact and a new golden age of empathy and understanding.  Yeah, we were deluding ourselves.  But it turns out, what the internet is <em>actually</em> good for is almost the exact <em>opposite</em> of direct person-to-person contact (sure it does that, but that's not where the value is).  What the Internet is good for is <em>avoiding</em> human contact when I don't want it.  To the point where I'm genuinely annoyed when I have to actually call a restaurant to place a to-go order.</p><p>Maybe the real value of LLMs is not conversations, or answering questions, or writing code.  Maybe it's somehow the <em>inversion</em> of those things.  What would that even mean?  Here's some half-baked bullshit from a real person for a change.</p><p>LLMs are, at their core, pattern-matching completion engines.  Stream of tokens in -&gt; plausible stream of tokens to continue out.  We're using mostly words as tokens now.  Giving explicit instructions and carefully crafted prompts to see what the machine responds with.  But I don't want a synthetic employee/teacher/servant.  I want to extend myself.  I want superpowers.  I want a smart home that is actually smart.  I want to know where I left a thing in my cluttered home and know without asking.  Or better yet, I want my home to de-clutter organise itself.</p><p>I don't want an "agent" submitting a flood of PRs to my codebase - (not an emdash) shifting my job from creation of something I understand deeply to maintenance of something I have a surface level understanding of.  I want to write code fluently and effortlessly.  I want to grok the effects of a change without running a test suite.  I want a little angel on my shoulder ready to notify me of potential bugs, to highlight areas of my code affected by upcoming deprecations and policy changes.</p><p>The current chat-based state of LLMs is borderline unusable garbage.  We haven't uncovered the real killer UX. </p><p>The lies are gonna be a problem too.</p>]]></content:encoded></item><item><title><![CDATA[Solo Developing]]></title><description><![CDATA[<figure class="kg-card kg-image-card"><img src="https://ghost.flax.wtf/content/images/2025/06/solo_developing.png" class="kg-image" alt="&quot;Solo Developing&quot; made to look like the logo for Solo Leveling" srcset="https://ghost.flax.wtf/content/images/size/w600/2025/06/solo_developing.png 600w, https://ghost.flax.wtf/content/images/2025/06/solo_developing.png 974w" sizes="(min-width: 720px) 720px"></figure><p>August 2024, Indeed.  A large portion of my party had fallen to layoff traps.  Morale was down, and going lower.  Upper management seemed to be trying to drive attrition through removing perks, increasing workload, and generally making stupid decision after stupid decision.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://ghost.flax.wtf/content/images/2025/06/statue_of_lumbergh.png" class="kg-image" alt="Demonic statue of God from Solo Leveling wearing glasses and necktie"><figcaption><strong>Yeah, and I'm also gonna need you to</strong></figcaption></figure>]]></description><link>https://ghost.flax.wtf/solo-developing/</link><guid isPermaLink="false">6849f703f28fe9464978d136</guid><dc:creator><![CDATA[steveship]]></dc:creator><pubDate>Thu, 12 Jun 2025 01:22:50 GMT</pubDate><content:encoded><![CDATA[<figure class="kg-card kg-image-card"><img src="https://ghost.flax.wtf/content/images/2025/06/solo_developing.png" class="kg-image" alt="&quot;Solo Developing&quot; made to look like the logo for Solo Leveling" srcset="https://ghost.flax.wtf/content/images/size/w600/2025/06/solo_developing.png 600w, https://ghost.flax.wtf/content/images/2025/06/solo_developing.png 974w" sizes="(min-width: 720px) 720px"></figure><p>August 2024, Indeed.  A large portion of my party had fallen to layoff traps.  Morale was down, and going lower.  Upper management seemed to be trying to drive attrition through removing perks, increasing workload, and generally making stupid decision after stupid decision.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://ghost.flax.wtf/content/images/2025/06/statue_of_lumbergh.png" class="kg-image" alt="Demonic statue of God from Solo Leveling wearing glasses and necktie"><figcaption><strong>Yeah, and I'm also gonna need you to go ahead and be on call all weekend too</strong></figcaption></figure><p>I don't have "Fuck You" money.  But with some budgeting and spending some savings (that's what it's there for!) I have "Fuck This" money.  For a while, anyway.</p><p>So I quit.</p><p>I've been telling myself it's a sabbatical.  The plan was to work on my game <a href="http://markmywordsgame.com">Mark My Words</a>, get it polished, write some short stories, enjoy spending time with my family.  One and a half outta three ain't bad, right?  I've enjoyed my time, and I've worked on my game a little.  Not as much as I should have.  I'm working on that now. </p><p>Developing on my own is hard.  But it's hard in different ways than I expected.</p><!--kg-card-begin: html--><table>
    <thead>
        <tr>
            <td></td>
            <td>Was Easy</td>
            <td>Was Difficult</td>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Expected to be Easy</td>
            <td>
                <ul>
                    <li>Developing in Flutter</li>
                    <li>Coming up with a good game</li>
                </ul>
            </td>
            <td>
                <ul>
                    <li>Dealing with App Stores (Both)</li>
                    <li>Keeping a schedule</li>
                    <li>Getting people to play</li>
                </ul>
            </td>
        </tr>
        <tr>
            <td>Expected to be Hard</td>
            <td>
                <ul>
                    <li>Doing everything myself</li>
                    <li>Back end (Firebase ftw)</li>
                    <li>Project Management</li>
                    <li>Monitoring</li>
                </ul>
            </td>
            <td>
                <ul>
                    <li>Making a profitable business model</li>
                    <li>Marketing</li>
                </ul>
            </td>
        </tr>
    </tbody>
</table><!--kg-card-end: html--><h2 id="the-job-change-quest">The Job Change Quest</h2><p>In the anime Solo Leveling, the main character gets a side quest to qualify for a class change.  After he completes it, he's able to recruit the shades of fallen enemies to be his shadow soldiers.</p><p>I haven't done the job change quest yet.  I'll probably need to soon.  My money won't last forever.  I've tried recruiting shadow soldiers in the form of generative AI, but I have not enjoyed it or had meaningful success.  While they can produce things "good enough" in domains I can't (like the graphic above), they also fail at incredibly simple tasks (like creating the table I manually built by hand above).  Every time I try to use generative AI for coding, it falls on its face.  I tried using Jules to add Widgetbook to my Flutter app.  I gave it references to the readmes and howtos, and told it to follow those instructions.  Instead, it proposed a change that would have completely broken my app by putting Widgetbook as a dependency in the main project instead of as a subproject, and completely wrecked the main.dart file.</p><p>I tried generating a simple vibe-coded app to generate a couple of images and write a story about them.  It appeared to work, but when I went to show my kid, it failed to generate images or handle errors.</p><p>So far the LLM powered autocomplete within Android Studio is pretty great.  It often does propose exactly what I want for boilerplate and copy/paste/edit, and even user-facing text. </p><p>But I absolutely do not trust it with non-trivial code of more than a few lines.</p><p>I want it to work, I really do.  I have important stuff to do, and delegating to my soldiers would be a huge power-up.</p><figure class="kg-card kg-image-card"><img src="https://ghost.flax.wtf/content/images/2025/06/Igris.png" class="kg-image" alt="Shadow Igris with Gemini logos" srcset="https://ghost.flax.wtf/content/images/size/w600/2025/06/Igris.png 600w, https://ghost.flax.wtf/content/images/size/w1000/2025/06/Igris.png 1000w, https://ghost.flax.wtf/content/images/2025/06/Igris.png 1024w" sizes="(min-width: 720px) 720px"></figure>]]></content:encoded></item><item><title><![CDATA[Consoles vs Computers]]></title><description><![CDATA[<p>Recently Apple has been in the news for cases against Epic and for rulings in the EU which will require them to allow sideloading on iphones (in the EU). From the perspective of a developer that has been steeped in open-source, and a user of open platforms (Linux, Android), this</p>]]></description><link>https://ghost.flax.wtf/consoles-vs-computers/</link><guid isPermaLink="false">644969bb4738a764b44b9fd8</guid><dc:creator><![CDATA[steveship]]></dc:creator><pubDate>Wed, 26 Apr 2023 18:18:07 GMT</pubDate><content:encoded><![CDATA[<p>Recently Apple has been in the news for cases against Epic and for rulings in the EU which will require them to allow sideloading on iphones (in the EU). From the perspective of a developer that has been steeped in open-source, and a user of open platforms (Linux, Android), this is a no-brainer.  <em>Obviously</em> people should be able to install whatever software they like on devices they own.  <em>Obviously</em> the tools to do so should be free or at-cost; more developers and more apps bring more value to the ecosystem.<br>But that's not what the Apple consumers see.  They see a benevolent king curating and protecting them from bad apps (nevermind that "bad apps" is nebulously defined at best, and that Apple's track record is nothing to be proud of).  They do not give a shit about developers.  They somehow think that the ability to voluntarily leave their prison will negatively impact them even if they don't use it.  In my opinion they are thoroughly institutionalized.  They don't think they can make it on the outside.  And honestly that's fine.  No one is forcing them to.  Apple will still run <em>the</em> app store.  They'll still have rules and curate etc.  These people are against the <em>concept</em> of freedom.  One example that comes up from this side over and over is that Facebook would leave the official app store, require users to install it from another source, and then abuse their app to spy on the users worse than they're allowed to in the app store.  But the idea of not using an app from a company they consider untrustworthy apparently never occurs to them.  The fact that this has not happened on Android does not comfort them.  The technical reality of permissions existing at an OS level that would prevent unauthorized usage regardless of install source is lost on them.<br><br>But that's not what I want to talk about.  One of the more coherent arguments that Apple apologists suggest is that game consoles are exactly the same.  Game consoles could technically run arbitrary software, but you don't expect to be allowed to run whatever you want on your Nintendo, PlayStation, or Xbox.  And this is true!  So my thoughts on this analogy:  First, we absolutely should expect to be able to run whatever we want on hardware we own.  This <em>should</em> be fixed.  But from a consumer perspective, games consoles were never marketed as anything other than a way to play the games that the company has permitted.  Iphones, on the other hand, were marketed as powerful handheld computers that can do anything.  "There's an app for that".  Or maybe they weren't.  Maybe that was a message that was inferred by developers that know that under the hood it must be a general purpose computer.  Apple's marketing certainly courted developers of all stripes by promoting their audience and revenue numbers.  They promoted this to the general developer audience all over the internet, not at industry insider conferences.  The developers they courted to get apps on the app store were accustomed to general purpose computer markets.   And buying a general purpose computer, one obviously expects to be able to run any software that one desires.  But the non-developer consumers didn't see that.  They see a "handheld apps console", more akin to a Nintendo Switch than to their laptop.<br><br>So that's the crux of it.  What <em>is</em> an iPhone?  Is it an "apps console" or is it a computer?  If Apple were honest and explicitly promoted it as using the console model, I think many developers would accept their policies more readily.<br><br>Let's also talk about a product that actually does what I'd have liked Apple to have done: the Steam Deck.  The Steam Deck is definitely marketed as a games console.  But, it's implemented as a general purpose Linux computer with some nice UI and ergonomics.  Go to the developer site thinking it's a games console, one might expect to have to buy a heavily marked up "development console", and pay out the nose for development tools, and pass through arbitrary gatekeeping to get your game in front of users.  But no!  One can develop for the Steam Deck without any particular hardware (as opposed to Apple, which requires a Mac to run their build tools).  The console itself is also the development console.  You can even use it as your coding environment.  No special open version required.  No special controlled certificate signing required.<br><br>And you know what?  The Steam games market is <em>thriving</em>.<br><br>If the Steam Deck had a 5G modem, I'd seriously consider one instead of my next Android phone.</p>]]></content:encoded></item><item><title><![CDATA[Mark My Words]]></title><description><![CDATA[<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://ghost.flax.wtf/content/images/2022/02/web_splash.png" class="kg-image" alt><figcaption>The splash screen. Doesn't it make you want to try it?</figcaption></figure><p>I've been working on a game for a while now in the few hours a week that aren't taken by my full time job and my full time toddler, and I'm running out of excuses to put off getting</p>]]></description><link>https://ghost.flax.wtf/mark-my-words/</link><guid isPermaLink="false">621aad192b655a310a9e0ca4</guid><category><![CDATA[Apps]]></category><dc:creator><![CDATA[steveship]]></dc:creator><pubDate>Sun, 27 Feb 2022 02:39:16 GMT</pubDate><content:encoded><![CDATA[<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://ghost.flax.wtf/content/images/2022/02/web_splash.png" class="kg-image" alt><figcaption>The splash screen. Doesn't it make you want to try it?</figcaption></figure><p>I've been working on a game for a while now in the few hours a week that aren't taken by my full time job and my full time toddler, and I'm running out of excuses to put off getting some play testers.<br><br>Do you like word games, hex grids, and area-control board games?  Have you ever wondered what the unholy offspring of Scrabble and Othello would be? </p><figure class="kg-card kg-image-card"><img src="https://ghost.flax.wtf/content/images/2022/02/final_share.png" class="kg-image" alt srcset="https://ghost.flax.wtf/content/images/size/w600/2022/02/final_share.png 600w, https://ghost.flax.wtf/content/images/2022/02/final_share.png 632w"></figure><p>Mark My Words is an online turn based board game where you attempt to capture letter tiles by playing words on a hexagonal grid.<br>1 to 4 color coded players take turns playing words on the field.  Any letters in words made in your turn become your color and count towards your score.  Tile values can continue to increase via double and triple word boosters.  You can take tiles by building new words with them.</p><p>I'm building this in <a href="https://flutter.dev">Flutter</a>, with a <a href="https://firebase.google.com/">Firebase</a> back end.  It's actually a really nice stack for a single developer to get stuff done.  I'm using <a href="https://riverpod.dev/">Riverpod</a> for client-side state management, the wonderful <a href="https://pub.dev/packages/hexagon">hexagon</a> library (with <a href="https://github.com/sshipman/flutter-hexagon">some tweaks</a>) for drawing all these hexagons and grids, and lots of Firebase support libraries for things like authorization and messaging.<br><br>Mark My Words will eventually be available on Android, iOS, and web.  Web is up now at <a href="https://markmywordsgame.com/" rel="nofollow">https://markmywordsgame.com</a> (desktop/laptop highly recommended).  If you'd like to help me test the Android client, please join the test group <a href="https://groups.google.com/g/mark-my-words-testing">here</a>, then you should be able to access the <a href="https://play.google.com/store/apps/details?id=wtf.flax.mark_my_words">play store listing</a>.  iOS <a href="https://testflight.apple.com/join/jEhWQPiK">here</a> (you'll need test flight for the pre-release).<br><br>I'm about to add monetization features, but I've decided <em>against</em> ads.  I hate when apps and games are just an excuse to shovel ads down your throat, and I've also heard horror stories about losing Google accounts due to fraud detection false positives.  So I'll be adding in app purchases and subscriptions, but no ads.  You're welcome.</p>]]></content:encoded></item><item><title><![CDATA[Verbal Supplement]]></title><description><![CDATA[<p>This is an old post that I queued up and never published.  Have at it.</p><p>What's the worst thing about this pandemic?  Other than hundreds of thousands of people dead.  And pervasive economic hardship.  And the utter, casual, banal evil demonstrated by about half the country?  You know what, forget</p>]]></description><link>https://ghost.flax.wtf/verbal_supplement/</link><guid isPermaLink="false">5fee789b3894c21ed30f301e</guid><category><![CDATA[3Dprinting]]></category><category><![CDATA[Apps]]></category><category><![CDATA[Prototyping]]></category><dc:creator><![CDATA[steveship]]></dc:creator><pubDate>Sat, 26 Feb 2022 21:33:45 GMT</pubDate><content:encoded><![CDATA[<p>This is an old post that I queued up and never published.  Have at it.</p><p>What's the worst thing about this pandemic?  Other than hundreds of thousands of people dead.  And pervasive economic hardship.  And the utter, casual, banal evil demonstrated by about half the country?  You know what, forget the question. <br>Conversing through a mask sucks.  Your voice is muffled, and nobody can read lips anymore.  To address that last issue, I've been working on a project I'm calling "Verbal Supplement".<br><br>Verbal Supplement is a device that you wear over your face mask that displays a transcription of your speech. It's real-life subtitles. It comprises 3 sub projects: Hardware, Embedded software, and a Flutter phone app.<br></p><h2 id="hardware"><br>HARDWARE</h2><p>The hardware is an <a href="https://www.amazon.com/gp/product/B07R1QDVWF/ref=as_li_tl?ie=UTF8&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B07R1QDVWF&amp;linkCode=as2&amp;tag=flaxwtf-20&amp;linkId=425e15869a85c8c68234a6df0f15654b">M5StickC</a> (paid link. As an Amazon Associate I earn from qualifying purchases.) in a <a href="https://www.thingiverse.com/thing:4707504">3D printed case</a>.  The case is designed to provide a place to attach elastics to keep it on your face and away from interfering with your speech. It sits between my upper lip and my nose. Unfortunately, the screen on the M5StickC is quite small. In practice, only about 6 words at a time can be displayed ¯\_(ツ)_/¯.  I've got hardware with a larger screen coming, so I expect to address that in the near future.<br></p><h2 id="embedded-software"><br>EMBEDDED SOFTWARE</h2><p>The <a href="https://github.com/sshipman/VerbalSupplement-M5StickC">Verbal Supplement embedded software</a> does two main things: bluetooth low energy connectivity and text display.  On startup it sets up a standard BLE serial service as well as a battery level service (currently unused).  Then it begins advertising.  On connection to the serial service by the phone app, any incoming text is piped straight to the screen.  I used a wonderful scrolling text library to accomplish the text display.  There's a bit of power management regarding sleeping and screen brightness too.  You can see the code <a href="https://github.com/sshipman/VerbalSupplement-M5StickC">here</a>.<br></p><h2 id="flutter-app"><br>FLUTTER APP</h2><p>For the phone side, I used Flutter, simply because I wanted to build something with it.  I basically hacked together the demo apps from <a href="https://pub.dev/packages/flutter_reactive_ble">flutter-reactive-ble</a> and <a href="https://pub.dev/packages/speech_to_text">speech-to-text</a> libraries.  I definitely need to revisit the app architecture in the future.  On initial run, the app will scan for nearby BLE devices that are advertising serial service and allow the user to select one.  Once a device is selected, it connects to that device, starts a speech to text listening loop, and sends any detected text over the serial channel.  There is no attempt to encrypt or otherwise protect this data, which is probably fine since this is the same data the user is speaking out loud, intending to be heard. But sending it to Google/Apple is less than ideal.  I recently came across <a href="https://alphacephei.com/vosk/">Vosk</a> which apparently supports both Android and IOS and supports local continuous speech recognition on Android at least.<br></p><h2 id="tasker"><br>TASKER</h2><p>To make it easier to use in the field, I created a Tasker task that starts up the Flutter app when the M5StickC is detected nearby.  That way, I don't have to find and open the app, or even take my phone out of my pocket.  Just turn on the M5StickC and in a second or two the phone will detect it and open the app.  The app automatically connects and starts listening.<br><br>FUTURE<br>I'd like to replace the naive listening loop with a sound threshold triggered mechanism.  Perhaps using the M5StickC microphone for it's proximity to the user's speech.  Of course, increasing the screen size will make it far more practical as well.  And I'd like to add some tactile feedback since the user usually won't be able to see the screens while actually using the app.<br>Making use of the battery service would also be a nice to have.<br><br>I'd love to test it with an iPhone, just to see if the supposed platform independence benefits of Flutter materialize, but I haven't yet looked into what I need to do so.  I'm not going to be paying Apple for the privilege of running my own software on a device I own.<br></p>]]></content:encoded></item><item><title><![CDATA[Welcome to Ghost]]></title><description><![CDATA[Welcome, it's great to have you here.
We know that first impressions are important, so we've populated your new site with some initial getting started posts that will help you get familiar with everything in no time.]]></description><link>https://ghost.flax.wtf/welcome/</link><guid isPermaLink="false">5fea49298df7f32d07927c2b</guid><category><![CDATA[Getting Started]]></category><dc:creator><![CDATA[Ghost]]></dc:creator><pubDate>Mon, 28 Dec 2020 21:07:59 GMT</pubDate><media:content url="https://static.ghost.org/v3.0.0/images/welcome-to-ghost.png" medium="image"/><content:encoded><![CDATA[<h2 id="a-few-things-you-should-know"><strong>A few things you should know</strong></h2><ol><li>Ghost is designed for ambitious, professional publishers who want to actively build a business around their content. That's who it works best for. </li><li>The entire platform can be modified and customised to suit your needs. It's very powerful, but does require some knowledge of code. Ghost is not necessarily a good platform for beginners or people who just want a simple personal blog. </li><li>It's possible to work with all your favourite tools and apps with hundreds of <a href="https://ghost.org/integrations/">integrations</a> to speed up your workflows, connect email lists, build communities and much more.</li></ol><h2 id="behind-the-scenes">Behind the scenes</h2><img src="https://static.ghost.org/v3.0.0/images/welcome-to-ghost.png" alt="Welcome to Ghost"><p>Ghost is made by an independent non-profit organisation called the Ghost Foundation. We are 100% self funded by revenue from our <a href="https://ghost.org/pricing">Ghost(Pro)</a> service, and every penny we make is re-invested into funding further development of free, open source technology for modern publishing.</p><p>The version of Ghost you are looking at right now would not have been made possible without generous contributions from the open source <a href="https://github.com/TryGhost">community</a>.</p><h2 id="next-up-the-editor">Next up, the editor</h2><p>The main thing you'll want to read about next is probably: <a href="https://ghost.flax.wtf/the-editor/">the Ghost editor</a>. This is where the good stuff happens.</p><blockquote>By the way, once you're done reading, you can simply delete the default Ghost user from your team to remove all of these introductory posts! </blockquote>]]></content:encoded></item><item><title><![CDATA[Writing posts with Ghost ✍️]]></title><description><![CDATA[Discover familiar formatting options in a functional toolbar and the ability to add dynamic content seamlessly.]]></description><link>https://ghost.flax.wtf/the-editor/</link><guid isPermaLink="false">5fea49298df7f32d07927c29</guid><category><![CDATA[Getting Started]]></category><dc:creator><![CDATA[Ghost]]></dc:creator><pubDate>Mon, 28 Dec 2020 21:07:58 GMT</pubDate><media:content url="https://static.ghost.org/v3.0.0/images/writing-posts-with-ghost.png" medium="image"/><content:encoded><![CDATA[<h2 id="just-start-writing">Just start writing</h2><img src="https://static.ghost.org/v3.0.0/images/writing-posts-with-ghost.png" alt="Writing posts with Ghost ✍️"><p>Ghost has a powerful visual editor with familiar formatting options, as well as the ability to add dynamic content.</p><p>Select your text to add formatting such as headers or to create links. Or use Markdown shortcuts to do the work for you - if that's your thing. </p><figure class="kg-card kg-image-card"><img src="https://static.ghost.org/v2.0.0/images/formatting-editor-demo.gif" class="kg-image" alt="Writing posts with Ghost ✍️"></figure><h2 id="rich-editing-at-your-fingertips">Rich editing at your fingertips</h2><p>The editor can also handle rich media objects, called <strong>cards</strong>, which can be organised and re-ordered using drag and drop. </p><p>You can insert a card either by clicking the  <code>+</code>  button, or typing  <code>/</code>  on a new line to search for a particular card. This allows you to efficiently insert<strong> images</strong>, <strong>markdown</strong>, <strong>html, embeds </strong>and more.</p><p><strong>For example</strong>:</p><ul><li>Insert a video from YouTube directly by pasting the URL</li><li>Create unique content like buttons or forms using the HTML card</li><li>Need to share some code? Embed code blocks directly </li></ul><pre><code>&lt;header class="site-header outer"&gt;
    &lt;div class="inner"&gt;
        {{&gt; "site-nav"}}
    &lt;/div&gt;
&lt;/header&gt;</code></pre><p>It's also possible to share links from across the web in a visual way using bookmark cards that automatically render information from a websites meta data. Paste any URL to try it out: </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://ghost.org/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Ghost: The #1 open source headless Node.js CMS</div><div class="kg-bookmark-description">The world’s most popular modern open source publishing platform. A headless Node.js CMS used by Apple, Sky News, Tinder and thousands more. MIT licensed, with 30k+ stars on Github.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://ghost.org/icons/icon-512x512.png?v&#x3D;188b8b6d743c6338ba2eab2e35bab4f5" alt="Writing posts with Ghost ✍️"><span class="kg-bookmark-publisher">Ghost</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://ghost.org/images/meta/Ghost.png" alt="Writing posts with Ghost ✍️"></div></a></figure><h2 id="working-with-images-in-posts">Working with images in posts</h2><p>You can add images to your posts in many ways:</p><ul><li>Upload from your computer</li><li>Click and drag an image into the browser</li><li>Paste directly into the editor from your clipboard</li><li>Insert using a URL</li></ul><h3 id="image-sizes">Image sizes</h3><p>Once inserted you can blend images beautifully into your content at different sizes and add captions and alt tags wherever needed.</p><figure class="kg-card kg-image-card"><img src="https://static.ghost.org/v3.0.0/images/image-sizes-ghost-editor.png" class="kg-image" alt="Writing posts with Ghost ✍️"></figure><h3 id="image-galleries">Image galleries</h3><p>Tell visual stories using the gallery card to add up to 9 images that will display as a responsive image gallery: </p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://static.ghost.org/v3.0.0/images/gallery-sample-1.jpg" width="6000" height="4000" alt="Writing posts with Ghost ✍️"></div><div class="kg-gallery-image"><img src="https://static.ghost.org/v3.0.0/images/gallery-sample-2.jpg" width="5746" height="3831" alt="Writing posts with Ghost ✍️"></div><div class="kg-gallery-image"><img src="https://static.ghost.org/v3.0.0/images/gallery-sample-3.jpg" width="5872" height="3915" alt="Writing posts with Ghost ✍️"></div></div></div></figure><h3 id="image-optimisation">Image optimisation</h3><p>Ghost will automatically resize and optimise your images with lossless compression. Your posts will be fully optimised for the web without any extra effort on your part.</p><h2 id="next-publishing-options">Next: Publishing Options</h2><p>Once your post is looking good, you'll want to use the <a href="https://ghost.flax.wtf/publishing-options/">publishing options</a> to ensure it gets distributed in the right places, with custom meta data, feature images and more.</p>]]></content:encoded></item><item><title><![CDATA[Publishing options]]></title><description><![CDATA[The Ghost editor post settings menu has everything you need to fully optimise and distribute your content effectively.]]></description><link>https://ghost.flax.wtf/publishing-options/</link><guid isPermaLink="false">5fea49298df7f32d07927c27</guid><category><![CDATA[Getting Started]]></category><dc:creator><![CDATA[Ghost]]></dc:creator><pubDate>Mon, 28 Dec 2020 21:07:57 GMT</pubDate><media:content url="https://static.ghost.org/v3.0.0/images/publishing-options.png" medium="image"/><content:encoded><![CDATA[<h2 id="distribute-your-content">Distribute your content</h2><img src="https://static.ghost.org/v3.0.0/images/publishing-options.png" alt="Publishing options"><p>Access the post settings menu by clicking the settings icon in the top right hand corner of the editor and discover everything you need to get your content ready for publishing. This is where you can edit things like tags, post URL, publish date and custom meta data.</p><h2 id="feature-images-url-excerpts">Feature images, URL &amp; excerpts</h2><p>Insert your post feature image from the very top of the post settings menu. Consider resizing or optimising your image first to ensure it's an appropriate size. Below this, you can set your post URL, publish date and add a custom excerpt.</p><h2 id="tags-authors">Tags &amp; authors</h2><p>You can easily add multiple tags and authors to any post to filter and organise the relationships between your content in Ghost.</p><h2 id="structured-data-seo">Structured data &amp; SEO</h2><p>There's no need to hard code your meta data. In fact, Ghost will generate default meta data automatically using the content in your post.</p><p>Alternatively, you can override this by adding a custom meta title and description, as well as unique information for social media sharing cards on Facebook and Twitter.</p><p>It's also possible to set custom canonicals, which is useful for guest posts or curated lists of external links.</p><p>Ghost will automatically implement <strong>structured data</strong> for your publication using JSON-LD to further optimise your content.</p><pre><code>{
    "@context": "https://schema.org",
    "@type": "Article",
    "publisher": {
        "@type": "Organization",
        "name": "Publishing options",
        "logo": "https://static.ghost.org/ghost-logo.svg"
    },
    "author": {
        "@type": "Person",
        "name": "Ghost",
        "url": "http://demo.ghost.io/author/ghost/",
        "sameAs": []
    },
    "headline": "Publishing options",
    "url": "http://demo.ghost.io/publishing-options",
    "datePublished": "2018-08-08T11:44:00.000Z",
    "dateModified": "2018-08-09T12:06:21.000Z",
    "keywords": "Getting Started",
    "description": "The Ghost editor has everything you need to fully optimise your content. This is where you can add tags and authors, feature a post, or turn a post into a page."
}
    </code></pre><p>You can test that the structured data <a href="https://schema.org/">schema</a> on your site is working as it should using <a href="https://search.google.com/structured-data/testing-tool" rel="noreferrer nofollow noopener">Google’s structured data tool</a>. </p><h2 id="code-injection">Code injection</h2><p>This tool allows you to inject code on a per post or page basis, or across your entire site. This means you can modify CSS, add unique tracking codes, or add other scripts to the head or foot of your publication without making edits to your theme files. </p><p><strong>To add code site-wide</strong>, use the code injection tool in the main admin menu. This is useful for adding a Google Analytics tracking code, or to start tracking with any other analytics tool.</p><p><strong>To add code to a post or page</strong>, use the code injection tool within the post settings menu. This is useful if you want to add art direction, scripts or styles that are only applicable to one post or page.</p><h2 id="next-admin-settings">Next: Admin settings</h2><p>Now you understand how to create and optimise content, let's explore some <a href="https://ghost.flax.wtf/admin-settings/">admin settings</a> so you can invite your team and start collaborating.</p>]]></content:encoded></item><item><title><![CDATA[Managing admin settings]]></title><description><![CDATA[There are a couple of things to do next while you're getting set up: making your site private and inviting your team.]]></description><link>https://ghost.flax.wtf/admin-settings/</link><guid isPermaLink="false">5fea49298df7f32d07927c25</guid><category><![CDATA[Getting Started]]></category><dc:creator><![CDATA[Ghost]]></dc:creator><pubDate>Mon, 28 Dec 2020 21:07:56 GMT</pubDate><media:content url="https://static.ghost.org/v3.0.0/images/admin-settings.png" medium="image"/><content:encoded><![CDATA[<h2 id="make-your-site-private">Make your site private</h2><img src="https://static.ghost.org/v3.0.0/images/admin-settings.png" alt="Managing admin settings"><p>If you've got a publication that you don't want the world to see yet because it's not ready to launch, you can hide your Ghost site behind a basic shared pass-phrase.</p><p>You can toggle this preference on at the bottom of Ghost's General Settings:</p><figure class="kg-card kg-image-card"><img src="https://static.ghost.org/v1.0.0/images/private.png" class="kg-image" alt="Managing admin settings"></figure><p>Ghost will give you a short, randomly generated pass-phrase which you can share with anyone who needs access to the site while you're working on it. While this setting is enabled, all search engine optimisation features will be switched off to help keep your site under the radar.</p><p>Do remember though, this is <em>not</em> secure authentication. You shouldn't rely on this feature for protecting important private data. It's just a simple, shared pass-phrase for some very basic privacy.</p><h2 id="invite-your-team">Invite your team </h2><p>Ghost has a number of different user roles for your team:</p><p><strong>Contributors</strong><br>This is the base user level in Ghost. Contributors can create and edit their own draft posts, but they are unable to edit drafts of others or publish posts. Contributors are <strong>untrusted</strong> users with the most basic access to your publication.</p><p><strong>Authors</strong><br>Authors are the 2nd user level in Ghost. Authors can write, edit  and publish their own posts. Authors are <strong>trusted</strong> users. If you don't trust users to be allowed to publish their own posts, they should be set as Contributors.</p><p><strong>Editors</strong><br>Editors are the 3rd user level in Ghost. Editors can do everything that an Author can do, but they can also edit and publish the posts of others - as well as their own. Editors can also invite new Contributors &amp; Authors to the site.</p><p><strong>Administrators</strong><br>The top user level in Ghost is Administrator. Again, administrators can do everything that Authors and Editors can do, but they can also edit all site settings and data, not just content. Additionally, administrators have full access to invite, manage or remove any other user of the site.<br><br><strong>The Owner</strong><br>There is only ever one owner of a Ghost site. The owner is a special user which has all the same permissions as an Administrator, but with two exceptions: The Owner can never be deleted. And in some circumstances the owner will have access to additional special settings if applicable. For example: billing details, if using <a href="https://ghost.org/pricing/"><strong>Ghost(Pro)</strong></a>.</p><blockquote><em>It's a good idea to ask all of your users to fill out their user profiles, including bio and social links. These will populate rich structured data for posts and generally create more opportunities for themes to fully populate their design.</em></blockquote><h2 id="next-organising-content">Next: Organising content</h2><p>Find out how to <a href="https://ghost.flax.wtf/organising-content/">organise your content</a> with sensible tags and authors, or for more advanced configurations, how to create custom content structures using dynamic routing.</p>]]></content:encoded></item><item><title><![CDATA[Organising your content]]></title><description><![CDATA[Ghost has a flexible organisational taxonomy called tags and the ability to create custom site structures using dynamic routes.]]></description><link>https://ghost.flax.wtf/organising-content/</link><guid isPermaLink="false">5fea49298df7f32d07927c23</guid><category><![CDATA[Getting Started]]></category><dc:creator><![CDATA[Ghost]]></dc:creator><pubDate>Mon, 28 Dec 2020 21:07:55 GMT</pubDate><media:content url="https://static.ghost.org/v3.0.0/images/organising-your-content.png" medium="image"/><content:encoded><![CDATA[<h2 id="sensible-tagging">Sensible tagging</h2><img src="https://static.ghost.org/v3.0.0/images/organising-your-content.png" alt="Organising your content"><p>You can think of tags like Gmail labels. By tagging posts with one or more keyword, you can organise articles into buckets of related content.</p><p>When you create content for your publication you can assign tags to help differentiate between categories of content. </p><p>For example you may tag some content with News and other content with Podcast, which would create two distinct categories of content listed on <code>/tag/news/</code> and <code>/tag/podcast/</code>, respectively.</p><p>If you tag a post with both <code>News</code> <em>and</em> <code>Podcast</code> - then it appears in both sections. Tag archives are like dedicated home-pages for each category of content that you have. They have their own pages, their own RSS feeds, and can support their own cover images and meta data.</p><h3 id="the-primary-tag">The primary tag</h3><p>Inside the Ghost editor, you can drag and drop tags into a specific order. The first tag in the list is always given the most importance, and some themes will only display the primary tag (the first tag in the list) by default. </p><blockquote><em><strong>News</strong>, Technology, Startup</em></blockquote><p>So you can add the most important tag which you want to show up in your theme, but also add related tags which are less important.</p><h3 id="private-tags">Private tags</h3><p>Sometimes you may want to assign a post a specific tag, but you don't necessarily want that tag appearing in the theme or creating an archive page. In Ghost, hashtags are private and can be used for special styling.</p><p>For example, if you sometimes publish posts with video content - you might want your theme to adapt and get rid of the sidebar for these posts, to give more space for an embedded video to fill the screen. In this case, you could use private tags to tell your theme what to do.</p><blockquote><em><strong>News</strong>, #video</em></blockquote><p>Here, the theme would assign the post publicly displayed tags of News - but it would also keep a private record of the post being tagged with #video. In your theme, you could then look for private tags conditionally and give them special formatting. </p><blockquote><em>You can find documentation for theme development techniques like this and many more over on Ghost's extensive <a href="https://ghost.org/docs/api/handlebars-themes/">theme docs</a>.</em></blockquote><h2 id="dynamic-routing">Dynamic routing</h2><p>Dynamic routing gives you the ultimate freedom to build a custom publication to suit your needs. Routes are rules that map URL patterns to your content and templates. </p><p>You may not want content tagged with <code>News</code> to exist on: <code>example.com/tag/news</code>. Instead, you want it to exist on <code>example.com/news</code> .</p><p>In this case you can use dynamic routes to create customised collections of content on your site. It's also possible to use multiple templates in your theme to render each content type differently.</p><p>There are lots of use cases for dynamic routing with Ghost, here are a few common examples: </p><ul><li>Setting a custom home page with its own template</li><li>Having separate content hubs for blog and podcast, that render differently, and have custom RSS feeds to support two types of content</li><li>Creating a founders column as a unique view, by filtering content created by specific authors</li><li>Including dates in permalinks for your posts</li><li>Setting posts to have a URL relative to their primary tag like <code>example.com/europe/story-title/</code><br></li></ul><blockquote><em>Dynamic routing can be configured in Ghost using <a href="http://yaml.org/spec/1.2/spec.html" rel="noreferrer nofollow noopener">YAML</a> files. Read our dynamic routing <a href="https://ghost.org/docs/api/handlebars-themes/routing/">documentation</a> for further details.</em></blockquote><h2 id="next-apps-integrations">Next: Apps &amp; Integrations</h2><p>Work with all your favourite apps and tools using our <a href="https://ghost.flax.wtf/apps-integrations/">integrations</a>, or create your own custom integrations with webhooks.</p>]]></content:encoded></item><item><title><![CDATA[Apps & integrations]]></title><description><![CDATA[Work with all your favourite apps and tools or create your own custom integrations using the Ghost API.]]></description><link>https://ghost.flax.wtf/apps-integrations/</link><guid isPermaLink="false">5fea49298df7f32d07927c21</guid><category><![CDATA[Getting Started]]></category><dc:creator><![CDATA[Ghost]]></dc:creator><pubDate>Mon, 28 Dec 2020 21:07:54 GMT</pubDate><media:content url="https://static.ghost.org/v3.0.0/images/app-integrations.png" medium="image"/><content:encoded><![CDATA[<h2 id="work-with-your-existing-tools">Work with your existing tools</h2><img src="https://static.ghost.org/v3.0.0/images/app-integrations.png" alt="Apps & integrations"><p>It's possible to connect your Ghost site to hundreds of the most popular apps and tools using integrations that take no more than a few minutes to setup.</p><p>Whether you need to automate workflows, connect your email list, build a community or embed products from your ecommerce store, our <a href="https://ghost.org/integrations/">integrations library</a> has got it all covered with hundreds of tutorials.</p><figure class="kg-card kg-image-card kg-width-full"><img src="https://static.ghost.org/v3.0.0/images/integrations-icons.png" class="kg-image" alt="Apps & integrations"></figure><h2 id="zapier">Zapier</h2><p>On top of this, you can connect your Ghost site to more than 1,000 external services using the official integration with <a href="https://zapier.com">Zapier</a>.</p><p>Zapier sets up automations with Triggers and Actions, which allows you to create and customise a wide range of connected applications.</p><blockquote><strong>Example</strong>: When someone new subscribes to a newsletter on a Ghost site (Trigger) then the contact information is automatically pushed into MailChimp (Action).</blockquote><p><strong>Here are the most popular Ghost&lt;&gt;Zapier automation templates:</strong> </p><!--kg-card-begin: markdown--><script src="https://zapier.com/apps/embed/widget.js?services=Ghost&container=true&limit=8"></script>
<!--kg-card-end: markdown--><h2 id="custom-integrations">Custom integrations</h2><p>At the heart of Ghost sits a robust JSON API – designed to create, manage and retrieve content with ease. </p><p>It's possible to create custom Ghost integrations with dedicated API keys and webhooks from the Integrations page within Ghost Admin. </p><figure class="kg-card kg-image-card"><img src="https://static.ghost.org/v3.0.0/images/integrations-and-webhooks-in-ghost.png" class="kg-image" alt="Apps & integrations"></figure><p>Beyond that, the API allows you to build entirely custom publishing apps. You can send content from your favourite desktop editor, build a custom interface for handling editorial workflow or use Ghost as a full headless CMS with a custom front-end.</p><p>The Ghost API is <a href="https://ghost.org/docs/api/">thoroughly documented</a> and straightforward to work with for developers of almost any level. </p><h2 id="final-step-themes">Final step: Themes</h2><p>Alright, on to the last post in our welcome-series! If you're curious about creating your own Ghost theme from scratch, <a href="https://ghost.flax.wtf/themes/">find out how that works</a>.</p>]]></content:encoded></item><item><title><![CDATA[Creating a custom theme]]></title><description><![CDATA[Ghost comes with a beautiful default theme designed for publishers which can easily be adapted for most purposes, or you can build a custom theme to suit your needs.]]></description><link>https://ghost.flax.wtf/themes/</link><guid isPermaLink="false">5fea49298df7f32d07927c1f</guid><category><![CDATA[Getting Started]]></category><dc:creator><![CDATA[Ghost]]></dc:creator><pubDate>Mon, 28 Dec 2020 21:07:53 GMT</pubDate><media:content url="https://static.ghost.org/v3.0.0/images/creating-a-custom-theme.png" medium="image"/><content:encoded><![CDATA[<h2 id="ghost-themes">Ghost themes</h2><img src="https://static.ghost.org/v3.0.0/images/creating-a-custom-theme.png" alt="Creating a custom theme"><p>Ghost comes with a default theme called Casper, which is designed to be a clean, readable publication layout and can be easily adapted for most purposes.</p><p>If you need something a little more customised, it's entirely possible to build on top of existing open source themes, or to build your own from scratch. Rather than giving you a few basic settings which act as a poor proxy for code, we just let you write code.</p><h2 id="marketplace">Marketplace</h2><p>There are a huge range of both free and premium pre-built themes which you can download from the <a href="https://ghost.org/marketplace/">Ghost Theme Marketplace</a>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://static.ghost.org/v3.0.0/images/theme-marketplace.png" class="kg-image" alt="Creating a custom theme"><figcaption>Anyone can write a completely custom Ghost theme with some solid knowledge of HTML and CSS</figcaption></figure><h2 id="theme-development">Theme development</h2><p>Ghost themes are written with a templating language called handlebars, which has a set of dynamic helpers to insert your data into template files. For example: <code>{{author.name}}</code> outputs the name of the current author.</p><p>The best way to learn how to write your own Ghost theme is to have a look at <a href="https://github.com/TryGhost/Casper">the source code for Casper</a>, which is heavily commented and should give you a sense of how everything fits together.<br></p><ul><li><code>default.hbs</code> is the main template file, all contexts will load inside this file unless specifically told to use a different template.</li><li><code>post.hbs</code> is the file used in the context of viewing a post.</li><li><code>index.hbs</code> is the file used in the context of viewing the home page.</li><li>and so on</li></ul><p>We've got <a href="https://ghost.org/docs/api/handlebars-themes/">full and extensive theme documentation</a> which outlines every template file, context and helper that you can use. You can also get started with our useful <a href="https://github.com/TryGhost/Starter/">starter theme</a>, which includes the most common foundations and components required to build your own theme.</p><blockquote>If you want to chat with other people making Ghost themes to get any advice or help, there's also a <strong>themes</strong> section on our <a href="https://forum.ghost.org/c/themes">public Ghost forum</a>.</blockquote>]]></content:encoded></item></channel></rss>