<?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:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Making Kumu]]></title><description><![CDATA[Follow along as we rewrite our product in public.]]></description><link>https://making.kumu.io</link><image><url>https://substackcdn.com/image/fetch/$s_!p3Hv!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccf8d1e7-b806-4ada-a6e7-fdd821be5ac8_978x978.png</url><title>Making Kumu</title><link>https://making.kumu.io</link></image><generator>Substack</generator><lastBuildDate>Sun, 03 May 2026 01:09:01 GMT</lastBuildDate><atom:link href="https://making.kumu.io/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Dan]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[makingkumu@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[makingkumu@substack.com]]></itunes:email><itunes:name><![CDATA[Dan]]></itunes:name></itunes:owner><itunes:author><![CDATA[Dan]]></itunes:author><googleplay:owner><![CDATA[makingkumu@substack.com]]></googleplay:owner><googleplay:email><![CDATA[makingkumu@substack.com]]></googleplay:email><googleplay:author><![CDATA[Dan]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Decoding Kumu]]></title><description><![CDATA[Why we're moving away from users writing code]]></description><link>https://making.kumu.io/p/decoding-kumu</link><guid isPermaLink="false">https://making.kumu.io/p/decoding-kumu</guid><dc:creator><![CDATA[Dan]]></dc:creator><pubDate>Sun, 14 Apr 2024 17:25:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff68c5725-8bc7-49b5-88bc-f5a41747d479_892x552.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Technical tools trend towards code. The more extensible a tool needs to be, the more likely it is that someone outside of the development team has to write some code. Sometimes that&#8217;s people creating plugins, scripts, or extensions. Sometimes it&#8217;s people writing formulae or filters. The expressive power of code helps bridge a void that might otherwise involve <em>incredibly complicated</em> user interfaces.</p><p>You can&#8217;t go very far with Kumu without needing to roll up your sleeves, open up <a href="https://docs.kumu.io/">the docs</a>, and get your hands dirty <a href="https://docs.kumu.io/overview/user-interfaces/view-editors#advanced-editor">writing some code</a>. It&#8217;s not a coincidence that many of the prolific and successful mappers in our community have a technical background, but Kumu isn&#8217;t a tool for programmers. It&#8217;s a tool for anyone that wants to make sense of connected complexity.</p><p>Kumu (as you know it today) uses a homemade language that is a dialect of <a href="https://en.wikipedia.org/wiki/CSS">CSS</a> for defining <a href="https://docs.kumu.io/guides/views">views</a>. It&#8217;s not a language that has a name, or any kind of formal specification. We started with CSS (the language browsers use for styling web pages) and translated some of the concepts to apply them to networks. Behind the scenes there&#8217;s a forked <a href="https://postcss.org/">PostCSS</a> parser, that we&#8217;ve extended to understand concepts like <a href="https://docs.kumu.io/overview/advanced-editor-hub/settings-reference">@settings</a>, <a href="https://docs.kumu.io/overview/advanced-editor-hub/controls-reference">@controls</a>, and <a href="https://docs.kumu.io/guides/selectors#traversals">traversal selectors</a>.</p><p>The decision to define views with code has saved us a huge amount of incidental complexity over the years. Adding new style properties is trivially easy. We already have the machinery in place to support powerful ideas, such as <a href="https://docs.kumu.io/guides/partial-views">partial views</a>, without ever having to think about how to give them a user interface.</p><p>The problem is that the complexity is still there, we&#8217;re just offloading it to our users instead. To use Kumu, they&#8217;ll have to learn to write code.</p><p>To tell a compelling story using Kumu, you&#8217;ll need to spend <em>far</em> more time in documentation than you would with most tools. You&#8217;ll need to understand concepts like <a href="https://docs.kumu.io/guides/selectors">selectors</a>. You&#8217;ll need to have an intuition for syntactic correctness, and fixing problems from our relatively vague parsing errors. Heck, for a long time, you even needed to know how to resolve Git-style <a href="http://help.kumu.io/guides/conflicts.html">merge conflicts</a> when multiple people were editing concurrently.</p><p>If you have a technical background, this isn&#8217;t a huge ask. Compared to modern day text editors, you&#8217;ll probably notice the lack of automatic completions and intellisense though. There&#8217;s some jank as controls modify the current view and we serialise the internal syntax tree back to CSS (clobbering most comments and any personal formatting preferences). It can be frustrating, but armed with the documentation, you can be reasonably productive, reasonably quickly.</p><p>If you don&#8217;t have a technical background, Kumu can be a bit of a scary place. We have a <a href="https://docs.kumu.io/overview/user-interfaces/view-editors#basic-editor">&#8220;Basic Editor&#8221;</a> which gives users access to an important subset of the power of views, but most projects need to go beyond that subset. <em>Most</em> people who use Kumu will need to learn to use the advanced editor, and learning to use the advanced editor is still a significant hurdle.</p><p>These are the kinds of hurdles we&#8217;re aiming to remove forever as we re-imagine the tool. It has become one of the principles that&#8217;s guiding our design. <strong>Users should never need to write code to make maps</strong>.</p><h2>Advanced Editor</h2><p>Let&#8217;s take a look at a fairly simple style rule in the advanced editor to get a sense of the level of complexity here (it is easy to forget, if you&#8217;ve been using Kumu for a while).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ixxd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b45c226-6430-41f6-9079-9342b1fbef6b_988x732.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ixxd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b45c226-6430-41f6-9079-9342b1fbef6b_988x732.png 424w, https://substackcdn.com/image/fetch/$s_!Ixxd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b45c226-6430-41f6-9079-9342b1fbef6b_988x732.png 848w, https://substackcdn.com/image/fetch/$s_!Ixxd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b45c226-6430-41f6-9079-9342b1fbef6b_988x732.png 1272w, https://substackcdn.com/image/fetch/$s_!Ixxd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b45c226-6430-41f6-9079-9342b1fbef6b_988x732.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ixxd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b45c226-6430-41f6-9079-9342b1fbef6b_988x732.png" width="566" height="419.34412955465586" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3b45c226-6430-41f6-9079-9342b1fbef6b_988x732.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:732,&quot;width&quot;:988,&quot;resizeWidth&quot;:566,&quot;bytes&quot;:109802,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Ixxd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b45c226-6430-41f6-9079-9342b1fbef6b_988x732.png 424w, https://substackcdn.com/image/fetch/$s_!Ixxd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b45c226-6430-41f6-9079-9342b1fbef6b_988x732.png 848w, https://substackcdn.com/image/fetch/$s_!Ixxd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b45c226-6430-41f6-9079-9342b1fbef6b_988x732.png 1272w, https://substackcdn.com/image/fetch/$s_!Ixxd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b45c226-6430-41f6-9079-9342b1fbef6b_988x732.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>Legend Metadata</h4><p>We&#8217;ll kick off with the odd way we encode legend information. The comment (the <code>/* &#8230; */</code> syntax) above this rule is a directive which says:</p><ul><li><p>Include a preview of this style rule in the legend.</p></li><li><p>Render the preview as an element rather than a connection.</p></li><li><p>Use the label &#8220;Congress&#8221;.</p></li></ul><p>This has some symmetry with the way programmers often use doc comments to annotate the details of functions, but in Kumu there&#8217;s nothing obvious that links that comment to the legend.</p><h4>Selectors</h4><p>The next thing you&#8217;re hit with is an attribute <a href="https://docs.kumu.io/guides/selectors">selector</a>. It selects all elements with the type &#8220;Institutional Norms &amp; Processes&#8221;. This is how you decide which elements or connections will be styled. Most selectors are easy enough to read, but for many users, <em>writing</em> them by hand will require a trip to the documentation.</p><p>This is one way to write this selector, but you also have access to <a href="https://docs.kumu.io/guides/selectors#shorthand-selectors">shorthand syntax </a>for writing type selectors.</p><pre><code>["Element type"="Congress"] { ... }

