On UI as Code

I’ve pasted some thoughts here on the assumptions I see implicit in the increasingly popular “UI as code” movement - On UI as code - Antranig Basman - I walk though a little journey of what it takes to implement an extremely innocuous-seeming UI change in a popular static publishing platform, and what the implications are for making systems malleable - the issue of being able to trace responsibility for why a particular UI element appears back to its source materials, which is an important capability of substrates a la Beaudoin-Lafon.

In general I expect to be blogging quite frequently leading up to upcoming meetings of people interested in Software Substrates. I haven’t yet set up comments on my blog so do paste any feedback or reflections here in the meantime, cheers!

4 Likes

Welcome to the forum, Antranig! I am glad to see you’re blogging about substrates and other malleable topics. :smile:

1 Like

Here are my major critiques of this case study, invariably colored by my own beliefs and prejudices:

  • In the extremely disempowered world we live in, removing an underline isn’t going to register as a pain point for anyone below a certain level of ability. Now to be fair, I don’t really know what does register. One pattern I’ve noticed so far is a desire for custom dashboards.
  • Browser tools are extremely powerful and great! The hard part is the last mile of persisting a change across sessions once you figure out how to make it. Accordingly, I’m extremely skeptical that browser manufacturers will ever permit such functionality at scale. Greasemonkey was a temporary blessing and will not return.
  • Choosing well-intentioned suppliers matters more than tools. Browser tools are no match for the obfuscation of Google Docs, and the creep of complexity leads all in that direction.
  • Total depth of stack matters. Any framework you build atop Typescript+Quarto can only add to those 1600 lines that will intrude on end users for any scenario more complex than removing an underline. They can’t subtract from those 1600 lines.

So what’s the answer? Choose me as your well-intentioned supplier! I’m mostly kidding, but the serious bit is to suggest that moving off the web or large frameworks is a way to minimize total depth of stack[1]. Even if it leads to less pleasing designs, they may be more malleable.

[1] In my case, 12k lines of C for Lua + 100k LoC for LÖVE + 1-3k lines for my apps on top. Crucially, the first 2 seldom change.

1 Like

Cheers, Kartik, thanks so much for taking the time to look at my post and produce such a thoughtful response!

I’ve long appreciated your big input into this community and glad to be able to take a part in it now. I’ve particularly appreciated your “show, don’t tell” idiom although I fear I will be stuck in the role of telling for just a bit longer.

  • In the extremely disempowered world we live in, removing an underline isn’t going to register as a pain point for anyone below a certain level of ability. Now to be fair, I don’t really know what does register. One pattern I’ve noticed so far is a desire for custom dashboards.

I just wanted to unpack this point a bit to make sure I grasp what you’re saying. Is it that it doesn’t register as a pain point, under what we could call
Model 1: Fork the 1600 TypeScript file, register a new content type in quarto backed by it which renders it when a subpage is selected,
Model 2: Inject a dozen line snippet into the the page header which adjusts the style after load time?
Or just that removing the underline doesn’t count as a significant design pain?

  • Total depth of stack matters. Any framework you build atop Typescript+Quarto can only add to those 1600 lines that will intrude on end users for any scenario more complex than removing an underline. They can’t subtract from those 1600 lines.

That’s hard to argue against - and indeed the immediate plan (ahead of anything more grandiose) is to migrate our communities off Typescript+Quarto onto a shorter stack. The erstwhile Quarto author, Yihui blogged recently on his apparently not entirely voluntary departure from Posit and was diplomatic in his language that he has “become more interested in developing smaller software tools that do fewer things”. One of my interests in exploring hugo for my own site, and its resulting rather lithified theme, is that it is the basis of Yihui’s older solution for publishing documents in R, blogdown. Even if in theory it is less malleable than quarto through having no kind of plugin architecture, the system should be more manageable as a result of its shorter stack and hopefully we can pick up the pieces later.

