18. Dezember 2018

Continuous learning at leanovate by teaching to type Pali

Fabian Bieker

Have you ever heard of a language called Pali?

It's an ancient language from India. It was a language spoken about 2500 years ago in northern India and Nepal.

The nice thing about Pali is that it was the language of the Buddha. The original teaching of the Buddha (called Suttas) where written down in it and are still available today.

In this regard it is a bit like Sanskrit: The Yoga Sutras are written in Sanskrit. Pali and Sanskrit also have some things in common, see here.

Even present day languages like Thai borrow about 30% of their words from Pali.

This is what Pali looks like:


19th century Burmese Kammavācā (confession for Buddhist monks), written in Pali on gilded palm leaf. Housed at the San Diego Public Library - from https://en.wikipedia.org/wiki/Pali#/media/File:Burmese_Kammavaca.jpg


The problem for most westerners is that Pali has its own character set (like Thai or Arabic for example) and most people don't want to learn new characters to read the Buddhist Suttas.

But luckily there is also a romanised version of Pali. It is more accessible since the characters are:

a ā i ī u ū e o ṃ k kh g gh ṅ c ch j jh ñ ṭ ṭh ḍ ḍh ṇ t th d dh n p ph b bh m y r l ḷ v s h

The complete suttas are available on sites like sutra central, even a translated version.

People writing romanised Pali use custom keyboard layouts - your typical QWERTY keyboard, for example - pressing key combinations like ALT+a (or something like FN+ALT+a) to get an ā. For uppercase characters this would then become SHIFT+ALT+a (or SHIFT+FN+ALT+a). That's all good fun, especially if you are used to emacs (just kidding!) .

But.. Maybe there is some room for improvement:

One of the nice characteristics of Pali is that a (18.6%), t (6.8%), i (6.7%) and ā (6.4%) are extremely common characters. And the general character distribution is very unbalanced, making it a bad language for ROT13 "encryption", but great for optimising a keyboard layout.

There is a software called carpalx which can be used to generate customised keyboard layouts for a given corpus of texts. You can for example generate a keyboard layout for English or German where your hand movements are optimized (to reduce carpal tunnel syndrome - hence the name). These layouts are generated based on your favourite few novels (and people have actually done that!). Alternatively, you could create a custom layout for Javascript, Scala, Smalltalk and Lisp...