/* is equivalent to */

congress { ... }</code></pre><p>The shorthand here is quicker to type and feels more familiar to folks with a CSS background, but users have to guess what our rules for normalising types are.</p><p>What would the shorthand be for the selector from the example?</p><pre><code><code>["Element type"="Institutional Norms &amp; Processes"] { ... }</code></code></pre><p>Well, it depends entirely on how our normalisation process handles the ampersand. It could be <code>institutional-norms-processes</code> or it could be <code>institutional-norms-and-processes</code>. I would bet on it being the former, but off the top of my head, I don&#8217;t actually know.</p><p>This also introduces an unfortunate bias towards people using the Latin alphabet. Want to take a guess at the shorthand selector for &#20351;&#29992;&#39640;&#32423;&#32534;&#36753;&#22120;? Software has a huge problem with <a href="https://en.wikipedia.org/wiki/Americentrism">Americentrism</a> and here we&#8217;re part of the problem!</p><p>Some of the complexity in selectors is invisible! Trying to figure out why one of your style rules is overriding another? Time to learn about <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity">specificity</a>!</p><p>Even the folks coming from CSS can have a hard time with selectors. Gone is the browser&#8217;s element tree, now you need to learn to think in <em>graphs</em>! There are no parent&#8212;child relationships, so you&#8217;ll need to learn about the syntactic extensions we&#8217;ve added, like traversals.</p><pre><code>person --&gt; organization</code></pre><p>Does this select all people that have a directed connection to organizations? Or does it select all organizations that have a directed connection <em>from </em>people?</p><p>If you come from CSS, you&#8217;re likely to assume it&#8217;s the latter, because of the associativity of CSS combinators. If you didn&#8217;t come from CSS, then you&#8217;ll need the docs to resolve the ambiguity.</p><h4>Style Properties</h4><p>And finally we get into the style properties inside the rule. These follow the traditional CSS key-value model, and when sensible, we&#8217;ve kept keys that overlap with CSS, but we&#8217;ve tweaked others which created confusion.</p><pre><code><code>["Element Type"="Institutional Norms &amp; Processes"] {
  color: #63A3AE;
  font-color: #111;
  size: 70;
  border-width: 0;
  text-align: center;
}</code></code></pre><p>For example, <code>color</code> will set the <em>background</em> <em>color</em> (not the <em>text color</em> like it would in CSS). Properties like <code>margin</code> and <code>padding</code> probably work like you&#8217;d expect, but they too come with caveats, such as requiring unitless values. No px or em here, please! Properties like <code>text-align</code> work on the vertical axis, because that&#8217;s more natural for element labels.</p><p>What&#8217;s this <code>#63A3AE</code> thing? To many people, it&#8217;s a meaningless jumble of letters. In fact (as you probably know if you&#8217;re reading this blog) it&#8217;s the hexadecimal representation of a color. The first pair of digits are the red channel, the second pair is the green channel, and the last pair is the blue channel. Even when you&#8217;ve gotten your head around hexadecimal numbers, RGB is a notoriously hard model for humans to work in. We&#8217;re terrible at figuring out how much green to subtract to make a colour less saturated, for example! Hex codes are a conveniently terse way to <em>express</em> color, but not to design or adjust it.</p><p>The example we&#8217;re looking at has five style properties and the syntax is approachable enough that it&#8217;s reasonably straightforward to read and to change. But consider that all style rules begin life as an empty block with no properties at all.</p><pre><code><code>["Element Type"="Institutional Norms &amp; Processes"] {
  
}</code></code></pre><p>Your cursor is there, blinking emphatically, waiting for you to start typing. There isn&#8217;t any more guidance than that. Either you&#8217;ve memorised our <a href="https://docs.kumu.io/overview/advanced-editor-hub/property-reference#supported-properties">property reference</a> or your next trip will be to the docs. Every single time you have to leave your map to read documentation disrupts your cognitive flow and the visits to the docs are an inescapable part of using the advanced editor.</p><h4>Syntax Errors</h4><p>So far we&#8217;ve only talked about the happy path where everything works first try. What happens when you make a mistake?</p><p>Well, it depends on the kind of mistake. An innocuous misspelling isn&#8217;t considered a syntax error. Are you the kind person who writes <code>colour</code> instead of <code>color</code>? That will be on you to spot. It&#8217;s technically feasible for us to detect unrecognised properties, but it would be harder than you&#8217;d expect due to the feature-by-feature parsing architecture we use.</p><p>When you do hit a legitimate syntax error, such as a missing brace or an unclosed quote, your whole map will revert to its unstyled form and we&#8217;ll show you a &#8220;descriptive&#8221; error.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6vhO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2577e77-e3a0-491a-942d-d221982122a0_996x398.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6vhO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2577e77-e3a0-491a-942d-d221982122a0_996x398.png 424w, https://substackcdn.com/image/fetch/$s_!6vhO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2577e77-e3a0-491a-942d-d221982122a0_996x398.png 848w, https://substackcdn.com/image/fetch/$s_!6vhO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2577e77-e3a0-491a-942d-d221982122a0_996x398.png 1272w, https://substackcdn.com/image/fetch/$s_!6vhO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2577e77-e3a0-491a-942d-d221982122a0_996x398.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6vhO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2577e77-e3a0-491a-942d-d221982122a0_996x398.png" width="628" height="250.94779116465864" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e2577e77-e3a0-491a-942d-d221982122a0_996x398.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:398,&quot;width&quot;:996,&quot;resizeWidth&quot;:628,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!6vhO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2577e77-e3a0-491a-942d-d221982122a0_996x398.png 424w, https://substackcdn.com/image/fetch/$s_!6vhO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2577e77-e3a0-491a-942d-d221982122a0_996x398.png 848w, https://substackcdn.com/image/fetch/$s_!6vhO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2577e77-e3a0-491a-942d-d221982122a0_996x398.png 1272w, https://substackcdn.com/image/fetch/$s_!6vhO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2577e77-e3a0-491a-942d-d221982122a0_996x398.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Maybe if we&#8217;d started building Kumu v2 in the days of <a href="https://microsoft.github.io/monaco-editor/">Monaco</a> and the <a href="https://microsoft.github.io/language-server-protocol/">Language Server Protocol</a> we&#8217;d have an advanced editor that gave you red squigglies and autocompletions, but our CSS language predates them both and retrofitting them now would be hard, if not impossible.</p><h2>New Editor</h2><p>The advanced editor has served us and thousands of others well for over a decade now. It has enabled us to iterate on features far faster than we ever would have done if we&#8217;d been needing to build user interface for every single style property we support.</p><p>All good things come to an end, and in v3 we&#8217;re saying goodbye to the advanced editor and hello to a more intuitive way to edit views.</p><p>Let&#8217;s take a look at that same style rule inside an early version of the new editor in Kumu v3.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Wkq9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e6325c-fff5-4604-9829-876d3cd2cd54_1012x1240.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Wkq9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e6325c-fff5-4604-9829-876d3cd2cd54_1012x1240.png 424w, https://substackcdn.com/image/fetch/$s_!Wkq9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e6325c-fff5-4604-9829-876d3cd2cd54_1012x1240.png 848w, https://substackcdn.com/image/fetch/$s_!Wkq9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e6325c-fff5-4604-9829-876d3cd2cd54_1012x1240.png 1272w, https://substackcdn.com/image/fetch/$s_!Wkq9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e6325c-fff5-4604-9829-876d3cd2cd54_1012x1240.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Wkq9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e6325c-fff5-4604-9829-876d3cd2cd54_1012x1240.png" width="472" height="578.3399209486166" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f1e6325c-fff5-4604-9829-876d3cd2cd54_1012x1240.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1240,&quot;width&quot;:1012,&quot;resizeWidth&quot;:472,&quot;bytes&quot;:145292,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Wkq9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e6325c-fff5-4604-9829-876d3cd2cd54_1012x1240.png 424w, https://substackcdn.com/image/fetch/$s_!Wkq9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e6325c-fff5-4604-9829-876d3cd2cd54_1012x1240.png 848w, https://substackcdn.com/image/fetch/$s_!Wkq9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e6325c-fff5-4604-9829-876d3cd2cd54_1012x1240.png 1272w, https://substackcdn.com/image/fetch/$s_!Wkq9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e6325c-fff5-4604-9829-876d3cd2cd54_1012x1240.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We&#8217;re bringing the editor much closer to what you&#8217;d expect to find in contemporary design tools, with <a href="http://figma.com/">Figma</a> being a particularly strong influence on how we&#8217;ve structured the interface.</p><p>This is <em>not</em> the finished product. We expect to do multiple rounds of refinements between now and the release of Kumu v3, but there&#8217;s enough here to give you a flavour of how it will eventually feel to create views in Kumu.</p><h4>Views &amp; Style Rules</h4><p>The first thing you may notice here is that we&#8217;re no longer looking at an entire view. Instead we&#8217;re focused in on a single style rule.</p><p>When you open a view, you&#8217;ll see a list of all the style rules it contains. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bfVq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed641550-1fc0-43cc-8d70-a2ca1d2fc23e_946x718.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bfVq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed641550-1fc0-43cc-8d70-a2ca1d2fc23e_946x718.png 424w, https://substackcdn.com/image/fetch/$s_!bfVq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed641550-1fc0-43cc-8d70-a2ca1d2fc23e_946x718.png 848w, https://substackcdn.com/image/fetch/$s_!bfVq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed641550-1fc0-43cc-8d70-a2ca1d2fc23e_946x718.png 1272w, https://substackcdn.com/image/fetch/$s_!bfVq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed641550-1fc0-43cc-8d70-a2ca1d2fc23e_946x718.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bfVq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed641550-1fc0-43cc-8d70-a2ca1d2fc23e_946x718.png" width="478" height="362.79492600422833" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ed641550-1fc0-43cc-8d70-a2ca1d2fc23e_946x718.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:718,&quot;width&quot;:946,&quot;resizeWidth&quot;:478,&quot;bytes&quot;:55814,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bfVq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed641550-1fc0-43cc-8d70-a2ca1d2fc23e_946x718.png 424w, https://substackcdn.com/image/fetch/$s_!bfVq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed641550-1fc0-43cc-8d70-a2ca1d2fc23e_946x718.png 848w, https://substackcdn.com/image/fetch/$s_!bfVq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed641550-1fc0-43cc-8d70-a2ca1d2fc23e_946x718.png 1272w, https://substackcdn.com/image/fetch/$s_!bfVq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed641550-1fc0-43cc-8d70-a2ca1d2fc23e_946x718.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Each rule has a style preview (same as you&#8217;d see in the legend) and if you&#8217;ve added a legend label, you&#8217;ll see that there too. If not, then you&#8217;ll instead see the <em>selector</em> that the rule uses, which is often the most accurate descriptor (it doesn&#8217;t look like a selector but it is. Read on!).</p><p>We also removed the idea of selector specificity whilst we were at it. Now your style rules are applied in the order they are defined. A rule at the bottom of the list beats a rule at the top of the list and you can drag and drop to re-arrange them.</p><h4>Selectors</h4><p>You can&#8217;t have Kumu without the concept of selectors. They&#8217;re an essential part of style rules, but we also use them for controls, for configuring clustering, focus, and showcasing, and even for presentations and widgets inside markdown. But there&#8217;s no escaping it, selectors are code and <strong>users should never need to write code to make maps</strong>.</p><p>Part of redesigning the editor involved a significant rethink of our selector builder (a process which deserves a whole post of it&#8217;s own).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!O_ZX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd78762bc-5395-4a1a-bb7c-e783de32498c_840x804.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!O_ZX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd78762bc-5395-4a1a-bb7c-e783de32498c_840x804.png 424w, https://substackcdn.com/image/fetch/$s_!O_ZX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd78762bc-5395-4a1a-bb7c-e783de32498c_840x804.png 848w, https://substackcdn.com/image/fetch/$s_!O_ZX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd78762bc-5395-4a1a-bb7c-e783de32498c_840x804.png 1272w, https://substackcdn.com/image/fetch/$s_!O_ZX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd78762bc-5395-4a1a-bb7c-e783de32498c_840x804.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!O_ZX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd78762bc-5395-4a1a-bb7c-e783de32498c_840x804.png" width="402" height="384.77142857142854" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d78762bc-5395-4a1a-bb7c-e783de32498c_840x804.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:804,&quot;width&quot;:840,&quot;resizeWidth&quot;:402,&quot;bytes&quot;:78934,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!O_ZX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd78762bc-5395-4a1a-bb7c-e783de32498c_840x804.png 424w, https://substackcdn.com/image/fetch/$s_!O_ZX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd78762bc-5395-4a1a-bb7c-e783de32498c_840x804.png 848w, https://substackcdn.com/image/fetch/$s_!O_ZX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd78762bc-5395-4a1a-bb7c-e783de32498c_840x804.png 1272w, https://substackcdn.com/image/fetch/$s_!O_ZX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd78762bc-5395-4a1a-bb7c-e783de32498c_840x804.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">An early look at the selector builder from v3</figcaption></figure></div><p>Instead of leaving you to get the syntax right on your own, you get to type freely and we&#8217;ll suggest tokens that you can use to build a selector. Not only does this tend to be faster, it&#8217;s far less mistake prone, because it&#8217;s impossible to make syntactic errors, and the filtering will often guide you towards picking an existing value, rather than ever finding yourself typing out &#8220;Institutional Norms &amp; Processes&#8221; by hand.</p><p>In those rare cases where you want to get at the underlying text, there&#8217;s still a way to hop back to editing manually!</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Bkuo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b7de8d1-b793-4d90-b404-e69838abd6b6_850x200.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Bkuo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b7de8d1-b793-4d90-b404-e69838abd6b6_850x200.png 424w, https://substackcdn.com/image/fetch/$s_!Bkuo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b7de8d1-b793-4d90-b404-e69838abd6b6_850x200.png 848w, https://substackcdn.com/image/fetch/$s_!Bkuo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b7de8d1-b793-4d90-b404-e69838abd6b6_850x200.png 1272w, https://substackcdn.com/image/fetch/$s_!Bkuo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b7de8d1-b793-4d90-b404-e69838abd6b6_850x200.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Bkuo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b7de8d1-b793-4d90-b404-e69838abd6b6_850x200.png" width="586" height="137.88235294117646" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9b7de8d1-b793-4d90-b404-e69838abd6b6_850x200.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:200,&quot;width&quot;:850,&quot;resizeWidth&quot;:586,&quot;bytes&quot;:26136,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Bkuo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b7de8d1-b793-4d90-b404-e69838abd6b6_850x200.png 424w, https://substackcdn.com/image/fetch/$s_!Bkuo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b7de8d1-b793-4d90-b404-e69838abd6b6_850x200.png 848w, https://substackcdn.com/image/fetch/$s_!Bkuo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b7de8d1-b793-4d90-b404-e69838abd6b6_850x200.png 1272w, https://substackcdn.com/image/fetch/$s_!Bkuo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b7de8d1-b793-4d90-b404-e69838abd6b6_850x200.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">This time, with red squigglies!</figcaption></figure></div><p>A <em>lot</em> of work went into figuring out a blend between a UI that would be approachable and UI that would be efficient compared to writing text. What you&#8217;re seeing above is actually &#8220;Selector Builder 5&#8221; but we finally feel like it&#8217;s into a really solid place.</p><p>I&#8217;m tactically sidestepping some of the unsolved challenges here. We&#8217;re still figuring out a natural way to build UI for traversal selectors and some kinds of parameterised psuedoselectors (think <code>:to</code> and <code>:from</code>) where you actually end up with selectors inside selectors. Maybe we&#8217;ll explore some of the options we&#8217;re considering in a future post about the selector builder.</p><h4>Style Properties</h4><p>Once you&#8217;ve tweaked the selector, all that&#8217;s left is to start editing the style properties!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Qvj8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff68c5725-8bc7-49b5-88bc-f5a41747d479_892x552.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Qvj8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff68c5725-8bc7-49b5-88bc-f5a41747d479_892x552.png 424w, https://substackcdn.com/image/fetch/$s_!Qvj8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff68c5725-8bc7-49b5-88bc-f5a41747d479_892x552.png 848w, https://substackcdn.com/image/fetch/$s_!Qvj8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff68c5725-8bc7-49b5-88bc-f5a41747d479_892x552.png 1272w, https://substackcdn.com/image/fetch/$s_!Qvj8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff68c5725-8bc7-49b5-88bc-f5a41747d479_892x552.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Qvj8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff68c5725-8bc7-49b5-88bc-f5a41747d479_892x552.png" width="474" height="293.3273542600897" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f68c5725-8bc7-49b5-88bc-f5a41747d479_892x552.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:552,&quot;width&quot;:892,&quot;resizeWidth&quot;:474,&quot;bytes&quot;:93842,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Qvj8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff68c5725-8bc7-49b5-88bc-f5a41747d479_892x552.png 424w, https://substackcdn.com/image/fetch/$s_!Qvj8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff68c5725-8bc7-49b5-88bc-f5a41747d479_892x552.png 848w, https://substackcdn.com/image/fetch/$s_!Qvj8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff68c5725-8bc7-49b5-88bc-f5a41747d479_892x552.png 1272w, https://substackcdn.com/image/fetch/$s_!Qvj8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff68c5725-8bc7-49b5-88bc-f5a41747d479_892x552.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Unlike the intimidating empty block in the advanced editor, everything you can possibly do to style an element is discoverable right there onscreen. Borders, shadows, bullseyes, flags, labels. They&#8217;re all right there. </p><p>We&#8217;ve gone to great lengths to make these controls as user-friendly as possible. Every number you see is draggable (no more guessing values). Every colour is actually a colour (and opens a colour picker when clicked). We&#8217;ve got buttons that toggle and buttons that cycle. We&#8217;ve got dropdowns for selecting fields.</p><p>We&#8217;re currently in the final stages of supporting dynamic style values (think scaling a property, or categorizing by color, based on a field value).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eYn2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6f63568-f4b6-44c2-8d01-f6c9943394d1_624x588.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eYn2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6f63568-f4b6-44c2-8d01-f6c9943394d1_624x588.png 424w, https://substackcdn.com/image/fetch/$s_!eYn2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6f63568-f4b6-44c2-8d01-f6c9943394d1_624x588.png 848w, https://substackcdn.com/image/fetch/$s_!eYn2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6f63568-f4b6-44c2-8d01-f6c9943394d1_624x588.png 1272w, https://substackcdn.com/image/fetch/$s_!eYn2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6f63568-f4b6-44c2-8d01-f6c9943394d1_624x588.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eYn2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6f63568-f4b6-44c2-8d01-f6c9943394d1_624x588.png" width="336" height="316.61538461538464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e6f63568-f4b6-44c2-8d01-f6c9943394d1_624x588.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:588,&quot;width&quot;:624,&quot;resizeWidth&quot;:336,&quot;bytes&quot;:56424,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!eYn2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6f63568-f4b6-44c2-8d01-f6c9943394d1_624x588.png 424w, https://substackcdn.com/image/fetch/$s_!eYn2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6f63568-f4b6-44c2-8d01-f6c9943394d1_624x588.png 848w, https://substackcdn.com/image/fetch/$s_!eYn2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6f63568-f4b6-44c2-8d01-f6c9943394d1_624x588.png 1272w, https://substackcdn.com/image/fetch/$s_!eYn2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6f63568-f4b6-44c2-8d01-f6c9943394d1_624x588.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>A great benefit of this approach will be knowing which properties can take can dynamic style values, just by looking at the editor.</p><h4>Internal Representation</h4><p>CSS is a great format for humans, but it&#8217;s kind of awkward for computers. To interpret CSS you need to <em>parse</em> it. What you get back from the parser is a syntax tree which is easy to program. If something changes the syntax tree, then you can serialise it to get new CSS. If something changes the CSS, you can parse it to get a new syntax tree.</p><p>In v3, we can skip the parser and serialiser completely and always work with the syntax tree instead. It&#8217;s not as readable as CSS but JSON is still readable enough.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vOgl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff59d3b88-ad76-4ce2-85cd-48414cc80768_1490x434.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vOgl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff59d3b88-ad76-4ce2-85cd-48414cc80768_1490x434.png 424w, https://substackcdn.com/image/fetch/$s_!vOgl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff59d3b88-ad76-4ce2-85cd-48414cc80768_1490x434.png 848w, https://substackcdn.com/image/fetch/$s_!vOgl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff59d3b88-ad76-4ce2-85cd-48414cc80768_1490x434.png 1272w, https://substackcdn.com/image/fetch/$s_!vOgl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff59d3b88-ad76-4ce2-85cd-48414cc80768_1490x434.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vOgl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff59d3b88-ad76-4ce2-85cd-48414cc80768_1490x434.png" width="1456" height="424" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f59d3b88-ad76-4ce2-85cd-48414cc80768_1490x434.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:424,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:131078,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vOgl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff59d3b88-ad76-4ce2-85cd-48414cc80768_1490x434.png 424w, https://substackcdn.com/image/fetch/$s_!vOgl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff59d3b88-ad76-4ce2-85cd-48414cc80768_1490x434.png 848w, https://substackcdn.com/image/fetch/$s_!vOgl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff59d3b88-ad76-4ce2-85cd-48414cc80768_1490x434.png 1272w, https://substackcdn.com/image/fetch/$s_!vOgl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff59d3b88-ad76-4ce2-85cd-48414cc80768_1490x434.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Most Kumu users won&#8217;t ever need to know what language we&#8217;re using internally, but the decision to move away from CSS means we&#8217;ll no longer be maintaining a custom CSS parser. That&#8217;s less code we need to ship to browsers for Kumu to work and it&#8217;s less time spent parsing views before your map can render.</p><h2>We&#8217;ll Miss Writing Code</h2><p>Sure, the advanced editor has some rough edges. Sure it&#8217;s unusual for a tool with a primarily non-technical user base to expect people to write code. And sure, it has a steep learning curve. But, it has its own charm and some of our users have invested significant time developing competency there.</p><p>When you&#8217;re editing in the advanced editor, you&#8217;re just editing text. It means you&#8217;re susceptible to making all sorts of mistakes, but plain text also has super powers.</p><p>The browser&#8217;s native search just works. Undo and redo are well defined operations with predictable operational semantics and built-in keyboard shortcuts.</p><p>You can see the complete definition of the view in one text input. That means you can edit multiple style rules in parallel without having to navigate backwards and forwards.</p><p>You can select, copy, and paste arbitrary selections and it&#8217;s hard to overstate how important this is. You can copy style rules to duplicate them. You can copy your view into a text editor of your choice as a backup. You can copy the style properties from one rule to another. We&#8217;ll try to mitigate some of this by making it straightforward to duplicate style rules and even entire views. We&#8217;ll also think about making it possible to actually copy (or export) a view or a style rule directly to your clipboard as JSON that you can paste into other projects.</p><p>The advanced editor also allowed us to iterate rapidly for years and years. We could experiment with new types of decorations, settings, and controls, without changing the UI at all. No need to figure out where something will fit, or which icon to use, or how to make it accessible to keyboard users. We&#8217;d just document the new properties and people could start using them immediately. There is no doubt that we will iterate more slowly when it comes to the new editor, but maybe that&#8217;s fine. There&#8217;s not a lot of decorative space left for Kumu to explore.</p><h2>What&#8217;s Next?</h2><p>There&#8217;s stuff we can&#8217;t show yet, like controls and partial views and that&#8217;s because we haven&#8217;t implemented them! But rest assured, we&#8217;re not planning to remove any advanced editor functionality, you&#8217;ll just be controlling it with inputs and buttons and dropdowns, rather than with text.</p><p>There&#8217;s a bright future for the new editor, but the ideas presented here are not yet rigid. We have some strong opinions but we&#8217;re ready to engage with feedback that challenges them too. Hop into our <a href="https://discord.gg/cUeuq8JuXa">Discord server</a> for v3 or drop us a line at <a href="mailto:support@kumu.io">support@kumu.io</a> and let us know!</p>]]></content:encoded></item><item><title><![CDATA[Time, Tools & Technical Debt]]></title><description><![CDATA[How not to modernise a codebase]]></description><link>https://making.kumu.io/p/time-tools-and-technical-debt</link><guid isPermaLink="false">https://making.kumu.io/p/time-tools-and-technical-debt</guid><dc:creator><![CDATA[Dan]]></dc:creator><pubDate>Sun, 24 Mar 2024 14:38:21 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/7a1c34c0-4922-449f-9284-773f52b19b33_1020x610.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We tried something and it didn&#8217;t work. That&#8217;s a common part of programming but we don&#8217;t often write about it. Teams are inspired to recount ambitious successes and postmortems of technical disasters are a sign of integrity, but these too, are usually success stories. &#8220;Something broke&#8212;<em>but</em>&#8212;we identified and fixed it&#8221;.</p><p>We spent much of the last two years trying to modernise the frontend of Kumu&#8217;s codebase, and ultimately, our slow progress caused us to abandon those efforts and contributed to the decision to <a href="https://making.kumu.io/p/were-rewriting-kumu">rewrite Kumu</a> instead. One of the inhibitors was CoffeeScript, and indirectly, the whole suite of tools that we use to turn code that isn&#8217;t-quite-JavaScript into JavaScript.</p><h3>CoffeeScript</h3><p><a href="https://coffeescript.org/">CoffeeScript</a> (for anyone lucky enough not to remember) is a little language that provides some subjective syntactic sugar for JavaScript. It was created during a time when JavaScript had no arrow functions, no classes, no destructuring, no default parameters, no rest parameters, no spreading, no nullish coalescing, and no string interpolation. CoffeeScript provided all of the above and more. If you were going to write significant quantities of code, it was a decent quality of life improvement.</p><p>CoffeeScript often went hand-in-hand with Ruby on Rails, and that&#8217;s how it ended up becoming the first language in Kumu&#8217;s frontend codebase.</p><p>Most languages for frontend development need to be compiled into JavaScript, which means you&#8217;ll need a way to run a compiler. In those early days, our tools were Sprockets and the Rails Asset Pipeline. CoffeeScript goes in, JavaScript comes out. This was way before CommonJS modules and before bundlers, but you could still sort of stitch files together with some funky <code>#= require</code> comments. Still, the only way for code in one file to interact with code in another file was through global variables, and this was one of the defining features of the older parts of our codebase.</p><h3>Webpack</h3><p>Then along came <a href="https://webpack.js.org/">Webpack</a>, an imperfect harbinger of better days for modules and tools. It was an alternative to the Rails Asset Pipeline, creating non-global module boundaries with CommonJS (CJS) modules. Webpack also supported the concept of &#8220;loaders&#8221;&#8212;ways to transform arbitrary code into bundleable JavaScript. Armed with the &#8220;Coffee Loader&#8221; we added Webpack into our tooling and began a new chunk of  caffeinated codebase.</p><p>Webpack was still a relatively new tool when we adopted it and a full migration from Sprockets would have been a gamble. Instead, Webpacked code lived in its own corner, and that&#8217;s where all the new code went. New code could talk to new code through requires and exports. New code could talk to old code through globals. Old code talking to new code? Well, that is a bit messy, the new code also needs to expose some globals. Not ideal, but we&#8217;d eventually move everything over, right?</p><p>Wrong. This setup was <em>good enough</em> that we ended up coasting for <em>long enough</em> that JavaScript had time to significantly improve as a language, implementing many of the syntactic niceties from CoffeeScript. There were fewer reasons to use CoffeeScript, and  for new code we began using modern JavaScript features (along with some non-standard ones like JSX) adding <a href="https://babeljs.io/">Babel</a> into our now burgeoning tool chain.</p><p>Our Webpack configuration grew to patch over some of the differences between the module formats we were using, and during this time we migrated all of our products to live in the same repository, in order to share Kumu&#8217;s core visualisation code. Monorepo-wide Webpack upgrades became a dreaded part of housekeeping, due to the complexity of the setup.</p><h3>TypeScript</h3><p>Ever turneth the wheel of frontend development, and we gradually began to adopt TypeScript in new projects. There was more contention around static types at the time, but these days it&#8217;s widely accepted that 20% more typing for 80% more confidence is an objectively good engineering tradeoff. Kumu is our primary tool, but it&#8217;s not our only tool. Of the other products we make, <a href="https://sticky.studio">Sticky Studio</a>, <a href="https://undercurrent.io">Undercurrent</a>, and <a href="https://weavr.app">Weavr</a> are all mature TypeScript codebases.</p><p>We&#8217;re sold on TypeScript, we have plenty of experience using it in production. Getting it into an existing codebase as big as Kumu, however, was a different challenge.</p><p>The story for incremental adoption is great. TypeScript is <em>just JavaScript</em> with some type annotations, so we began by sprinkling some types around the more modern parts of the Webpack side of our codebase. There was still friction where TS files imported completely untyped CoffeeScript files, but we were able to patch over that in many common cases by writing type declarations for CoffeeScript files.</p><p>It was a breath of fresh air to get some type safety into the codebase, but it wasn&#8217;t quite the strict TypeScript experience we were used to from our other codebases either. First, we couldn&#8217;t run the compiler in <em>strict<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></em> mode without creating lots of difficult work around the migration boundaries where TS and JS files interact. Second, we were still missing types for many of the bits of data that flow around Kumu&#8217;s frontend. Trying to fill in types for rabbit holes of object references was a trap we discovered in our earliest migration branches.</p><p>When types don&#8217;t line up, <code>any</code> is the easiest tool to reach for. In my experience, it&#8217;s also one of the few really poor design choices in the language. It&#8217;s easy to type and it looks harmless. It should instead be screaming &#8220;ALL BETS ARE OFF&#8221; in neon red. We opted to alias <code>any</code> as <code>$FixMe</code> which would serve as a clear indicator that we identified a missing or broken type, but fixing it would have been out of scope for whatever we were writing.</p><h3>Decaffeination</h3><p>Inspired by some wonderful write-ups on how <a href="https://dropbox.tech/frontend/the-great-coffeescript-to-typescript-migration-of-2017">Dropbox</a>, <a href="https://www.bugsnag.com/blog/converting-a-large-react-codebase-from-coffeescript-to-es6/">Bugsnag</a>, <a href="https://benchling.engineering/from-200k-lines-of-coffeescript-to-zero-making-decaffeinate-super-stable-4de0ca68d9bc">Benchling</a>, and others, wrangled ambitious CoffeeScript migrations, we tried our hand at <a href="https://decaffeinate-project.org/">decaffeinate</a>, a tool that turns CoffeeScript into readable JavaScript. Despite the battle-tested success of the tool, some of the quirks of our codebase and our Webpack setup meant that the automatic migration process didn&#8217;t go off without some significant hitches, generating code that lost a lot of clarity when translated from our idiosyncratic style of CoffeeScript.</p><p>With no way to confidently translate the whole codebase automatically, we began a painstaking file by file migration strategy.</p><p>We&#8217;d each take a CoffeeScript file, ensure it had unit tests, run decaffeinate to get JavaScript, clean up warnings and oddities by hand, convert it to loose TypeScript, check that the tests still pass, then apply more rigorous types. 50 lines of CoffeeScript would routinely turn into 200 or 300 lines of TypeScript, often due to the code in question being resistant to testing and requiring complex stubs for globals.</p><p>The line count inflation would have been reasonable if the code coming out the other side was rock solid, but time and time again, we introduced bugs during translation, because adding types steered us into adding <em>safer</em> checking branches, which conflicted with subtle edge case behaviours that would have been hard to infer and test from the original code. Many of these bugs made it through our end-to-end tests and we broke production in some fairly spectacular ways during this period. Sorry!</p><p>The direction of travel was good, but progress was Sisyphean and Sprockets was still doing its best to throw wrenches into many of our plans. Our codebase was still split (by this time, fairly evenly) between code on the Rails side, packaged by Sprockets, and code on the Webpack side, that could use modules and loaders. The only way to translate a CoffeeScript file under Sprockets, was to pull it across to the new side of the codebase, a process which invariably involved some hairy problems around the order in which global variables were declared.</p><p>We decided it would be good for our sanity to move everything from Sprockets to Webpack. We left the global variables alone, moved the asset directory over and replaced all of the Sprockets require comments with CJS require calls. There was a minor adventure in topological sorting to resolve some of the dependency chains that Webpack wouldn&#8217;t jive with, but somehow, miraculously, everything started working.</p><p>Major version upgrades to Webpack and Babel were surprisingly significant  challenges during this process (including a particularly painful transition away from a plugin that smoothed over the Babel 5 changes to default exports at the CJS/ESM boundary). Normally a bundler would give you some kinds of static guarantees around module shape mismatch, but enough of our codebase still relied on globals that we sometimes didn&#8217;t notice errors until development runtime at best, and CI failures or bug reports at worst.</p><p>Then there&#8217;s also the inevitable, incidental firefighting which will always demand urgent attention:</p><ul><li><p>Oh, hey AWS, what&#8217;s that? Our main database server is running outside a VPC and we need to move it into the VPC by June? Ok. I&#8217;ll get right on that.</p></li><li><p>Oh, not quite? the new database server was provisioned with a much smaller disk? That shouldn&#8217;t matter because our data is mounted onto a separate EBS volume with plenty of capacity. Then why is production down? Because our database stores gigabytes of indexes outside the mount point. Oh &#129318;.</p></li><li><p>Oh, why is search down? Because a rogue crawler ignored our robots.txt and decided to start crawling paginated search results for generic terms, overloading our Elasticsearch cluster.</p></li><li><p>Oh, why are we getting huge bills from Twilio? Looks like our multi-factor authentication is being abused to send tens of thousands of SMS messages. Time to learn about &#8220;Toll Fraud&#8221; &#129335;.</p></li><li><p>Oh, why is there huge latency when creating new projects? Ah, looks like our database is overloaded due to spammers automating new project creation so that they can share suspicious links into social media platforms, using Kumu as a proxy. Time to deal with them. Again.</p></li></ul><p>Energy is a precious resource in small engineering teams. If someone burns out, you notice their absence in ways that you can&#8217;t paper over, and this kind of tedious but well-intentioned work saps energy. No one enjoys sitting down to translate CoffeeScript, or to debug stack traces from tools by diving deep into the source for dependencies of dependencies of dependencies in the node modules directory. We were working harder than ever, and yet Kumu looked and felt the same.</p><p>Ultimately, we paused our migration process due to a lack of energy, to focus on some user facing improvements. That catalysed our decision to <a href="https://making.kumu.io/p/were-rewriting-kumu">start from scratch</a>, but we learned some important lessons from trying <em>and failing</em> to modernise a large codebase.</p><ol><li><p><strong>Bet cautiously but move confidently</strong>. Incremental approaches are good for exploration, but once you make a decision see it through, don&#8217;t get stuck straddling two approaches. </p></li><li><p><strong>Static types are here to stay</strong>. We are betting on TypeScript for the next ten years of Kumu. It&#8217;s not a perfect language, but it is good enough.</p></li><li><p><strong>Stay close to standards</strong>. Every deviation from the languages that actually run in browsers is an explicit decision to give yourself more work in the future when the landscape changes again.</p></li><li><p><strong>Unopinionated tools create work</strong>. Our enormous Webpack configuration is effectively a new tool that no one else uses. This kind of complexity encourages abstractions and each layer of disconnect is a fragmentation that makes it harder to reason about the overall behaviour.</p></li><li><p><strong>Be pragmatic around how you spend energy</strong>. Teams need energy in reserve to work effectively. Burned out engineers can&#8217;t fight fires, and the drip drip drip of slow CoffeeScript translations is not restorative.</p></li></ol><p>There won&#8217;t be any CoffeeScript in the next version of Kumu. A rewrite is a chance to wipe the slate clean, but that doesn&#8217;t count for much if we make the same kinds of mistakes again.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>This should absolutely be the default and you should have to opt-out of strict type checks, not opt-in.</p></div></div>]]></content:encoded></item><item><title><![CDATA[We're Rewriting Kumu]]></title><description><![CDATA[Never rewrite software. That&#8217;s good advice.]]></description><link>https://making.kumu.io/p/were-rewriting-kumu</link><guid isPermaLink="false">https://making.kumu.io/p/were-rewriting-kumu</guid><dc:creator><![CDATA[Dan]]></dc:creator><pubDate>Fri, 26 Jan 2024 13:46:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fccf8d1e7-b806-4ada-a6e7-fdd821be5ac8_978x978.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a href="https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/">Never rewrite software.</a> That&#8217;s good advice. If you want a predictable trajectory as a business, ride the inertia for everything it&#8217;s worth. The problem with that advice is that the ride always ends eventually. One day, your market will change, your users will jump ship for a shinier alternative, or you&#8217;ll simply run out of track faster than you can lay it down.</p><p>If we&#8217;d stayed with the <em>first</em> version of Kumu, our ride would have stopped long ago, but because we rethought and rewrote the product at the right moment in time, we&#8217;re still here in 2024.</p><p>The <em>second</em> version of Kumu has been a wild success. It&#8217;s likely the only version of Kumu you&#8217;ll have ever known. It&#8217;s the version that has helped thousands of people all around the world wrangle complexity and make sense of stuff that matters.</p><p>It&#8217;s also the version of Kumu that has confused thousands of people around the world as they&#8217;ve tried to understand the differences between maps and views and elements and controls, or tried to import unstructured data, or had to learn our homebrew version of CSS to use the advanced editor. If you&#8217;ve used Kumu much, you&#8217;ll know that it&#8217;s an extremely powerful tool, with a steep learning curve and some pretty rough edges.</p><p>People arrive at Kumu hoping to make sense of something complicated and we hand them additional complexity. That&#8217;s a really difficult experience for a new user, especially if they don&#8217;t have a technical background, or the time to immerse themselves in our documentation, in order to map productively.</p><p>When people arrive with expectations from simpler tools, we often find ourselves having to say &#8220;No, you can&#8217;t do X, but if you combine Y and Z with a bit of Q, then you can get the same result with more control&#8221;. This is cool, but it isn&#8217;t helpful. Making powerful tools user-friendly is really tough.</p><p>For a long time, we&#8217;ve been chipping away at some of those barriers. We&#8217;ve learned a lot about how people <em>expect</em> Kumu to work, and we even built entire products like <a href="https://sticky.studio/">Sticky Studio</a> to serve as an on-ramp for people who don&#8217;t need all of the features of Kumu to start mapping.</p><p>And here&#8217;s the crux of the problem; those barriers are growing faster than we can chip at them. We&#8217;re not trying to a cut out a chess piece, we&#8217;re trying to hold a cathedral together. We polish the floor, and an archway collapses. We work on the cloisters and the congregation never sees them. We add a flying buttress and the secret entrance into the crypts vanishes mysteriously, but we only find out three weeks later when the one monk who was using it sends a bug report.</p><p>Kumu has become resistant to change. The codebase is ten years old and many of the underlying technologies have not aged well. We spend more time than we&#8217;d like working behind the scenes to keep some of these obscure things stable. Technical debt is a very real problem and for every step we take towards modernisation, we watch another part of our product trend towards disrepair.</p><p>People often talk about these kinds of technical challenges whilst ignoring the fact that there&#8217;s an emotional angle that&#8217;s equally important. It&#8217;s hard to stay positive and motivated when progress is slow and the future is uncertain. If you hire thoughtful humans, it will be difficult for them show up every day, if they don&#8217;t feel like their work will make a meaningful difference.</p><p>We lost Ryan, our technical founder, in 2021. With him we lost a lot of the vision, and the energy, and the soul of Kumu. Losing a friend and a mentor is hard, and continuing his work without him is hard, but it&#8217;s the right thing for us to do.</p><p>We <em>know</em> how to improve Kumu, but we&#8217;re struggling to do it. We&#8217;ve spent the last few years filling the gaps in our knowledge, slowly modernising the codebase, upgrading the underlying technologies, and fighting the fires that are inevitable as a product grows and ages simultaneously. We live with an uncomfortable reality.</p><p>Kumu is aging faster than Kumu is improving.</p><p>That&#8217;s a difficult thing to write. You&#8217;re not supposed to be that honest about your product in public. You&#8217;re meant to project success and trap users on a treadmill of tedious tidbits of trivial changes to keep them &#8220;engaged&#8221;, but that&#8217;s not where we are today, and that&#8217;s not where we plan to be tomorrow.</p><p>We think it&#8217;s time to rethink Kumu.</p><p>Rewriting software is a dangerous undertaking. Starting over is a huge gamble, but for the sake of a world that seems determined to lose sight of the big picture, Kumu needs to still exist in ten years time. It won&#8217;t reverse climate change. It won&#8217;t solve world hunger, or end global conflict. It&#8217;s just a tool. But it&#8217;s a tool that might help in the hands of the people who could.</p><p>We&#8217;ve learned what works and what doesn&#8217;t. We know where people struggle, and we know where the cracks are starting to show behind the scenes. It&#8217;s time for us to do something ambitious and bold, something to make Kumu sustainable again. We&#8217;re going to rewrite the product from scratch. In fact, we already started, but now we&#8217;re confident that it&#8217;s the right decision at the right time.</p><p>The next version of Kumu is going to look a bit different, it&#8217;ll feel different, but Ryan&#8217;s ingenuity and ideas will live on as the heart of whatever we build.</p><p>This &#8220;Making Kumu&#8221; series is where we&#8217;ll tell the story as the next version of Kumu comes together. We&#8217;ll look at how we&#8217;re solving UI/UX problems, and the technological decisions we&#8217;re making. Most importantly, we want you&#8212;the people who use this crazy product&#8212;to get involved and ensure that Kumu v3 is the tool you need it to be.</p><p>We&#8217;ve set up a Discord server, where we&#8217;ll post sneak peaks, ask questions, and eventually, invite people to try closed betas of v3 when they&#8217;re ready. <a href="https://discord.gg/hpJwWKAjvD">Here&#8217;s the invite link</a> if you want to get involved. See you there! &#128075;</p><div class="pullquote"><p>It's a dangerous business, Frodo, going out your door. You step onto the road, and if you don't keep your feet, there's no knowing where you might be swept off to.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://making.kumu.io/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://making.kumu.io/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item></channel></rss>