In my case, 12k lines of C for Lua + 100k LoC for LÖVE + 1-3k lines for my apps on top. Crucially, the first 2 seldom change.

I love the look of LÖVE and its community feels welcoming and collaborative. I was wondering if there was anything malleable within it along the lines of a document model such as the DOM or any means of seeing substructure other than source code in running applications. If my page had been written in LÖVE rather than Quarto+Typescript, would I have been able to follow a means like Method 2 above or would I have had to find a way to edit the original source and rebuild the app?

2 Likes

Thanks so much for your kind words! I’ve always appreciated your work, so they mean more coming from you.

I just wanted to unpack this point a bit to make sure I grasp what you’re saying.

Yeah, I should be more clear. I didn’t fully follow your 2 models, but I don’t mean to say, “oh removing an underline is such a trivial task, you have to do more complex things to be taken seriously.”

What I mean instead is, when I talk to people and try to ask them what they would like to change in the programs they use, somehow it is simultaneously true that everything is broken and nothing is broken. So much is not how they would want it, that a) they learn a form of helplessness in terms of growing accustomed to things not working as they want, and b) in this mode of learned helplessness, small pain points like a confusing bit of design disappear, and what eventually tends to rise up is bigger things like, “I want an app that does ____,” which often boils down to “do what I mean.”

So it becomes hard to do science. You can’t run experiments about, “how do people use functionality to make small changes?” independently of “how well does the infrastructure supports large changes?” The perceived size of a program affects people’s sense of freedom. Even if they could easily accomplish some task, it’s very easy for them to get intimidated and think they can’t do anything. And paradoxically when they think they can’t do anything, small things disappear because they’re subconsciously excluded from consideration. And big things that manage to get past the intimidation are ill-posed and impossible to act on.

This is all hypothesis. I observe the intimidation, but I’m guessing at reasons. I haven’t actually been able to create that sense of freedom either yet.

if there was anything malleable within it along the lines of a document model such as the DOM or any means of seeing substructure other than source code in running applications. If my page had been written in LÖVE rather than Quarto+Typescript, would I have been able to follow a means like Method 2 above or would I have had to find a way to edit the original source and rebuild the app?

Short answer: yes they would be left at the level of editing the source code. There’s certainly no X-ray vision yet on the level of a browser’s wonderful inspect operation.

That said, I have some partial answers to this gap:

  1. I spent a while looking at Quarto after my previous comment and it does look quite nice in many ways. I think on one level I’m asking if they’re undoing all their nice work of keeping the markup open by just trying to do too much, polish too much, and so having a quantity of code that intimidates.

  2. On another level, I think I’m questioning declarative vs imperative representation. Mutating a declarative representation is wonderful once you gain some fluency with it, but gaining that fluency becomes a hurdle. And a lot of declarative representation is very hard to wrap your head around. For example nobody it seems can guess ahead of time what any non-trivial CSS will do. With simple imperative programs I feel like I can always understand things to arbitrary levels of detail. Whereas with CSS I’m stuck cargo-culting black boxes. And (here I’m projecting) that might be adding to the intimidation factor. Declarative representation is nice if you consider just the declarative code in isolation, but realistically I think it can still be intimidating proportional to the size of the implementation. At that point, is it maybe better to just write imperative code in a very simple way?

  3. While you have to edit the original source, you don’t need to have a heavyweight step of rebuilding the app. I have been live-editing my apps for a while now, and the kernel of code to accomplish this (documented here) is tiny thanks to Lua being just as dynamic as Javascript. The key thing I do is maintain source code separately for each top-level definition (rather than some larger file or module). Now I can request from an app the source code of any definition, and then mutate that definition while the app is running. None of this is at the maturity of the web of course, which is why I’m constantly wishing for the world to exercise it more often.

  4. As it happens, I’ve actually been working on a markup language built entirely out of Lua literals. Version 1 is a couple of years old, but I hope to share the current version in the next day or two. It’s extremely bare-bones:

    • Markup can consist of graphic shapes, or rows or columns or text.
    • Rows can contain columns or text.
    • Columns can contain rows or text.
    • Text consists of lines that can wrap.
    • (the new bit) Lines can contain some very basic inline styling: color, bold/italic and link targets.

    I want this markup for a mobile-friendly in-app browser for browsing source code, while providing some level of graphic affordance so I can describe source code using box-and-arrow diagrams. That previous link above shows the desired behavior, but only mocks up the markup. I’m working on a real implementation.

