Skip to main content
╔════════════════════════════════════════════════════════════════════════════════════════════╗
║                                                                                            ║
║       ██████╗ ███████╗███╗   ███╗ █████╗ ██████╗ ██╗    ██╗██████╗  █████╗ ██████╗         ║
║       ██╔══██╗██╔════╝████╗ ████║██╔══██╗██╔══██╗██║    ██║██╔══██╗██╔══██╗██╔══██╗        ║
║       ██████╔╝█████╗  ██╔████╔██║███████║██████╔╝██║ █╗ ██║██████╔╝███████║██████╔╝        ║
║       ██╔══██╗██╔══╝  ██║╚██╔╝██║██╔══██║██╔═══╝ ██║███╗██║██╔══██╗██╔══██║██╔═══╝         ║
║       ██║  ██║███████╗██║ ╚═╝ ██║██║  ██║██║     ╚███╔███╔╝██║  ██║██║  ██║██║             ║
║       ╚═╝  ╚═╝╚══════╝╚═╝     ╚═╝╚═╝  ╚═╝╚═╝      ╚══╝╚══╝ ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝             ║
║                                                                                            ║
║                             your phone is the control surface                              ║
║                                                                                            ║
╚════════════════════════════════════════════════════════════════════════════════════════════╝

PyPI Python Licence

RemapWrap layouts, built by machine. A folder of samples becomes a soundboard, a list of applications becomes a mixer, a list of shortcuts becomes a deck.

pip install remapwrap

remapwrap soundboard ./samples -o board.json     a pad per sound file
remapwrap mixer Discord Spotify chrome -o mix.json   a slider per application
remapwrap deck "Copy:ctrl+c" "Paste:ctrl+v" -o keys.json
remapwrap check board.json                       would this work
remapwrap describe board.json                    what is in it

Open the RemapWrap dashboard, import the file, and the surface is on your phone.

Why this exists

A forty-pad soundboard is twenty minutes of dragging, and the folder of samples already knows what the pads are. So does the list of applications currently playing audio, and so does the config file where somebody keeps their shortcuts. Every one of those is a layout that a person should not have to build by hand.

The dashboard is where a surface gets adjusted — moved, recoloured, tried. This is where one gets made.

What a layout is

One JSON document. Cells, not pixels, so the same layout fits a phone held either way.

{"cols": 12, "rows": 21, "keys": [
  {"id": "k1", "type": "pad", "behaviour": "trigger",
   "command": "sound.play", "arg": "airhorn.wav",
   "label": "AIRHORN", "sub": "soundboard", "color": "#2a1216",
   "x": 0, "y": 0, "w": 4, "h": 4, "shape": "rect"}
]}

Seven control types — key, toggle, pad, dial, slider, timer, input — four shapes, and a command from a fixed catalogue of twenty-nine. Read or write it with anything; it is JSON, and this package imports nothing that is not in the standard library.

Every command in COMMANDS is one the surface actually carries out — including speak.text, which is what makes a board of keys a way of talking rather than only a way of pressing things, mouse.* for stepping a pointer around without holding a mouse, and clip.phrase, which puts a whole sentence on the clipboard and pastes it — so what arrives is what was written, emoji and all, which typing it key by key cannot promise. Eight more are named in PLANNED and deliberately kept out of the catalogue: obs.* needs an obs-websocket connection and stream.* needs a Twitch token, and a list where a third of the entries exist only to announce their own absence is a worse list than a shorter true one. Binding one is reported as its own kind of problem, not as a typo:

REC is bound to 'obs.record', which is planned but not built.
It would be a key that does nothing.

The rules are written twice on purpose

The dashboard enforces these rules in JavaScript. This package enforces them again in Python, and that is not duplication for its own sake: two implementations of one rule set disagree exactly where one of them is wrong. Running them against each other has found more defects in this codebase than reading either one ever did.

check returns sentences rather than codes, because the person reading them is the person who has to fix it:

