<?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[Jonas blog]]></title><description><![CDATA[The future of Technologoy integrating mind and spirit]]></description><link>https://blog.jonas.liljegren.org/</link><image><url>https://blog.jonas.liljegren.org/favicon.png</url><title>Jonas blog</title><link>https://blog.jonas.liljegren.org/</link></image><generator>Ghost 5.51</generator><lastBuildDate>Tue, 14 Apr 2026 06:54:59 GMT</lastBuildDate><atom:link href="https://blog.jonas.liljegren.org/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Chasing the Sun]]></title><description><![CDATA[<p>Since every other lyrics page on the web has it wrong, here is the lyrics of <strong>Chasing the Sun</strong> by <strong>Pia</strong> from <strong>Magical Eclipse</strong> (1999):</p><p>(Instrumental Intro with vocalizations)</p><p>Dancing footprints in soft sand<br>Counting prayers with right hand<br>Sacred waters waist deep<br>Closing eyes, facing East<br>Ever since we</p>]]></description><link>https://blog.jonas.liljegren.org/chasing-the-sun/</link><guid isPermaLink="false">683a8e3ee98fac81069ee34f</guid><category><![CDATA[mind]]></category><category><![CDATA[protopia]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Sat, 31 May 2025 05:13:58 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2025/05/pia-magical-eclipse.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.jonas.liljegren.org/content/images/2025/05/pia-magical-eclipse.jpeg" alt="Chasing the Sun"><p>Since every other lyrics page on the web has it wrong, here is the lyrics of <strong>Chasing the Sun</strong> by <strong>Pia</strong> from <strong>Magical Eclipse</strong> (1999):</p><p>(Instrumental Intro with vocalizations)</p><p>Dancing footprints in soft sand<br>Counting prayers with right hand<br>Sacred waters waist deep<br>Closing eyes, facing East<br>Ever since we began<br>Birth of the spirit, chasing the sun</p><p>Surya Narayana<br>You&apos;ve been sleeping so long<br>Come chase the sun<br>Now</p><p>(Instrumental/Vocalise Break - &quot;Om&quot; like sounds)</p><p>Angels close their eyes and breathe<br>Colors sound like harmonies<br>Secret words bestowed on dreams<br>Full of love that&apos;s free from lust<br>Teachings, yes, their whole life long<br>Open our hearts, chasing the sun<br>Come chase the sun</p><p>Surya Narayana<br>You&apos;ve been sleeping so long<br>Come chase the sun<br>Now</p><p>(Vocalise Break - &quot;Om&quot; sounds)</p><p>(Sanskrit Chant - transliteration of what is sung)<br>&#x100;rtaveno nin&#x101;datasya taim&#x16B;rtirmahiyatehi<br>Smaranti pr&#x101;vive&#x15B;u&#x15B;ca mukha&#xF1;c&#x101;ni saya&#x1E41; bhuva&#x1E25;<br>G&#x101;yatr&#x12B;&#x1E41; g&#x101;yatastasmat &#x101;dhik&#x101;ty&#x101;t sarojaja&#x1E25;<br>Sa&#x1E41;sk&#x1E5B;&#x15B;c&#x101;pi dvij&#x101;gurun&#x101;&#x1E41; dvijat&#x101;&#x1E41; agamat tad&#x101;</p><p>(Instrumental section with vocalizations builds)</p><p>Soaring hearts with abandoned force<br>Perfect words with perfect tunes<br>Sparkling answers around us all<br>Illumination serves the soul<br>Soul, you&apos;ll know what&apos;s to be done<br>Filled with love, go chasing the sun<br>Chase the sun</p><p>Surya Narayana<br>You&apos;ve been sleeping so long<br>Come, chase the sun<br>Oh, the fading sun<br>The stars will be weaving<br>The darkening sky</p><p>(Outro with fading vocalizations and instrumental)</p>]]></content:encoded></item><item><title><![CDATA[Implementing the latest web technologies in a fast and flexible search component]]></title><description><![CDATA[I recently built this inline autocomplete search component from scratch with no dependencies, using several bleeding edge browser APIs.]]></description><link>https://blog.jonas.liljegren.org/modern-search-component/</link><guid isPermaLink="false">65ff9288bd5de594ce13683a</guid><category><![CDATA[code]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Sun, 24 Mar 2024 05:35:00 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2024/03/modern-search-component-2x1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://blog.jonas.liljegren.org/content/images/2024/03/modern-search-component-2x1.png" alt="Implementing the latest web technologies in a fast and flexible search component"><p>The goal is to have something that can be integrated in any framework of styling and DOM manipulation, while keeping it simple with few abstractions. I&#x2019;m using existing and upcoming technologies of the web platform to keep things readable, easy to change and extend. The combination of several async flows together with animations and differing browser capabilities makes this non-trivial. Rather than abandoning things that didn&#x2019;t work out, I kept at it to find the most elegant solution. You can see the result here and on <a href="https://wiki.para.se/?ref=blog.jonas.liljegren.org">wiki.para.se</a> and check out the code directly in the browser DevTools and on <a href="https://github.com/aigan/jl-search?ref=blog.jonas.liljegren.org"><svg class="icon icon--github"><use xlink:href="#icon-github"/></svg>aigan/jl-search</a>.</p>
<script type="module">
    import "https://wiki.para.se/demo/encapsulated/jl-search-wiki.mjs";
    import "https://jonas.liljegren.org/2023/components/jl/code/code.mjs";
</script>
<style>
    jl-search {
    --font-family: sans-serif;
    --lineheight: 1.625;
    --padding: .75em;
    --border-width: .125rem;
    --border-width-focus: .25rem;
    --focus-color: #347f53;
    --jl-search_move-speed: .25s;
    justify-self: center;
   }
   div:has(jl-search){ display: grid }
</style>
<div><jl-search autocomplete onchange="window.location=`https://wiki.para.se/?${this.value}`"></jl-search></div>
<p>See my article about <a href="https://blog.jonas.liljegren.org/getting-started-with-web-development-in-2024/">modern web development</a> for why bundling is no longer needed. Features used include ES 2022 syntax (2021), cascading css variables (2020), color mixing with oklch (2023-05), mobile keyboard handling with beforeinput (2021), custom elements with optional shadowdom (2020). I&#x2019;m also using the popover api (2024-05), anchor positioning api (TBA), view transitions api (TBA), the navigation api (TBA) and more. For compatibility with older browsers, these are handled with polyfills or graceful degradation. Dates are for when it was added to all three major engines. Mozilla is often the last and has trouble keeping up. The anchor positioning api is not finalized and is only available behind <a href="chrome://flags/#enable-experimental-web-platform-features">a flag in Chromium</a>.</p>
<h2 id="wikipedia-database">Wikipedia database</h2>
<p>In order to have a good demonstration of something to search for, I downloaded some of the wikipedia <a href="https://dumps.wikimedia.org/backup-index.html?ref=blog.jonas.liljegren.org">SQL database dumps</a>. No point in having a client-server search widget if all of the options can be downloaded before the user starts typing. The tables were adjusted for quick prefix search results, which took a lot of work. The default table was actually not stored as unicode, but binary. So I converted them to <em>utf8mb4</em> and indexed them with Swedish collation. Even that was not quite quick enough for retrieving the total number of search results for the first letter, so I added an additional table for the most common prefixes. The complete source code along with notes of the changes made to the tables can be seen in <a href="https://github.com/aigan/jl-search/blob/main/demo/server/searches.mjs?ref=blog.jonas.liljegren.org">searches.mjs</a> on github. The total number of search results along with retrieval time is displayed at the bottom of the options list in the demo.</p>
<pre><code class="language-sql">INSERT IGNORE INTO prefix_counts (prefix, row_count)
SELECT DISTINCT 
    UPPER(LEFT(title_se, 2) COLLATE utf8mb4_swedish_ci ) AS prefix,
    COUNT(*) AS row_count
FROM page 
GROUP BY UPPER(LEFT(title_se, 2) COLLATE utf8mb4_swedish_ci );
</code></pre>
<p>The Wikipedia dumps are quite large so I created a dedicated <a href="https://xenproject.org/?ref=blog.jonas.liljegren.org">Xen</a> virtual debian server for the database to limit the impact on other servers. After all the work of transforming and indexing, the actual use of the table doesn&apos;t require much memory or CPU. This dump is from January 1st 2024.</p>
<h2 id="async-results">Async results</h2>
<p>I could have downloaded even more of wikipedia in order to also return the images and description, but the official wikipedia api turned out to be fast enough to fill out the details of the search results, and it also gave the opportunity to showcase async processes where parts of the search result is filled in when the additional information is finished loading, at the same time as new search results are coming in while the user is typing. I also gave the option to animate the options row, meaning that several rows may be animating out while new rows are added. And all this while taking care of jitter in the search responses.</p>
<p>It&#x2019;s often the case that a backend server handling the incremental search will return results out of order. Searching for <code>s</code> will be slower than searching for <code>spock</code>. I added a <strong>Slow down</strong> option to increase this effect. The demo has an option to simulate slower server response, that will on purpose send back results in the wrong order just to make sure that it will not mess up the presentation.</p>
<p>The <code>on_result()</code> handles the jitter by checking <code>if (res.req &lt; $el._data.received.req)</code>. But the same goes for the whole process. Retrieved data will be prepared and then rendered. Here I&#x2019;m assuming that searching and preparing is async while the rendering is done sync, based on the latest prepared data. Thus, the state exists in three versions as <code>received</code>, <code>prepared</code> and <code>rendered</code>. I will not cancel or ignore results from older queries since they will come in useful if the user backspace characters. If necessary, the req_id could be sent to the server that could use it to cancel ongoing searches if a later <code>req_id</code> comes in from the same client.</p>
<h2 id="autocomplete">Autocomplete</h2>
<p>How do I implement inline suggestion? With autocomplete, I&#x2019;m referring to how the first search result is inserted in the input field, but selected so that you can continue to type and ignore the suggested completion. You may accept the suggestion by using the <strong>right arrow</strong>, jumping to the end of the text and de-selecting the text, or by pressing <strong>enter</strong>, which will submit the search with the suggested text. You can also step between the entries in the dropdown by using the <strong>up</strong> or <strong>down</strong> arrow keys. Using the <strong>backspace</strong> key will first remove the suggestion and after that delete characters as usual. You may also use the <strong>esc</strong> key to back out of the search field. First esc closes the options list, second selects all the text and the third will revert/remove the text.</p>
<p>Have you noticed how the <a href="https://www.google.com/?ref=blog.jonas.liljegren.org">google.com</a> search field no longer uses autocomplete? The Chrome <strong>new tab</strong> Google search field and the <strong>URL</strong> field have the capability, but not the actual webpage version. This type of autocomplete is not compatible with how mobile virtual keyboards function. The virtual keyboard will update the input field through autocorrects by selecting text to be replaced and then replace it with the new string.</p>
<p>If you for example try to type <code>bold</code> but the keyboard autocorrects it to <code>books</code>, you can tap the correct word on the keyboard. The phone will first get the current value of the field, and then send a selection event selecting <code>ld</code>, followed by an insertReplacementText event with <code>oks</code>. Since these events are async, it is very possible that you may have changed either the selection, the text or both in the field in between the virtual keyboard doing its own selection and replacement. This also works differently on desktop, phone and differs between the different browser vendors and versions. Chrome has for example completely stopped sending letter information in keydown events. In order to make this type of autocomplete work you would have to completely take over the update of the field, by parsing the <strong>beforeinput</strong> events. On top of that, It&#x2019;s really not a good option to try to detect if a phone is used. There are other types of virtual keyboards that could possibly be used with the desktop browser version. As far as I know, <em>there is no right way</em> to know if the keyboard is going to send auto-of-sync events. Even so, I did some things to make the autocomplete work pretty good. And I have more things I can do to make it 100% solid if needed.</p>
<h2 id="flexible-style">Flexible style</h2>
<p>The style for <a href="https://wiki.para.se/jl-search.mjs?ref=blog.jonas.liljegren.org">the search component</a> is placed in <a href="https://wiki.para.se/jl-search.css?ref=blog.jonas.liljegren.org">a separate file</a> in order to make it easier to change or completely replace, using any other type of design system. <a href="https://wiki.para.se/demo/plain/jl-search.html?ref=blog.jonas.liljegren.org">The main demo</a> is using the traditional light dom, making the search component part of the main style. I also have <a href="https://wiki.para.se/demo/encapsulated/jl-search-wiki.html?ref=blog.jonas.liljegren.org">one demo that encapsulates the component in shadow</a> and another <a href="https://wiki.para.se/demo/lit/jl-search-lit.html?ref=blog.jonas.liljegren.org">one that uses it from inside a Lit element</a>. The component will work both with and without shadowdom, and the demo that uses shadowdom transform the main jl-search.css while loading it, converting the <code>jl-search</code> selectors to <code>:host()</code> selectors.</p>
<pre><code class="language-html">  &lt;jl-search&gt;
    &lt;main&gt;
      &lt;fieldset&gt;
        &lt;input placeholder=&quot;Do the search&quot;&gt;
        &lt;span class=&quot;state&quot;&gt;&lt;/span&gt;
      &lt;/fieldset&gt;
      &lt;nav&gt;
        &lt;section&gt;
          &lt;hr&gt;
          &lt;ul&gt;&lt;/ul&gt;
          &lt;hr&gt;
          &lt;footer&gt;&lt;/footer&gt;
        &lt;/section&gt;
      &lt;/nav&gt;
    &lt;/main&gt;
  &lt;/jl-search&gt;
</code></pre>
<p>Since we are using semantic markup, there is less visual noise. The expected tags are:</p>
<ul>
<li><code>&lt;main&gt;</code> for the part of the component that will popup and may also move in the viewport as is the case for mobile devices.</li>
<li><code>&lt;fieldset&gt;</code>, that will serve as the input group and can hold more prefix and suffix icons. The dictionary icon was added for the demo.</li>
<li><code>&lt;input&gt;</code>, as the main field where the user will type.</li>
<li><code>&lt;span.state&gt;</code> is used for conveying the state, such as loading or error, and also used for expanding or collapsing the options list.</li>
<li><code>&lt;nav&gt;</code>, is the container for the search result and will be the part that expands or contracts.</li>
<li><code>&lt;section&gt;</code>, placed in nav is a concession for handling sizing and animation of the options list. Ideally it would not be needed.</li>
<li><code>&lt;ul&gt;</code> is the container for the options list.</li>
<li><code>&lt;footer&gt;</code> is intended for user feedback, such as instructions, validation messages, error messages and the like.</li>
</ul>
<p>In the default style, I&#x2019;m also using <code>&lt;hr&gt;</code> tags for separating the list from the input field and footer.</p>
<h2 id="css-variables">CSS variables</h2>
<p>How do I make the hover color relative the existing color? For making the component theming flexible I used css variables with default fallbacks. As a naming convention I&#x2019;m using underscore prefixes for the internal variables. For example, <code>--_padding</code> is initialized based on <code>--padding</code>, with a default fallback value. This makes it easy to style the component with <code>jl-search { --padding: .75rem }</code> but the value can still be used internally without having to provide a default everywhere it&#x2019;s used. The outline can be a combination of <strong>theme</strong>, the state such as <strong>valid</strong>, <strong>invalid</strong> input, <strong>focus</strong>, <strong>disabled</strong>, <strong>hover</strong> and <strong>active</strong>.</p>
<pre><code class="language-css">main {
  --_outline-color: var(--_outline-base-color);
  --_outline-width: var(--_border-width);
  outline: solid var(--_outline-width) var(--_outline-color);
}

main:focus-within {
  --_outline-base-color: var(--_focus-color);
  --_outline-width: var(--_border-width-focus);
}

main:active {
  --_outline-base-color: var(--_active-color);
}