Sorry about the wall of text!

2 Likes

BTW, this link seems broken. (I still need to digest this paragraph of your response.)

Hi Bosmon,

Thank you for the nice blog post, and your work on the Salish Sea mapping website(it’s where I live!) I wasn’t aware of the X as Code saying until today.

It’s an interesting cautionary tale all this trying to fix the underline, it’s giving me shivers(as a recovering website developer) to see you tasked to navigate a heap of webshit to patch something like this. Seeing as there is no part of this website that should effectively need javascript in any form, and that the navigation relies on more than a thousand lines of code(and that the result is completely broken, too), it’s impressive and sends a strong message about that stack/reliability that Kartik is talking about.

I love exploring malleability in software, and how this jazzes with open platform like the web, which often trades developer convenience against accessibility. There’s lots of work to be done here yet, and I’m excited to see where this leads.


Unrelated, but I couldn’t stop thinking about the idea of UI as code after reading the post, in the sense of what it means, and not how it’s actually used. I was wondering how hard it would be to make a dropdown using UI as code.

1 Like

I have yet to read your blog post, so for now I am limiting myself to a comment on Quarto, which is quite popular in some branches of computational science. It’s not only a huge amount of code, it also has lots of dependencies, which moreover evolve rapidly. I don’t know anyone who tried to modify Quarto, but I do know people who just tried to build Quarto from source in a stable environment (a prerequisite to modifying anything durably), and found it to be a very painful experience.

This is just one out of many examples of software packages that are advertised as Open Source, but so hard to build that you can’t really profit from their Open Source nature. The spirit of Open Source is completely eroded.

1 Like

A nice illustration of how “X as Code” implies adopting the social norms of code as part of the social norms of X. Something I pointed out in a blog post on science a few days ago. Science suffers a lot from developers imposing decisions on users via the opacity of the medium, but this has become so normal in everyday life that few scientists are even aware of the problem.

You mention plugins a few times, which are an interesting intermediate between malleable and non-malleable systems, giving other an authorization to modify some but not all of the behavior of the system. I’d rather have fully malleable systems, but plugins are better than nothing.

I am really looking forward to you work on substrates! It’s something I am exploring as well, but in the specific context of scientific computing.

1 Like

I just want to say I like this quote. It feels something like a mission statement.

Yes, we’ve made things too opaque and too complex, and the Web has been paradoxically both a big part of doing that… and also a tiny glimpse of a better, older, world. There’s nothing like F12 in the Android interface, for example, and I’m always surprised that Google (because there’s nobody else driving web browsers now, it’s just Google) allows it to continue to exist. I guess WASM will just quietly sidestep it.

1 Like

Cheers, Kartik - looks like this forum isn’t threaded but hopefully it won’t be too confusing if I respond to your 29th March post down here.

I think this is a very interesting question close to my interests. And riffing off my speed of development note, perhaps the crucial task is to find ways to make what is in practice a large program appear like a small one from some views. The parts of a program that should be evident as context for a small change should be on the scale of the change itself, rather than necessarily the likely arbitrarily sized unit which the programmer used to house their original expression of the thing which needs to be changed - e.g. a 1600 line TypeScript file. I consider, optimistically, that any solution to this problem would help AI coders as much as it helps human ones.

