swipe-typing

A small offline neural network that reads the path of a finger across an on-screen keyboard and says which keys it passed over. With a word list and a search step it turns a swipe into ranked word guesses. One model serves English, Spanish, French and German on any key layout. It is built for the Swipe Keyboard, an open-source swipe-typing and word-prediction add-on for KDE Plasma's on-screen keyboard, which uses it as its only swipe engine from version 0.5.0 (earlier versions used FUTO's engine).

Models trained and released by Destin Moss via youcoded.ai, 2026

File swipe-model.bin, 2,115,260 bytes (2.1 MB)
Languages English, Spanish, French, German (any layout)
Shape 2 convolution layers (96 wide, kernel 5), 2-layer bidirectional GRU (128 hidden units), small shared "pointer" scorer; about 529,000 numbers, stored as float32
Licence MIT
SHA-256 941272a7017229a73e07d1c0bd766757e739174db3a42fb622c26256b8c46110

It outputs probabilities over keys, not words, so it is not a word decoder on its own and cannot be used for handwriting or other gestures.

How it was built

  • Data: real swipes from FUTO's public swipe.futo.org collections (MIT licence, Copyright (c) 2025 FUTO): about 317,000 swipes from 35% of the recording sessions of collections 1 to 4, FUTO's dev set (about 47,600 English swipes after holding out validation sessions), and all of collection 5, which includes real French, German and Spanish swipes on their own layouts (repeated three times). Plus 100,000 synthetic swipes each for Spanish, French and German from our own generator (scripts/swipe/synth_swipes.py). No synthetic English.
  • Held out: FUTO's test split (including the 2,000-swipe bench-2000 and 10,000-swipe test-extra-10000 slices) and the validation sessions were never trained on. A check dropped any swipe whose id or session appeared in them, and found no overlap in any collection (56,005 swipe keys and 768 sessions compared). The HeliBoard gesture sets (CC BY-SA) were used for testing only.
  • No FUTO code or model weights were used; the network and code are our own, written from published methods (CTC, lexicon-constrained gesture decoding, SHARK2).
  • Training: scripts/swipe/train.py (PyTorch): CTC loss on the sequence of keys the finger passes, AdamW, one-cycle learning rate, 30 epochs, batch 512, dropout 0.2, and random changes to key geometry, speed and position of the trace during training. About 16 minutes on one NVIDIA RTX 4070 Super. The exact command line and augmentation strengths of the shipped run were not recorded (the script's random seed default is 1).
  • How it handles any layout: the network has no fixed output per key. At each of 64 time steps it scores every key from the finger's offset to that key (in key widths) and the key's size, with one small shared scorer, so QWERTY, AZERTY, QWERTZ and Spanish keyboards use the same weights.

How to use it

Who it is for: developers of an on-screen keyboard who want offline swipe recognition (about 3.5 ms per swipe on one CPU thread, no machine-learning library) in these four languages.

Pieces you need besides this file: a word list for the language (every answer is a word from it), and the search step. The project's code does all of this, in plain C++20 (needs only Qt 6 Core 6.8+ for Unicode): the network is engine/src/swipe_net.cpp, the word search engine/src/swipe_beam.cpp. The search is a beam search over a trie of the word list; its scores add the network's key probabilities, word frequency, a sentence prior when previous words are known, and a classical shape-matching cross-check. With no model file, or a damaged one, the engine falls back to the shape-matching decoder alone.

Input: the path (x, y, time) is resampled by arc length to 64 steps with 8 features each (x, y, dx, dy, log elapsed time, fraction of path done, step length, log path length), plus the live key rectangles. scripts/swipe/swipelib.py (trace_to_input) shows the same preparation in Python.

Minimal example (C++, from the project's engine/README.md; word lists are in GitHub release language-files-2026-10-23-apostrophes):

#include "swipekb/language_engine.hpp"
using namespace swipekb;

LanguageEngine engine;
LanguageEngineSetup setup;
setup.language   = "en";                 // "en", "es", "fr" or "de"
setup.dictionary = "en_swipe.combined";  // required word list
setup.ngram      = "en.ngram";           // optional sentence prior
setup.swipeModel = "swipe-model.bin";    // this file
if (!engine.init(setup)) { /* word list unreadable */ }

// trace: finger samples {x, y, t_ms}; keys: one {letter, x, y, w, h} per letter key, same pixel space
auto guesses = engine.recognize(trace, keys, contextWords("I think we"), 3);
// guesses[0].word is the best guess; engine.hasModel() is false if the model was not loaded

Limits

  • English trails FUTO's engine by 1 to 2 points on first guess (table below). Spanish and German also trail on the HeliBoard swipes; French is ahead.
  • A word missing from the word list is always a miss (42 of 2,000 English test targets, 2.1%). German is hit hardest: the shipped German list contains only 80% of the HeliBoard targets.
  • Only English has large real recordings. Spanish, French and German training is partly synthetic (plus a small amount of real data), so their results are less certain.
  • Accent twins (Spanish que / qué, French ou / où) have the same swipe path; the sentence prior or word frequency has to choose.
  • The training swipers are FUTO volunteers; their handedness, devices and language mix are not documented. No bias evaluation was done.
  • The file has no internal checksum; the keyboard checks its SHA-256 before loading it.

File layout (little-endian, engine/src/swipe_net.cpp): the 4 bytes SKNN; ten 32-bit integers (version 1, data type 0 = float32 or 1 = float16, time steps 64, features per step 8, key features 4, number of convolution layers 2, kernel size 5, GRU hidden size 128, GRU layers 2, pointer width 32); one integer per convolution layer (its width); then the weights as plain arrays: each convolution layer (weights [out][in][kernel], bias), each GRU layer and direction (input weights, recurrent weights, two biases, PyTorch gate order r, z, n), the pointer scorer and the "no key" (blank) scorer. Layer sizes come from the header, so a different size needs no code change.

How well it does

All figures are percent. First guess = the top suggestion is the intended word; top 3 = it is among the first three. Real swipes are from volunteers, never trained on: bench-2000 = 2,000 English swipes spread evenly over FUTO's MIT test split. "FUTO's scorer counts" = the 1,946 of them that FUTO's tool can score (target of 2+ letters, more than 2 trace points).

English, bench-2000

What was measured Swipes counted First guess Top 3
This model alone (frequency prior only) all 2,000 90.40 94.95
Whole keyboard (this model + word list + sentence prior, previous words given), build 0.5.0-0.5 all 2,000 90.10 93.10
Whole keyboard, same build 1,946 FUTO's scorer counts 91.47 94.55
FUTO's engine in the previous keyboard (0.3.x), previous words given 1,946 FUTO's scorer counts 93.32 96.56

So on the same 1,946 swipes the keyboard trails FUTO's engine by 1.9 points on first guess and 2.0 on top 3. FUTO's own command-line tool with its stock dictionary scored 92.50 / 95.43 on these swipes, which makes the gap 1.0 and 0.9; the 93.32 / 96.56 figure comes from running FUTO's models in the project's test harness with the project's word list. (The keyboard also hides stretched and rare spellings from guesses 2 and 3, so they are real words more often; that costs a little top-3 accuracy against the model alone.)

Other languages, first guess, real swipes from HeliBoard (test only; no sentence given; lower-case, accents kept, apostrophes ignored; "Swipes" is how many of the 5,000 per language were scored)

Language Swipes Whole keyboard (this model) FUTO's engine in keyboard 0.3.1
English 4,576 80.5 84.5
Spanish 4,790 75.9 77.7
French 4,999 68.2 64.6
German 4,980 64.7 69.7

Each engine used the word list it shipped with, and FUTO's was older and smaller, so this is a comparison of shipped keyboards, not of models alone. Two common English boards with nearly the same geometry differ by 5 to 7 points for every decoder tested, so some of the spread between rows is the swipers, not the decoder.

No comparison with Gboard's swipe typing was made. Test-set details and how each number was produced: METHODS.md.

Licence and credit

swipe-model.bin is MIT. The real training swipes come from FUTO's swipe.futo.org (MIT, Copyright (c) 2025 FUTO); keep the licence text FUTO-SWIPE-DATA-LICENSE.txt from this repository when you redistribute. Also keep:

  • the credit line above (Models trained and released by Destin Moss via youcoded.ai, 2026) and NOTICE.md.

The word lists used with the model carry their own attribution terms (FineWeb / FineWeb-2: ODC-By 1.0; Tatoeba: CC BY 2.0 FR; English also Apache-2.0); they are separate files.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Dataset used to train youcoded/swipe-typing

Evaluation results

  • first guess right, all swipes on bench-2000 (2,000 real English swipes, FUTO MIT test split)
    self-reported
    90.400
  • right word in top 3, all swipes on bench-2000 (2,000 real English swipes, FUTO MIT test split)
    self-reported
    94.950