That’s a better syntax, but I’m still not quite sure what benefits you get from separating state and text so completely. One of Dialog’s main benefits is that it doesn’t require you to separate game code from text output, and interleaving them is very helpful in writing concise code. This way, it seems like if (for example) I want certain actions to make a guard more suspicious, I need to put my code in two entirely separate places: the part that increments the suspicion variable, and the part that describes the variable incrementing.
This is one implementation. You could build it all in the entity. Sharpee, because it’s Typescript/Javascript, is very hackable.
I know this is controversial, but because the code and future sample implementations will be online and in Typescript, you’ll be able to use any LLM to generate code snippets and build your stories very fast. I could build a VS Code plugin that uses the API of Claude or ChatGPT and lets you prompt for code.
Sure, but I don’t think you’re going to get many adherents here if your main selling point is LLM compatibility.
You’ve made some very unusual choices in building the underlying architecture; I’m just wondering, what benefits does the end user see from that? Most other IF languages seem to be moving in the other direction, coupling text and code as closely together as possible; what’s the benefit of doing the opposite?
I have not proven the benefits yet.
Draconis isn’t asking about the benefits you’ve proven, merely the reasoning for “going against the grain”. There doesn’t need to be quantitative (or even qualitative) data, but some insight into your thought process could be helpful.
I answered this here:
I’m afraid I just don’t see the benefit. Suppose I want to add a new constraint: you can’t sing while underwater. In your model, I have to add a rule to the singing action, which logs an event of “prevented singing while underwater”, and then write a separate rule in the text-generation service, which watches for an event of “prevented singing while underwater”, and prints an appropriate message. Right?
But imo there’s a reason why all (current, major) IF systems only require writing each rule once: when you’re maintaining two copies of all your action-processing code, one to trigger the errors and the other to report the errors, it’s very easy for them to get out of sync, no?
And to follow up on that blog entry, one of my primary interests is in how modern software architecture can impact IF. Event sources and read models are standard patterns in distributed systems. Typescript is so common it’s at the top of every LLM model for generating code and it’s the standard for web development and nodejs development.
And I wanted to move away from custom syntaxes and virtual machines. We have excellent platforms that follow older technology patterns.
I’m exploring modern technologies and modern patterns.
Why can’t I have a SingingTrait that has behavior for when singing is valid? There’s be an event for every case including not being allowed to sing under water.
I think the problem people will have is using a declarative system. I do understand that.
But aren’t both Dialog and Inform declarative systems?
In Inform’s case I’ve always struggled with the syntax, not the declarative nature. Sharpee is about my own experiences. I’m not selling anything.
@DavidC - Given the high level of AI-snark on this board, I just wanted to weigh in and give you a
++ for what you are attempting to do.
I’ve read your Sharpee blog posts as they appear and, while I can’t say I understand it all 100% (I’ve been away from full-time coding for about 10 years), what I’ve read has made me decide to dig in deeper on Sharpee in the near future when I get the time.
Having been a long-time C# .NET developer in the past, I am a bit disappointed that you decided to moved to TypeScript, but I can’t fault your decision.
Keep up the good work.
Oh stay tuned. I might convert the code to a C# version!
@DavidC - Don’t do a TypeScript → C# migration just on my account.
Seriously, TypeScript is fine.
I have one question that I’m unclear about. You collaborated with an LLM to create the Sharpee system. But when I write my game, would I hand code it according to the repository examples or would I create LLM prompts and have LLM create the TypeScript code for me.
Sorry, might be a stupid question, but I’m unclear on the process.
This is the secret sauce of using Claude’s understanding and training on Typescript. It shows an enormous amount of capability compared to other languages like C#. (I believe its top languages are TS, JS, and python).
So theoretically I could train one of the smaller models on Sharpee and create a VS Plugin to allow authors to prompt for code snippets.
> create three rooms (kitchen is south of living room and north of foyer). I'll
fill in the details. All rooms are lit by default. There is an immovable table
in the kitchen, an immovable couch and coffee table in the living room, and a
coat rack on the wall in the foyer.
And this would create the Sharpee code. You’d then fill in the proper name and description in the generated code.
I do intend to make the fluent Forge layer regardless, but it will be an interesting world when you can prompt-develop your IF game, but still write the story elements yourself.
Speed-IF 2025 in December is going to be very weird.
And I wanted to move away from custom syntaxes and virtual machines. We have excellent platforms that follow older technology patterns.
Custom syntaxes and virtual machines stood the test of time because they allow to update the libraries without changing the game code or even binaries. JavaScript ecosystem is notoriously prone to hype and kinda expects the programmer to keep his code always up to date; some code I wrote in 2017 won’t compile on modern node.js since half of dependencies are deprecated. (goodbye, CoffeeScript…)
Pure JavaScript without the libraries does boast a great backward compatibility but TypeScript introduces breaking changes in every minor version. Games you’re writing now will not compile in 2030 without digging for contemporary versions of Sharpee, TypeScript and node. That’s a big step backwards from the popular IF-specific engines.
Virtual machines haven’t really stood the test of time, it’s just that people are still using them. In fact, i would say an IF system with a virtual machine isn’t a modern IF system at all.
Regarding custom syntax, you have a point about compatibility over time. I call this “change or die”, and it’s not very nice. One of the things i think is bad about the modern dev world. I’m interested to see how this pans out with Sharpee.
I did develop a DSL for my own IF system, but it is a double-edged sword. On the upside, sure, it will work in the future (so long as i don’t myself add breaking changes. And secondly, it’s easy to write IF in it (which was the main objective). But on the downside, it’s not a general language and, as such, if you wanted to write say, a chess program, you’d be stuck.
So i was compelled to add a second “sister” language that was for general programming. This i don’t actually use very much because the main purpose of the DSL is to cover nearly everything. But it’s there for that <1% of cases.
What we have here with Sharpee is an experiment to see if a general language with a confluent style is also easy to develop IF in and can rival a DSL. I’m really interested to see.
One would think that a critera for standing the test of time is that people still use them?
Indeed, I would agree. If we’re talking about virtual machines enabling long-term code stability, as originally suggested, then VMs like the JVM and CLR are strong examples. The JVM has been around since 1995 and still runs Java code from decades ago without breaking. Similarly, the CLR in .NET supports older C# applications. Both of these languages and the VMs continue to evolve. Both have had breaking changes, to be sure, but arguably of less impact on the development experience over time.
Given that context, I would argue these VMs show how you can update the runtime or libraries without forcing changes to the original code or binaries, which was at least part of the point about IF engines. Probably one of the better case studies here would be BEAM, the Erlang VM. This has pretty much thrived for telecom/apps since the late 1980s, with demonstrable excellent compatibility.
I think it’s risking caricature to just say this is solely because people just keep using them. They do, for sure, but people still use these VMs because they do solve the compatibility problem effectively. Not perfectly, perhaps. But effectively. It’s not just inertia.
So, yeah, I would agree that ongoing use is a sign of standing the test of time, especially when paired with technical stability. This isn’t a given, of course. The Flash VM, which powered ActionScript code in Adobe’s Flash Player, is a classic example of a VM that enjoyed massive popularity but ultimately faded due to various issues. Parrot VM is perhaps another example. This was intended for Perl 6 and was hyped quite a bit, but then largely abandoned. We could also put the Squeak VM in this category. Likewise, the Da Vinci Machine for the dynamic languages.
If I had a point here (and I’m not sure I did), I guess it’s that “standing the test of time” is really about balancing innovation with compatibility. This is something WebAssembly, as just one example, might achieve, but only time will tell.
I realize everything I’m saying is orthogonal to the discussion of Sharpee, which I’m still going through as we speak, but I do think it’s at least relevant to realize Sharpee is taking a particular stance on the virtual machine concept. Which I don’t think is a bad thing. Experimentation around ideas and the implementation of them is always good. (That, in fact, is how we got virtual machines in first place!)
Well kind-of, but the fact that something is still being used by people doesn’t make it necessarily the best way or even a good way.