But this is also crucial to me since the distinction between these two models is at the heart of my programme and if I haven’t managed to put it across clearly yet, that is my problem! That is, the distinction between needing to “change someone’s words” (model 1) in order to make your adaptation and the need only to “add to their design” (model 2). This distinction was at the heart of my 2018 paper The Open Authorial Principle which was of course widely incomprehensible. This is at the heart of what could be needed to make large designs appear like small ones. Is it any clearer now or can you think of some direction I could take to put this across better? Obviously I could just build it and do “show don’t tell” but this will still take a while longer : P

OK, so lots to say here…

On the one hand:

to start with, I fully agree with the unmanageability of “the CSS we have”. It takes me forever to hack at these things although I find it is hugely more achievable in the flexbox era. But I think the “values of CSS”, that is, that there is an inspector that will show you the full space of expressions impacting any element together with which ones are overridden, are the “pearl of great price” for which one will sacrifice practically anything to see if they can be spread more widely. This was another goal of the 2018 OAP paper - could there be a means of expressing more of the effects of a design, rather than just layout, using the “values of CSS”?

On the other hand:

People will want apps that “don’t look funny”, that is, that they use the full layout and rendering capabilities of their browser/system. I want to be able to deliver apps like Melittoflora that are fully acceptable presentations in an actual substrate, rather than the half-assed scaffolded substrate that I so far used. The fact that Boxer apps, for example, “looked funny” was a principal reason for students in the end rejecting it and the same curse afflicts apps, by and large, written in any of the substrates so far constructed e.g. Lively Kernel. So I feel that letting designers tangle with real CSS, if they need to, is essential, although I dream of being able to supply some friendly approach to this to guide people who don’t want to tangle with it. So far I’m unencouraged by the CSS frameworks I’ve seen, but necessity will find a way.

And then on the third hand:

People writing code in an imperative way, unless this is mitigated somehow, is going to defeat the “context reduction” aims I described above, since by tradition, the context of some imperative code is the entire source file it’s written in. There is a place for imperative code, just as there is for CSS, but there needs to be some route for expressing designs that doesn’t necessarily require either of them.

On the fourth hand:

I’m primarily interested as “declarative representations” as a proxy for hoisting direct manipulation of the UI itself onto equivalent actions on the underlying design. One argues (without any kind of proof) that having a declarative representation of a substrate will make it easier to trace the lines of influence between the rendered surface of the substrate back to the expressions that produced it, than it would be with declarative code. Allowing people to mutate the declarative representation itself might be desirable for some but is not the endpoint of end user programming.

I love the language of Lua literals and find it pretty interesting that so many languages evolved to more or less embed a similar dialect. Lots to say here!

No worries, I’ve been producing walls of text for the last 20 years now and having to put up with having made it too obstructive to respond, so I’ll cut this short now even though there’s plenty more to say :slight_smile:

2 Likes

Don’t bet on it - if Google and Microsoft didn’t succeed in destroying the free web in 20 years, they’re not likely to in the next 20 :slight_smile:

In practice, systems actually need to work for real communities, and be buildable. Stephen Kell’s 2015 paper on object models within UNIX processes shows that technologists, despite their ideologies, quite often cannot avoid betraying themselves (if only privately) by creating workable designs especially if their communities end up living long enough. They could only do with a little encouragement.

2 Likes

Sorry about that, link fixed now! You know the syndrome of pasting a link from the wrong window at midnight …

@Bosmon:

looks like this forum isn’t threaded but hopefully it won’t be too confusing if I respond to your 29th March post down here.

Yes, this seems to be the way.

I find neither trees nor linear threads quite suit all purposes. So I sometimes create custom views of conversations. Here’s one I just made for our exchanges, in case you find it useful. At least in the draft view it looks like Discourse doesn’t downsample it to uselessness, so hopefully you’ll be able to open the image in a new tab to read it. I’ll also include the “source code” I used to create it using snap.love. The text looks crisper if you zoom in a little bit.

