Snake Arabic (Snarabic)
About the game
The goal of the game is to grow your snake as long as possible. The snake steers itself, you just need to type in the correct Arabic letter before the snake gets there. Your snake is a string of classical Arabic text, moving in languid loops and arcs, reminiscent of Arabic calligraphy. Like Arabic text, the gameplay moves from right to left (how often do you see that in a game?). There's a "normal" mode, an "easy" mode that shows you what key to press, and a "demo" mode that plays itself, endlessly. That's about it! It's helped me learn to discern the different forms the characters can take and how to sound out Arabic words. This is surprisingly helpful! Even if I don't know what most words mean, I can use my newfound sound-it-out knowledge to figure out important words like كافيه kafyh "café" and حمص humas "hummus".
Whatever you do, don't press "M" while you're on the title screen.
Canvas? Why Canvas?
My first draft did not use Canvas. The path of the snake would be calculated in advance and I'd slap the text string onto the path with an SVG textpath. Working with right-to-left (RTL) text is bonkers, y'all. I can't believe how little consensus there is on how to work with a writing direction used by more than a billion people. Different SVG renderers handle Arabic textpaths in completely contradictory ways. Web architects, do better! Come up with a unifying set of rules for handling RTL text in SVG!
Consequently, SVG texpaths were out. HTML5 Canvas is an okay substitute. You can see from the screenshot that it's far from perfect. I have to render each character individually, which produces a new set of challenges for a cursive, ligature-laden script like Arabic.
Most Arabic letters have an initial, medial, final, and isolated form. Since I'm rendering Arabic letters one-at-a-time, they default to their isolated forms, which is almost never the form I want them to take. For example, the nonce word بيدرا beydra:
The letter bāʾ takes its initial form; yāʾ takes its medial form; dāl takes its medial/final form; rāʾ can't connect to dāl so rāʾ also takes its medial/final form; and ʾalif takes its isolated/initial form since it can't connect to rāʾ. Things would look way worse if all of the letters were in their isolated forms.
The secret to getting the right letterforms was to insert zero-width joiners and zero-width non-joiners flanking every character I printed to the screen. For example, by putting a zero-width joiner on both sides of a letter, it forces that letter to take its medial form instead of its isolated form.
Fun fact: I tried putting a little text-processing demo here, but it works on Chrome and not Firefox. So I went to get screenshots from an old presentation I had on Google Slides, and all my Arabic examples had returned to isolated letterforms?? I swear it used to look perfect a few months ago. It just goes to show how little web support there is for the FIFTH-LARGEST LANGUAGE ON EARTH.
The code is all right here on Github and you're free to fork it and do whatever you please! There are oh-so-many ways the game could be improved, but I don't feel qualified to do much more in the Arabic-teaching space than I've already done.