Loreline - like Ink but cleaner syntax?

I have nothing to do with this, but saw it listed on Hacker News, and it seemed like something that would be of interest to folks here. I checked to see if I was duplicating any other thread and didn’t find any references, so…

https://loreline.app/

Looks like Ink, but with cleaner syntax? I haven’t really worked with Ink so that’s just my uneducated impression.

4 Likes

Looks promising! Previously the only real comparator to Ink in the “portable-narrative-scripting-as-middleware” niche was Yarn Spinner, which has a couple of advantages but IMO ultimately comes out well behind Ink. It would be nice to have more options in this specific niche.

Based on the About page it looks like they have their priorities straight (“Portable from the start” is important, and I agree that the syntax of Ink can be annoyingly cluttery). They say they considered the existing options and made a principled decision to make something new, so that’s a green flag for me as well.

Thoughts looking at the actual documentation:

  • Maybe this is my bias as a Python user showing, but I’m fan of the choice to use English keywords and indentation over special characters. Also, I often find that despite involving more characters, keywords still feel “easier” to type than special characters; despite years of programming, my touch-typing muscle memory is still way better for regular characters than for the top row of symbols, and not having to use shift makes a noticeable difference as well.
    • This does create some weirdness with respect to knowing when you will or won’t need to escape regular English words in the main text, which in turn increases the importance of syntax highlighting in the editor, but that’s not the end of the world.
  • Looks like they’ve fixed two of the biggest issues with Ink from a programmer’s perspective, i.e. namespacing and the lack of usable data structures.
  • The syntax for “alternatives” looks less convenient than Ink, in the sense that Ink lets you do that sort of thing in-line, but that’s not a huge issue.
  • The API looks like callback hell, which, again, not a huge issue.
  • There does appear to be an equivalent to Ink’s “threads,” which is something I specifically look for when evaluating proposed Ink alternatives.
  • I think the only major flaw I’m seeing is that there’s no ability to pass parameters to beats. This can probably be worked around with functions and/or the improved state features, though.

Overall, I find this very compelling! Ink still has the major advantage of an existing community behind it (and backing from a successful studio), but I’m seeing enough here that this reads to me as a solid competitor. It’s not just a nicer syntax; there are genuine improvements to things that have been pain points in Ink. I’ll definitely be trying it out soon.

EDIT: Couple minor complaints:

  • looks like there’s no way to store beats or functions as variables, which is somewhat limiting compared with Ink.
  • also looks like there’s no way to pre-compile a .lor script. It always gets compiled at runtime, which in turn requires you to write some boilerplate to handle imports for multi-file scripts.
2 Likes

The author of Loreline is really active on the French Discord, I’ll give them the link to this topic. Maybe they’ll chime in and answer some of your points!

2 Likes

Having started playing around with it, I’m finding the inability to pass parameters to beats pretty annoying. In Ink, I use parameterized threads a lot to dynamically generate choices (e.g. “get item” for all items in a list), but I’m struggling to find a non-awkward way to dynamically generate a list of choices in Loreline so far (EDIT: or, more specifically, a non-awkward way to dynamically generate a list of choices and then modify the state of the original beat from within those choices).

EDIT2: I’m seeing now that state from one beat actually remains accessible in other beats unless it’s specifically overwritten by them, which does alleviate the problem with dynamic choices somewhat (not entirely), but is also very unintuitive?

Quick thoughts:

  • The documentation could be clearer that this thing can export to HTML. (The Loreline Writer has an Export button; the Playground doesn’t. The documentation makes it appear as if the only way to distribute a Loreline game is to pick an “integration” platform, e.g. JS.)
    • The HTML leaves a lot to be desired, even compared to very basic Twine story formats. Back button, restart button, save/restore, display options.
  • I guess it has a CLI tool, but I couldn’t figure out how to install it. https://loreline.app/en/docs/introduction/ mentions it, but doesn’t link to it.
  • For a tool designed for French, I’m surprised to see that its localization tool doesn’t support gender/number variations.
1 Like

Hey, thanks for trying Loreline! Some answers to your observations:

- Yes, you are right that Loreline’s syntax highlighting is rather important. The syntax is designed with the intent that the language does need only the minimum of markup and symbols as the syntax highlighting do the work of identifying each element.