kartik-antranig
{ "next" : 38, "nodes" : {
"a": {"type":"text","h":75,"width":120,"x":8.25,"y":-4,"id":"a","data":["Single","trustworthy","supplier"],"margin":0,"outgoing_edges":["b"],"incoming_edges":["l"],"w":120}
,"b": {"type":"text","h":50,"width":283.75,"x":209,"y":12,"id":"b","data":["Complex implementations imbalance power"],"margin":0,"outgoing_edges":["c","d","g","h"],"incoming_edges":["a","w"],"w":283.75}
,"ba": {"type":"text","h":50,"width":276.25,"x":-291,"y":-828.58333333333,"data":["Change someone's words\"","(Model 1)"],"w":276.25,"id":"ba","margin":0,"outgoing_edges":["w","be"],"incoming_edges":["z"]}
,"bb": {"type":"text","h":50,"width":275,"x":-289.75,"y":-688.58333333333,"data":["\"Combine existing words\"","(Model 2)"],"w":275,"id":"bb","margin":0,"outgoing_edges":["w"],"incoming_edges":["q"]}
,"bc": {"type":"text","h":25,"width":286.25,"x":-646,"y":-362.33333333333,"data":["Tchernavskij, tailoring"],"w":286.25,"id":"bc","margin":0,"outgoing_edges":[],"incoming_edges":["t"]}
,"bd": {"type":"text","h":50,"width":278.75,"x":-648.5,"y":-223.58333333333,"data":["Basman, \"What Lies in the Path of the Revolution\""],"w":278.75,"id":"bd","margin":0,"outgoing_edges":[],"incoming_edges":["t"]}
,"be": {"type":"text","h":75,"width":281.25,"x":211.5,"y":-839.83333333333,"data":["Simpler implementations","Open Authorial Principle","\"values of CSS\""],"w":281.25,"id":"be","margin":0,"outgoing_edges":[],"incoming_edges":["ba"]}
,"bf": {"type":"text","h":50,"width":135,"x":1289,"y":-108.58333333333,"data":["Problem:","\"looks funny\""],"w":135,"id":"bf","margin":0,"outgoing_edges":["bg","bh"],"incoming_edges":["e"]}
,"bg": {"type":"text","h":100,"width":267.5,"x":1509,"y":-134.83333333333,"data":["Not always a negative","","Games culture embraces non-standard looks"],"w":267.5,"id":"bg","margin":0,"outgoing_edges":[],"incoming_edges":["bf"]}
,"bh": {"type":"text","h":25,"width":333.75,"x":1510.25,"y":-262.33333333333,"data":["Adoption doesn't always matter"],"w":333.75,"id":"bh","margin":0,"outgoing_edges":[],"incoming_edges":["bf"]}
,"bi": {"type":"text","h":75,"width":238.75,"x":1289,"y":88.916666666667,"data":["Problem:","imperative = profligate with context"],"w":238.75,"id":"bi","margin":0,"outgoing_edges":["bj","bk"],"incoming_edges":["e"]}
,"bj": {"type":"text","h":25,"width":220,"x":1707.75,"y":107.66666666667,"data":["Works at small scales"],"w":220,"id":"bj","margin":0,"outgoing_edges":[],"incoming_edges":["bi"]}
,"bk": {"type":"text","h":50,"width":217.5,"x":1710.25,"y":231.41666666667,"data":["Works for a single global context"],"w":217.5,"id":"bk","margin":0,"outgoing_edges":[],"incoming_edges":["bi"]}
,"bl": {"type":"text","h":100,"width":253.75,"x":1292.75,"y":343.91666666667,"data":["Problem:","declarative code vs ??","","Not understood"],"w":253.75,"id":"bl","margin":0,"outgoing_edges":[],"incoming_edges":["e"]}
,"c": {"type":"text","h":25,"width":149,"x":609,"y":-89,"id":"c","data":["Limit features"],"margin":0,"outgoing_edges":["e","f"],"incoming_edges":["b"],"w":149}
,"d": {"type":"text","h":25,"width":120,"x":609,"y":10,"id":"d","data":["Isolate tools"],"margin":0,"outgoing_edges":["e","f"],"incoming_edges":["b"],"w":120}
,"e": {"type":"text","h":50,"width":120,"x":951,"y":-19,"id":"e","data":["Avoid web","browsers"],"margin":0,"outgoing_edges":["bf","bi","bl"],"incoming_edges":["c","d","g","h"],"w":120}
,"f": {"type":"text","h":50,"width":185,"x":950,"y":110,"id":"f","data":["Extremely simple html+javascript"],"margin":0,"outgoing_edges":[],"incoming_edges":["c","d","g","h"],"w":185}
,"g": {"type":"text","h":50,"width":177,"x":608,"y":109,"id":"g","data":["Shallow stacks","of dependencies"],"margin":0,"outgoing_edges":["e","f"],"incoming_edges":["b"],"w":177}
,"h": {"type":"text","h":50,"width":331,"x":544,"y":241,"id":"h","data":["Trustworthy suppliers.","Your opinion has consequences."],"margin":0,"outgoing_edges":["e","f"],"incoming_edges":["b"],"w":331}
,"i": {"type":"text","h":25,"width":1179,"x":10,"y":-231,"data":["                                                                                Kartik"],"w":1179,"id":"i","margin":0,"outgoing_edges":[],"incoming_edges":[]}
,"j": {"type":"text","h":25,"width":1180,"x":8.75,"y":-991.33333333333,"data":["                                                                            Antranig"],"w":1180,"id":"j","margin":0,"outgoing_edges":[],"incoming_edges":[]}
,"k": {"type":"text","h":50,"width":120,"x":-1591.4166666667,"y":-488.58333333333,"data":["Malleability requires"],"w":120,"id":"k","margin":0,"outgoing_edges":["l","m","n","y"],"incoming_edges":[]}
,"l": {"type":"text","h":50,"width":257.5,"x":-1289.75,"y":-88.166666666667,"data":["Trustworthy suppliers","(Kartik)"],"w":257.5,"id":"l","margin":0,"outgoing_edges":["a"],"incoming_edges":["k"]}
,"m": {"type":"text","h":50,"width":259.16666666667,"x":-1291.4166666667,"y":-492.33333333333,"data":["Easy to learn","from each other"],"w":259.16666666667,"id":"m","margin":0,"outgoing_edges":["s","t"],"incoming_edges":["k"]}
,"n": {"type":"text","h":75,"width":252.5,"x":-1287.25,"y":-688.16666666667,"data":["Easy to understand what the computer is doing"],"w":252.5,"id":"n","margin":0,"outgoing_edges":["o","p"],"incoming_edges":["k"]}
,"o": {"type":"text","h":25,"width":120,"x":-888.5,"y":-816.08333333333,"data":["In the large"],"w":120,"id":"o","margin":0,"outgoing_edges":["z"],"incoming_edges":["n"]}
,"p": {"type":"text","h":25,"width":120,"x":-889.75,"y":-688.58333333333,"data":["In the small"],"w":120,"id":"p","margin":0,"outgoing_edges":["q","r"],"incoming_edges":["n"]}
,"q": {"type":"text","h":25,"width":150,"x":-689.75,"y":-687.33333333333,"data":["Better syntax"],"w":150,"id":"q","margin":0,"outgoing_edges":["bb"],"incoming_edges":["p"]}
,"r": {"type":"text","h":50,"width":120,"x":-687.25,"y":-589.83333333333,"data":["DSLs","(Antranig)"],"w":120,"id":"r","margin":0,"outgoing_edges":["w"],"incoming_edges":["p"]}
,"s": {"type":"text","h":50,"width":120,"x":-889.75,"y":-487.33333333333,"data":["Discovering","others"],"w":120,"id":"s","margin":0,"outgoing_edges":[],"incoming_edges":["m"]}
,"t": {"type":"text","h":25,"width":120,"x":-891,"y":-362.33333333333,"data":["Community"],"w":120,"id":"t","margin":0,"outgoing_edges":["bc","bd"],"incoming_edges":["m"]}
,"u": {"type":"text","h":50,"width":697.5,"x":1277.75,"y":-432.33333333333,"data":["More unstructured debate here between Antranig and Kartik","Boxes tend to alternate call and response/rebuttal."],"w":697.5,"id":"u","margin":0,"outgoing_edges":[],"incoming_edges":[]}
,"v": {"type":"text","h":50,"width":120,"x":-1470.1666666667,"y":128.08333333333,"data":["Substrates??"],"w":120,"id":"v","margin":0,"outgoing_edges":[],"incoming_edges":[]}
,"w": {"type":"text","h":50,"width":277.5,"x":211.5,"y":-587.33333333333,"data":["Complex implementations","imbalance power"],"w":277.5,"id":"w","margin":0,"outgoing_edges":["x","b"],"incoming_edges":["r","bb","ba"]}
,"x": {"type":"text","h":75,"width":298.75,"x":910.25,"y":-597.33333333333,"data":["Jungle DOM","Cutting through complexity","DOM inspector"],"w":298.75,"id":"x","margin":0,"outgoing_edges":[],"incoming_edges":["w"]}
,"y": {"type":"text","h":50,"width":262.5,"x":-1291,"y":-289.83333333333,"data":["Easy to change programs","and to share changes"],"w":262.5,"id":"y","margin":0,"outgoing_edges":[],"incoming_edges":["k"]}
,"z": {"type":"text","h":75,"width":235,"x":-691,"y":-843.58333333333,"data":["Overlapping views","Size of change vs size of context"],"w":235,"id":"z","margin":0,"outgoing_edges":["ba"],"incoming_edges":["o"]}
}}