main:hover {
  --_outline-color:
    color-mix(in oklch, var(--_outline-base-color) 
    var(--_hover-brightness), black);
}
</code></pre>
<h2 id="material-design-v3-color-system-and-oklch">Material design v3 color system and OKLCH</h2>
<p>To showcase the dynamic theme capability, I implemented the <a href="https://m3.material.io/styles/color/system/how-the-system-works?ref=blog.jonas.liljegren.org">Material Design version 3 color system</a>, but with <a href="https://oklch.com/?ref=blog.jonas.liljegren.org#78.97,0.147,154.06,100">the OKLCH color space</a> that supports colors way beyond the RGB, P3 and even <a href="https://en.wikipedia.org/wiki/Rec._2020?ref=blog.jonas.liljegren.org">REC.2020 color gamut</a>. The OK variant is adjusted for <a href="https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl?ref=blog.jonas.liljegren.org">the human perception</a> such that color-mixing will match up with human expectation of color blending and lightness. But the current browser implementation in mozilla and chromium has a bug where chroma beyond the monitor capability will be mapped to the closest available color even if it&#x2019;s another hue, making darker shades of yellow turn out green. I submitted <a href="https://issues.chromium.org/issues/325598621?ref=blog.jonas.liljegren.org">a bug report</a> along with <a href="https://para.se/2024/oklch-palette.html?ref=blog.jonas.liljegren.org#100">a demo</a>.</p>
<p>Here is <a href="https://wiki.para.se/demo/color/colors.html?ref=blog.jonas.liljegren.org">the full color palette</a> of my Material 3 implementation. One part of the palette involves rotating the hue for a matching complementary color. Support for doing that type of color calculation within css is limited. Chromium supports css <code>@proprty</code> declarations while Mozilla supports math functions like <code>mod()</code>. I constructed the css so that it will work on both. Safari can do it either way. I found the solution at <a href="https://css-tricks.com/using-absolute-value-sign-rounding-and-modulo-in-css-today/?ref=blog.jonas.liljegren.org">css-tricks</a>.</p>
<h2 id="material-symbols-font">Material symbols font</h2>
<p>The demo is using icons from the <a href="https://material.io/blog/introducing-symbols?ref=blog.jonas.liljegren.org">google fonts material symbols</a>, but those are optional and the main library defaults to <strong>unicode</strong> icons. The font is currently the thing that slows down the demo most. But they also serve as an opportunity to show how external resources can be loaded async without holding up the <strong>first paint</strong>. You can slow down <strong>cpu</strong> and <strong>network</strong> in the browser devtools to see the loading slowed down. The indirection of loading a css from google fonts that in turns load the actual font not only slows things down, but also makes the promise a two step process. First load the style, waiting on the load event, and then using the <code>document.fonts.load</code> promise. The material symbols font is using <a href="https://fonts.google.com/knowledge/glossary/ligature?ref=blog.jonas.liljegren.org">ligatures</a> which leads to simpler code and good accessibility fallback, but are awful if rendered before the font is ready. A <code>user-select: none</code> will help with the unintuitive behavior during text selection. The font is easy to work with since all the symbols have the same size.</p>
<h2 id="animations">Animations</h2>
<p>The component is using a mix of animation techniques. On top of the css <strong>transition</strong> and <strong>keyframe</strong> animations, it also uses <strong>web animations</strong> api, <strong>view transition</strong> api and direct use of <strong>requestAnimationFrame</strong>. All of these are orchestrated with async events that may start, stop or reverse additional animations. For mobile viewports, there is a <strong>chained</strong> animation that will first finish loading the popover polyfill if needed, then activating the popover, doing a view transition to the top of the viewport, followed by animating the expansion of the options list. There are also fallbacks for the options to not use animations, so that promises don&#x2019;t get stuck waiting for the next step. It would be faster to use <strong>scaleY</strong> for opening the dropdown, but that looks ugly. The current animation is possibly a bit heavy, but using <code>contain: content</code> helped a bit. Also take a look at the <strong>flash</strong> animation for validated selections and the <strong>shake</strong> animation for invalid selections.</p>
<h2 id="viewtransition-api">ViewTransition API</h2>
<p>The ViewTransition api allows for smooth transitions of elements both inside a SPA and between pages. It can handle fadeouts of elements removed from the dom, or movement and resizing of elements even if they are rendered as different elements in different parts of the tree. This allows for hero animations. I&#x2019;m using this for the <a href="https://blog.jonas.liljegren.org/tag/code/">images in my blog</a>, but that capability is still behind the <a href="chrome://flags/#view-transition-on-navigation">#view-transition-on-navigation flag in chromium</a>, since it&#x2019;s for transition between page loads. In the <code>&lt;jl-search&gt;</code> component, I&#x2019;m using it for moving the input to the top on smaller (mobile) viewports. This allows for easy movement animation even when it&apos;s the result of something that usually isn&#x2019;t possible to transition. In this case, changing the position from <strong>static</strong> to <strong>fixed</strong>. You can use the chrome devtools animations tool to slow down the animation to see how it handles the transition by <em>stretching</em> and <em>fading</em> between the start and end state.</p>
<p>The view-transitions operate on the document root, so there needs to be some coordination while doing it. It also pauses all pointer events, which can cause problems when a click will start a transition with the default <code>.5s</code> duration causing the click on other parts of the viewport to fall through to the document root. This is not a problem in the demo since I only do the transition if actually needed, and also removes the default <code>animation-duration</code>. But for handling those more unusual situations, I <a href="https://github.com/aigan/jl-search/blob/main/jl-search.mjs?ref=blog.jonas.liljegren.org#L1456">record the clicks</a> happening during the transition and play them back afterwards.</p>
<h2 id="popover-api">Popover API</h2>
<p>Many new web platform APIs introduce new capabilities that do things that can&#x2019;t be fully polyfilled. Without these, you would often have limitations on what can be done within a single web page. All the components have to be orchestrated together to not step on each other&apos;s toes. The popover API solves a couple of those problems where different parts of the page compete for the top position. A common solution is to put the component last in the main body and give it a high z-index. Another solution that I have previously used is to create a <code>ensure_ontop()</code> method that will go up the tree and give each parent a <code>z-index</code> higher than its siblings. That will make sure that the component still inherits all the styles. Things like <em>Tailwind</em> that give up on the whole idea of the cascading part of styles has probably increased in popularity because of the problems of having to move components around to handle positioning, rendering and animation. But the popover and positioning apis solves a lot of this by introducing the <strong>top layer stacking context</strong>, also used by <code>&lt;dialog&gt;</code>. Now you can use menus, dropdowns, tooltips, popups and the like without having to do extra work so make it actually appear above everything else.</p>
<h2 id="error-handling">Error handling</h2>
<p>Errors can occur even in a completely bugfree application, due to variations in internet connectivity, browser plugins, memory exhaustion and other exceptions. But it&#x2019;s usually good to also handle bugs gracefully. Especially in a larger application with components loading in on demand and updating independently. This component will handle errors both from <strong>search</strong>, <strong>result</strong> processing and <strong>rendering</strong>, including plain syntax errors. For a production environment, there should be a <strong>telemetry</strong> set up by listening on the global <strong>error</strong> and <strong>unhandledrejection</strong> events. But I would still show unresolved issues to the end user, making it possible for power-users to work around any issues.</p>
<p>You may check out an example of an error presentation by entering <code>trigger error</code> for a server side error or <code>i am lying</code> for a client side error. (Because Kirk proved thet you can make any computer explode by giving it a paradox.)</p>
<h2 id="reactive-state-signals">Reactive state (Signals)</h2>
<p>The component doesn&#x2019;t use reactive state. That means that functions using specific properties must be called when any of their dependencies updates. For larger projects, I would prefer to use <a href="https://en.wikipedia.org/wiki/Reactive_programming?ref=blog.jonas.liljegren.org">reactive programming</a>, where dependent functions will be repeated when any of their dependencies are updated, even if its indirect dependencies, like in a spreadsheets application.</p>
<p>Signals is currently in the process of becoming <a href="https://github.com/tc39/proposal-signals?ref=blog.jonas.liljegren.org">a javascript standard</a>, in collaboration with authors of many of the largest frameworks. I mostly know of the design pattern as presented by <a href="https://mobx.js.org/the-gist-of-mobx.html?ref=blog.jonas.liljegren.org">MobX</a>, but many other frameworks and libraries are using similar patterns for their state management.</p>
<p>I have done extensive work on <strong>multi-user client-server reactive state</strong> on semantic graphs using the <a href="https://www.npmjs.com/package/causalityjs?ref=blog.jonas.liljegren.org">Causality</a> library (similar to MobX), and that was the base implementation that inspired this limited <code>&lt;jl-search&gt;</code> widget.</p>
<h2 id="chatgpt">ChatGPT</h2>
<p>ChatGPT 4 has been a useful companion while writing this component. But not for actual code. It has been all too happy to output code examples, but I don&#x2019;t think it has produced a single line of usable code. Probably trained on Stack Overflow, it usually produces code for ancient browsers, excessive verbosity, hallucinated APIs and so on. But it works well as a <strong>Rubber duck</strong> for thinking through problems. It&#x2019;s good for brainstorming, familiarizing myself with new things and finding gaps in my knowledge. Also good for looking up API for specific use cases and sometimes to get stubs for new functionality. I also often use if to get an overview of terms and naming conventions used in different design patterns. Just don&#x2019;t believe anything it says because it will often validate your approach and totally ignore the much better option.</p>
<h2 id="jl-searchmjs">jl-search.mjs</h2>
<p><jl-code src="https://wiki.para.se/jl-search.mjs"></jl-code></p>
<p>[[<a href="https://www.facebook.com/aigan/posts/10159872220392393">https://www.facebook.com/aigan/posts/10159872220392393</a>]]<br>
[[<a href="https://www.linkedin.com/pulse/implementing-latest-web-technologies-fast-flexible-search-liljegren-00ygf?ref=blog.jonas.liljegren.org">https://www.linkedin.com/pulse/implementing-latest-web-technologies-fast-flexible-search-liljegren-00ygf</a>]]<br>
[[<a href="https://twitter.com/aigan/status/1772409188854989006?ref=blog.jonas.liljegren.org">https://twitter.com/aigan/status/1772409188854989006</a>]]</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Everything wrong with hand-written narrative]]></title><description><![CDATA[The limitations of authored narrative as opposed to systemic]]></description><link>https://blog.jonas.liljegren.org/hand-written-narrative/</link><guid isPermaLink="false">61955e29fb356f5697b88f3d</guid><category><![CDATA[systemic]]></category><category><![CDATA[story]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Sun, 04 Feb 2024 19:11:19 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2024/02/DALL-E-2024-02-04-19.52.11---game-designer-graph.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.jonas.liljegren.org/content/images/2024/02/DALL-E-2024-02-04-19.52.11---game-designer-graph.png" alt="Everything wrong with hand-written narrative"><p>This is part of <a href="https://blog.jonas.liljegren.org/tag/systemic/">the series about my design for a <strong>Systemic story</strong> game</a>. See the <a href="https://blog.jonas.liljegren.org/the-promise-of-adventure/">Promise of Adventure</a> for how <em>hand-written</em> narrative limits player freedom. This part covers everything else.</p><p>The <strong>Narrative</strong> is how the story is presented as a series of plot events. For games, this includes how the player experiences and interacts with the story through the game. The creators of the game construct a story with a scenario consisting of places, factions, characters, relationships and so on. The player then experiences this story through the narrative. But the term Narrative is also often used to signal that the story is an important part of the game, to the degree that the game <em>is</em> the story rather than <em>having</em> a story.</p><p>I have chosen to use the term <em>hand-written</em> instead of <em>authored</em> or <em>scripted</em>, for making it clear that it&#x2019;s about the game designer creating a tree of narrative events with details such as dialogue lines and quest logs. There could still be some scripts with a <em>Systemic Story</em> and the story could still be authored even if each narrative step is systemic.</p><p>The positives are obvious for those of us who want to play the story. The cost is all the work that has to go in to cover all the combination of choices that comes from the player. Even more so when the game has higher fidelity with motion-capture and recorded voice lines.</p><h2 id="open-world">Open-world</h2><p>Almost no games are completely <strong>linear</strong> or <strong>branching</strong>. The now common story-based open-world action-adventure game has a mix of components used to enhance the gameplay. There is often a lot of optional content that can be experienced in any order. <strong>Fragments</strong> of backstory are often spread throughout the world in the form of audio logs or the like. The game is often divided in stages where the player gets access to more and more of the world as the story progresses.</p><p>Even if individual quests are linear, they may differ depending on the order they are completed. There may be an additional voiceline acknowledging something that happened before, depending on character progression or world state. Individual quests are designed to only have limited influence on other quests in order to keep the number of permutations manageable.</p><p>The narrative structure is often what can be described as <strong>beads-on-a-string</strong> or <strong>diamond</strong> shape, where any branches in the narrative goes back to the same place at the end of the quest or level. The game remembers that the quest has been completed. You may have gotten a new object during the quest that can be used in other places. Your actions may have contributed to a change in faction or NPC reputation. Some choices in dialogue are just for expressing personality and will have no influence on the future. Other choices are just for getting additional information or optional backstory.</p><p>Even with all the tricks to keep quests isolated, there are usually lots of situations where NPCs should have a reaction that&apos;s missing, or the player should have an option. Some games give you the freedom to kill anybody, but it&apos;s too much work to make the world actually respond to it. The NPC will say something like</p><p>&#x2014; I can&#x2019;t believe you just murdered my friend! &#x2026; Anyway, what did you want to buy?</p><h2 id="sandbox">Sandbox</h2><p>A sandbox game has repeatable activities that encourage experimentation. Open-world games are often also sandbox games, but the sandbox part is independent from all the <em>hand-written</em> quests. There may be a gang of bandits that you encounter on your quest while traveling from point A to B. But if you would encounter those same bandits outside of the quest, it&apos;s something that is independent of the quests. The experimentation is something you get from the <strong>tactical</strong> and <strong>exploratory</strong> freedom. It&#x2019;s an effect of the <strong>Systemic Environment</strong>.</p><p>A sandbox game can facilitate <strong>emergent</strong> narrative, where the player&apos;s interaction with a systemic environment is experienced as a story. It can for example involve mistakes that get compounded by other factors, the player barely survives, sets out to recover, and re-establish control by revenge on the initial perpetrators. This will often be enhanced by the presence of NPCs that the player tries to help. The random events and limited details that give room for imagination helps the player to create the narrative through <strong>apophenia</strong>.</p><p>Lots of games are using procedurally generated places, characters and loot. But some games also have random repeatable <strong>procedurally generated</strong> events and quests. An example of a procedural event is a person running from bandits in a way that the person runs right in front of the player. A procedural quest can be an NPC that asks the player to do a specific task in a specific place with a specific enemy, selected from a template and based on the level of the player, their playstyle and what parts of the world they haven&#x2019;t yet visited.</p><h2 id="systemic">Systemic</h2><p><strong>Systemic Story</strong> is different from branching, emergent or procedural narrative. A lot of games have developed a <em>Systemic Environment</em> that gives the player tactical freedom. Let&apos;s make the story systemic in a similar way. Doing that means that all parts of the story have to be encoded as interactive systems. In order to have a satisfactory overarching main story, we need a top-down approach. The story is continuously adapted as a possibility-space using rules of story structure and theme.</p><p>Think of the story as a table-top D&amp;D <strong>module</strong>. A new story may require a couple of new systems that fit the featured themes and dynamics. The locations, characters and scenarios are described. There are inciting incidents and some extra care for expected events that can come up on the way to the final resolution. There are a lot of techniques that can guide the player back to the content of the story, but the player is free to turn around and do something that&apos;s not at all covered by the module.</p><p>The story will be a mix of authored content adapted to the player choices and backed up by systems and generated content. It&#x2019;s not a traditional procedural generation or simulation, but rather a type of top-down <strong>constraint-based generation</strong> based on story-structure, theme and tone. More of that in other parts of this series.</p><p>There will probably be a temptation to mix traditional <em>hand-written</em> dialogue with systemic dialogue. Some games have used generated content in side activities alongside the <em>hand-written</em> quests and main story. But I think that would lead to inconsistencies in what you can do in the world and how the world would react. It would also lead to inconsistencies in the NPC interactions. I would rather see a refinement of the systems needed than a continuation of this type of compromise.</p><h2 id="finite-content">Finite content</h2><p>A common thing with <em>hand-written</em> narrative is the desire to experience all the content and achieve the best or intended version of the story. You go through all the available options not because that&apos;s what you would want to do as your character, but because you don&apos;t want to miss anything important or good. It becomes a game about sweeping through the locations, objects and dialogue choices. You become more focused on what&apos;s left in order to cover everything rather than the actual content of the story and dialogue.</p><p>The game will help you out with markers on the map and quest logs listing everything left to do. All these directions take away from the player&apos;s autonomy of deciding on their own path. Some players want the directions so they can get to the good stuff. Others just want to reach 100% completion. And yet others want to do whatever is needed to level up.</p><p>A <em>Systemic story</em> game will not have <em>hand-written</em> dialogue options, so it&#x2019;s not possible to exhaust the dialogue. But it will be very possible to exhaust the NPC patience with you for pestering them with every little detail. Locations may be moved around, altered or generated from scratch to fit the need of the story, all within the limitation of what has already been revealed by clues and NPC dialogue. You can get hints and direction by asking people rather than some omniscient quest log.</p><h2 id="guessing-game">Guessing game</h2><p>What do the game want you to do now? Watch someone that has never played a game and you will see how much of what we do in games is based on video-game logic that often makes no sense. Experience will make you better at figuring out what you the game creators probably intended for you to do in each specific situation.</p><p>Getting stuck in adventure games can suck. There are often a lot of places, people and things in the game that could potentially help. But mostly everything is just part of the background graphics and has no interactivity. Most people in the game have nothing to say about the things I would like to do and I can&apos;t use the things I have found in the way I would like.</p><p>Total freedom does not exist either in life or in games. But there is a big difference between <em>hand-written</em> and <em>systemic</em> solutions. Systems are something you can learn and trust to behave consistently. It will not be some type of one-off thing where the author decided to give a specific object some property just for a specific puzzle or part of the story.</p><h2 id="story-triggers">Story triggers</h2><p>Story games will often have some stuff to collect while traversing through the levels. It can be story fragments, crafting materials, ammunition, powerups, money and so on. That is something that is rather specific for games and is usually not seen in movies or books. (I would hope that an adventure game could be good enough to not need all that bling.)</p><p>Action-adventure games usually have scripted events that advance the narrative. Combine that with collectibles and you will have constant anxiety about accidentally triggering the next cutscene before you had time to finish searching the level for everything of value.</p><h2 id="finding-the-good-ending">Finding the good ending</h2><p>There are more reasons to provide choice than just the sense of freedom. Alternate endings have the potential to make the story work better for more people, where the different branches can suit different types of player personalities. The game should lead the player to what is the best completion of their individual story. Best as in the best story experience, not necessarily happy. It should complete the arc.</p><p>But then there is the point of games as providing a challenge, as opposed to <strong>toys</strong> or <strong>interactive</strong> experiences. The possibility of failure will contribute to the feelings of <strong>meaning</strong> and <strong>accomplishment</strong>. The perils of the adventure gives <strong>excitement</strong>. What is the point of choosing if you can&#x2019;t choose poorly?</p><p>One common way of handling failure in games is to stop and rewind to an earlier point to let the player try again. Another way common in adventure games is to not let the player do anything that will get them killed or stuck. Just say that the thing they try doesn&#x2019;t work and let them try something else. Non-lethal failure can be as easy as failing a jump, getting up, going back and trying again.</p><p>But then you have narrative games with bad endings. The player may not even realize that there is another ending they would enjoy much more. Getting the better ending may require going back hundreds of hours of gameplay. It&apos;s a good thing that choices can have big consequences hundreds of hours later. Sad endings can be good. But this type of massively delayed failure feedback has problems.</p><p>Some people have choice anxiety to the degree that they prefer a completely linear narrative. Choice games should have accessibility options that clearly mark up or block choices that will lead to bad things. Especially in regards to characters in the game that you may care about.</p><p>Players should also be able to fix mistakes without reloading. Did you say something that angered the NPC? Let&apos;s just talk about it. Did this person tragically die? Oh no, she is still barely alive. Let&apos;s heal her. Did we lose this very important quest item? Let&apos;s find something else that will work. A systemic game can provide much more options than would be reasonable to handle in a <em>hand-written</em> narrative.</p><p>Having ways to fix mistakes will not negate the challenge. It will just provide a much better alternative to just reloading a previous save. Fixing mistakes is what makes up the bulk of many classic adventures. You want mistakes. But they should come from the player and not from scripted events.</p><p>Failing a combat challenge could lead to mocking, escape, injury, capture, last-minute rescue or something else. There are so many more options than just death and rewind. What happens in a <em>Systemic story</em> game will depend on what would make sense for that part of the story and the relationship with the enemy.</p><p>A <em>Systemic story</em> game can also provide much more customization options. You can adjust the level of danger, brutality, stress, complexity, sorrow, uncertainty and so on. The same game can be kind and nice for some players while grueling hard for others, depending on their preferences.</p><h2 id="lacking-reactivity">Lacking reactivity</h2><p>NPCs should react to things that&apos;s happening. The NPC in Horizon Zero Dawn comments on the outfit I&apos;m wearing. But that&apos;s almost only for the systemic barks. The scripted authored dialogues don&apos;t mention what I&apos;m wearing. No mention if I&apos;m badly hurt and need medical attention. No mention of if I&apos;m soaking wet from a swim. No mention of if I&apos;m carrying around loads of heavy things. No mention if someone was just killed a few feet away. Some dialogues (in some games) refer to the world state or faction reputation. But most of this is done by brute force or by sticking in additional voice lines in certain places. But there are lots of games where the lines don&apos;t match with the situation. There are too many voice lines that just seem to be random picks from lists. Sometimes it feels like almost everything NPCs say is nonsense. Like they come out from combat and then randomly say something about being bored.</p><p>I would like to talk to random people. Not just trigger a voice line. I might want to ask for directions, ask for help about something or help with stuff. There are many games where you see people clearly needing help but have no way to actually help them. I might have lots of money and several magical healing potions that can revive me from the brink of death but I can&apos;t decide to help them with it?</p><p>I would like to be able to come back to people I previously helped. Most games have the NPC just forget you after the quest is complete. Or they have a set of static voice lines that may depend on the quest outcome. But I want to continue helping them or just see how it goes for them or talk about other things. Or I would like to ask for help with something.</p><p>Some games have companions and some of them have lots of situation-specific reactions. That&apos;s nice as long as it lasts. But it is usually related to authored quests or combat or basic world exploration. If I would like to ask a companion to come with me because I would like to show them a large tree I found, they would probably have no authored reactions for that specific thing.</p><p>I recently played a game where my choice changed the stance to a specific faction. Suddenly I had an entire planet against me. No regard for how they would even know about the change of status. How did they know what I did? What do they think about me? And why can we not deescalate the situation? If I see a bandit, I would like to have choices other than combat. Bargain, deception, bribes or maybe talk about their situation and find other solutions. Maybe I could help them with something?</p><p>Traditional systems for NPC reactions and barks are too limited and take too much manual work. It&apos;s not that I would not like the traditionally crafted game. It&apos;s that it can&apos;t handle the combinatorial explosion of possibilities and the volume of an open world like Witcher.</p><h2 id="conclusion">Conclusion</h2><p>A <em>Systemic Story</em> game can lead to experiences much better than anything in existence today, because it can adapt to the individual player. The realization will be gradual and take many iterations before they will surpass the fidelity of current AAA story-based games. But I hope I showed that it will be worth the effort. <a href="https://blog.jonas.liljegren.org/tag/systemic/">More to come</a>.</p><p>[[ <a href="https://www.facebook.com/aigan/posts/10159802548477393">https://www.facebook.com/aigan/posts/10159802548477393</a> ]]<br>[[ <a href="https://twitter.com/aigan/status/1754418269568561154?ref=blog.jonas.liljegren.org">https://twitter.com/aigan/status/1754418269568561154</a> ]]<br>[[<a href="https://www.gamedev.net/forums/topic/715957-everything-wrong-with-hand-written-narrative/?ref=blog.jonas.liljegren.org">https://www.gamedev.net/forums/topic/715957-everything-wrong-with-hand-written-narrative/</a>]]</p>]]></content:encoded></item><item><title><![CDATA[The Promise of Adventure]]></title><description><![CDATA[The impossible dream of freedom in story games]]></description><link>https://blog.jonas.liljegren.org/the-promise-of-adventure/</link><guid isPermaLink="false">65bd6fb6bd5de594ce1366fd</guid><category><![CDATA[systemic]]></category><category><![CDATA[story]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Sat, 03 Feb 2024 12:51:42 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2024/02/DALL-E-2024-02-03-13.46.56---Create-an-immersive-21_9-fantasy-game-illustration.-Visualize-a-man-fighter-and-a-woman-ranger--standing-back-to-back--lovingly-supporting-each-other-.webp" medium="image"/><content:encoded><![CDATA[<img src="https://blog.jonas.liljegren.org/content/images/2024/02/DALL-E-2024-02-03-13.46.56---Create-an-immersive-21_9-fantasy-game-illustration.-Visualize-a-man-fighter-and-a-woman-ranger--standing-back-to-back--lovingly-supporting-each-other-.webp" alt="The Promise of Adventure"><p>Imagine a game where you inhabit a living breathing world with the freedom to go anywhere you want. Find your own unique solutions to the problems you encounter. Befriend any NPC on your way and form lasting relationships.</p><p>This is part of <a href="https://blog.jonas.liljegren.org/tag/systemic/">the series about my design for a <strong>Systemic story game</strong></a>. This part and <a href="https://blog.jonas.liljegren.org/hand-written-narrative/">Everything wrong about hand-written narrative</a> compares systemic with hand-written narrative. Other parts will go into details of how to make this &#x201C;impossible&#x201D; dream possible. (And that is without any need for advanced AI.)</p><p>A <strong>Story-driven</strong> game has events throughout the game that contribute to the beginning, middle and end of the story, through dialogue and world interactions that advances the plot. Those games can be classical RPGs, text adventures, action-adventures or anything else with an unfolding story.</p><p>There is a sort of common wisdom in game development that player freedom has to be sacrificed in order to create a more emotional meaningful story experience. That is why the emotional story parts often are created with hand-written narrative and cutscenes. Rather than compromise, I believe we can have <a href="https://blog.jonas.liljegren.org/systemic-story-game-development/">both the sandbox gameplay together with the top-quality story</a>.</p><h2 id="who-cares-about-game-stories">Who cares about game stories?</h2><p>There are many factors that make it hard to clearly know just how many people enjoy story-based games, regardless of the type of game they spend most of their time with. Among everyone who plays games, a large amount of playtime is spent in multi-player games where the focus is on the social aspects rather than the story. There are also a lot of people who play multiplayer games as if they were single-player. There are also some players who focus on the story in social multiplayer games. The statistics for the most played games will give the wrong impression since story-based games have a limited playtime. The multiplayer games have a longer total play-time and often a larger player-base since many of them are free to play. Among <a href="https://store.steampowered.com/charts/mostplayed?ref=blog.jonas.liljegren.org">the most played games on Steam</a> only 8% was primarily single-player games.</p><p><a href="https://www.statista.com/statistics/259577/us-single-player-vs-multiplayer-frequency-among-gamers/?ref=blog.jonas.liljegren.org">One source from Statista</a> from 2022 says that half of PC and console gamers spent most of their time playing alone. When I last looked at Steam charts two thirds of the most played single-player games were story-based. There is also a smaller portion that plays story-based games but ignores the story and will skip cutscenes even on a first playthrough. That totals to about 33% that enjoys the story of story-based games.</p><p>We can broadly divide story-driven games into <strong>linear</strong> and <strong>branching</strong> games. I&#x2019;m using branching here in the sense that the player will be locked out of narrative content based on choices in the game. Based on <a href="https://www.ludologie.de/fileadmin/user_upload/PDFs/Ludology_Master_Thesis_Narrative_and_Gamer_Types_Design_Sofia_Sabarini_2021.pdf?ref=blog.jonas.liljegren.org">partial statistics from Quantic Foundry</a>, there is about 35% who prefer the linear story, 50% who like the branching story and 15% who have no preference.</p><p>I don&#x2019;t have data for the overlap of branching preference with story-preference, but I estimate it to be about 20% that would prefer non-linear story-driven games. This is all very approximate. The point is that even if most people may not see the draw of freedom of choice, there are a portion of gamers who do.</p><p>As to the type of player, it&apos;s related to the <a href="https://en.wikipedia.org/wiki/Bartle_taxonomy_of_player_types?ref=blog.jonas.liljegren.org">Bartle</a> Explorer, the <a href="https://quanticfoundry.com/gamer-types/?ref=blog.jonas.liljegren.org">Quantic</a> Bard, the <a href="https://en.wikipedia.org/wiki/Big_Five_personality_traits?ref=blog.jonas.liljegren.org">Big Five</a> Open or the <a href="https://www.gamified.uk/user-types/?ref=blog.jonas.liljegren.org">Hexad</a> Free Spirit.</p><h2 id="single-player">Single-player</h2><p>Story-driven games are easier to do as a single-player game. Places and events are put together specifically for the experience of the player. Introducing more people will severely restrict the experience. The story beat that will work for player 1 may not fit with player 2.</p><p>A tabletop roleplaying game master will adapt places, people and events for the choices of the group. That will still work for co-operative games, but not so much for competing players. Many <strong>MMO</strong> games have solved this problem by creating <strong>instances</strong>, where each group will get its own version of a place not touched by the actions of other groups. The same goes for quests where the same quest will be available for each player or each group.</p><p>The introduction of multiple players will also limit the use of time, as for fast-forwarding all boring parts or even going back in time if you want to try something different. You would also have to handle what happens when the player is off-line, among many other things that come with a multiplayer game.</p><p>The type of <em>Systemic story</em> game I&#x2019;m propagating for will not use instanced locations or quests. It can be made to work for multiple players or even massively multiplayer, but it will make the implementation much harder and limit the possibilities to optimally shape the story to each single player.</p><h2 id="immersion">Immersion</h2><p>Being immersed is the feeling of being present in the game world. It will evoke the emotions of real life. For me, it can have an effect similar to a lucid dream, flying through the land. You are transported and absorbed and lose awareness of the before. This can be a partial or complete experience. <a href="https://en.wikipedia.org/wiki/Absorption_(psychology)?ref=blog.jonas.liljegren.org">Absorption</a> is a normal psychological trait related to dreamers, dissociation, meditation, suggestibility, flow and the like.</p><p>Immersion can take place with any media, such as daydreams, verbal storytelling, books or movies. The feeling of immersion is not conditional on advanced graphics. Computer games have had the potential of being immersive since the beginning. But there is an aspect of <a href="https://en.wikipedia.org/wiki/Hedonic_treadmill?ref=blog.jonas.liljegren.org">hedonic adaptation</a> in the works. The first time you see something in a game that reminds you of your world experience, it will help your immersion. After a while you may get used to the experience and automatically classify your sensations as coming from the game, thus lessening the experience. I think this may be a factor of the never-ending drive to increase graphical fidelity in games.</p><p>Animations that look natural can help immersion, even if it&apos;s just a few pixels as with <a href="https://youtu.be/H6tU7se18Sk?ref=blog.jonas.liljegren.org">Choplifter on C64</a>. But you will also have to look past the things in the game that aren&apos;t immersive. The ability to do that will depend on individual differences in the ability to be absorbed, the level of engagement and personal tastes or beliefs that have to be willingly suspended. Unexpected sensations that don&apos;t remind you of your world have the risk of breaking the immersion.</p><p>There are many things games can do to facilitate immersion, like idle animations, ambient sounds, trees blowing in the wind and so on. The environment can be painted with words or even suggested by established icons. I love the immersion of moving through 3D worlds in 1st or 3rd person perspective.</p><h2 id="freedom">Freedom</h2><p>Freedom can make the game more interesting and is a way to improve immersion. Based on <a href="https://www.reddit.com/r/truegaming/comments/1fktm2/a_different_kind_of_freedom_an_examination_of/?ref=blog.jonas.liljegren.org">a reddit article</a>, I&#x2019;m going to cover freedom under the topics of mechanics, traversal and story. These correspond to the concepts of Volition, Autonomy and Agency. Most discussions about freedom in games usually refer to just one or two of these.</p><h3 id="mechanics">Mechanics</h3><p>The mechanics connect you to the world. The responsiveness of the control will let you <strong>embody</strong> your avatar. The world should react to everything you do. The ability to touch the grass, move objects and leave your mark will enhance the immersion.</p><p><strong>Volition</strong> is your ability to act according to your will. Anything that temporarily blocks your actions will diminish your volition. For example, if a door can&#x2019;t be opened because of a scripted quest that requires you to do something else first. If there is an object you should be able to push but it doesn&apos;t react. Cutscenes are another example of something that takes your volition away.</p><p>The basic actions you use are often called <em>verbs</em>. I don&#x2019;t like to use <em>interact</em> as a verb, since that will mean very different things depending on the context. The verb should be directly mapped to a specific movement of your avatar. That will not only enhance the embodiment, but also make the actions easier to understand. It will also remove the worst of the downside of the contextuality when you are on the edge of switching context. See my suggestion for <a href="https://blog.jonas.liljegren.org/embodied-manipulation/">embodied manipulation</a>.</p><p>It should be clear what you can do in the world and what effect you can expect from your actions. Ideally, anything seen in the world should interact with everything else according to rules you can learn to understand and use to your advantage. The combination of all the player equipment and abilities with everything in the environment should create a possibility space large enough to give players the freedom to choose their own approach according to their playstyle and preference and give them the ability to find their own uniquely clever solutions for what they want to do. This type of <strong>Systemic Environment</strong> giving you <strong>tactical</strong> freedom can be seen in many sandbox games, CRPGs and immersive sims.</p><h3 id="traversal">Traversal</h3><p>The freedom to <strong>explore</strong> anywhere you want. You should not be locked to a specific area because of a specific quest. You may be trapped in a room, but you should be able to use all the mechanics and environment to try to escape if you want. No blocked actions. No invisible walls. No indestructible doors. This will build on your volition to increase your <strong>Autonomy</strong>; the power to make your own plans.</p><p>A character that can or should be able to jump and climb should also be able to get up on objects in the world. Unclimbable rubble or invisible walls restricts your autonomy. Rubble blocking passages are all too often used in linear games to keep the player on the right path. Some linear action-adventure games have started using wide-linear levels where you have the freedom to choose a couple of different paths or at least feel like you have the choice of path, but still end up in the same place at the end of the level. The design of the level with rubble and highlighted paths are of course meant to serve the pacing of the <em>hand-written</em> narrative. All the resources can be focused on a limited set of locations that are needed for the story.</p><p>Even open worlds often have places with invisible borders or indestructible objects just so that they can function in specific scripted quests. That is an effect of the old way of doing quests where it becomes too hard to make the quests work if the player has the freedom to visit and affect places in the wrong order. It&apos;s often done with an object you must interact with, that only becomes available according to the quest progression. The better alternative is to use <em>Systemic Story</em> to adapt quests to anything the player has done.</p><p>The possibility to go everywhere will also introduce numerous ways to get stuck. The locking down of places and actions are often a way to avoid puzzles getting to an unsolvable state. Quest items can be lost or destroyed. Doors can be buried under tons of rubble. Important characters can die. Or you could find yourself in a hole with nowhere to go. Handling all this with a traditional <em>hand-written</em> narrative would be too much work. See my article about <a href="https://blog.jonas.liljegren.org/traversal-freedom/">traversal freedom</a> for more about what happens if the player is stuck.</p><p>Some games use procedural generation in order to populate a world with objects. Most open worlds use those algorithms during the development of the world, so they don&#x2019;t have to hand-place each tree and blade of grass. With a set random seed, the world will look the same for every player, and that also allows the game to be fine-tuned with hand-crafted details that overrides the procedural parts.</p><p>For a <em>Systemic story</em> game, that can adopt the story based on player choice, the actual locations can be kept undetermined until the player actually gets knowledge about it. The simulation that updates the world will only simulate the parts that the player has in memory, gradually phasing out the details as the possibility-space grows. This will allow the virtual game-master to relocate story elements based on which clues the player decides to follow.</p><h3 id="story">Story</h3><p>The <strong>Agency</strong> to affect significant and lasting change in the world and shape your future. That doesn&#x2019;t mean that you will automatically succeed in anything you do. The world will remember the things you have done and <strong>react</strong> accordingly.</p><p>A good story usually has an arc with a promise in the beginning that gets fulfilled in the end, with emotional depth, a cohesive theme and much more. As part of the story and character development, there usually needs to be a low point that finally forces the protagonist to give up one of their prevailing faulty assumptions about life. The events in most great story games are carefully crafted to serve the theme and arc for the future resolution. They would lose their impact if the player avoided the misfortune that the story needed.</p><p>Story-based games usually set up limitations in order to keep the story on track. This is usually done by restricting where the player can traverse, what things the player can interact with, available dialogue options, or with scripted events or cutscenes. No matter what you do, your character will get themself into trouble. Great care is put into the framing to create <strong>parity</strong> between the player and what the player character must do. Agency is upheld if the game succeeds in making the player want to do the things that progresses the story.</p><p>A game with linear narrative is described as <strong>railroading</strong>. For players there the parity is not upheld, this becomes a problem. More often than not, you will smell the coming ambush and be frustrated that your avatar had no autonomy to prepare and be more careful. Even worse is when the avatar is forced to do things that the player absolutely doesn&apos;t want to do, as in making an NPC upset, saying stupid things, or even killing people when you would rather avoid them or make friends. As a pacifist, this is something that frustrates me in almost every chapter of every action-adventure game.</p><p>One of the most common critiques of games with branching narrative is that choices that felt important did not have the impact they hoped for. Why bother making the choice if it doesn&#x2019;t matter in the end? Most game developers try to make the choices feel impactful, but there is a certain percentage of the players that are left unsatisfied. The limits of branching narrative is that every combination takes additional development resources. Some players see how outside events again and again push them back to the main branch.</p><h2 id="conclusion">Conclusion</h2><p>A lot of people want more freedom in games. A <em>Systemic Story</em> game can avoid many frustrations of hand-written narratives, without sacrificing the character development, emotional depth and dramatic tension of the story. The development will be gradual and take many iterations before they will surpass the fidelity of current AAA story-based games. It will be worth it. <a href="https://blog.jonas.liljegren.org/tag/systemic/">More to come</a>.</p><p>[[ <a href="https://www.gamedev.net/forums/topic/715536-the-promise-of-freedom-in-story-games/?ref=blog.jonas.liljegren.org">https://www.gamedev.net/forums/topic/715536-the-promise-of-freedom-in-story-games/</a> ]]<br>[[ <a href="https://www.reddit.com/r/gamedesign/comments/1ai7vqu/the_promise_of_freedom_in_story_games/?ref=blog.jonas.liljegren.org">https://www.reddit.com/r/gamedesign/comments/1ai7vqu/the_promise_of_freedom_in_story_games/</a> ]]<br>[[<a href="https://www.facebook.com/aigan/posts/10159800732692393">https://www.facebook.com/aigan/posts/10159800732692393</a>]]<br>[[<a href="https://twitter.com/aigan/status/1753765089553904062?ref=blog.jonas.liljegren.org">https://twitter.com/aigan/status/1753765089553904062</a>]]</p>]]></content:encoded></item><item><title><![CDATA[Getting started with web development in 2024]]></title><description><![CDATA[The web has evolved tremendously during the last few years. Searching for help on how to get started, what to use and answers to questions will give you tons of answers that might have been relevant last year, but not today.]]></description><link>https://blog.jonas.liljegren.org/getting-started-with-web-development-in-2024/</link><guid isPermaLink="false">6582862dbd5de594ce13656d</guid><category><![CDATA[code]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Wed, 20 Dec 2023 11:38:37 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2023/12/optimal-hello-v2.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="short-history">Short history</h2>
<img src="https://blog.jonas.liljegren.org/content/images/2023/12/optimal-hello-v2.jpg" alt="Getting started with web development in 2024"><p>1994: <a href="https://winworldpc.com/product/netscape-navigator/0x?ref=blog.jonas.liljegren.org">Netscape Navigator</a> made the web popular.</p>
<p>2004: <a href="https://winworldpc.com/product/internet-explorer/10?ref=blog.jonas.liljegren.org">Internet Explorer</a> by Microsoft destroyed Netscape, dominating with 94% market share.</p>
<p>Then started the browser war, with Firefox, Chrome and Safari. It became a real pain trying to create websites that would look and work as intended in all popular browsers. All the browsers had numerous differences in implementation and bugs. Libraries like jQuery were created for helping building sites that would work on most versions of most browsers. Many features could not be used since they would not work the same on all browsers. New features could not be used since you would still need to support all the older browsers used by people.</p>
<p>All this changed in 2014. HTML5 would revitalize the web after many years of XHTML. <a href="https://en.wikipedia.org/wiki/ECMAScript_version_history?ref=blog.jonas.liljegren.org#5th_Edition_%E2%80%93_ECMAScript_2009">ES5</a> would finally get full support in all the browsers. But more important than this was the introduction of <a href="https://babeljs.io/?ref=blog.jonas.liljegren.org">Babel</a>.</p>
<p><a href="https://nodejs.org/en/about?ref=blog.jonas.liljegren.org">NodeJS</a> is a javascript engine that lets you run programs outside the browser. Babel was one such program that can rewrite other javascript programs so that they can run on older versions of browsers. That would let you write javascript using the latest version ES6, and still having it work on older versions of all the popular browsers. ES6 introduced a lot of new things including class declarations.</p>
<p>The power of Babel allowed for programs to use packages from the NodeJS ecosystem. Babel would transform them for compatibility with the web and tools like <a href="https://webpack.js.org/?ref=blog.jonas.liljegren.org">Webpack</a> would optimize them by minimizing the size and bundle all the files together for faster load times. This led to an explosion in popularity and the rise of <a href="https://react.dev/?ref=blog.jonas.liljegren.org">React</a>.</p>
<h2 id="the-evolution-of-the-web-platform">The evolution of the web platform</h2>
<p>Around the same time in 2014, all the major browsers would start to use automatic updates. Instead of many browsers being 5 or more years old, most users would have the latest browser while using the web. This was the rise of the evergreen browsers, that would eventually shorten the time for new features being available for almost all of the users.</p>
<p>Every year there would be lots of new functionality introduced. The last couple of years would see major improvements every single month. Popular libraries and frameworks would serve as inspiration for new features added to the browser.</p>
<p>This means that popular libraries with much needed features bit by bit would be made obsolete by similar features being built into the language and web api in the browser. Popular frameworks like React, Angular and Vue have evolved but their core architecture is based on the capabilities of the web at the time of their creation. They are still using build tools with transpilation and bundling even though this is no longer necessary and makes the whole framework much more complicated than it has to be.</p>
<p>Every added library <a href="https://www.spicyweb.dev/?ref=blog.jonas.liljegren.org">comes with a cost</a>. Updates in one part can force an upgrade of other parts. There may be security vulnerabilities or bugs. Every added interdependent component makes it harder to replace or fix functions that don&apos;t do what you want. The framework will <a href="https://surma.dev/things/cost-of-convenience/?ref=blog.jonas.liljegren.org">limit what you can do</a>, making many custom solutions complicated and suboptimal. More time will go to adapting what you want to do to the capabilities and architecture of the chosen framework. Every library and every part of the toolchain and build process is another potential point of failure. Installing the example project with create-react-app will download 1500 package dependencies totaling over 2 million lines of javascript code. At the time of writing, they include 6 high level vulnerabilities. How long will it take you to understand what&apos;s happening across all those lines of code?</p>
<p>Since frameworks like React and Angular have cemented its position as a de facto webstandard, there is a huge ecosystem of existing sites, apps, libraries and people. Mastery in these prevailing toolchains are required by more than 95% of existing jobs. But this article is not about culture or popularity. It&#x2019;s about how to do better. And regardless of what framework you end up using, you should still learn the foundation and capabilities of the modern web. And be prepared to re-learn every year.</p>
<h2 id="the-modern-web">The modern web</h2>
<p>There are three main browser engines today. These are the ones used by <a href="https://www.chromium.org/Home/?ref=blog.jonas.liljegren.org">Chrome</a>, <a href="https://webkit.org/?ref=blog.jonas.liljegren.org">Safari</a> and <a href="https://www.mozilla.org/?ref=blog.jonas.liljegren.org">Firefox</a>. Most other browsers are using Chromium, which is the engine known for Chrome. About 95% of all users have a browser version that is less than two months old.</p>
<p>The core features of the modern web includes <a href="https://en.wikipedia.org/wiki/ECMAScript_version_history?ref=blog.jonas.liljegren.org#6th_Edition_%E2%80%93_ECMAScript_2015">ES6</a> (2017), <a href="https://en.wikipedia.org/wiki/HTTP/2?ref=blog.jonas.liljegren.org">HTTP/2</a> (2017), <a href="https://css-tricks.com/snippets/css/complete-guide-grid/?ref=blog.jonas.liljegren.org">CSS Grid</a> (2017), <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM?ref=blog.jonas.liljegren.org">Shadow DOM</a> (2018), <a href="https://web.dev/blog/cq-stable?ref=blog.jonas.liljegren.org">CSS Container Query</a> (2023), <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap?ref=blog.jonas.liljegren.org">importmap</a> (2023), <a href="https://developer.chrome.com/docs/css-ui/declarative-shadow-dom?ref=blog.jonas.liljegren.org">Declarative Shadow DOM</a> (2024) among many other Web APIs, javascript features and CSS modules. Many of these features have conditional polyfills that is javascript code that will make the feature work even in older browsers. The years given is the time it was supported in all three engines.</p>
<p>This article will start from the beginning for how to develop web applications that use <a href="https://www.npmjs.com/?ref=blog.jonas.liljegren.org">npm packages</a>. I may continue in later articles with more considerations often covered by popular frameworks, like routing, user sessions, database access, state management with reactivity, Server Side rendering, testing, documentation and deployment.</p>
<h2 id="vs-code">VS Code</h2>
<p>I started out with <a href="https://www.gnu.org/software/emacs/?ref=blog.jonas.liljegren.org">Emacs</a> and still use it daily. You can use whatever text editor you like. But it should include syntax highlighting, indentation and some sort of integrated documentation like code autocompletion. Microsoft <a href="https://code.visualstudio.com/?ref=blog.jonas.liljegren.org">Visual Studio Code</a> is very popular, especially for web development.</p>
<p>You will need a web server for serving the website. The easiest to start with might be the <a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer&amp;ref=blog.jonas.liljegren.org">ritwickdey.LiveServer</a> extension for VS Code. Open your project folder, create a html file and then <em>Go Live</em> using the button at the bottom right.</p>
<p>I hate all distracting elements including all the helpful popups that VS Code throws at you. The editor has thousands of things to configure to your liking. I disabled most things related to quickSuggestions, suggestOnTriggerCharacters, cursorBlinking, inlineSuggest, parameterHints, suggest, snippetSuggestions, closeEmptyGroups, autoClosingQuotes, autoClosingBrackets, autoClosingTags and lightbulb. I also removed some of the columns in the editor like minimap, glyphMargin and showFoldingControls. I&#x2019;m also using the extension garaemon.vscode-emacs-tab and bound it to shift enter for indenting the current line.<br>
I also have <a href="https://blog.jonas.liljegren.org/vs-code-keyboard-shortcuts/">a personal &#x201C;Cheat sheet&#x201D; for VS Code</a>.</p>
<h2 id="es-modules">ES modules</h2>
<p>NodeJS introduced <a href="https://nodejs.org/api/modules.html?ref=blog.jonas.liljegren.org">CommonJS modules</a> (cjs), but those only work on the server. You will recognize them by their use of <code>require</code> for importing libraries. ES6 introduced platform support for <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules?ref=blog.jonas.liljegren.org">modules</a> (mjs) using <code>import</code> and <code>export</code> syntax, which will also work in the browser.</p>
<p>Most examples of importing libraries are using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules?ref=blog.jonas.liljegren.org">bare module specifiers</a>. Those assume you are using nodeJS or that you are transpiling the code before running them on the browser. You don&#x2019;t need a compilation step. Just provide the actual path to the module you want to require, using a relative or absolute path. The mjs file extension may not be associated with the mime type text/javascript in older web servers. You could use js instead, but I prefer mjs since that is suggested by NodeJS and I use it as a way to declare them as real modules and not something that has to be transpiled. You can add the mime type to the web server if needed.</p>
<p>Here is a complete example of module use for remembering form input, in case the user accidentally closes the page before submitting.</p>
<p><code>index.html</code></p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;
&lt;style&gt;
	textarea { width: 100%; min-height: 10rem; box-sizing: border-box; }
&lt;/style&gt;
&lt;body&gt;
    &lt;textarea disabled id=&quot;notes&quot;&gt;&lt;/textarea&gt;
&lt;/body&gt;
&lt;script type=&quot;module&quot;&gt;
	import {persist_input} from &quot;/utils.mjs&quot;;
	persist_input( document.getElementById(&apos;notes&apos;) );
&lt;/script&gt;
</code></pre>
<p><code>utils.mjs</code></p>
<pre><code class="language-js">export function persist_input($el){
  $el.value = localStorage.getItem( $el.id );
  $el.disabled = false;
  $el.addEventListener(&apos;input&apos;, on_input);
  function on_input() {
    localStorage.setItem($el.id, $el.value);
  }
}
</code></pre>
<p>A larger project will usually use several layers of nested folders. For those projects, it&#x2019;s usually easier to use absolute paths. But while using absolute paths, you must keep track of what folder to use as the web root. It&#x2019;s usually named <code>public</code>. You can tell the Live Server extension to use that folder by creating a file <code>.vscode/settings.json</code> with the content</p>
<pre><code class="language-json">{
  &quot;liveServer.settings.root&quot;: &quot;/public&quot;
}
</code></pre>
<h2 id="web-components">Web components</h2>
<p>Web components are the standard for reusable encapsulated components. Not to be confused with the non-standard framework-specific component systems such as react components and the like. Components lets you create your own html tags with any functionality you like. Here we encapsulate the persist_input function as a component:</p>
<p><code>persist-input.mjs</code></p>
<pre><code class="language-js">import {persist_input} from &quot;/utils.mjs&quot;;
class El extends HTMLElement {
  connectedCallback(){
    const $inputs = this.querySelectorAll(&quot;input,textarea&quot;);
    for( const $inp of $inputs ) persist_input( $inp );
  }
}
customElements.define(&quot;persist-input&quot;, El);
</code></pre>
<p>And now we can use it for persisting all input elements inside the tag:</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;
&lt;style&gt;
	textarea { width: 100%; min-height: 10rem; box-sizing: border-box; }
&lt;/style&gt;
&lt;body&gt;
  &lt;persist-input&gt;
    &lt;textarea disabled id=&quot;notes&quot;&gt;&lt;/textarea&gt;
  &lt;/persist-input&gt;
&lt;/body&gt;
&lt;script type=&quot;module&quot;&gt;
  import &quot;/persist-input.mjs&quot;;
&lt;/script&gt;
</code></pre>
<h2 id="nodejs">NodeJS</h2>
<p>NodeJS is the server side javascript engine used by most frontend frameworks. It can run under Windows, but will work better on a unix-like system like MacOS or Linux or the <a href="https://learn.microsoft.com/en-us/windows/wsl/tutorials/wsl-vscode?ref=blog.jonas.liljegren.org">Windows Subsystem for Linux</a> (WSL). You will be using a terminal with the <a href="https://www.gnu.org/software/bash/?ref=blog.jonas.liljegren.org">Bash</a> shell for command line interface (CLI) tools. Start by installing the <a href="https://github.com/nvm-sh/nvm?tab=readme-ov-file&amp;ref=blog.jonas.liljegren.org#table-of-contents">Node Version Manager</a> (nvm). With that, you can install the latest stable version of node.</p>
<p>Each project can have its own installed CLI tools, located in <code>./node_modules/bin</code>. Those can be run by using <a href="https://docs.npmjs.com/cli/v10/commands/npx?ref=blog.jonas.liljegren.org">npx</a>, the relative path, or with a tool that checks the project bin dir using bash <a href="https://www.linuxjournal.com/content/bash-command-not-found?ref=blog.jonas.liljegren.org">command_not_found_handle()</a>. Keeping the tools with the project makes it easier to share the code and make sure that the project works with the version of the tool installed.</p>
<p>The modules we created don&apos;t need to be compiled. But many modules from <a href="https://www.npmjs.com/?ref=blog.jonas.liljegren.org">npm</a> do need a compilation step. We often need to change the module paths used inside the imported modules so that they can work in the browser. We can use <a href="https://rollupjs.org/?ref=blog.jonas.liljegren.org">rollup</a> for repairing the paths in the module. We will have to tell rollup to not bundle or mangle the files. We only need <a href="https://www.npmjs.com/package/@rollup/plugin-node-resolve?ref=blog.jonas.liljegren.org">the path translation</a>.</p>
<p>An alternative to repairing the import paths is to use the <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap?ref=blog.jonas.liljegren.org"><code>&lt;script type=&quot;importmap&quot;&gt;</code></a> feature for mapping directories or bare module specifiers to their actual location. For this, you can use a tool that finds all the module paths and places them in an importmap.</p>
<p><a href="https://lit.dev/?ref=blog.jonas.liljegren.org">Lit</a> is a library that can simplify writing web components. During rollup, we can tell it to use the uncompressed <em>development</em> version of the files. In most cases, there is no need to use minified files. I believe in giving every user the freedom of seeing what&apos;s happening in the pages they visit. We can always optimize later if it&apos;s truly needed.</p>
<p>Standing in your project directory, install lit and rollup with <code>npm i -D lit rollup @rollup/plugin-node-resolve</code>. This will create a manifest in <code>package.json</code> and install the modules in node_modules.</p>
<p>Here is the rollup.config.mjs I use for repairing the files. Use the config by running <code>npx rollup -c</code>.</p>
<pre><code class="language-js">import resolve from &quot;@rollup/plugin-node-resolve&quot;;
export default {
 input: [
   &quot;lit&quot;,
   &quot;lit/decorators.js&quot;,
 ],
 output: {
   dir: &quot;public/x&quot;,
   format: &quot;es&quot;,
   preserveModules: true,
   minifyInternalExports: false,
   entryFileNames: (chunkInfo) =&gt; {
     return (
       chunkInfo.name
         .replace(&quot;node_modules&quot;, &quot;&quot;)
         .replace(&quot;/index&quot;, &quot;&quot;) +
       &quot;.mjs&quot;
     )
   },
 },
 plugins: [
   resolve({ exportConditions: [&quot;development&quot;] }),
 ],
}
</code></pre>
<p>The result is put in the folder <code>x</code>. I like short names, but you may want to call it <code>external</code> or <code>vendor</code> to show that it is an external dependency.</p>
<p>Now we can use the library for creating components, like this minimal</p>
<p><code>say-hello.mjs</code></p>
<pre><code class="language-js">import {html, LitElement} from &apos;/x/lit.mjs&apos;;
class El extends LitElement {
 render() { return html`&lt;p&gt;Hello&lt;/p&gt;` }
}
customElements.define(&apos;say-hello&apos;, El);
</code></pre>
<p>And now it can be used as a component with</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;body&gt;
 &lt;say-hello&gt;&lt;/say-hello&gt;
&lt;/body&gt;
&lt;script type=&quot;module&quot;&gt;
 import &quot;/say-hello.mjs&quot;;
&lt;/script&gt;
</code></pre>
<p>npmjs.com has millions of packages. And this is how you can use them for building web applications.</p>
<h2 id="optimized-delivery">Optimized delivery</h2>
<p>Once upon a time we used HTTP/1 for delivering files. That protocol had an overhead for each file, so we used bundlers to minimize the number of files the browser needed to fetch. This is no longer the case with HTTP/2 and HTTP/3. It doesn&#x2019;t make a difference if the content resides in one large file or 1000 small ones. In fact, it&#x2019;s much better to keep them as many small files, since the browser will only fetch the files that are needed for the current page, and only if the files have updated since the last fetch.</p>
<p>For a tree of dependencies where module 1 imports module 2 that imports module 3, the browser will only start to download the dependent modules after the previous ones have been loaded and parsed. This is called the network waterfall. For optimizing the load, you can just declare what modules to load directly from the html page. One way to do that is to use <code>&lt;link rel=&quot;modulepreload&quot; href=&quot;/my-module.mjs&quot;&gt;</code> tags at the beginning of the page. You can use the <a href="https://www.npmjs.com/package/modulepreload?ref=blog.jonas.liljegren.org">modulepreload</a> tool from npmjs to automatically look up all nested dependencies of the page and inject the modulepreload tags that will eliminate the network waterfall. In our example, this will add</p>
<pre><code class="language-html">&lt;link rel=&quot;modulepreload&quot; href=&quot;/x/lit.mjs&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/x/@lit/reactive-element/development/reactive-element.mjs&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/x/@lit/reactive-element/development/css-tag.mjs&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/x/lit-html/development/lit-html.mjs&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/x/lit-element/development/lit-element.mjs&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/x/lit-html/development/is-server.mjs&quot;&gt;
</code></pre>
<p>I did my own tool for generating preloads before found this newly published tool.</p>
<!--kg-card-end: markdown--><p>[[<a href="https://dev.to/aigan/getting-started-with-web-development-in-2024-2b9n?ref=blog.jonas.liljegren.org">https://dev.to/aigan/getting-started-with-web-development-in-2024-2b9n</a>]]<br>[[<a href="https://www.facebook.com/aigan/posts/10159741717467393">https://www.facebook.com/aigan/posts/10159741717467393</a>]]<br>[[<a href="https://twitter.com/aigan/status/1737440066161516812?ref=blog.jonas.liljegren.org">https://twitter.com/aigan/status/1737440066161516812</a>]]</p>]]></content:encoded></item><item><title><![CDATA[Semantic databases]]></title><description><![CDATA[<p>Traditional relational databases have well understood properties for performance and locking with indexes and works well for well-defined homogenous data where you usually search for selections from one specific table.</p><p>I <a href="https://blog.jonas.liljegren.org/30-years-in-the-web/">have always</a> been drawn to more flexible data structures. A simple address book would have a name, email, phone</p>]]></description><link>https://blog.jonas.liljegren.org/semantic-databases/</link><guid isPermaLink="false">655d7c1d5ecb32075cff9635</guid><category><![CDATA[code]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Wed, 22 Nov 2023 04:02:35 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2023/11/abstract-erd-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.jonas.liljegren.org/content/images/2023/11/abstract-erd-1.png" alt="Semantic databases"><p>Traditional relational databases have well understood properties for performance and locking with indexes and works well for well-defined homogenous data where you usually search for selections from one specific table.</p><p>I <a href="https://blog.jonas.liljegren.org/30-years-in-the-web/">have always</a> been drawn to more flexible data structures. A simple address book would have a name, email, phone and address. But some people have several names or types of names. Several emails. Several phone numbers. And so on. Some of it is temporal. Some of it is domain segmentation, like work/home. With a relational database schema, you would convert the single table to a main person table with relations to one table for phone, one for email and so on. But then you come to all the extra things you would like to know about those connected information. When was the email address last updated, is it connected to a specific job, what is the status of the email account, regarding email bounces, what is the canonical form and the formatted form (that could include the full name and sometimes title).</p><p>Now consider the similarity between people, departments, offices and businesses. They may all have emails, phone numbers, visiting addresses and names. The name may be different depending on context or language. There are also a lot of metadata that should be connected to each individual data, like the source of the data, information of when it was updated or confirmed to be still valid, who is allowed to see it and in what contexts its intended to be the preferred value among its alternatives. You may also want to keep track of the reliability, quality and precision of each value. A normal datetime field may have a value stored in millisecond precision, but may have been entered with the precision as minute, day or even just the year. You may want to store more information of how it was imported as to consider the type of dirt it has.</p><p>On top of that, you have the <strong>tri-temporal</strong> data that should be accessible by all parts of the frontend and backend, including considerations in changes of data structure, application logic and changes in what agents have authorization to reach or write. The tri-temporal data consists of a traditional change-log along with changes over time in the modeled domain, as in a person changing name, phone number, email or living address. An updated value may be a correction of a wrongful input, or reflect that the previous value was correct until recently. You also want a third dimension of decision time, for changes that can go through the stages of draft, proposed and accepted.</p><p>SQL was not made for data structures that conditionally can spread out forever. You don&apos;t want to make the schema more complicated or detailed than needed for the application. All the facets will have a cost in speed, storage requirement and complexity. But expanding the schema will require an abstraction layer. You wouldn&apos;t want to refactor old SQL statements for every addition. Tho, I don&#x2019;t think there is any existing abstraction library that will handle all the things I mentioned here, in addition to the deep reactive propagation through layers of composition I will cover in another article.</p><h2 id="nosql">noSQL</h2><p>Going back to basics, you can define lookup tables with offsets or pointers for stored binary data, defining your own data types. It can be strings of text holding things like JSON, or other types of objects. It&apos;s similar to a directory of files, with indexes using hashes or binary trees.</p><p>Types or features of databases include <strong>key-value</strong> stores, hierarchical data and <strong>document</strong> stores. Some databases have added features for handling and searching XML, JSON, <strong>geospatial</strong> or ML vector data.</p><p>The next level is the <strong>Entity&#x2013;attribute&#x2013;value</strong> (EAV) data model. It&#x2019;s the easiest way to support ad-hoc data. <strong>Wordpress</strong> uses it in a mysql table with columns for entity_id, key and value, for users, posts and comments.</p><p>Add support for the values being pointers to other entities, and you end up with a <strong>graph database</strong>.</p><p><strong>Triplestores</strong> are a specific type of graph database, built for <strong>Resource Description Framework</strong> (RDF) data. RDF defines the triple as Subject&#x2013;Predicate&#x2013;Object, where the object can be another subject or a Literal. Subjects and Predicates should have a globally unique URI.</p><p>There is no dominant standard similar to SQL for how to search data in graph databases. <strong>SPARQL</strong> was created for RDF databases. There has been a process for creating a standard for a Graph Query Language (GQL) based on Cypher that is used with <strong>Neo4J</strong>. Meanwhile, the completely unrelated (FB) GraphQL has become very popular.</p><p><strong>Gremlin</strong> Query Language has some support among graph databases. It&apos;s a form of graph traversal that treats each node as its own object. The selections and groupings are done as method calls rather than plain text strings sent to a server as in SQL. This is the type of API that will work best with the type of <strong>multi-granular</strong> or flexible complexity I described here.</p><h2 id="ml-vector-databases">ML Vector databases</h2><p>Any database application will have some sort of search functionality. A <strong>full-text</strong> search index is expected. But you should also handle alternative spellings and typos. Results should be prioritized and grouped based on what would be most useful in the specific context. Text data can be indexed using phonemes or tokens allowing for the related spellings.</p><p>There are a lot of full-text extensions to existing databases. But the recent improvements in Machine Learning (ML) <strong>Large Language Models</strong> (LLM) will allow for more flexible search capabilities, using vector databases. Each document or record will be converted to <strong>embeddings</strong> and stored in the vector database. This DB can then be used for finding the most relevant documents for any free-form text search.</p><p>An LLM can also be used in search even without a custom vector database. You can simply ask it to translate the free-form query into one or more formal search queries, get the result from those queries, and then ask the LLM to sort and return the most relevant results.</p><p>A vector database can also be used for clustering. Grouping similar data together, making it easier to navigate. Also for classifying data, such as automated tagging.</p><p>Artificial Intelligence (AI), Generative pre-trained transformers (GPT) and LLM is not an alternative to structured data. But it will make it easier to search and parse all available data.</p><h2 id="symbolic-ai-vs-machine-learning">Symbolic AI vs Machine Learning</h2><p>AI has traditionally been synonymous with what now falls under Symbolic AI. Symbolic AI is using <strong>Knowledge Representation</strong> (KR) with <strong>Ontologies</strong> and the rules of <strong>logic</strong> for step by step <strong>reasoning</strong>. This has been the image of AI in science fiction for a long time, depicting it as emotionless rigid mathematical thinking.</p><p>On the other hand we have the Machine Learning, Deep Learning, <strong>Generative pre-trained transformers</strong> (GPT) and LLMs, that uses fuzzy pattern-matching statistics in a way that is closer to creativity and feeling. Tho, there have been amazing improvements to reliability for many tasks.</p><p>There has been a lot of work in the symbolic AI field trying to build up a knowledge base that would have the ability to reason across all domains. All those models have failed to handle the fuzziness in human language, thinking and the complexities of the real world. Trying to handle all the edge cases can make the logic complex and hard to understand. The resulting reasoning will be rather far removed from how people think in the corresponding situation, and will still fail in many simple scenarios.</p><p>All computer programs work by algorithmic processing of structured data. KR is used together with ML, regardless of the use of symbolic AI. One of the most popular uses for LLM is to search databases, parse text and output JSON. KR in and KR out. Humans use tools and logic in addition to neural network associations.</p><p>There needs to be a symbiosis between feeling and thinking. <strong>Neuro-symbolic</strong> AI. This is happening in many ways now in how LLMs can use APIs for looking up or validating information, such as code syntax, or integrations like <strong>Wolfram Alpha</strong>.</p><h2 id="semantic-databases">Semantic databases</h2><p>Most traditional databases restrict the encoding of real-world information in a way that often loses important information. People will often knowingly input wrong information since that is the only thing the application accepts. That is one of many ways that introduces &#x201C;dirt&#x201D; in the data.</p><p>A semantic database refers to the storage and DB functions for using semantic data. The point of semantic data is to have enough information to know how to use the data in all places where it could be relevant. Only having a table definition with data types and some constraints is not enough. The promise is of being able to generalize functionality in a way that you don&apos;t have to hand-code special cases for how the data is used in each new system. It will make <strong>integrations</strong> and expanded functionality easier. For example, consider what a calendar program would need to know to actually help you with when you are busy and when it&#x2019;s time to prepare for the next part of your day. And consider how much of this it could deduce from available information such as not to force you to provide the information again.</p><p>There are many ways to build a semantic database. This is how I would do it. RDF was constructed to be the simplest way to represent semantic data. A single table of statements with id and the triple subject&#x2013;predicate&#x2013;object is enough since metadata can be added by letting the subject refer to another statement. But there is some <strong>metadata</strong> important enough to be added directly to each statement, like the origin, agent, transaction id, the tri-temporal transaction time, activation time and valid time, object type, sorting weight and low-level metadata for authorization and inference.</p><p>Each part of data in RDF is called a resource. All resources can have properties by using the resource as a subject in a statement. Statements are also resources. With my extended metadata, the origin and agent are also resources. Resources can also be literals. A literal is a value with a data type such as a text or number. The object type metadata is used to refer to where and how the literal is stored in the database.</p><p>Predicates may have an inferred type for its object. Subjects can have one or more type statements, referring to the class that defines the resource. Each class can have a schema defining its relationship to other resources. For example; names, phone numbers and email addresses may all be stored as text strings. The type can be implicit from its predicate or explicit from another type-statement. If there is a label for the phone number, it can be given in an additional statement with the literal as the subject.</p><p>The power of the semantic database comes from when the type is augmented with programming code used to compose the properties of the resource. This gives a uniform and flexible interface, regardless of how the data is stored in the database. This allows for <strong>multi-granular</strong> or flexible specificity of the data. You don&#x2019;t have to consider if the address is stored as a single text block or divided into several fields. Just use the <strong>dynamic properties</strong> of the address resource.</p><h2 id="data-integrity-and-consistency">Data Integrity and Consistency</h2><p>Graph databases have the flexibility of adding data and relations with no constraints. This will also make it easier to create and evolve the model. Constraints can be introduced gradually, with optional and required properties, relationship <strong>cardinality</strong> and the expected data type.</p><p>I prefer to define the actual schema with the class rather than with the rest of the data, in order to keep the schema in sync with all the code for dynamic properties, methods and validations. The class can list mixins and inheritance. Properties will be declared with min and max cardinality for the domain and range. A property can be defined to point to a literal type that may be a subclass of another literal, compatible and mapped to XML datatypes and the primitive types stored in the DB.</p><p>The system should handle <strong>state transitions</strong> with transactions. Traditional RDB transactions will usually not allow multi-stage updates spanning client-server. The temporal data structure allows you to set up a future transaction that will exist alongside the active version, but only used within that agent&apos;s transaction context.</p><p>Each class will have <strong>authorization</strong> checks for reading or writing. There will also be hooks for creating, updating and deleting data. They will validate the change, notify dependent data, do the change, validate the resulting state, and then commit or throw an exception based on the result. A commit will return a list of all resources updated.</p><h2 id="performance-and-scalability">Performance and Scalability</h2><p>A semantic database is inherently slower than a traditional DB. But you will still have the usual ways to optimize the performance. Inferred and composed data can be indexed and stored for quick lookup. Those lookup tables may be created dynamically or set up by hand as part of optimization work for the application that needs it.</p><p>Searches in the DB should go through the process of planning the query based on available indexes and the amount of resources returned by each constraint. Start with the lookup returning the least amount of resources before going through and filtering out all the results not having the rest of the constraints.</p><p>Data can be replicated to several servers for read transactions. Write transactions can be put in an event log that will be used (by <a href="https://github.com/aigan/tail-file?ref=blog.jonas.liljegren.org">tail-file</a>) to update the other servers. The application needs to handle updates in a way where expected changes may be denied or may take a while to commit. The data versioning with transaction id and time plays a part in this.</p><p>I have been using syllogism rules for inferring statements such as types through subClassOf, memberships, locations and the like. Instead of searching for resources having a specific inferred property, they can be stored directly on creation, among other dynamic properties. Just mark the origin as an inferred statement. This will make lookups much faster.</p><p>The parts of the database that are more uniform can be stored in a more traditional way. With the API being the same and the dynamic properties handled by the class, it doesn&apos;t matter how the data is stored. It can be a local cache, a remote database or anything else. Just map the resources and let the origin state the source of the data.</p><h2 id="data-manipulation">Data Manipulation</h2><p>Everything here is stuff I have worked with for the last 25 years of semantic database development. Everything except the &#x201C;valid time&#x201D; for the temporal data, modeling slowly changing dimensions. The query language used is similar to Gremlin, where you search, traverse, collate and modify data through property and method calls on objects.</p><p>I have created 5 different semantic databases. See my article <a href="https://blog.jonas.liljegren.org/30-years-in-the-web/">30 years in the Web</a>, for more details. I would like to publish more from the latest cutting edge semantic database named <strong>Gad</strong>, written in <strong>isometric javascript</strong>. That system was set up to overcome many of the problems from the older <a href="https://blog.jonas.liljegren.org/rdf-base/">RDF::Base</a>.</p><p>[[<a href="https://www.facebook.com/aigan/posts/10159702481267393">https://www.facebook.com/aigan/posts/10159702481267393</a>]]<br>[[<a href="https://twitter.com/aigan/status/1727295041893450098?ref=blog.jonas.liljegren.org">https://twitter.com/aigan/status/1727295041893450098</a>]]<br></p>]]></content:encoded></item><item><title><![CDATA[mv-sorter]]></title><description><![CDATA[<MV-SORTER> is a custom element for making content sortable and movable. No dependencies. No buildstep.]]></description><link>https://blog.jonas.liljegren.org/mv-sorter/</link><guid isPermaLink="false">654ab84b5ecb32075cff9473</guid><category><![CDATA[code]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Fri, 10 Nov 2023 01:23:26 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2023/11/mv-sorter-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://blog.jonas.liljegren.org/content/images/2023/11/mv-sorter-1.png" alt="mv-sorter"><p>Try it out here:</p>
<script type="module">
    import "https://jonas.liljegren.org/2023/components/jl/code/code.mjs";
    import "https://jonas.liljegren.org/2023/components/jl/embed.mjs";
    import "https://para.se/proj/mv-sorter/mv-sorter.js";
</script>
<link rel="stylesheet" href="https://para.se/proj/mv-sorter/mv-sorter.css">
<style>
mv-sorter {
	--gap: .3rem;
	margin: 1rem 0;
}
mv-sorter > div {
	padding: .2rem 1rem;
	background: lightblue;
	border: .2rem solid grey;
}
</style>
<section>
	<mv-sorter group="1">
		<div>A</div>
		<div>BBB</div>
		<div>CCCCCCCCC</div>
	</mv-sorter>
	<mv-sorter group="1">
		<div>D</div>
	</mv-sorter>
</section>
<p><jl-code src="https://para.se/proj/mv-sorter/demo/example-1.html"></jl-code></p>
<!--kg-card-end: markdown--><p>In 2019, I worked with converting a jquery application to web components. Specifically replacing Sortable with something that would work well with Polymer. This was also before the browser DragEvent API got adopted by Safari. Most libraries used compromises that made them less usable. Some libraries would lose hold of the dragged item if it was dragged outside the specified region of the page, or would freeze. I didn&#x2019;t find any library usable with Polymer and Shadow Dom that also made it easy to just drag and drop, with mouse or touchscreen, with a feature set similar to jQuery Sortable. So I made my own.</p><p>Liking the physicality of swiping on touchscreen, I decided to do the sorting with physicalized animations, letting you throw items, and animating them falling into place. Even though those animations are not necessary for usability, I needed the custom implementation in order to work around all the then existing limitations for achieving a good user experience. All the layered animations were just me taking the opportunity to make it more fun. It was never fully polished since I couldn&#x2019;t rationalize giving this task too much time in the project.</p><p>In preparation for this article, I completely removed the dependency on Polymer, and also added support for grid and flexbox. There was the beginnings of support for drag and drop between nested containers, as you would do in a file browser. That part is not working with multiple moving containers that are also dynamically resizing to fit its content. But sorting columns of sortable items would work fine.</p><p>So this is &lt;MV-SORTER&gt; with visualized dropzones, customizable presentation and physicalized animations.</p><hr><!--kg-card-begin: markdown--><p>The default style sits in a separate <code>mv-sorter.css</code> file so that it can be completely replaced. The default content adds shadows and highlights:</p>
<p><jl-code src="https://para.se/proj/mv-sorter/mv-sorter.css"></jl-code></p>
<p>In addition, the example here used the additional style for the sortable items:</p>
<p><jl-code src="https://para.se/proj/mv-sorter/demo/example-1.css"></jl-code></p>
<p>Supported attributes are:</p>
<ul>
<li>row: elements are displayes horizontal (default)</li>
<li>column: elements are displayed vertical</li>
<li>lock: Only move in selected axis</li>
<li>group: Allow movement to other containers in the same group</li>
<li>autosave: move element in DOM after drop</li>
<li>disabled: make container inactive</li>
</ul>
<p>Events you can listen to on the <code>mv-sorter</code> container:</p>
<ul>
<li>drop: details <code>{element, item}</code></li>
<li>dropoutside: details <code>{element, item}</code></li>
</ul>
<p>Methods availible on the <code>mv-sorter</code> container:</p>
<ul>
<li>reset(): move all items back to their original DOM positions</li>
<li>commit(): update DOM placing items in their new place</li>
<li>elements(): lists elements in the container, similar to what you would get from the DOM after a commit()</li>
<li>elements_removed(): list elements moved to another contianer</li>
<li>elements_added(): lists elements moved here from another container</li>
</ul>
<p>The property <code>is_altered</code> tells you if anything has changed, like sort order or anything added or removed.</p>
<p>You can also add a <code>mv-draghandle</code> in an element for using that for dragging, instead of the whole element.</p>
<p><jl-embed src="https://para.se/proj/mv-sorter/demo/handle.html"></jl-embed><br>
<jl-code src="https://para.se/proj/mv-sorter/demo/handle.html"></jl-code></p>
<p>Combining all this for a simple scrum-like board with sortable columns and items:<br>
<jl-embed src="https://para.se/proj/mv-sorter/demo/nested.html"></jl-embed><br>
<jl-code src="https://para.se/proj/mv-sorter/demo/nested.html"></jl-code></p>
<p>Availible from <a href="https://www.npmjs.com/package/mv-sorter?ref=blog.jonas.liljegren.org">https://www.npmjs.com/package/mv-sorter</a> or <a href="https://github.com/aigan/mv-sorter?ref=blog.jonas.liljegren.org">https://github.com/aigan/mv-sorter</a></p>
<p>There are lots of things to improve. Using the new top-layer stacking context, and doing all animations relative page rather than as offset of original position would make things a lot cleaner.</p>
<!--kg-card-end: markdown--><p>[[<a href="https://www.facebook.com/aigan/posts/10159685446812393">https://www.facebook.com/aigan/posts/10159685446812393</a>]]</p>]]></content:encoded></item><item><title><![CDATA[Adapting a Ghost Theme]]></title><description><![CDATA[Even a professional web developer can use some help to get things done. Having my hands full with work deadlines and other personal projects, I looked for something I could start using with minimal effort.]]></description><link>https://blog.jonas.liljegren.org/ghost-theme-simply/</link><guid isPermaLink="false">64b668ee392852490f117895</guid><category><![CDATA[meta]]></category><category><![CDATA[code]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Wed, 19 Jul 2023 11:05:29 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2023/07/simply-wide.webp" medium="image"/><content:encoded><![CDATA[<img src="https://blog.jonas.liljegren.org/content/images/2023/07/simply-wide.webp" alt="Adapting a Ghost Theme"><p>In 2020 I <a href="https://blog.jonas.liljegren.org/first-post/">decided to finally create</a> my own personal blog. Until then, I preferred to write about things in a timeless manner. A blog is by definition about points in time rather than timeless entities in a topic-space. I had also written about things on Facebook I wanted to make visible and keep for the future. My <a href="https://jonas.liljegren.org/myself/?ref=blog.jonas.liljegren.org">1999 homepage</a> had the articles grouped by category with minimal site navigation chrome. I think I used <strong>SSI</strong> (NCSA server-side includes) at one point, but that is something that makes it harder to move the homepage to new servers.</p><p>The default option would have been to start up yet another <strong>Wordpress</strong> site. I have created lots of those, using web servers under my own control, with my own mysql servers, along with lots of custom created themes in PHP along with custom and modified plugins. But since I&#x2019;m now deeply immersed in the bleeding edge of javascript and web technology with <strong>NodeJS</strong> in the back and <strong>Custom Elements</strong> in the front, I wanted something I could later modify and customize. Thus, I was looking for the first best JS-based blog and CMS that would be easy to use. Checked out <a href="https://ghost.org/?ref=blog.jonas.liljegren.org">Ghost CMS</a> and it looked good enough. The default was good enough. Just had to select the <a href="https://godofredo.ninja/ghost-theme/simply/?ref=blog.jonas.liljegren.org">theme I liked</a> and install it through the Ghost admin web frontend.</p><h3 id="upgrading-ghost">Upgrading Ghost</h3><p>Three years later, I decided to update more of <a href="https://jonas.liljegren.org/myself/?ref=blog.jonas.liljegren.org">my 1999 website</a> with updated contact information, CV and more. The Ghost CMS had gone from version 3 to version 5 with incompatible changes. The new version of <a href="https://godofredo.ninja/ghost-theme/simply/?ref=blog.jonas.liljegren.org">Simply</a> had changed<a href="https://github.com/godofredoninja/simply/compare/0.2.8...0.4.0?ref=blog.jonas.liljegren.org"> a lot of stuff</a> that I liked in the original, and other stuff was simply broken. That is the cost that usually comes with spending a lot of time perfecting a site, just to have it break after an upgrade. As a result, the current Simply theme is not as clean as the original version. On top of that, there were things I wanted that weren&apos;t included in the theme, leading me to fork the theme so that I could adapt it to my own needs. In the process I had to learn more about the <a href="https://ghost.org/docs/themes/?ref=blog.jonas.liljegren.org">ghost backend</a>, the <a href="https://handlebarsjs.com/guide/expressions.html?ref=blog.jonas.liljegren.org">basics of handlebars</a> and <a href="https://tailwindcss.com/docs/responsive-design?ref=blog.jonas.liljegren.org">tailwind css</a>.</p><h3 id="tailwind">Tailwind</h3><p>Tailwind has become very popular since its creation in 2017. I don&#x2019;t like all the repeated classes all over the HTML. It breaks the separation between information and presentation. I&apos;d much prefer <strong>Bootstrap</strong> that also has the utility classes, but those are more often only used in special cases where it&apos;s the only thing having that specific style rule. That makes Bootstrap the semantic alternative to Tailwind.</p><p>CSS has seen a ton of improvements during recent years. For new projects, I would probably opt to choose something more similar to <a href="https://open-props.style/?ref=blog.jonas.liljegren.org">Open Props</a> that uses css variables and color calculations without a need for pre-processing.</p><h3 id="tags-cloud-menu">Tags cloud menu</h3><p>I added back the Tags Cloud Menu that I got used to from version 3, that displayed the top 6 topics from the blog.</p><p> </p><!--kg-card-begin: markdown--><pre><code class="language-handlebars">{{#get &quot;tags&quot;
  limit=&quot;6&quot;
  include=&quot;count.posts&quot;
  order=&quot;count.posts desc&quot;
  as |category_nav|
}}
  {{#if category_nav}}
    &lt;ul class=&quot;nav&quot;&gt;
      &lt;li&gt;{{#link href=&quot;/&quot; }}{{t &quot;All&quot;}}{{/link}}&lt;/li&gt;
      {{#foreach category_nav}}
        &lt;li&gt;{{#link href=(url) }}{{name}}{{/link}}&lt;/li&gt;
      {{/foreach}}
    &lt;/ul&gt;
  {{/if}}
{{/get}}
</code></pre>
<!--kg-card-end: markdown--><h3 id="social-accounts">Social accounts</h3><p>Ghost CMS only supports connections for <strong>facebook</strong> and <strong>twitter</strong>. That&#x2019;s partly needed in order to provide metadata for sharing articles. But since the Simply theme used those also for social media links in the footer, I needed to find a way to add more accounts. I soon found out that Ghost has a <a href="https://ghost.org/docs/themes/custom-settings/?ref=blog.jonas.liljegren.org#guidelines-for-theme-developers">hard cap</a> on the number of custom settings (15) and provided no other way to add handlebar variables. The only other ways provided is to add javascript code injection for every page, hardcoding the variables in the theme, or fork Ghost. This sucks. It would be nice if others could just install my theme and use it. But for now, the social media connections are all done as handlebar templates. I created <em>partials/widget/social-item.hbs</em> and used it in <em>partials/widget/social-media.hbs</em> in the menu and footer.</p><!--kg-card-begin: markdown--><pre><code class="language-handlebars">{{&gt; &quot;widget/social-item&quot;
  social=&quot;Github&quot;
  user=&quot;aigan&quot;
  social_url=&quot;https://github.com/aigan&quot;
  icon=&quot;github&quot;
}}
</code></pre>
<!--kg-card-end: markdown--><h3 id="svg-icons">SVG icons</h3><p>Next up was to add icons for all the missing socials I wanted to link. The Simply theme had the SVGs created by an <a href="https://icomoon.io/?ref=blog.jonas.liljegren.org">external tool</a>. In order to include all the icons I wanted, I replaced the static files with a gulpfile job that would gather all svg files in <em>src/img/icon</em> and save them in <em>partials/icons/svgdefs.hbs</em>. That way I could both style them with CSS or use them as images. Had to hand-edit a lot of the icons in order to normalize the size and proportions. Having the svg symbol definitions in each page is not ideal. I would rather use custom elements (without shadow-dom) so that more icons can be added without loading them on pages that don&apos;t use them. But for this I just modified the existing theme, keeping with what&apos;s already done for style and layout.</p><!--kg-card-begin: markdown--><pre><code class="language-js">function svgdefs(done) {
  pump([
    src(`src/img/icon/*.svg`),
    svgSymbols({
      templates: [`default-svg`],
      slug: name =&gt; name.replace(/^/, &quot;icon-&quot;),
    }),
    rename(&apos;svgdefs.hbs&apos;),
    dest(`partials/icons`),
  ], handleError(done))
}
</code></pre>
<!--kg-card-end: markdown--><h3 id="secret-backdoor">Secret backdoor</h3><p>I also added a secret backdoor at the bottom right corner of the page. This is an homage to <a href="https://youtu.be/pXPXMxsXT28?ref=blog.jonas.liljegren.org">the 1995 movie with Sandra Bullock</a>, which has been a part of many of my websites since I started building web applications during that same year. The icon is supposed to be flaming, but I&#x2019;m still waiting on that CSS property. The link goes to the editor so that I can update the corresponding page or post.</p><!--kg-card-begin: markdown--><pre><code class="language-handlebars">&lt;div id=&quot;pi-pos&quot;&gt;
  &lt;div class=&quot;flame&quot;&gt;&lt;/div&gt;
  &lt;a href=&quot;/ghost/
    {{~#is &quot;post&quot;}}#/editor/post/{{post.id}}{{/is~}}
    {{~#is &quot;page&quot;}}#/editor/page/{{page.id}}{{/is~}}
    &quot;&gt;&#x3C0;&lt;/a&gt;
&lt;/div&gt;
</code></pre>
<!--kg-card-end: markdown--><h3 id="social-sharing-links">Social sharing links</h3><p>I decided to remove all the <em>Share this article</em> noise. Desktop users know how to copy URLs. Mobile users have their own systems for sharing. And those systems will soon also come to the desktop. Keep the page clean but make it simple for everyone to add their own stuff.</p><p>Accessibility is much more than supporting screen readers. For me, it&#x2019;s about</p><ul><li>Only move things in response to user actions. This includes pop ups, animations or anything else that grabs attention.</li><li>Use semantic markup so that your tools can process the page for you, such as printing or reading the article.</li><li>Don&apos;t block things like selecting text or downloading images.</li></ul><h3 id="dark-mode">Dark mode</h3><p>Did some adjustments in order to get a transition for switching between light and dark themes. That thing is basically a toy. It&apos;s fun to see it pulse between dark and light. It will react to the <em>prefers-color-scheme</em> css media feature, which often syncs to the device preferences. The implementation in the theme is a bit messy. All the listeners should have been put in an external script and loaded after first render. But it works ok and uses <strong>localStorage</strong> and <strong>matchMedia</strong>.</p><!--kg-card-begin: markdown--><pre><code class="language-css">body, body&gt;div&gt;footer, body&gt;div&gt;header, .post-related {
  transition: background-color 1.5s ease;
}
</code></pre>
<!--kg-card-end: markdown--><p>Added a frosted glass look to the header by combining transparency and blur.</p><!--kg-card-begin: markdown--><pre><code class="language-css">header {
  transition: transform .3s, background-color .7s ease;
  backdrop-filter: blur(10px);
  background-color: var(--header-bg);
}
</code></pre>
<!--kg-card-end: markdown--><h3 id="scrollbar">Scrollbar</h3><p>The scrollbar situation is a mess. The browser default is to only show the scrollbar when needed, but that will result in changes in the page width. My solution has usually been to always add the vertical scrollbar, so that centered items don&apos;t move when scrollbar appears, or on jumping to another page with or without the scrollbar. For this site, I opted to use <strong>scrollbar-gutter</strong>, available since the middle of 2022. But it should not be used on pages specifically designed to not scroll. For this site, it solves the layout shift that would happen when clicking on the search icon.</p><!--kg-card-begin: markdown--><pre><code class="language-css">html:not(:has(&gt;body.overflow-hidden)){
  scrollbar-gutter: stable;
}
</code></pre>
<!--kg-card-end: markdown--><h3 id="discussion-links">Discussion links</h3><p>I wanted a more consistent formatting of the discussion links. Those are links to the posted article on social network sites. I may have posted the article to more than one, like reddit, facebook and twitter. The Ghost CMS provides no way to add the data to the post settings, other than using tags or code injection. Frankly, this is why <strong>Wordpress</strong> dominates the CMS market. They provide hooks for every part of the GUI and <strong>ontology</strong>. Some other frameworks allow for custom data in <strong>frontmatter</strong>. Missing that, I ended up constructing a post-processing of the article, that would extract additional data from the last paragraph. It basically scans the paragraph for <em>[[...]]</em> and adds the links to the list of discussion pages.</p><!--kg-card-begin: markdown--><pre><code class="language-js">const re = /\[\[\s*(.*?)\s*\]\]/g;
for (const match of txt.matchAll(re)) {
  const link = place(match[1]);
  if (!link) continue;
  links.push(link);
}
</code></pre>
<!--kg-card-end: markdown--><p>The Simply theme has a basic layout that allows for content in the article to have normal width, extra width or full width, by using a grid layout. A common case would be to have some images use the extra or full width. I wanted to have some images float to the side with text wrapping around, but use the available margin. This is the Simply theme grid layout for articles, using tailwind compiler:</p><!--kg-card-begin: markdown--><pre><code class="language-scss">.godo-canvas {
  display: grid;
  grid-template-columns:
    [full-start] minmax(4vmin,auto)
    [wide-start] minmax(auto,240px)
    [main-start] min(680px,calc(100% - 8vw))
    [main-end] minmax(auto,240px)
    [wide-end] minmax(4vmin,auto) 
    [full-end];

  &amp; &gt; * {
    grid-column: main-start/main-end;
  }
}
</code></pre>
<!--kg-card-end: markdown--><p>Using that, I wanted to have a special template with floating image, if there was enough width for it. This is used in my about and techstack page.</p><!--kg-card-begin: markdown--><pre><code class="language-scss">figure.aigan-float &gt; img {
  height: max(45vh,10em);
  object-fit: cover;
  object-position: center 33%;
  width: 100%;
  border-radius: 3px
}

/* transpiled by tailwind as media query */
@screen lg {
  figure.aigan-float {
    width: 20em;

    /* move right based on .godo-canvas */
    margin-right: calc(-46vw + 340px);
    margin-left: .5em;
    float: right;
  }

  figure.aigan-float &gt; img {
    height: 100%;
  }
}
</code></pre>
<!--kg-card-end: markdown--><h3 id="and-more">And more</h3><p>There were a lot of other bug fixes and layout changes done. You can look at the result on this site or <a href="https://github.com/aigan/ghost-aigan?ref=blog.jonas.liljegren.org">the code in github</a>.</p><h3 id="ghost-replacement">Ghost replacement</h3><p>After all this, I would rather have a more flexible system, using more of the modern web. Something like <a href="https://www.11ty.dev/?ref=blog.jonas.liljegren.org">11ty</a> or <a href="https://docs.astro.build/en/guides/cms/?ref=blog.jonas.liljegren.org">Astro</a>. That would allow me to add more stuff without stupid workarounds. Especially with the <strong>markdown frontmatter</strong>. That would also let me save all the pages with git. Ghost seems more business oriented. I&apos;m more of a idealist.</p><p>[[<a href="https://twitter.com/aigan/status/1681626691783852032?ref=blog.jonas.liljegren.org">https://twitter.com/aigan/status/1681626691783852032</a>]]<br>[[<a href="https://www.facebook.com/aigan/posts/10159479835207393">https://www.facebook.com/aigan/posts/10159479835207393</a>]]</p>]]></content:encoded></item><item><title><![CDATA[30 years in the Web]]></title><description><![CDATA[After 23 years at the same company, it's time to leave and join a new enterprise.]]></description><link>https://blog.jonas.liljegren.org/30-years-in-the-web/</link><guid isPermaLink="false">642c5e8d196bcc03f487156b</guid><category><![CDATA[code]]></category><category><![CDATA[myself]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Sat, 03 Jun 2023 23:27:35 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2023/06/amiga-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.jonas.liljegren.org/content/images/2023/06/amiga-2.jpg" alt="30 years in the Web"><p>I started writing HTML in 1995 after enrolling at the <a href="https://www.gu.se/tillampad-informationsteknologi?ref=blog.jonas.liljegren.org">university informatics department</a>. That was the year when <a href="https://www.webdesignmuseum.org/old-software/web-browsers/netscape-navigator-2-0?ref=blog.jonas.liljegren.org">Netscape</a> just started adding new capabilities to the web, like background images, colors, tables, javascript and animated gifs.</p><p>The first parts of <a href="https://paranormal.se/old2/welcome.html?ref=blog.jonas.liljegren.org">what would become</a> paranormal.se were created at that time. In those days, a homepage was your home on the web. It was a place for your notes, bookmarks and contact information. I have basically kept <a href="https://jonas.liljegren.org/myself/?ref=blog.jonas.liljegren.org">my homepage</a> from that time, with just some minor updates to keep it usable and somewhat up to date over the years.</p><p>I soon found my home at the student computer club. Spending all nights learning programming in Perl on the <a href="https://en.wikipedia.org/wiki/SPARCstation?ref=blog.jonas.liljegren.org">Solaris</a>, while listening on MP3s of <a href="https://youtu.be/j2F4INQFjEI?ref=blog.jonas.liljegren.org">Belinda Carlisle</a>, <a href="https://youtu.be/AIOAlaACuv4?ref=blog.jonas.liljegren.org">Tracy Chapman</a> or anything else I found on the server. Installing <a href="https://tcrf.net/Proto:Quake_(PC)/Qtest1?ref=blog.jonas.liljegren.org">qtest1</a> on all the lab computers for checking it out.</p><p>I used <a href="https://www.perl.org/?ref=blog.jonas.liljegren.org">Perl</a> for creating the first <a href="https://jonas.liljegren.org/myself/cv/skip.html?ref=blog.jonas.liljegren.org">online facebook</a> for the students at the informatics department. Also created the student newspaper CMS (Snutten), and the computer club website (<a href="https://www.gotastudentkar.se/sv/foreningar/skip?ref=blog.jonas.liljegren.org">SKIP</a>) along with the growing paranormal site.</p><p>I have always preferred dynamic languages that cover the space between low level functionality and high level concepts, from <a href="https://en.wikipedia.org/wiki/ARexx?ref=blog.jonas.liljegren.org">ARexx</a> to <a href="https://jonas.liljegren.org/perl/advocacy/perl/joy.html?ref=blog.jonas.liljegren.org">Perl</a> to <a href="https://tc39.es/ecma262/?ref=blog.jonas.liljegren.org">Javascript</a>. Living on the edge, submitting bug reports and patches to the language or libraries since around 1996.</p><p>Paranormal.se was a project to create a semantic knowledge base with a hypertext frontend. The idea was to discover and surface new knowledge by integrating a large body of research and existing theories. I was hoping to create a sort of discussion forum where each new discussion would help to organize all existing information, making the whole continually more connected and refined. So many algorithms today work by surfacing the most popular and generally understood thinking. I had an idea of how to nurture ideas and perspectives and let them grow until more people understand them. Unlocking the secrets of the universe.</p><p>Dreaming of <a href="https://www.xanadu.net/?ref=blog.jonas.liljegren.org">Xanadu</a>. I love the original vision of Ted Nelson, who coined the terms hypertext and hypermedia. This would later inspire Tim Berners-Lee creation of the Web. I was deeply involved in <a href="https://www.w3.org/RDF/Metalog/docs/sw-easy?ref=blog.jonas.liljegren.org">the semantic web</a> during the introduction of <a href="https://www.w3.org/RDF/?ref=blog.jonas.liljegren.org">RDF</a> in 1999. The dream of connecting all the world&apos;s knowledge with machine-readable semantic markup and a universal API for all public databases. <a href="https://schema.org/docs/schemas.html?ref=blog.jonas.liljegren.org">The ontologies</a> would &#xA0;allow for artificial intelligence to answer any question using deduction with symbolic logic. This is still very much a central part of knowledge representation today and used in combination with machine learning and large language models.</p><p>Changing workplace, I picked up my personal GNU/Linux server with all my sites and mail, to find a new home at the next company. This would be the place where I fully developed my hypertext dream, using the technology both for the company and the personal project.</p><p>Paranormal.se <a href="https://paranormal.se/?ref=blog.jonas.liljegren.org">version 3</a> (P3) consists of about 30.000 topics and 16.000 users. It was a very active community around 1998 - 2008. This was before Wikipedia and Facebook. In 2007, I started developing version 4 (P4) with a much better system for version management, graph database flexibility and deduction capabilities. By 2009, I was burned out.</p><p>P4 was supposed to use my semantic database library <a href="https://blog.jonas.liljegren.org/rdf-base/">RDF::Base</a> (RB), which was created to run on my application framework <a href="https://blog.jonas.liljegren.org/para-frame/">Para::Frame</a> (PF), built with Perl. PF and RB have been continually developed and refined since 2003. It&apos;s powerful and versatile, including multisite frontends, content management, request tracker, email handing, translations, external API and load balancing. All of it built on a <a href="https://blog.jonas.liljegren.org/semantic-databases/">semantic database</a> inspired by RDF with typed literals, reified statements, class schemas and syllogism inference. Since it&apos;s a temporal database, parts or whole of queries can be constrained to a selected date.</p><p>PF and RB was the foundation for <a href="https://web.archive.org/web/20031012204429/http://hotellguiden.se/">Hotellguiden.se</a> from 2003 to 2009. After that, the system would continue to serve as the main customer management database, handling bookings and statistics, newsletters and even the internal call center administration, integrating all the business systems.</p><p><a href="http://valdemo.direktdemokraterna.se/proposition/list_open.tt?ref=blog.jonas.liljegren.org">GOV</a>, a web voting system for liquid democracy, was built in 2009 by my brother for Aktiv Demokrati. It was built using RDF::Base and included ranked pair condorcet method for voting on lists. The liquid democracy was implemented by letting users delegate voting to other users. If you did not vote, the vote of your delegate would be counted. This also handled prioritized lists of delegates, voting jurisdiction and the temporal information of membership and voting history. I took over the development in 2010 and continued its development until 2017.</p><p>I have administered a lot of sites for forums, blogs or facebook pages related to groups I participated in. This includes Perl Mongers, <a href="http://aktivdemokrati.se/?ref=blog.jonas.liljegren.org">Aktiv Demokrati</a>, Occupy G&#xF6;teborg, <a href="https://thezeitgeistmovement.se/?ref=blog.jonas.liljegren.org">Zeitgeist Movement Sweden</a>, Direktdemokraterna, in addition to many more personal sites. I also produced a lot of IRL events for <a href="https://www.youtube.com/@tzmse?ref=blog.jonas.liljegren.org">Zeitgeist</a> and <a href="https://www.youtube.com/@AktivDemokrati?ref=blog.jonas.liljegren.org">Direktdemokraterna</a>, including several Z-day conferences and election campaigns. This included a lot of marketing on the streets, public speaking and also online campaigns using ads, facebook and emails. Also did a lot of printing material, recording and editing of audio and video.</p><p>All of this ended in 2015. Burned out again, but now with <a href="https://blog.jonas.liljegren.org/tag/health/">health problems</a>. I started investigating what I could do better for recovering my health, including diet, exercise and supplements. Eventually <a href="https://blog.jonas.liljegren.org/re-botad/">learned what to do</a> to stay productive. I also took more time for rest and relaxation with playstation gaming, renewing my interest in game design. Especially <a href="https://blog.jonas.liljegren.org/tag/systemic/">systemic story games</a>.</p><p>A new generation for the booking system started development in 2015, now based on Javascript, NodeJS and the graph database Neo4J. I made the jump from Perl to Javascript and took the opportunity to jump to the bleeding edge, with ES modules, web components and low complexity. That which later would be called <a href="https://modern-web.dev/?ref=blog.jonas.liljegren.org">Modern Web</a>.</p><p>I see so many problems in apps from Facebook, Youtube and others. Especially for making systems that support you switching devices or working with other people, with all information kept up to date regardless of their source. I did a lot of work to make it easy to build large interconnected semantic systems with guaranteed consistency in all async scenarios. More on that later.</p><p>By 2020, the project was halted. My workplace decided to simplify and outsource all IT. The world-leading system I had developed was not the right match for the company.</p><p>Now, I&#x2019;m <a href="https://blog.jonas.liljegren.org/techstack/">looking for my dream job</a>, advancing the state of the web using bleeding edge web technologies like buildless web components and reactive state semantic graphs, connected to the latest of LLM AI using embeddings for ML vector databases.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://blog.jonas.liljegren.org/contact/" class="kg-btn kg-btn-accent">Contact me</a></div><p>[[<a href="https://dev.to/aigan/30-years-dreaming-of-the-semantic-web-411b?ref=blog.jonas.liljegren.org">https://dev.to/aigan/30-years-dreaming-of-the-semantic-web-411b</a>]] [[<a href="https://twitter.com/aigan/status/1667785718175768578?ref=blog.jonas.liljegren.org">https://twitter.com/aigan/status/1667785718175768578</a>]]<br>[[<a href="https://www.facebook.com/aigan/posts/10159401132557393">https://www.facebook.com/aigan/posts/10159401132557393</a>]]</p>]]></content:encoded></item><item><title><![CDATA[Surviving the Burning Shores]]></title><description><![CDATA[Have you ever seen anyone else even try to do it? I may be the only one who tried to survive the Horizon 2 Forbidden West DLC: Burning Shores.]]></description><link>https://blog.jonas.liljegren.org/surviving-the-burning-shores/</link><guid isPermaLink="false">647264f2196bcc03f4871c18</guid><category><![CDATA[horizon]]></category><category><![CDATA[story]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Wed, 31 May 2023 00:36:47 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2023/05/h2bs68-o.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.jonas.liljegren.org/content/images/2023/05/h2bs68-o.jpg" alt="Surviving the Burning Shores"><p>You can see my blind, NG, Ultra Hard, HUDless, careful, 4K 60fps HDR, <a href="https://www.youtube.com/playlist?list=PLbvfm0ge12qlqWpmgraY0b0ntj5J9k_h6&amp;ref=blog.jonas.liljegren.org">Let&#x2019;s Play on YouTube</a>, including commentary on the fascinating concepts showcased in the Horizon world.</p><h1 id="survive">Survive</h1><p>Surviving means that you would finish the main quest without dying. Or at least, in trying, do it with as few deaths as possible. Treat the game as permadeath. That includes that you should not restart the game. Do it on the first try, blind, without any outside help.</p><p>Why? Because I love how immersive this game can be. I like to behave as Aloy would if it really was life-or-death. Being careful, smart and prepared. Not knowing what&#x2019;s to come. Behaving realistically, so far as it can be done in the game. That would also mean that I will always try to avoid getting hurt. A low-health strategy is out of the question. No hero would willingly aim to hurt themselves just to get motivated to fight harder. I would ideally do everything without ever getting hurt.</p><p>The same goes for NG+. That whole concept breaks immersion. And it&apos;s per definition not your first try. That means, to survive the Burning Shores, you would have to do it on a New Game (NG) Ultra Hard (UH) playthrough. No NG+.</p><p>Upgrading all the weapons, outfits, tools and skills will give you ample opportunity to survive everything that comes your way. Some experienced players may impose extra limitations to increase the challenge. I fully understand that different players like the games in different ways, with their own playstyles. For me, I gladly use everything I have, if it means that I may come out of all this alive.</p><p>I like doing all this carefully, since I&#x2019;m pretty risk-averse by nature. I prefer to find the safest way to solve any challenge, using smarts and patience rather than combat prowess. For that reason, I have also skipped all of the Arena and melee pits, missing out on some of the beast weapons and outfits in the game. Would not risk hurting Aloy just for sports. Especially not under time constraints.</p><p>I set out to experience the Burning Shores blind. After the first teaser, I decided to avoid everything related to the DLC. I usually enjoy seeing other people play the game and after I finished the main game, I looked up more information about things I missed about the world, machines and the game mechanics. But for playing the Burning Shores blind, I decided to not use any guides or tips or any other outside help, from the start to the end of the DLC. That&apos;s also how I prefer to experience the media. Preferably not having any information about it. Ideally not even a name or a cover image.</p><h1 id="immerse">Immerse</h1><p>Majestic wilderness, awe-inspiring machines and exotic tribes. The world of Horizon Zero Dawn is beautiful. Even more so in its sequel Horizon Forbidden West, in 4K resolution on the PlayStation 5, on a HDR display with surround sound, rendered with 60 FPS. The detail and density of foliage, the thickness of life in the air and the warm saturated colors. The light shining through the gently moving leaves. &#x2014; Stop and smell the Vigorstems.</p><p>I like to spend time in this world. Moving naturally for immersion and for giving myself time to experience the cinematic beauty. Why would you jump and run around and miss all of this? Run when you need to, in combat, but save your energy when you can. And running around in the middle of settlements is just plain rude.</p><p>You can use the settings to customize HUD (head-up display). The game UI (user interface) can be <a href="https://blog.jonas.liljegren.org/health-in-games/">flat, diegetic, spatial or meta</a>. I prefer the diegetic or meta variants. Most of the game can be played fairly with all of the flat and spatial UI turned off. This means that you will have no icons, text or bars in the corners of the screen, or attached to objects and places in the world. I enjoy seeing the world in all its uncluttered beauty. I will tread carefully, listening for any sound around me.</p><p>There is a &#x201C;dynamic&#x201D; HUD preset, that will hide most of the UI, but that is not nearly good enough. I&#x2019;d prefer turning almost everything off and using the focus or touch to see things on demand. (The HUD will display temporarily when you swipe up (not click) on the touchpad.) The only HUD component I keep is the reticule.</p><p>The HUDless config is not done as a challenge. I just don&#x2019;t like distractions and enjoy the immersion of the minimal HUD. There are times where I temporarily activate some components to help me survive in tricky situations. The nice part is that almost all of the HUD is explained in game with the augmented reality (AR) capabilities of the focus device.</p><p>Take a break from all the running. It&apos;s time for Games Done Slow! Relax with my immersive slowplay. I will explain my thinking and preparation every step on the way. There will probably be a lot of things you didn&#x2019;t think of doing. Did you find any part hard to get through without getting hurt? I may have tips for you, even though I did not know what I would encounter behind the next corner.</p><p>Was there anything I could have done safer? Please let me know in the comments under the respective video.</p><h1 id="contemplate">Contemplate</h1><p>Horizon Zero Dawn is <a href="https://blog.jonas.liljegren.org/horizon-zero-dawn-deep-dive/">built on an amazing concept</a>. I love science fiction exploring ideas related to our world and the human condition. There are so many interesting topics in this game. The tension between nature and technology. How culture and language forms our values and understanding of the world. The idea of a better world. Hopes and fears.</p><p>I was hoping to find the time to talk about everything while walking through the world. Thinking freely on all the places, events and data-points, as they happened.</p><p>&#x2026; I got distracted.</p><p>But I did take the time to cover some topics. Especially during some episodes after the main quest. Here are some of the things I talked about. Please comment on anything of interest.</p><p>All the videos are marked with chapters for easy navigation.</p><h3 id="difficulty-and-surviving">Difficulty and surviving</h3><p><a href="https://youtu.be/cpBk0sHH_qM?ref=blog.jonas.liljegren.org">#00</a> Ultra Hard, Blind<br><a href="https://youtu.be/QvCMwmfi6pk?ref=blog.jonas.liljegren.org">#01</a> What is game difficulty? Complexity Open World<br><a href="https://youtu.be/FcShYr02Tso?ref=blog.jonas.liljegren.org">#08</a> Permadeath<br><a href="https://youtu.be/elB1uOSe5GQ?ref=blog.jonas.liljegren.org">#51</a> Trying to survive<br><a href="https://youtu.be/1Lv6e7ePd-s?ref=blog.jonas.liljegren.org">#86</a> Being careful</p><h3 id="game-systems">Game systems</h3><p><a href="https://youtu.be/QvCMwmfi6pk?ref=blog.jonas.liljegren.org">#01</a> Playstyle Freedom<br><a href="https://youtu.be/413sRRIMlR8?ref=blog.jonas.liljegren.org">#77</a> <a href="https://blog.jonas.liljegren.org/health-in-games/">Systems vs Random</a><br><a href="https://youtu.be/9B30NzDrx4I?ref=blog.jonas.liljegren.org">#78</a> <a href="https://blog.jonas.liljegren.org/health-in-games/">Machine health</a><br><a href="https://youtu.be/HuVgtIgG3nA?ref=blog.jonas.liljegren.org">#83</a> <a href="https://blog.jonas.liljegren.org/terraforming/">Systemic restoration</a>, <a href="https://blog.jonas.liljegren.org/systemic-story-game-development/">Quests in a systemic world</a><br><a href="https://youtu.be/KyYQyOTCfKY?ref=blog.jonas.liljegren.org">#88</a> <a href="https://blog.jonas.liljegren.org/systemic-story-game-development/">Systemic Story</a><br><a href="https://youtu.be/I92-TUxeTFQ?ref=blog.jonas.liljegren.org">#89</a> Tears of the Kingdom, <a href="https://blog.jonas.liljegren.org/nethack/">NetHack</a>, Half-Life 2, <a href="https://blog.jonas.liljegren.org/systemic-story-game-development/">Systemic World</a>, Systemic Story, <a href="https://blog.jonas.liljegren.org/traversal-freedom/">Systemic Traversal</a>, <a href="https://blog.jonas.liljegren.org/embodied-manipulation/">Active Climbing</a><br><a href="https://youtu.be/QB-gnvWBSlo?ref=blog.jonas.liljegren.org">#90</a> Non-systemic mechanics, <a href="https://blog.jonas.liljegren.org/health-in-games/">Critical Hits</a></p><h3 id="game-interactivity">Game Interactivity</h3><p><a href="https://youtu.be/0XwQSX8DWVY?ref=blog.jonas.liljegren.org">#25</a> <a href="https://blog.jonas.liljegren.org/traversal-freedom/">Puzzles and locked doors</a><br><a href="https://youtu.be/9B30NzDrx4I?ref=blog.jonas.liljegren.org">#78</a> Diegetic Interface<br><a href="https://youtu.be/jkj7vim2BiA?ref=blog.jonas.liljegren.org">#81</a> Mechanics added in Burning Shores<br><a href="https://youtu.be/1Lv6e7ePd-s?ref=blog.jonas.liljegren.org">#86</a> Changes from H1 to H2<br><a href="https://youtu.be/I92-TUxeTFQ?ref=blog.jonas.liljegren.org">#89</a> <a href="https://blog.jonas.liljegren.org/embodied-manipulation/">Active Climbing</a></p><h3 id="game-story">Game Story</h3><p><a href="https://youtu.be/8AVDmpXTPxY?ref=blog.jonas.liljegren.org">#26</a> Mystery<br><a href="https://youtu.be/jkj7vim2BiA?ref=blog.jonas.liljegren.org">#81</a> Realism<br><a href="https://youtu.be/Kx_iXGyTB-k?ref=blog.jonas.liljegren.org">#82</a> <a href="https://blog.jonas.liljegren.org/rite-of-passage-and-heros-journey/">Hero&apos;s journey</a>, The found family</p><h3 id="game-immersion">Game Immersion</h3><p><a href="https://youtu.be/tXBxbhii3nw?ref=blog.jonas.liljegren.org">#34</a> Loading times<br><a href="https://youtu.be/I92-TUxeTFQ?ref=blog.jonas.liljegren.org">#89</a> Simulation fidelity, Walks in nature<br><a href="https://youtu.be/07HlB_f99n0?ref=blog.jonas.liljegren.org">#91</a> Idle Animations</p><h3 id="psychology-and-culture">Psychology and culture</h3><p><a href="https://youtu.be/QvCMwmfi6pk?ref=blog.jonas.liljegren.org">#01</a> <a href="https://blog.jonas.liljegren.org/psychopathy-neurodiversity/">Psychopathy</a><br><a href="https://youtu.be/9B30NzDrx4I?ref=blog.jonas.liljegren.org">#78</a> <a href="https://blog.jonas.liljegren.org/mbti-infj/">Why so careful?</a>, Sensory overload<br><a href="https://youtu.be/jkj7vim2BiA?ref=blog.jonas.liljegren.org">#81</a> Utaru harmony, Utaru relationships<br><a href="https://youtu.be/KOZ7sSYJe7Q?ref=blog.jonas.liljegren.org">#84</a> <a href="https://blog.jonas.liljegren.org/hunter-gatherer-tribes/">Hunter-gatherer</a>, Brand optics<br><a href="https://youtu.be/3oXS1Wpbblw?ref=blog.jonas.liljegren.org">#85</a> <a href="https://blog.jonas.liljegren.org/hunter-gatherer-tribes/">Environmentalism</a><br><a href="https://youtu.be/07HlB_f99n0?ref=blog.jonas.liljegren.org">#91</a> The Quen</p><h3 id="artificial-intelligence">Artificial Intelligence</h3><p><a href="https://youtu.be/flM2oMeCltY?ref=blog.jonas.liljegren.org">#14</a> Transformer AI<br><a href="https://youtu.be/9s0M0-ZZ4B0?ref=blog.jonas.liljegren.org">#60</a> <a href="https://blog.jonas.liljegren.org/emotional-computer-intelligence/">Adjusting the personality of AI assistants</a><br><a href="https://youtu.be/3oXS1Wpbblw?ref=blog.jonas.liljegren.org">#85</a> Computability, <a href="https://blog.jonas.liljegren.org/emotional-computer-intelligence/">Machine Learning feelings</a>, Symbolic Logic<br><a href="https://youtu.be/jeFnq3MTptQ?ref=blog.jonas.liljegren.org">#87</a> Nature of consciousness, <a href="https://blog.jonas.liljegren.org/emotional-computer-intelligence/">Artificial General Intelligence</a>, Artificial Emotions, Artificial Consciousness</p><h3 id="technology">Technology</h3><p><a href="https://youtu.be/flM2oMeCltY?ref=blog.jonas.liljegren.org">#14</a> Augmented Reality<br><a href="https://youtu.be/Mwt7-ZjluCo?ref=blog.jonas.liljegren.org">#27</a> Recording dreams<br><a href="https://youtu.be/KOZ7sSYJe7Q?ref=blog.jonas.liljegren.org">#84</a> Focus functionality, <a href="https://blog.jonas.liljegren.org/runaway-replication/">Dangers of technology</a></p><h3 id="ecology">Ecology</h3><p><a href="https://youtu.be/jkj7vim2BiA?ref=blog.jonas.liljegren.org">#81</a> <a href="https://blog.jonas.liljegren.org/biomimetic-robotics/">Machines purpose for terraforming</a><br><a href="https://youtu.be/HuVgtIgG3nA?ref=blog.jonas.liljegren.org">#83</a> <a href="https://blog.jonas.liljegren.org/biomimetic-robotics/">HEPHAESTUS</a>, <a href="https://blog.jonas.liljegren.org/holistic-ecology/">Healing the land</a>, Resilience of animal morphology<br><a href="https://youtu.be/KOZ7sSYJe7Q?ref=blog.jonas.liljegren.org">#84</a> <a href="https://blog.jonas.liljegren.org/biomimetic-robotics/">Nature resilience</a>, <a href="https://blog.jonas.liljegren.org/terraforming/">DEMETER</a>, <a href="https://blog.jonas.liljegren.org/climate-change/">The Hot Zone Crisis</a>, Zero Dawn Project, <a href="https://blog.jonas.liljegren.org/holistic-ecology/">Ecology</a>, <a href="https://blog.jonas.liljegren.org/runaway-replication/">Dangers of technology</a>, Technology in harmony with ecology and humanity<br><a href="https://youtu.be/3oXS1Wpbblw?ref=blog.jonas.liljegren.org">#85</a> Biological reductionism, <a href="https://blog.jonas.liljegren.org/holistic-ecology/">Holistic Ecology</a>, Computing ecology<br><a href="https://youtu.be/QB-gnvWBSlo?ref=blog.jonas.liljegren.org">#90</a> Permaculture</p><h3 id="economy">Economy</h3><p><a href="#16 Unconditional Basic Income">#16</a> <a href="https://blog.jonas.liljegren.org/automation-and-unconditional-basic-income/">Unconditional Basic Income</a><br><a href="https://youtu.be/0XwQSX8DWVY?ref=blog.jonas.liljegren.org">#25</a> <a href="https://blog.jonas.liljegren.org/automation-and-unconditional-basic-income/">Unconditional Basic Income</a><br><a href="https://youtu.be/KOZ7sSYJe7Q?ref=blog.jonas.liljegren.org">#84</a> Capitalism, Negative externalities, Company reputation, Brand optics, Economic pressures, <a href="https://blog.jonas.liljegren.org/automation-and-unconditional-basic-income/">Basic Income</a>, Zero Marginal Cost</p><p>Please comment and share your thoughts. Tell me if there is anything you would like me to cover in more depth.</p><p>[[<a href="https://twitter.com/aigan/status/1664436297702752257?ref=blog.jonas.liljegren.org">https://twitter.com/aigan/status/1664436297702752257</a>]]<br>[[<a href="https://www.facebook.com/groups/105986599829686/posts/1667272637034400/">https://www.facebook.com/groups/105986599829686/posts/1667272637034400/</a>]]</p>]]></content:encoded></item><item><title><![CDATA[Embodied manipulation]]></title><description><![CDATA[Designing a control scheme for interacting with the world in a immersive sim open world adventure game
]]></description><link>https://blog.jonas.liljegren.org/embodied-manipulation/</link><guid isPermaLink="false">638ea3e9d218f00485be7ccf</guid><category><![CDATA[systemic]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Thu, 08 Dec 2022 00:36:52 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2022/12/dualsense-crop.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.jonas.liljegren.org/content/images/2022/12/dualsense-crop.jpg" alt="Embodied manipulation"><p><em>This is part of the series about </em><a href="https://blog.jonas.liljegren.org/tag/systemic/"><em>my design for a systemic story game.</em></a></p><p>I love the controls in the original 1996 <a href="https://blog.jonas.liljegren.org/tomb-raider/"><em>Tomb Raider</em></a>. It feels like I&apos;m touching the world. Holding down the keys for holding objects or holding on to ledges. Using the lower key for the legs and the upper key for the arms. It&#x2019;s intuitive, consistent and it felt right for me.</p><h2 id="contextual-buttons"><strong>Contextual buttons</strong></h2><p>My main frustration for controls are the contextual actions that depend on proximity to an object. I have been vaulting over campfires in <a href="https://blog.jonas.liljegren.org/horizon-zero-dawn-deep-dive/"><em>Horizon</em></a> more often than not just because the quicksave button is the same as the dodgeroll button. I think that the generic &#x201C;action&#x201D; button is bad. The action can be radically different depending on what pixel you are looking at in the case of two different targets next to each other. Games with auto-climb often make me climb over tables when I&#x2019;m just wanting to go to pick something up. It&#x2019;s another case of immersion-breaking when I&#x2019;m with a group of companions indoors and trying to talk to them but accidentally climb and jump all over the place.</p><h2 id="keeping-control"><strong>Keeping control</strong></h2><p>Most games don&#x2019;t allow you to cancel, change or modify actions. You should be able to change your mind in the middle of anything you do. Never take away the control from the right stick camera or left stick movement. For example, if you tell the avatar to sit down, and that starts a 1.5 second animation, you should be able to cancel the action at any point, resulting in what would be physically reasonable. If you issue the action to drink, resulting in you reaching in your bag, taking out a flask, opening it and moving it to your mouth, you should be able to cancel that at any time. More important still; If you are knocked down during a fight, you should be able to steer yourself while falling, for the possibility to get back up on your feet faster. You should be able to grab hold of things. You should be able to roll to lessen the damage. It may be hard, but it should be possible to minimize the setback. Never take the control away from the player. Keep the basic things easy while providing lots of things to master.</p><h2 id="more-inspirations"><strong>More inspirations</strong></h2><!--kg-card-begin: markdown--><p><em>Death Stranding</em> uses <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> and <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> as grip buttons for the left and right hand. You can throw stuff by swinging while holding something and let go mid swing. The monkey climbing in <em>Astro&#x2019;s Playroom</em> is wonderful, where you can reach for and grab handholds with <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> and <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy">, even using the motion sensor for the reaching and also for swing jumps. <em>Uncharted 4</em> also lets you steer your hands when selecting where to climb. <em>The Last Guardian</em> use circle as the grip button, allowing you to push/pull and move with objects.  The playstation symbol buttons should not be used for things where you also want to keep using the right stick. <em>Dying Light</em> has the right idea by using <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> to jump and holding on to ledges. Off-stick buttons should only be used for things that in-world would interfere with moving or looking around. <em>Half Life 2</em> was influential in not restricting the movement while people were talking with you, even though you actually didn&apos;t say anything. <em>Cyberpunk 2077</em> gives you the power to select things to say while still letting you look around and move at the same time. The quicktime events of <em>Detroit: Become Human</em> hints at something that could resemble embodied actions, but fails miserably. You should never have to state what button to press, other than as a reminder.</p>
<p>The original meaning of the playstation symbols are <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_T.svg" alt="Embodied manipulation" loading="lazy"> viewpoint, <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy"> document, <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy"> yes and <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"> no. With time, now they usually are used for <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_T.svg" alt="Embodied manipulation" loading="lazy"> Interact, <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy"> Action, <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy"> Evade and <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"> Jump.</p>
<!--kg-card-end: markdown--><h2 id="immersive-sim-open-world-adventure-game-control-scheme"><strong>Immersive Sim Open World Adventure Game Control Scheme</strong></h2><p>This is my suggestion for allowing many different actions but in a way that feels natural. Keep the action buttons reachable while keeping the thumbs on the sticks. Slower actions can require long-press.</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Playstation</th>
<th>Xbox</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td><img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"></td>
<td>left trigger</td>
<td>Left</td>
</tr>
<tr>
<td><img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"></td>
<td>right trigger</td>
<td>Right</td>
</tr>
<tr>
<td><img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"></td>
<td>left bumper</td>
<td>Force</td>
</tr>
<tr>
<td><img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"></td>
<td>right bumper</td>
<td>Up</td>
</tr>
<tr>
<td><img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"></td>
<td>A</td>
<td>Down</td>
</tr>
<tr>
<td><img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy"></td>
<td>B</td>
<td>Collect</td>
</tr>
<tr>
<td><img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy"></td>
<td>X</td>
<td>Equip</td>
</tr>
<tr>
<td><img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_T.svg" alt="Embodied manipulation" loading="lazy"></td>
<td>Y</td>
<td>Think</td>
</tr>
<tr>
<td><img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_L3.svg" alt="Embodied manipulation" loading="lazy"></td>
<td>click LS</td>
<td>Sprint</td>
</tr>
<tr>
<td><img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_R3.svg" alt="Embodied manipulation" loading="lazy"></td>
<td>click RS</td>
<td>Inspect</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><h3 id="your-hands"><strong>Your hands</strong></h3><!--kg-card-begin: markdown--><p>The <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> and <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> trigger buttons represent your left and right hand. The trigger buttons are analog, meaning that it registers gradual impressions from zero to one. The Playstation 5 controller triggers are also adaptive, meaning that they can resist at different positions to different degrees at different points. The adaptive trigger will create a connection between your hands and the hands of your avatar in game. You can feel when you pick something up, the force when you try to pull, push or lift something heavy, the thug when you catch hold of a ledge after a jump or fall, or the resistance while pushing open a door or pulling a lever.</p>
<p>Gradually pushing down the trigger will first raise your arm, ready the item in it and finally squeeze or use the item. Use the right stick to select a target and press down a trigger to reach and pick up that item. Releasing the trigger will put down the item at the place you are looking at, or just in front of you if you are not looking at a place within reach. If an item is just out of your reach, you will reach for it. Use the left stick to move or try to extend your arm towards the item if you&apos;re stuck.</p>
<p>The target for your hands is the item you are looking at that&apos;s within reach. The default setting would be to first subtly highlight the current target. When a trigger press starts the pickup movement, the target will be more clearly highlighted, and you will be able to cancel the action by releasing the trigger before you actually move the item.</p>
<p>If the target is stuck, you will place your hand on it. Stuck items include things that can&#x2019;t be picked up, because they are heavy, equipped or connected to something else. You can squeeze the item by pushing the trigger to the max. Squeezing an item while looking at it will enable you to move it with your right stick.</p>
<p>You can move items between your hands. If you are holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> with an item in that hand, and then selecting that item by looking at it with the right stick, you may place your left hand on it by holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy">. Releasing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> will move the item to the left hand. The looking part is optional if you have no other target within reach, the other hand is empty, and the item is not equipped.</p>
<!--kg-card-end: markdown--><h3 id="equipment"><strong>Equipment</strong></h3><!--kg-card-begin: markdown--><p>Hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy"> to open your inventory as a radial menu of stuff near at hand. That menu will also have options for accessing your bags and other stuff. Select the item and release. Selecting an item from your inventory while not holding up a hand will equip it directly in its place or to the right hand. Selecting an item while holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> or <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> will put the item in that hand. Anything already in that hand will be put in your inventory or released if not collectable.</p>
<p>While holding an item, you can press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy"> to equip it. When the item is equipped, you will not drop it by releasing the hand. Equipping something that isn&#x2019;t wearable will make you hold on to it with the selected hand. Equipping a two-handed item will make you hold on to it with your left hand, if you can carry it with just one hand. Equipping something you wear on your arm or hand will put it on the opposite hand. If you are holding a ring in your right hand and equipping it, you will put it on the left hand. You can select the exact placement by raising your other hand and pointing with your right stick. Equipping other wearable items will put them on your body. You should also be able to look at all parts of your body by looking down on yourself.</p>
<!--kg-card-end: markdown--><h3 id="looting"><strong>Looting</strong></h3><!--kg-card-begin: markdown--><p>While not holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> or <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy">, pressing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy"> will make you collect the item you are looking at, and put it in your inventory. You may hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy"> as a shortcut for unlocking and opening containers.</p>
<p>Looking at an item within reach and holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> or <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> will pick it up in that hand. If the item is stuck, you will place your hand on the item. Having your hand on an item and pressing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy"> will make you try to unequip it and take it in your hand. For example, you would take your shoes off by looking down at them, hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> and <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> to place your hands on them, and then press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy"> to untie them and place them in your hand.</p>
<p>If not having your hand on an item, press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy"> while holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> or <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> to put the items you are holding in that hand in your inventory. Those items are always quickly reachable from your inventory by holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy">.</p>
<!--kg-card-end: markdown--><h3 id="shooting"><strong>Shooting</strong></h3><!--kg-card-begin: markdown--><p>Let&apos;s say you see a bow and arrows on a table. Look at the bow and hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> to pick it up. While holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy">, you can move it to your left hand by holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> and releasing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy">. Having an item in your hand means that you use it, if it&apos;s the kind of item you use by holding it in your hand. You may also equip it with <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy"> so that you will not drop it by releasing the trigger.</p>
<p>Now hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> for picking up the arrows. While holding the arrows, press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy"> to store them in your inventory, or hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> to raise your bow while storing all but one of the arrows. Then hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> to draw the bow with one of your arrows. Release <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> to shoot an arrow.</p>
<p>You can throw an unequipped item by holding it up, hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> to aim and release <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> to throw the item. If the item is equipped, you must also release the hand to actually let go of the item during the throw. You don&#x2019;t have to do the manual release or even the holding up of the hand if the equipped item has a stash of throwable ammunition. For a stash of equipped rocks, you may just hold down and release <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> to do a throw, as long as you have a free hand.</p>
<p>Having a rifle equipped means that you will raise it with <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> and use it with <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy">, using the same principles as for everything else. Gradually pressing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> will raise your arm to the trigger. The adaptive trigger will push back at the position of the trigger, where the squeeze will fire the gun.</p>
<p>Reload the guns by releasing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy">, look at the left hand and press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy">, meaning that you hold the gun in the left hand and use the right hand to re-equip it. If no other target within reach is selected, you may just press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy"> while holding up the gun. Though you still need an empty hand.</p>
<p>This will also allow having one item in each hand, be it single-handed guns, melee weapons, throwables, or any other type of item, like a torch, compass, rope, or a brass key.</p>
<!--kg-card-end: markdown--><h3 id="melee">Melee</h3><!--kg-card-begin: markdown--><p>Holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> or <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> will block with whatever you have in your left or right hand. Time pressing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> or <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> to parry. All of these are variations of raising your left or right arm.</p>
<p>Melee weapons can be used by squeezing. Hold squeeze for a strong attack. Modify the type of attack by the direction you move with the left stick and the movement of your pointing with the right stick, for swinging to the left, right, up, down. If your opponent parried your attack, you may follow up with a riposte by pressing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy">.</p>
<p>Use <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> to force your movement. <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> while moving towards a target within reach will kick or tackle the target. <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> in a direction with no target will do a short dodge in that direction. <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> while standing still will apply force towards the target without moving. Do <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> without a target for a nice grunt.</p>
<!--kg-card-end: markdown--><h3 id="crouching"><strong>Crouching</strong></h3><!--kg-card-begin: markdown--><p>Press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"> to crouch. Hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"> to go prone. Press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"> near cover to hug cover. Then <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"> again to crouch if standing behind cover. Press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"> while crouching to duck. Hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"> while prone to hold your breath and play dead.</p>
<p>While prone, you can press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> to go back to a crouching position or hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> to stand up. While crouching and standing still you can press or hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> to raise up.</p>
<p>Pressing against an incline while crouching or prone and holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> will make you try to climb while crouching or prone.</p>
<p>Moving crouching or prone will be silent while not in sprint mode, meaning that your avatar will try to not do something that would make noises.</p>
<!--kg-card-end: markdown--><h3 id="jumping"><strong>Jumping</strong></h3><!--kg-card-begin: markdown--><p>Pressing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> will jump. Combine with <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> for different jump-attacks. Hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> while standing still to charge a standing jump. <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> + <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_L.svg" alt="Embodied manipulation" loading="lazy"> forward in any direction will jump in that direction. <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> + <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_L.svg" alt="Embodied manipulation" loading="lazy"> sideways or backwards will dodge and duck in that direction.</p>
<p>Press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> + <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_L.svg" alt="Embodied manipulation" loading="lazy"> while crouching to roll, or <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> + <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"> + <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_L.svg" alt="Embodied manipulation" loading="lazy"> to roll while running. This will work in any combination. Begin jumping in a direction and press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"> before your feet left the ground to modify a basic jump ro a roll, or press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"> while in air to roll after you land. Press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"> while in air to pull your legs up for clearing obstacles.</p>
<p>Combining moves with <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_X.svg" alt="Embodied manipulation" loading="lazy"> will take you away from the right stick, but I think that is ok since it&apos;s something that should be a bit harder and would limit your awareness of your surrounding, since you would focus on the ground.</p>
<!--kg-card-end: markdown--><h3 id="climbing"><strong>Climbing</strong></h3><!--kg-card-begin: markdown--><p>Hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> while running at obstacles for parkouring over them. This will work for everything where you don&#x2019;t have to hold on with your hands. Bracing or pushing off with your hands can be done even while holding items, as long as they aren&#x2019;t fragile or heavy. You will parkour the thing you look at as long as you keep up your momentum. This will also work for things like ladders that are especially easy to climb.</p>
<p>For climbing with your hands, make sure to have them free. Look at something you can hold on to and hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> or <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> for grepping with the left or right hand. With your free hand, look at the next handhold. Move your body and arm with <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_L.svg" alt="Embodied manipulation" loading="lazy"> and grab it. Release the other hand and repeat for the next handhold. You can use <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy"> to lock your latest grip if you want to hang on without holding down the trigger.</p>
<p>Your feet will follow along using the nearest footholds while climbing with your hands. To climb over an edge, hold on to the edge with both hands, move the left stick upward to press your body up and then hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> to climb up with your legs.</p>
<p>Press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> for using your arms to thrust your body to something out of reach. While reaching for a handhold, press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> to jump in that direction. Jumping while not reaching for or holding on to the environment will let you jump backwards.</p>
<p>You can climb down over an edge by looking at the edge and using an empty hand. Holding the ledge, you can continue to move forward to drop down and turn around.</p>
<!--kg-card-end: markdown--><h3 id="balance">Balance</h3><p>You will pause at edges, but can continue for jumping down if it&apos;s a comfortable drop. For larger drops, you will have to initiate climbing or switch to sprint mode. This will also help you with balancing on stocks. You will not step of the ledge, but can still lose your balance.</p><p>You can center your mass to regain balance by raising your left or right arm. The degree of press on the trigger correspond to how high your arms are raised. Looking down at the stock or ledge and pressing a trigger will take hold on the ledge. You may also crouch or go prone to keep your balance.</p><h3 id="dragging"><strong>Dragging</strong></h3><!--kg-card-begin: markdown--><p>Use <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> + <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> for putting your hands on the target item in front of you and move forward to push. If you have a grip, you can also drag backward or rotate to the side. Hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> to try to lift the object from the ground, or <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> + <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_L.svg" alt="Embodied manipulation" loading="lazy"> to force the item in that direction.</p>
<!--kg-card-end: markdown--><h3 id="ropes"><strong>Ropes</strong></h3><!--kg-card-begin: markdown--><p>Hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy"> to open your inventory as a radial menu of stuff near at hand. Select your rope with the left stick and release <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy"> to place the rope in your left hand. Ready the rope by holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy">. For binding to something, look at the item within reach and hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> and press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy">. Cancel the binding by releasing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> and/or <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> before finished. Untie the rope by pressing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy">.</p>
<p>Pull the item by moving backwards while holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy">. Moving while not holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> will just let the rope out til the limit of its reach. Hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> + <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_L.svg" alt="Embodied manipulation" loading="lazy"> to pull the rope while standing still.</p>
<p>Hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> + <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_L.svg" alt="Embodied manipulation" loading="lazy"> for climbing up/down the rope. While hanging on the rope with <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy">, use movement direction to run on walls. Press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R1.svg" alt="Embodied manipulation" loading="lazy"> to jump against the wall with your feets. Release <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> to let go of the rope, for a swinging jump.</p>
<p>Look at the rope and press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy"> to lock yourself to the rope, in case you want to use your hands for something else. Press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy"> to free yourself again.</p>
<p>For throwing a lasso or grappling hook or similar, you can hold a rope with your left hand and throw the part in your right hand by holding and releasing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy">. Press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy"> to collect the rope back to your hand and <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy"> again to put it back in your inventory.</p>
<!--kg-card-end: markdown--><h3 id="widgets"><strong>Widgets</strong></h3><!--kg-card-begin: markdown--><p>While looking at a stuck item in reach, you can hold a trigger to raise your arm and place your hand at the item. While your hand is placed, use <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_R.svg" alt="Embodied manipulation" loading="lazy"> to move it left, right, up and down. <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_L.svg" alt="Embodied manipulation" loading="lazy"> will still control your walking, giving you the option to move forward and backward or to the sides.</p>
<p>Squeeze the trigger to grab hold on the item. Use your sticks to move the item in any direction. Combine with <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> to jank the item with force, or use <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> by itself to just punch your target.</p>
<p>Push buttons by squeezing them. Levers can be pulled by squeezing them and moving with the sticks. Wheels can be rotated by rotating the right stick. You may try to loosen it by holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> and loot it with <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy">.</p>
<p>The shortcut for opening a container is holding down <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_C.svg" alt="Embodied manipulation" loading="lazy">. Not using shortcuts, you will open a chest by placing your hand on the lid and move it with the sticks. Unlocking a chest would be done by equipping the key to your right hand, placing your left hand on the lock and then raising your right hand. Insert the key by squeezing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> and then rotate it with <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_R.svg" alt="Embodied manipulation" loading="lazy">.</p>
<p>You can open doors in a similar way, or do it quickly by pressing <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L1.svg" alt="Embodied manipulation" loading="lazy"> while you are pressing up against the door.</p>
<!--kg-card-end: markdown--><h3 id="inspecting"><strong>Inspecting</strong></h3><!--kg-card-begin: markdown--><p>Press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_R3.svg" alt="Embodied manipulation" loading="lazy"> to inspect your target. It will mark up situational relevant things in your environment representing the awareness and knowledge of your avatar, lingering for a while like short-term memory.</p>
<p>The thing you are looking at with <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_R.svg" alt="Embodied manipulation" loading="lazy"> is your target. Inspecting will display more in-depth information of the current target, including tips for available actions and how the thing relates to your quests and places you know.</p>
<p>Inspecting your hand will let you rotate it with <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_L.svg" alt="Embodied manipulation" loading="lazy">, including the item you are holding. Holding the item in your left hand allows you to manipulate it with your right hand.</p>
<!--kg-card-end: markdown--><h3 id="crafting"><strong>Crafting</strong></h3><!--kg-card-begin: markdown--><p>Hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy"> to get your tool from the menu. Hold the thing you want to modify in your left hand and process it with your right hand by holding <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy">, and directing your action with your right stick. You may for example put a knife in your right hand and take hold of a tree branch with your left hand, for making an arrow or spear.</p>
<p>Place things together by releasing an item you&apos;re holding while looking at the other item. Attach one item to another by having the thing you want to attach equipped to the right hand, place the left hand at the target or hold the target with your left hand, and then look at the target while you raise your right hand and press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_S.svg" alt="Embodied manipulation" loading="lazy">.</p>
<!--kg-card-end: markdown--><h3 id="talking"><strong>Talking</strong></h3><!--kg-card-begin: markdown--><p>The <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_T.svg" alt="Embodied manipulation" loading="lazy"> is used for mind-stuff, like dialogue, quest-tracking or magic. Hold <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_T.svg" alt="Embodied manipulation" loading="lazy"> to select what to do from a radial menu for fast action or go one step further for a more comprehensive list of options.</p>
<!--kg-card-end: markdown--><h3 id="careful-or-fast"><strong>Careful or Fast</strong></h3><!--kg-card-begin: markdown--><p>Press <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_L3.svg" alt="Embodied manipulation" loading="lazy"> to toggle sprint mode.</p>
<p>While in <em>normal</em> mode, you will behave civilized among people, actively avoiding bumping into things or people and avoiding climbing on stuff just by walking towards things. You will also refrain yourself from stepping over cliff edges and falling to your death.</p>
<p>Tilting <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_L.svg" alt="Embodied manipulation" loading="lazy"> in normal mode will increase the movement to running after about two seconds. Bumping up against obstacles while not running will make you stop for a second and then find a reasonable way to continue to the place you&#x2019;re looking at, by moving in a direction similar to the direction of <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_L.svg" alt="Embodied manipulation" loading="lazy">. You will go around obstacles if you can avoid them by one or two steps in either direction. If there&apos;s no way to step over or around the obstacle, you will walk over it.</p>
<p>By entering sprint mode, you will have to take responsibility for your own safety. You may still choose your actual speed by how much you move <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_button_analog_L.svg" alt="Embodied manipulation" loading="lazy">, but the maximal speed will be much greater and you will also change your speed faster. You will automatically step over or press through anything that comes in your way. The main difference is your speed and lack of safety net and that you don&#x2019;t care if you break things in your way by pushing them to the side.</p>
<p>You will still have to manually jump or climb over things that reach over your waist. You must still use <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_L2.svg" alt="Embodied manipulation" loading="lazy"> + <img src="https://blog.jonas.liljegren.org/assets/images/ps/PlayStation_4_button_R2.svg" alt="Embodied manipulation" loading="lazy"> to grab hold of edges if needed during a jump. Engaging in combat in sprint mode will trade speed for increased vulnerability and faster stamina drain.</p>
<!--kg-card-end: markdown--><p>[[<a href="https://www.gamedev.net/blogs/entry/2293465-embodied-manipulation-a-control-scheme-for-immersive-sim-gameplay/?ref=blog.jonas.liljegren.org">https://www.gamedev.net/blogs/entry/2293465-embodied-manipulation-a-control-scheme-for-immersive-sim-gameplay/</a>]]<br>[[<a href="https://www.reddit.com/r/gamedesign/comments/zn12h1/embodied_manipulation/?ref=blog.jonas.liljegren.org">https://www.reddit.com/r/gamedesign/comments/zn12h1/embodied_manipulation/</a>]]<br>[[<a href="https://www.facebook.com/aigan/posts/10159087820897393">https://www.facebook.com/aigan/posts/10159087820897393</a>]]<br>[[<a href="https://twitter.com/aigan/status/1647581129665306624?ref=blog.jonas.liljegren.org">https://twitter.com/aigan/status/1647581129665306624</a>]]</p>]]></content:encoded></item><item><title><![CDATA[Traversal freedom]]></title><description><![CDATA[A systemic game should provide variety that invites use of different tools and tactics without strictly enforcing those.]]></description><link>https://blog.jonas.liljegren.org/traversal-freedom/</link><guid isPermaLink="false">638d29ffd218f00485be7c70</guid><category><![CDATA[systemic]]></category><category><![CDATA[horizon]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Mon, 05 Dec 2022 22:56:19 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2022/12/Horizon2-climbing-invisible-wall-crop.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.jonas.liljegren.org/content/images/2022/12/Horizon2-climbing-invisible-wall-crop.jpg" alt="Traversal freedom"><p>This is part of my series about <a href="https://blog.jonas.liljegren.org/tag/systemic/">my design for a systemic story game</a>.</p><p>The world can be linear or open. The environment can be hand-crafted or procedural. But more important is the requirements of the story structure. Is the story scripted or systemic? Most games use a mix of all of the above. But the needs of the story will usually result in limits of the available verbs in specific places. Verbs are the actions in the game, like walk, run, jump, hit, climb, open, use. The needs of the story will keep the player from going in the wrong direction or doing the wrong thing by disabling verbs. You will see that you often aren&apos;t allowed to hurt friendly characters, or you may not be able to open a door before you do what&apos;s expected in a certain room.</p><p>A systemic game has locations with properties that interact with each other and the actions of the player using rules that apply everywhere in the game. That allows the player to find solutions to puzzles, quest objectives or scenarios that the game designer did not consider. The much more common variant is the scripted game where places in the world are marked up and rules for what happens depend on quest progression.</p><h2 id="invisible-walls">Invisible walls</h2><p>Games like <em>Horizon</em>, <em>Tomb Raider</em> and <em>Uncharted</em> are infuriatingly bad in this respect. It becomes a game about guessing where the creator wants you to go. Some classic adventure games do it better with the avatar just stating that they don&#x2019;t want to go that way or do that specific thing. <em>Detroit Become Human</em> will show &#xA0;a visible barrier in the world stating that the place or action is not available since it&#x2019;s not in line with your current objective.</p><p>The design team will usually develop a consistent style for indicating where you can and can&#x2019;t go. In some games, wines indicate unclimbable walls, while in other games they indicate the opposite. And I really don&#x2019;t like it. Lara Craft will jump and climb all over the place but can&#x2019;t for her life find it in her to climb over a piece of rubble on the street. Aloy will push through narrow cracks in deep underwater caverns, but stands dumbfounded in front of a relic ruin with gaps between the beams in the wall, far wider.</p><p>The very first scene in <em>Horizon Forbidden West</em> has a whole bunch of these walls. There are thickets, rubble and walls she should be able to pass. The invisible wall breaks the immersion and puts a damper on the sense of exploration. Even worse; you see the way forward, but can&#x2019;t go where. The jump button has been disabled. And if you are like me and turn off all the screen UI for maximal immersion, you will easily miss that the game wants you to both collect and use the healing herbs before you continue. Neither Aloy or Varl says anything at the ledge. The jump/climb button doesn&#x2019;t work. I was about to reload the game because this seemed like a bug. &#x2013; But this is just one of thousands of similar examples. You are supposed to be able to read game developers&apos; minds.</p><p>There are games with less invisible walls. <a href="https://blog.jonas.liljegren.org/tomb-raider/">The first generation of <em>Tomb Raider</em></a> was excellent. The block based design made everything perfectly consistent. There was a complete mapping between all your moves and everything in the environment. Other examples are Dying<em> Light</em> and <em>Death Stranding</em> that use systems to determine where you can run and climb, rather than manually placed borders and tags.</p><h2 id="level-design">Level design</h2><p>Adventure puzzles are usually scripted in a way where the game designer accounted for all the allowed solutions. A systemic puzzle may instead be characterized as a problem that can be solved in several different ways, using the interactions of tools on the environment and objects.</p><p>Just disabling verbs in order to limit the choices for solving a puzzle is lazy design. I would prefer to use the knowledge of the game to figure out what I can do. I don&apos;t like the manually marked climbing and grappling points in <em>Horizon Forbidden West</em> or <em>God of War</em>. Each tool should have a defined and logical interaction with every other object in the game. <a href="https://blog.jonas.liljegren.org/nethack/">See NetHack</a>.</p><p>Games will often impose limitations in where you can go as a way to optimize for fun. By limiting the players options, they will have to handle the situation in new ways. I will always try to find a safe way to survive combat, often climbing up to an advantage and peeking out from as far away as I can. But doing the same thing every time might get boring after a while. I hate to get locked in a room with nowhere to run or hide. It feels okay if it happens naturally as part of the story, but I hate it if I see a way to do it better, but the game stops me for no good in-world reason.</p><p>A non-lazy level design will naturally vary viable tactics. Don&#x2019;t have things that look climbable if it&#x2019;s part of the puzzle to find another way up. Don&#x2019;t provide a clear view of the enemy from a hidden vantage point if the intent is to have a variety of encounters. Many games do this well for combat encounters, but not so well for puzzle rooms.</p><p>A game will usually introduce a game mechanic in the form of a tool or skill and follow that up with a series of situations where the newly introduced mechanic can be used. It&#x2019;s a common problem that the player may have gotten used to and prefer another tool and try to brute force progression. A non-systemic game can force the player to use the intended mechanic to proceed. A systemic game will have to find other ways to make sure that the player actually learns the intended mechanic. One such way would be an actual in-world guided training scenario with some sort of judge commenting on your result.</p><p>A systemic game should provide variety that invites use of different tools and tactics without strictly enforcing those. Let&apos;s say you have explosives that would break open a door, but the current puzzle is set up for you to find and use a key. You may start with a hint that the key can be found. The way to the door may go through water, making the explosive unusable. The explosive may also cause sound attracting unwanted attention. And it could also cause the wall to fall down or nearby lanterns to explode or start a fire burning up the things you wanted from behind the door. These are results you often don&#x2019;t see in authored games, since that would be too many permutations to handle.</p><p>The game should continuously evaluate if the player is stuck in a place, or generally seems frustrated. A systemic world will allow avatars to get themself in places they can&#x2019;t get themself out of. It should always help the avatar to climb or move out of narrow spaces, back to a previous position. The game should always check that the player can solve the current situation. For example, if the avatar is stuck between the door and a recently collapsed hallway, and doesn&apos;t have any of the known ways to get through the door or get back out, the game should introduce something appropriate for the situation. It could be that someone opens the door from the other side, or the rubble shifted to provide a way to squeeze through back out, or someone eventually comes to the rescue.</p><p>You can also encourage the player to use different approaches by altering the rewards, through the connected systems. Some tools may destroy things that would be valuable to collect using other more specific techniques. It may be an optional reward connected to speed or skill. Varying the situations should be enough to promote variation in approach without limiting what you actually can do. A rich system of interaction would allow the player to find their own way.</p><p>[[<a href="https://www.gamedev.net/blogs/entry/2283683-traversal-freedom/?ref=blog.jonas.liljegren.org">https://www.gamedev.net/blogs/entry/2283683-traversal-freedom/</a>]]<br>[[<a href="https://www.facebook.com/aigan/posts/10159084463337393">https://www.facebook.com/aigan/posts/10159084463337393</a>]]<br>[[<a href="https://twitter.com/aigan/status/1646553961321705477?ref=blog.jonas.liljegren.org">https://twitter.com/aigan/status/1646553961321705477</a>]]</p>]]></content:encoded></item><item><title><![CDATA[Health in games]]></title><description><![CDATA[Replacing health can lead to deeper immersion, clearer understanding an interesting depth.]]></description><link>https://blog.jonas.liljegren.org/health-in-games/</link><guid isPermaLink="false">63640261d218f00485be7b5b</guid><category><![CDATA[horizon]]></category><category><![CDATA[systemic]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Sun, 13 Nov 2022 14:45:36 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2022/11/horizon2-start.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.jonas.liljegren.org/content/images/2022/11/horizon2-start.jpg" alt="Health in games"><p>This is part of my series about <a href="https://blog.jonas.liljegren.org/tag/systemic/">my design for a systemic story game</a>. I will be reflecting on aspects of Horizon Forbidden West, how it differs from Horizon Zero Dawn, and what I would like to see in a future systemic story game. Topics sorted in order of appearance. Starting at the beginning.</p><p>The concept of health points comes from old tabletop games such as Dungeons and Dragons. It&apos;s a simple abstraction of the real world complexities. With computers keeping track of the game, it should be possible to do something much more interesting.</p><h2 id="health-bar-as-user-interface">Health bar as user interface</h2><p>For a typical action game where you are trying to stay alive, the health bar serves as a clear indication to the player of how close you are to death. Even if the game uses a more intricate simulation of several factors, we would still need to aggregate all that data to help the player gauge the situation.</p><p>Most people learn to filter out things on screen that&apos;s not relevant to the current situation. When things get chaotic, it&apos;s easy to miss important information about the state of the player represented by bars and icons in the corner of the screen. New players will often understand the meaning of the UI and will have no time to try to understand what it means while there are dangers in the game.</p><p>Game UI can be flat, diegetic, spatial or meta. The traditional health bar in the corner of the screen is an example of flat UI. Example of Diegetic UI in Horizon is when Aloy will turn her head towards things you can interact with. Herbs you can pick up will have blue butterflies flying around them. Machines will display their current state by the color of their lights and their sounds. The interaction markers such as grappling points are an example of spatial UI.</p><p>In a third-person game, where you control a character that you also can see on screen, you embody the character but also look at it from the outside. The screen is not the eyes of the character, but some effects modify the screen as if it&#x2019;s connected to the character. When the character gets blinded, you will experience a similar effect. That is meta UI. When Aloy is close to death, the corners of the screen will display a red haze, and you will feel her heartbeat through haptic feedback.</p><p>I personally hate Game interface elements popping up on the screen calling for attention. I usually turn off everything I can to the point where the screen only contains the beauty of the world. Aloy in Horizon will turn her head towards things you can interact with. Herbs you can pick up will have blue butterflies flying around them. Machines will display their current state by the color of their lights and their sounds. I like the system where I have access to the information on demand, by touching/swiping the touchpad.</p><p>There could be a lot of diegetic and meta UI that could replace the need of a health bar, such as blurred vision, limping, noises of pain, marks on the body and clothes, damaged equipment, breathing, heartbeats and more.</p><p>The Infamous games don&apos;t have a health bar. In the Second son, you will get smudges at the end of the screen, then desaturated colors, and then audio changes with vibrations indicating how close to death you are. Uncharted has a similar system, except that it&#x2019;s actually a luck meter. The more close calls you have in short succession, the closer you are to your luck running out, resulting in the next bullet actually hitting you.</p><h2 id="the-logic-of-health-points">The logic of health points</h2><p>Having healthpoints is not realistic. There are games where you can magically fully restore health by a potion. Yet, when your companion gets hurt, you have no ability to just use one of your potions to heal them. And at certain points in the story, you get knocked out and have to spend several moments or days or weeks recovering. You could have easily handled much worse injuries in normal gameplay. There is a disconnect between the story and the gameplay.</p><p>There are lots of games that don&apos;t have or at least expose health as a number of points. In the 1985 game Ghosts &apos;n Goblins, you will start out almost naked, but can find and put on a suit of armor. That armor will protect you from one hit but you will also lose the armor.</p><p>I want to clear up three different concerns in choosing how to design the game mechanics of healing. The first is the simulation of the real world. The second is to have the mechanic understandable with feedback communicating states and changes between states making the player understand the situation. The third is to have a depth of interconnectivity that will give rise to more interesting combinations than anyone can ever grasp.</p><p>Simulation is interesting in itself but could easily be boring. A game will bend the physics of the world to suit the gameplay and story. Simulating details beyond the comprehension of the player is useless. The point of simulation is how it creates a relation to the known world. We can connect what happens in the game with knowledge and experience from our life and from other stories and games. There are still so many aspects of stories that haven&apos;t been converted to game mechanics.</p><p>What does it mean to have 100 health points? How does it differ from 99 or 101? It&#x2019;s not clear what it means for the player and it&#x2019;s not deep. When you hit an enemy you want to know what it actually did. You want a reaction and also see the difference. That will also let you know what the enemy still can do and how close it is to surrender. Giving the enemy 100 hit points would mean having 100 different animations and textures. &#x2013; The practical hitpoints translate to the number of hits it takes to defeat an enemy. As a rule of thumb. You should never have to hit the enemy more than three times before you can visibly see the change.</p><p>I like the design in Horizon Zero Dawn where the machines have lots of parts. You will have to remove protective plating to expose vulnerable parts, and usually make the machine stand still in order to find the right angle and hit the right spot. All the damage is predictable. The randomness only comes from the difficulty to actually hit the right spot due to movement. I would have liked the game to develop this aspect even more by not having large pools of hit points but rather many parts for different functions, like sight, mobility, and so on, that can be disabled by using the right weapon in the right spot.</p><p>More interesting than hitpoints is the actual states and parts. Some of them can be timed. You could have a boss with no hitpoints. First you knock its shield off. Then you stagger it. Then you knock it down. Then you defeat it. It will try to counter you and strike back, but do so in different ways depending on its state. And it will stand up and pick up its shield if it gets the chance. Rather than hitpoints, it could have levels of stress and tiredness. You could add other stuff, but the point is that the player can learn the state of the enemy without the need for hitpoints. And the same goes for the player health.</p><h2 id="systems">Systems</h2><p>I&#x2019;m proposing to replace the basic health points with a combination of systems connected to the world you can interact with. It would open up more possibilities to try out different combinations of things to affect your state. You could use more of your prior world knowledge to form ideas about how things might work and what to try.</p><p>So it&#x2019;s not about realism for its own sake. An action oriented game could be frustrating if the player would lose mobility due to injury. The system should not take away from the fun of the game. Making a mistake resulting in an injury should not take away from your survivability. And you should not have to do boring stuff, like gathering healing herbs and resting, just because you weren&apos;t perfect in the last encounter.</p><p>I often see players run through lakes and jump down cliffs just because it entails slightly less effort than taking a couple of steps to the side and going over the bridge or taking the stairs. Behaving like that outside of battle or time sensitive situations should at least decrease the level of comfort. It should take a long time to dry out clothes and running in wet shoes should increase the risk of abrasions. Doing stuff like that should be visible in the mood of the character, taking her out of the &#x201C;well rested&#x201D; state. Discomfort should build up slowly, just as a nudge for players wanting the immersion, without hindering those who choose to ignore it. That is, let players run/fly everywhere if they want, but I would love the game to recognize when I&#x2019;m taking care of my avatar. The game should recognize and reward things you would do if this was real, while still enabling doing awesome stuff and not take away from the fun of combat.</p><p>Generic health-points can be replaced with things like stamina, pain, stress, stagger, daze, bleeding, and so on. Stamina that starts generating after a couple of seconds is loosely based on ATP. You can find suitable connections to the real world through blood oxygen, pressure, sugar, hydration, nutrients, cortisol, adrenaline, endorphins, glycogen and ATP.</p><p>A system of adrenaline can be used to give the player a good chance to fight back even after injuries. They have a certain number of seconds to fight back or escape, and then a certain number of minutes until they must stop and rest and take care of wounds. A sprained ankle should result in sound, animations and screen effects, but only have a small effect during the immediate battle. Horizon Forbidden West has the crushed status effect that doesn&apos;t stop the player from continuing the fight, but it does stack up future cost, as it would if you would continue to run with a sprained ankle. After the battle and a few minutes after you stopped running, the ankle will swell to begin healing, thus limiting your mobility. You will not be able to sprint, in the same way as you would actively try to keep pressure off the swollen part of the body.</p><p>The power of games is that it&#x2019;s possible to cut out all the boring parts. Finding your way back to safety is interesting if there is a real risk of failure. Taking care of the injury can be interesting the first time you do it. Finding ways to heal can be an adventure in itself. But after you mastered the process, or already gathered all the things you need for it, we could just skip the details. Resting at a camp would imply taking care of injuries and equipment. Games often do this skipping of details through a skill-tree where you don&#x2019;t have to go through all the steps of upkeep in the later parts of the game.</p><p>The level of detail for healing would depend on the type of game. If the game mostly consists of the same type of combat over and over again, you would probably not use this type of system. But I would love it if Horizon had a mode of play where you only could heal at a camp and only craft stuff at a bench.</p><p>For the systemic story game I would like to see, every fight would be unique and part of the story. The game will try to give the player different outcomes, in such a way that you would not have to do the same type of recovery in the same way. More on that later.</p><p>[[<a href="https://www.gamedev.net/blogs/entry/2283684-health-in-games/?ref=blog.jonas.liljegren.org">https://www.gamedev.net/blogs/entry/2283684-health-in-games/</a>]]<br>[[<a href="https://www.facebook.com/aigan/posts/10159003994567393">https://www.facebook.com/aigan/posts/10159003994567393</a>]]<br>[[<a href="https://twitter.com/aigan/status/1645444910126964742?ref=blog.jonas.liljegren.org">https://twitter.com/aigan/status/1645444910126964742</a>]]</p>]]></content:encoded></item><item><title><![CDATA[Horizon Zero Dawn Deep Dive]]></title><description><![CDATA[Being smart will count for nothing if you don’t make the world better.
]]></description><link>https://blog.jonas.liljegren.org/horizon-zero-dawn-deep-dive/</link><guid isPermaLink="false">624b35e0fb356f5697b8907e</guid><category><![CDATA[horizon]]></category><category><![CDATA[protopia]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Tue, 28 Jun 2022 16:13:49 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2022/06/point-of-the-spear-6-jl1.jpg" medium="image"/><content:encoded><![CDATA[<blockquote>Rost: The strength to stand alone, Aloy, is the strength to make a stand. To serve a purpose greater than yourself.</blockquote><img src="https://blog.jonas.liljegren.org/content/images/2022/06/point-of-the-spear-6-jl1.jpg" alt="Horizon Zero Dawn Deep Dive"><p>Full spoilers for Horizon Zero Dawn. No spoilers for the Forbidden West. I wrote <a href="https://blog.jonas.liljegren.org/horizon-zero-dawn/">a mostly spoiler free article here</a>.</p><p>Horizon is a beautiful, emotional and intellectually fascinating combination of technology, ecology, politics, psychology and spirituality. I see many connections to both technological optimism, deep ecology, spiritual science and egalitarianism.</p><p>I&apos;m interested in positive alternatives for a better future. What can we do to make the Utopia real? I&apos;m envisioning a harmony of <strong>nature and technology</strong> with people living in peace and creative freedom.</p><p>I&apos;m not an expert in these topics. I&apos;m just trying to explain what it is I find interesting in how this world is presented. I&apos;ll try to put it into words.</p><p>Here is the things I written about, in a series of separate posts:</p><ol><li><a href="https://blog.jonas.liljegren.org/hunter-gatherer-tribes/">Hunter-gatherer tribes</a></li><li><a href="https://blog.jonas.liljegren.org/mother-goddess-and-matriarchy/">Mother goddess and Matriarchy</a></li><li><a href="https://blog.jonas.liljegren.org/taboos-and-shunning/">Taboos and Shunning</a></li><li><a href="https://blog.jonas.liljegren.org/rite-of-passage-and-heros-journey/">Rite of Passage and Hero&apos;s Journey</a></li><li><a href="https://blog.jonas.liljegren.org/religion-and-gnosis/">Religion and Gnosis</a></li><li><a href="https://blog.jonas.liljegren.org/automation-and-unconditional-basic-income/">Automation and Unconditional Basic Income</a></li><li><a href="https://blog.jonas.liljegren.org/climate-change/">Climate change</a>.</li><li><a href="https://blog.jonas.liljegren.org/runaway-replication/">Runaway replication</a></li><li><a href="https://blog.jonas.liljegren.org/neurodiversity-eccentricity/">Neurodiversity eccentricity</a></li><li><a href="https://blog.jonas.liljegren.org/emotional-computer-intelligence/">Emotional computer Intelligence</a></li><li><a href="https://blog.jonas.liljegren.org/holistic-ecology/">Holistic ecology</a></li><li><a href="https://blog.jonas.liljegren.org/terraforming/">Terraforming</a></li><li><a href="https://blog.jonas.liljegren.org/biomimetic-robotics/">Biomimetic robotics</a></li><li><a href="https://blog.jonas.liljegren.org/gamified-education/">Gamified education</a></li></ol><h2 id="the-point-of-the-spear">The Point of the Spear</h2><p>The beginning mission &quot;The Point of the Spear&quot; gives you the point of the game. To care about the petty narrow-minded people that has done nothing than shunned you.</p><blockquote><strong><strong>Aloy:</strong></strong> My tribe?! You said I wouldn&#x2019;t need them.</blockquote><blockquote><strong><strong>Rost:</strong></strong> But I never said the tribe wouldn&#x2019;t need you! The strength to stand alone, Aloy, is the strength to make a stand. To serve a purpose greater than yourself. That is the lesson you must learn. And remember it&#x2026; after the Proving, and after I am gone.</blockquote><p>When the tribe finally realize that Aloy do have something of value to give, they fall to their knees:</p><blockquote><strong>Aloy:</strong> No! NO! Stop this! Up! UP! First you shun me, now this?! I will NOT be worshiped! I&#x2019;m not your &quot;Anointed!&quot; I don&#x2019;t belong to you! There&#x2019;s a whole world beyond your borders. Whole tribes of people just as good as you, and it is all in danger! It&#x2019;s a world worth fighting for. Not just here. Everywhere.</blockquote><p>The game continually shows the limits of dogma. Ted thought the humans would be better of by returning to nature with a life without technology. But lack of knowledge will not end suffering. The technology can be used to destroy nature and all living things. But it can also be used to ease suffering, restore life and build a better world.</p><p>I have met people that has developed a scepticism against technology, and especially the view that environmental problems can be solved with advanced technology. There are a lot of valid criticisms against several techno utopian proposals. But that doesn&apos;t mean that the only solution is to revert to a life without computers or electricity. I believe nature and technology can live in harmony.</p><p>The game as a whole is a meditation on humanity in the space between nature and technology.</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/Fkg5UVTsKCE?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="Horizon Zero Dawn - E3 2015 Trailer | PS4"></iframe></figure><blockquote><strong>Miriam:</strong> Being smart will count for nothing if you don&#x2019;t make the world better. You have to use your smarts to count for something, to serve life, not death.</blockquote><p>[[<a href="https://www.facebook.com/groups/105986599829686/posts/1436161476812185/">https://www.facebook.com/groups/105986599829686/posts/1436161476812185/</a>]]<br>[[<a href="https://twitter.com/aigan/status/1642919433881493507?ref=blog.jonas.liljegren.org">https://twitter.com/aigan/status/1642919433881493507</a>]]</p>]]></content:encoded></item><item><title><![CDATA[Gamified education]]></title><description><![CDATA[<p>Play is the natural way children learn. The passion for play has lead to people developing games in many different forms. We have physical and mental games. Indoor and outdoor games. Imaginative and intellectual games. The advancement of computers has led to new possibilities in the types and scopes of</p>]]></description><link>https://blog.jonas.liljegren.org/gamified-education/</link><guid isPermaLink="false">62b0b567fb356f5697b8a82b</guid><category><![CDATA[horizon]]></category><category><![CDATA[software]]></category><dc:creator><![CDATA[Jonas Liljegren]]></dc:creator><pubDate>Tue, 21 Jun 2022 10:40:27 GMT</pubDate><media:content url="https://blog.jonas.liljegren.org/content/images/2022/06/focus-interface.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.jonas.liljegren.org/content/images/2022/06/focus-interface.jpg" alt="Gamified education"><p>Play is the natural way children learn. The passion for play has lead to people developing games in many different forms. We have physical and mental games. Indoor and outdoor games. Imaginative and intellectual games. The advancement of computers has led to new possibilities in the types and scopes of games.</p><p>We look at successful games to learn about motivation and engagement. Different people like different games. The important part is that the player is given the space to discover and select their own goals with the prospect to learn something new and achieve something meaningful. The game should give the player clear feedback in a way that facilitates mastery and celebrates accomplishments. It will show the progress towards the player-selected goals. It will adapt the level and pacing of challenges to keep up the interest.</p><p>Most traditional systems of educations has some of these things, like tests and degrees. But we can do more to use what we learned about the psychology of motivation to make learning stuff better. Computers also has the potential to personalize the material to each individual person. Combine this computerized gamified education with physical and social activity, creating and carrying out projects to solve real world problems.</p><p>[[<a href="https://twitter.com/aigan/status/1642386137418199040?ref=blog.jonas.liljegren.org">https://twitter.com/aigan/status/1642386137418199040</a>]]</p>]]></content:encoded></item></channel></rss>