Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Hoot example project

A topic by David Thompson created May 06, 2025 Views: 299 Replies: 13
Viewing posts 1 to 9
HostSubmitted (1 edit) (+1)

If you are interested in making a web game using Scheme then Hoot is a great option for you! Hoot is a Scheme to WebAssembly compiler that supports most of R7RS-small and some Guile extensions such as delimited continuations (useful for scripting games via coroutines). At Spritely, we just released version 0.6.1 and updated our game jam template repository on Codeberg that has everything you need to get started making 2D games.

The template repository includes:

  • Bindings to the necessary web APIs to make an interactive game with HTML5 canvas
  • A Makefile for compiling, running a development web server, and generating a .zip bundle for uploading to itch.io
  • A very simple Breakout-like example game that demonstrates how to put all the pieces together

Some games made with Hoot for past jams:

I'll do my best to help anyone that uses Hoot for the jam, whether here in this forum, on the official Spritely forum, or on the #spritely channel on the Libera.Chat IRC network. Have fun!  馃

I have some questions regarding hoot.

- is there some sort of enum or constant?  the (rnrs enums) guile module is not available.

- how can I use  #:print  with define-record-type?, bytevectors printed using pk are not very informative; and I can't use pk in a module so I'm not sure how to create a print function.

- what is the use case for the call-external function?. It seems that it allows direct access of javascript function without the need of a binding.

HostSubmitted (1 edit)
  1. We don't have (rnrs enums) built-in. We have very little R6RS support, in general. It might be possible to import it from Guile itself but it's more likely that it will have some unmet dependencies. Scheme doesn't have a "define constant" expression, in general, but if you were to do (define foo 42) then Guile's compiler will perform constant propagation to optimize all references to foo if it is never modified with set!
  2. Here's an example of a custom printer. The #:printer keyword comes before all the usual record type specification. https://codeberg.org/spritely/hoot/src/branch/main/test/test-records.scm#L116
  3. call-external is for invoking a reference to an external function (a JS function in practice). Let's say you have a foreign binding like (define-foreign foo "example" "foo" -> (ref extern)) and the (ref extern) is expected to a function reference. call-external provides an easy way to call that external function almost as if it were a Scheme procedure.

Thank you. Simply adding a  printer to vec2 improves how pk displays all the other records (that have vec2 fields).

HostSubmitted

Ah yes, good idea! We should update the template repo with it for next jam.

Submitted

Hi, I'm interested in using hoot, but I'm new to wasm and web dev in general. I have some questions wrt hoot's FFI.

Following the example from the documentation: https://files.spritely.institute/docs/guile-hoot/latest/Foreign-function-interfa..., I created hello.scm as follows:

(use-modules (hoot ffi))
(define-foreign make-text-node 
"document" "createTextNode" 
(ref string) -> (ref extern))

Then, I compiled it to wasm:

guild compile-wasm --bundle -o hello.wasm hello.scm

Then, I loaded it into guile repl:

(use-modules (wasm parse))
(use-modules (hoot reflect))
(hoot-instantiate (call-with-input-file "hello.wasm" parse-wasm)
(("document" .  
(("createTextNode" . ,(lambda (str) (text ,str)))))))  

Then, I tried to use the make-text-node function: 

(define hello (make-text-node "Hello, world!"))

But it always gives me the error: Unbound variable: make-text-node.

I'm not sure if I'm fundamentally missing something. I'm just wondering if there's a way to test these kinds of procedures in a guile repl.

HostSubmitted (2 edits)

You're close! The misunderstanding seems to be that your are expecting that instantiating the module will modifiy the top level REPL environment. This is not the case and it would be kinda scary if it did that. Wasm modules are their own separate, isolated things. If you want a reference to the make-text-node procedure then you should return it by referencing it in the final line of the program you're compiling with Hoot. From there, run hoot-load on the instantiated module and if you've done everything correctly, the result will be a reference to the make-text-node procedure. The tutorial in the manual goes through this process in more detail.

Submitted

Hey! 

I'm struggling using conditional expand with guile hoot. E.g., I want to have a "message" function display stuff either to terminal (when called there) or to a  HTML element (when called in wasm).

I tried something like:

(cond-expand
 (hoot 
  (define-module (ui ui)     #:use-module (web dom)     #:export (message)))  (else   (define-module (ui ui)     #:export (message)))) (cond-expand  (hoot   (define (message msg)     "Display a text message"     (append-child! (document-body) (make-text-node msg))))  (else   (define (message msg)     "Display a text message"     (display msg)     (newline)))) (message "Foo")

This works when called in normal guile, but not when trying to build wasm ("hoot/library-group.scm:604:5: In procedure parse-library:invalid module forms (lot of stuff)")

I'd be really thankful if I could have any pointer on the way to do that cleanly :)

(Thought in any case given the deadline I'm afraid I won't be able to send more than a hello world to this jam 馃槶 )

HostSubmitted

You can't cond-expand a module definition because you need the module definition in order to know what names are imported, including cond-expand. Rather than wrapping define-module in cond-expand, you need an inner cond-expand.  Unfortunately, Guile's define-module doesn't support a cond-expand form. Fortunately, R7RS's define-library does! So, you'd want to do something like this:

(define-library
  (cond-expand
    (hoot (import (web dom)))
    (else))
  (export message)
  ...)
Submitted

Thanks a lot!

Hey there :)

I am trying to publish my "game" to itch.io. How do I make it playable in the browser ? Do I have to host it myself and embed it ?

I found how to embed it but I get `Uncaught (in promise) ReferenceError: Scheme is not defined` when opening in itch.io

Ok I also get this error locally. Something is not working when bundling

(1 edit)

I just bypassed the `make bundle` command and used zip manually, now it works. Keyboard input does not seem to work though