Ok, now I can respond further, and hopefully it’ll be apparent which box in the map above my responses correspond to.

  • Your model 1 and model 2 distinction makes sense to me now. But it still seems independent of the use case in OP. At the point where someone is trying to remove that underline, they likely have no idea whether to define new words or orchestrate existing words. So the distinction seems to add more cognitive load, and it’s unclear if it helps. The route you took in OP seems much more realistic: just open the DOM inspector and YOLO it up to do what you want.

  • I have to admit that your OAP paper didn’t land for me as much as “What lies in the path of the revolution,” which was really got me to pay close attention to you. Rereading it now, it really does lie at the crux of our disagreement, in 2 ways:

    • It sounds like magic, and I have no idea how to achieve that goal. So if you manage to “show not tell” this and build something with the values of CSS that generalizes beyond layout concerns, it’s going to be a hugely impactful achievement. It would upend my whole belief system in the picture above. I think there’s no good way to achieve malleability at scale, so the declarative approaches seem to have limited upside and imperative approaches seem more competitive.
    • Partly because it seems so difficult, I tend to rationalize that the grapes are too sour. Large scale is something large organizations need; there’ll always be a limit to how much one entity can subversively make use of the output of another across a chasm of scales. So it seems more important to choose my counterparties wisely. I can use websites that are say 10x larger than I can handle and hope to make targeted subversive interventions on them. But at 100x larger that becomes unlikely and less economic for me. The more impactful move for me is to try to avoid sites 100x larger.
  • It is absolutely true that things made outside the browser will “look funny”, particularly things made on shoestring budgets. I see positives there as well. Shoestring budgets don’t push for a return on investment either. It’s fine if few see it or adopt it, it wasn’t expensive to make. For example, indie games like 1000xRESIST are able to make a virtue out of looking funny.

  • I didn’t quite understand your “fourth hand” point about declarative representations vs direct manipulation.