- BAD DIAL is a dial bound to 'capture.shot', which takes no value. A dial cannot fire it.
- BAD KEY is a key bound to 'audio.master', which reports a value. Use a dial or a slider.
- OFF BOARD sits at 22,14 and is 4x4, which runs off a 24x16 board.
- TYPO is bound to 'not.a.command', which is not a command.
- ELLIPSE is a circle 4x6; a circle has one dimension.
- 'BAD DIAL' and 'OVER A' overlap.

A generator that cannot produce a valid layout raises instead of writing a broken one.

As a library

A timer counts down from its arg in seconds, or up when it is blank. An input opens the phone's own keyboard and what is written lands on the PC through the clipboard, so an accent or an emoji arrives as it was written. Neither carries a command, and check says so if one is given.

A toggle can carry a second face for when it is on, so a key says what is true rather than only what it does:

{"type": "toggle", "command": "audio.mic.mute", "label": "MIC LIVE",
 "whenOn": {"label": "MUTED", "color": "#2a1216"}}
from remapwrap import generate, layout

board = generate.soundboard("./samples")
layout.place(board, layout.control(
    type="slider", command="audio.master", label="MASTER"))

problems = layout.check(board)
if not problems:
    layout.save(board, "board.json")

place finds a free spot and leaves a cell of air around it, because a surface where every key touches its neighbour is a surface people press two of at once.

What it does not do

It does not talk to your phone, press a key, or open a socket. It writes the document a surface is made of, and the RemapWrap dashboard does the rest. There is no network code in this package at all.

Dependencies

None. Standard library, Python 3.8 and up.


╔════════════════════════════════════════════════════════════╗
║                                                            ║
║      ███████╗      ██╗  ██╗███████╗██╗   ██╗███████╗       ║
║      ██╔════╝      ██║ ██╔╝██╔════╝╚██╗ ██╔╝██╔════╝       ║
║      █████╗  █████╗█████╔╝ █████╗   ╚████╔╝ ███████╗       ║
║      ██╔══╝  ╚════╝██╔═██╗ ██╔══╝    ╚██╔╝  ╚════██║       ║
║      ██║           ██║  ██╗███████╗   ██║   ███████║       ║
║      ╚═╝           ╚═╝  ╚═╝╚══════╝   ╚═╝   ╚══════╝       ║
║                                                            ║
║               ·   C  R  E  A  T  I  V  E   ·               ║
║                                                            ║
║          ────────────────────────────────────────          ║
║                                                            ║
║                      Vincent Gonzalez                      ║
║                         f-keys.com                         ║
║                 ORCID 0009-0005-3640-014X                  ║
║                                                            ║
╚════════════════════════════════════════════════════════════╝

Part of F-Keys — independent hardware, software and internet products. See the working log and live status.

Part of F-Keys — independent hardware, software and internet products. See the working log and live status.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

remapwrap-0.4.0.tar.gz (15.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

remapwrap-0.4.0-py3-none-any.whl (14.4 kB view details)

Uploaded Python 3

File details

Details for the file remapwrap-0.4.0.tar.gz.

File metadata

  • Download URL: remapwrap-0.4.0.tar.gz
  • Upload date:
  • Size: 15.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for remapwrap-0.4.0.tar.gz
Algorithm Hash digest
SHA256 a7eaaace287383f013573b378fdad9aa808fd68753ae4cf9bdf38598b4bcfd26
MD5 a10705464d218b2ef525b27b6ac24e6b
BLAKE2b-256 f9b6435e1743281e350e5f45bb386c4b6222835cfdc485331ce0337c397cea51

See more details on using hashes here.

File details

Details for the file remapwrap-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: remapwrap-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 14.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for remapwrap-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 30e52748fbd8d46a06909f54d1d60c88b96a2468717dbcb2059ca6ed679c0c5b
MD5 8e12ae219f52bbd35f2c75fd3b61cb08
BLAKE2b-256 09026f3b3e7197f5194734b868f795f051ea775db77416e950bbb359484257ed

See more details on using hashes here.

Release history Release notifications | RSS feed

0.6.0

2 files

0.5.0

2 files

This release

0.4.0 This release

2 files

0.3.0

2 files

0.2.0

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page