Carpalx uses Monte Carlo simulations to find an optimal layout and they have done quite a bit of research on layouts like QWERTY (http://mkweb.bcgsc.ca/carpalx/?qwerty) or Dvorak (http://mkweb.bcgsc.ca/carpalx/?dvorak).

Now, about our project: We used carpalx to generate a decent layout for romanised Pali (turns out we can do a lot better than using ALT modifiers for super common characters). The carpalx and auto hot key files for the Pali Layout can be found on github. We call it the “meat layout”, due to the home row actually starting with the word "ṃeāt" - Sometimes Monte Carlo finds funny solutions...

keyboard layout


So... What's the problem?

The layout is quite different from QWERTY. That means you basically have to relearn typing. A typing tutor would be helpful. There is a bunch of open source software out there, that's great for learning the common layouts, and a few even support custom layouts. But I couldn’t find anything that worked well on all systems -  Mac, Windows and Linux.

The problem with Windows for example is that we have to use auto hot key to do the keyboard mapping. This does not work well with some keyboard tutors.


So... Who cares about romanised Pali anyway?

Well... My Buddhist Teacher cares, that means I care, as do a lot of other Buddhist monks, nuns, lay followers, researchers and language nerds. It's a bit of a niche, but we like it.

And my Teacher uses a Windows notebook.


So... What can we do?

Well... we just write a little keyboard layout training app. And let's make it a progressive web app. Writing windows software is a bit to much suffering for my personal taste.

But, it is going to be a bit of work...


Now... there is this awesome guy:

He is my boss at Leanovate (awesome company btw) and he figured we want to work a week on our own project to facilitate learning. I explained to him what I was up to and he liked the idea.

So... without further ado: https://github.com/notfb/palikeys - It's open source. An PWA build with Angular 7 (no mobile support though, just an MVP for desktops / notebooks ) and node.js 10.

I made it an PWA, because some users of Pali live in places like this:

Internet bandwidth might be low or non existent at times... (Actually, most of those places have decent 4G coverage by now, but you get my point.)


So... Let's talk about the tech stuff

Turns out, creating a PWA with angular cli boils down to ng add @angular/pwa and configuring some caching strategies. (And trying not to get confused by the prod environment, caching stuff in wired ways.)

Which is great, because it left me time to create customer value and even build a small backend using firebase functions for storing high scores for the typing lessons. More details on creating an angular PWAcan be found at the angular website.

I shifted away from my normal mode of operation (writing a lot of tests, making sure the code is nice) and thought more about the needs of my stakeholder. Keep in mind I only had a week to do this and I wanted to build a decent product / MVP, not a polished code base to show to other developers.


Generating the Typing Lessons

Since we want to support custom keyboard layouts, we need a way to generate typing lessons for any given layout.

Turns out that is quite simple: If we know which keys are on the top-, home- and button-row, we can just generate random character sequences and let the user type those. We start with a few keys on the home row and expand from there.

For a QWERTY layout the data structure to create the lessons looks like this:

private readonly qwerty = {
  numberRow: '§1234567890-='.split(''),
  topRow: 'qwertyuiop[]'.split(''),
  homeRow: 'asdfghjkl;\'\\'.split(''),
  bottomRow: '`zxcvbnm,./'.split(''),
  homeRowWords: ['add', 'alaska', 'as', 'ask', 'dad', 'fad', 'flagfalls', 'gag', 'gal', 'galagala', 'galahads', 'hadassahs',
    'haggadahs', 'hash', 'haskalah', 'lad', 'lag', 'saga', 'salad', 'salads', 'shakalshas', 'shall', 'slash', 'jfk'],
  texts: englishLong

Then we just use a massive switch statement to generate the characters we will use to generate a lesson:

switch (lessonNumber) {
  case 1:
    chars = [layout.homeRow[3], layout.homeRow[6]];
  case 2:
    chars = [layout.homeRow[2], layout.homeRow[3], layout.homeRow[6], layout.homeRow[7]];
  // ....


Next, we create four character random words with a space in between and display them in a text area with a fixed size font (remember... MVP...).

private makeLessonFromChars(chars: string[], length: number) {
  let lesson = '';
  for (let i = 1; i <= length; i++) {
    if (i % 5 !== 0) {
      lesson += chars[Math.floor(Math.random() * chars.length)];
    } else {
      lesson += ' ';
  return lesson.trim();

And voila - here is our typing lesson...

Yes, the massive switch statement is a bit messy, but we want to do a few other things as well:

For lesson five and six, we can use some real words that can be typed by only using the home row:

Especially the Pali layout offers quite a lot of words to be typed by just using the home row. As any decent keyboard layout should. (Hint, hint) That is what the homeRowWordsattribute in the layouts is used for (s.a.). At the end of the course we can let the user type a real text. That’s what the textsattribute is used for. The complete code can be found in the lesson.service.tsfile.


Lesson UI

The rest is quite simple: We ensure that the text area keeps the focus (this is a bit nasty, but remember MVP...) and mark the typed text in green when the users types the correct keys.



When the user makes an error, they have to start over.  Why? To really increase the typing speed.

Most typing tutors let you make as many errors as you want and then tell you that you are capable of typing 30+ words/minute with an accuracy of something like 90%.

This basically means you make an an error every ten characters, which forces you to correct those later, completely ruining your typing speed.

By insisting that the user keeps training until they don’t make any errors anymore, we make sure that they can actually type a lot faster in real life.

This is quite painful in the beginning, but very, very beneficial in the long run.

We give the user some points if they manage to type more than 20 characters correctly. And a lot of points if the manage to complete the whole lesson.

The final UI looks like this (we show the user the keyboard layout and provide a mapping service to allow users to start learning the Pali layout with having to install a custom keymap):

The high score ui looks like this (don’t worry it’s only made up test data in the screenshot):

REST API for Scoring

There is a small REST API that handles high scores. The API design itself is not particularly interesting, but the GETs are cached via the PWA Service Workers. The PUT / POST calls are not cached by a Service Worker, but it would be nice if this part worked offline, too.

The idea is be to cache the POSTs and PUTs and play them back when the user is online. It's only possible to increment a high score by a certain amount, instead of doing a full update. This enables us to ignore most ordering issues.

For caching / syncing the Chrome Background Sync might be used for example. Due to the limited timeframe, I never got around to implementing this.


In case I got you interested - check out the code at https://github.com/notfb/palikeys. You are welcome to create pull requests or fork the project.

I'm going to travel for some time, please don’t be disappointed if I don't respond quickly...

Fabian Bieker
Software Craftsmanship | Analytics | Agile

Rufen Sie uns an: 030 – 555 74 70 0

Made with 
in Berlin. 
© leanovate 2020
Leanovate GmbH, Besitzer: (Firmensitz: Deutschland), würde gerne mit externen Diensten personenbezogene Daten verarbeiten. Dies ist für die Nutzung der Website nicht notwendig, ermöglicht aber eine noch engere Interaktion mit Ihnen. Falls gewünscht, treffen Sie bitte eine Auswahl:
Leanovate GmbH, Besitzer: (Firmensitz: Deutschland), würde gerne mit externen Diensten personenbezogene Daten verarbeiten. Dies ist für die Nutzung der Website nicht notwendig, ermöglicht aber eine noch engere Interaktion mit Ihnen. Falls gewünscht, treffen Sie bitte eine Auswahl: