-
SurveyJS
Open-Source JSON Form Builder to Create Dynamic Forms Right in Your App. With SurveyJS form UI libraries, you can build and style forms in a fully-integrated drag & drop form builder, render them in your JS app, and store form submission data in any backend, inc. PHP, ASP.NET Core, and Node.js.
Web Audio support
In addition to Canvas, I've implemented Web Audio support. So you can live-code music now!
Adding Web Audio wasn't trivial because the Gambit interpreter is running in a Web Worker. So I have to send messages between the worker and the main JS thread to access any browser APIs.
Canvas was easy to implement, because it's mostly procedural calls like `fillRect`, `stroke` etc. So I'm just sending commands from Lisp to JS.
Web Audio, on the other hand, is about creating trees of audio nodes. E.g. you create an Oscillator node and connect it to a Gain node, and finally connect the Gain node to a Destination node (output). Also you can set parameters on each node (e.g. the frequency of an oscillator).
This all means that Scheme needs a way to reference created nodes. However, I cannot send a node directly in a message from JS. Only atomic values like strings and numbers. To circumvent this limitation, I've created a registry of nodes in JS which can be accessed by id.
Scheme, when calling a Web Audio method, provides an id to store the result in. Also if it passes an id in one of the arguments, JavaScript looks it up in the registry and makes the call on the corresponding node.
setTimeout as a Scheme macro
Web Audio is not fun if you can't program timed events for it. E.g. a sequence of notes, or a volume envelope that changes over time. So I had to make the Scheme code asynchronous.
Scheme, just like JavaScript, is single-threaded and "synchronous". It needs a second process to tell it when to run a delayed call to achieve asynchronous behavior.
I've implemented a macro – https://github.com/katspaugh/lambda.quest/blob/main/scheme/w... – (which is btw my first macro ever) to put a Scheme callback in a JS `setTimeout`.
Macros, for me, is such a mind-blowing thing. It was amazing to code one purposefully, to achieve a practical goal.
GitHub API and OAuth
You can save your Scheme creations as gists on GitHub. I've implemented GitHub OAuth with a serverless worker on CloudFlare. The worker, of course, is also written in JS. All my projects are hosted on CloudFlare btw, it's amazing.
Preact
Finally, I've used Preact and HTM for a React-like UI rendering. HTM is basically JS template strings that look like JSX and spit out DOM trees. Pretty neat, although a bit hard to edit.
Github
All the code is open-source (MIT) and can be read on GitHub: https://github.com/katspaugh/lambda.quest
Pull requests and feedback are very welcome. Thanks for reading!