Final note: I really appreciated your definition of substrate on your website.

2 Likes

Thanks for posting this, Antranig, and for pointing me to your blog.
In general, I should really start paying more attention to this forum.

I have thoughts on your substrates definition that I will see if I can collect my thoughts around it. I should say your ‘substrate’ definition, because one of my complaints is the lack of plurality :smile:

2 Likes

I have seen that happening as well, but I tend to consider it a case of newbie confrontation with something alien whose downsides are highly visible but whose advantages require experience. It is then the task of educators to guide students towards the insight that the gain in agency over their software is worth some loss of polished UI.

Working with today’s student generation (not CS but physics, chemistry, biology), I notice that the very idea that you could look at and understand the source code of some piece of software you use is completely alien to many of them. I see this as learned helplessness, and as something that requires counteraction.

3 Likes

Thanks, this is really lovely - I’m touched you went to the trouble to map this out! It feels like we need some dedicated scheme for tracking these - perhaps in the form of a “substrate” or so? : P

Here’s where I think the distinction is important. Indeed - the OP has no idea at the point they find the requirement e.g. for the underline whether they want to change words or add words. This can only be informed once they find where the words and what form they take which are responsible for the underline, which for a start requires there to be some intelligible journey they can take towards the words from what they see on the screen. At the point they find them, they will likely form an opinion then which model they prefer - and especially, if they find they take the form of anything like a 1600 line TypeScript file, they will likely want model 2. However, unless the artefact they interact with was already built on some kind of substrate with coordinates to it (in addition to them having some ability to rebuild/redeploy it due to its being open source etc. etc.) model 2 is not going to be available.