- Alternatives are on multiple lines, but you can use array_pick() if you want to do a similar operation inside a dialogue:

Today’s menu is ${["salad", "potatoes"].pick()}.

- The callback hell as you mention it is a design choice so that Loreline can be integrated into asynchronous systems by default. On some platforms, that’s a requirement, and that’s also what makes it easy to, say, play animations or anything else in between dialogue lines, when you integrate it within a game engine.

- I agree that passing parameters to beats would be very useful, and in fact I intend to add this later, but I had to draw a line where I stop adding features for the first releases of Loreline. In a future update? For sure :slight_smile:

- Regarding assigning functions and beats as variables, it would be nice. There are already some places (function helpers like has_beat()) where you can reference a beat using a string, but it could definitely be improved. Though, same thing as beat parameters, it would likely land in a future version.

- Not necessarily pre-compiling, but it would also be a good addition to be able to export a single-file package that includes a whole Loreline story indeed.

- Regarding your EDIT2: Mmmmh, state lookup follows the beat hierarchy: if you read a state field from a given beat, it will first try the current scope, and bubble up until top level scope until it finds it (or finds nothing). If you experience a case where it doesn’t behave like that, I’m interested to see it!

2 Likes

Thanks for the feedback too!

  • The Loreline Writer app has been added very recently, so some parts of the documentation could benefit from mentioning it more.

  • The HTML export of Loreline Writer, being as recent as the app itself, is also pretty basic for now. We are at early stages of it. I plan to improve that part too, although it is meant to stay simple and text-based. More custom and advanced systems can be done using one of the different runtimes available and their integration guides that come with it, while a more “full-featured” authoring app that could allow to export more advanced narrative games (like visual novels) without programming skills is planned in the future, but that’s outside of the scope of Loreline Writer.

Also, as mentioned on Github, there are already helpers for plural. For straightforward cases, the pipe syntax can be used:

items = 3
You found $items coin|coins.
// "You found 3 coins."

boxes = 1
$boxes (box was|boxes were) found.
// "1 box was found."

Whereas more advanced use cases can be handled with the plural() helper or even custom helpers you write yourself.

Note that this has nothing to do with localization specifically. It’s standard loreline syntax, which can be used both in loreline files and in translation files (which accept any loreline dialogue syntax for translated values), and you can even come up with different solutions depending on the locale, if the spoken language requires it. The idea is that simple cases can stay simple (with the pipe syntax), while more advanced ones are unlocked with more advanced helpers, without forcing those helpers on the simpler cases.

Gender variation will likely follow similar ideas, but that doesn’t exist yet. As a workaround, you can make your custom helpers to manage it however you want already.

And yes, the CLI is downloadable from the Github release page, but it could deserve its own page on the website I agree!

Thanks for the response! Hopefully I didn’t sound too critical - I like it a lot, thanks for making it! After playing around a bit more and understanding the scope better, I’m still finding some things that cause friction for me relative to Ink (including the lack of an explicit “return” statement), but nothing that I would consider a blocker, I think.

Is there full API documentation for the interpreter object somewhere? In the “Using JS/Python/whatever” examples you show calling interpreter.getCharacterField, but I’d hope that there’s other stuff you can do with it (e.g. getting/setting state)?

No worries, your feedback is appreciated! (although it’s definitely nice to know you like it too :smiley: )

Yes, a return statement could make sense. Right now you only have the natural indented block structure to control where the flow is going inside a beat indeed. It should not be difficult to add and would add more flexibility.

I’m interested to know any other pain points you are having relative to Ink, even if that’s not a blocker. These can really help shape the next round of updates to the language!

Right now there is not a full per-target API documentation. I’d like to have that, but first I need to figure out a smart enough way to maintain it properly given the many targets Loreline supports, so for the time being there are only the integration guides and the example projects that come with it.

Regarding reading and writing states, you can use interpreter.getStateField() and interpreter.setStateField() (or the snake_case equivalent on languages that use snake case like python).

If there is a specific thing you’d like to do but don’t know how to do it with Loreline, you can also ping me. There are things that are not properly documented but I can point to the right direction!

2 Likes