I see this as almost a political kind of distinction, amounting to Freedom of Association for code - the user should have a free choice of options for how they want their communities to be connected.

Does that help situate the distinction any?

Yes, I agree with that - but also, at this scale, we are at the level where one could expect AI to satisfactorily produce the entire design for us, meaning that any distinction between approaches is pretty minor. But every big design starts as a small design, and I hope that eventually substrates can be developed which ease the task of designs growing up, becoming mature, and having more and more variants shared amongst communities with slightly divergent needs. So even if there is no real advantage at the small scale I think it’s worth exploring different means of expression. Unfortunately this is a microcosm of the “poison tree” which AI spreads in so many different communities - it makes it very much harder for immature ideas or workers to find space to grow up.

Well this sounds a bit intimidating to me - hopefully there is some middle ground in which I could produce something which is neither a paradigmatic smash, nor a humiliating failure, but something “a bit funny” which stimulates further ideas and work!

To put a line in the sand, “ancient Infusion” did actually succeed in delivering most of the goals of the OAP paper, it’s just that Jonathan Edwards (quite rightly, I think) considered that we should remove mention of the system itself from the paper since it was already massively crammed. In an older version of the paper there were system details and even a dynamic video of a CATT. You can see some test cases for the CSS selector-like system, “distributeOptions” here and some docs here. The problem was that the system was so race-laden and unperformant I wouldn’t dare render more than a couple of dozen components in it and certainly not its own self-editing interface.

What’s changed since 2022 is that I’ve rather better got my head around reactive programming techniques/incremental computation and have more confidence that I can orchestrate the workflow without it being full of transactions and weird stovepipes.

One thing I realise is, that, since you’ve developed LuaML2 we don’t need to agree about whether the Web is a worthy platform or not. I see that what I consider the premier JS reactive programming library,
alien-signals has been ported to Lua and that also there is good support for proxies in Lua so many of the underpinnings are there - should I produce anything usable “it shouldn’t be too hard” to port it in to LuaML2. Have you tinkered with reactive programming much?

{type='line', data={0,0, 0,600}},
{type='line', data={0,0, 800,0}},

Does this kind of lingo have a name, LSON or so? : P

2 Likes