Moddable SDK 9.5.0
Pre-releaseModdable SDK 9.5 contains improvements made between August 4, 2026 and September 4, 2026.
IMPORTANT: Because of the many changes in this release, we want to give our developers some time to work with it before we make it the default. Therefore, this release is not yet marked as "latest". We plan to switch it to latest on Monday September 7 if there are no blocking issues reported.
A special thank you to @d01c2 for reporting eleven JavaScript conformance issues in a single month. And, yes, all of them are fixed in this release.
FreeType – Scalable Text
Rendering text is tough. The Moddable SDK has provided great tools to let you easily include pre-renderered anti-aliased fonts in your projects, thanks to our integration of fontbm into our build system. Through our partnership with Monotype, we've been able to offer scalable fonts using their amazing Spark renderer for commercial use. But until now, we haven't had an open-source solution for scalable fonts.
Moddable has long used FreeType to render outlines to bring SVG shapes to embedded devices. It is natural that we build on that to use FreeType to render scalable OpenType and TrueType fonts on embedded devices. This release does just that. By switching to our new FreeType font engine, both Commodetto and Piu applications can easily integrate scalable fonts. It does require more memory and code space, but many devices today can handle that, including Moddable Six. Performance is generally great, and the quality is excellent.
We've added several new examples so you can try our scalable fonts immediately.
- Text Styles. An interactive application to exercise the many text properties available using Piu.
- Pinch. Use two fingers to scale the text and one finger to drag - just like on your mobile phone.
- Text Clock. Beautifully rendered clock with multiple fonts and sizes. This uses FreeType to convert the words to outlines so they can be easily rotated and scaled.
The FreeType integration shares many of the lessons learned from the Monotype integration, including a Poco-friendly compressed font cache that both reduces the size of glyphs in the cache and allows them to render faster.
The FreeType configuration excludes the TrueType bytecode interpreter, to minimize code size. The interpreter is required for some East Asian fonts (CJK). Enable it with MODDEF_CFE_FT_HINTINGBYTECODE in your project manifest.
RFID
Hardware to support RFID (Radio-Frequency Identification, aka Near-Field communication) has been increasingly common. We're introducing an RFID API based on the ECMA-419 Sensor Class Pattern. It supports common NFC operations including detecting when a tag is present, reading and writing blocks, and using the NDEF format (NFC Data Exchange Format). We've implemented this for the MFRC522/WS1850S, PN532, and ST25R3916 RFID chips. There are new examples to get you started - detecting RFID presence and logging that to the console or display, and writing using NDEF. Check out the readme to get started.
The M5Dial includes the MFRC522, so we've updated its host instance provider so you can instantiate the RFID sensor through new device.sensor.RFID().
WebDAV – Every Device is a File Server
Wouldn't it be great if you could easily copy between your computer and your embedded device? With our new WebDAV module, you can. WebDAV is a file server protocol, standardized in RFC 4918, with client support on macOS, Windows, and Linux. That means you can mount your embedded device as a file server from your computer and use the GUI or command line to move files back and forth.
The macOS Finder integration of WebDAV is very chatty, which slows things down. If you have lots of transfers to do, we like Transmit 5 from Panic as a GUI, or you can use the command line.
Our new WebDAV implementation is actually not that new. It is an update of unpublished work from nearly a decade ago by Mark Wharton.
XML - Parse and Serialize
XML? In 2026?!? Yes. XML never went away, even if JSON does rule the world. One use of XML is the WebDAV protocol (another is our xsbug protocol!). We've integrated an XML parser and serializer in this release, and it is used extensively by the WebDAV implementation. Both the parser and serializer are carefully optimized for embedded use, taking great care to minimize memory use and work with data efficiently. Many thanks to Mark Wharton for his meticulous work. When your project needs to handle XML, there's now a reliable solution built into the Moddable SDK.
HTTP Server - Keep-alive and Hardening
Our ECMA-419 HTTP Server implementation has received a lot of attention in this release. Much of that was motivated by the WebDAV integration, as WebDAV is an extension to the HTTP Server. Requests are handled faster and more reliably.
- Keep-alive now supported. With keep-alive support, the HTTP Server can respond to several requests over a single TCP connection. This eliminates the overhead of creating a TCP connection for each request, overhead that is substantial, particularly when the requests themselves are small.
- onRoute callback. The routing of incoming requests has been significantly streamlined with the new
onRoute()callback. Our HTTP Server Guide explains how to use it. - Hardening. The underlying TCP and Listener sockets had race conditions on platforms using lwip (ESP32, Raspberry Pi Pico). These led to stalls, subtle failures, and crashes. These have been resolved.
- Optimization. HTTP request header parsing has been rewritten to eliminate the garbage collector thrashing of the original versions.
ECMA-419 Migration Continues
Our mission to have the Moddable SDK fully based on ECMA-419 continues to make progress. This release migrates the Button, LED, and Backlight classes from the original pins API to ECMA-419. This required updates to dozens of device build targets. We've done this work to be backwards compatible as well, but it is a lot of changes to test.
To help with your migration to ECMA-419, we've added warnings to the build when the project includes the manifest of a module that has an ECMA-419 alternative available. The migration warnings appear at the very start of the build. Please check your projects. There's still more work to do in the Moddable SDK to complete the migration. Your PRs to assist, especially in the device targets, are very much appreciated.
Guides – More Docs for Developers and their LLMs
Our new Guides, introduced in August, are the documentation you've always wanted: code-first, concise, and clear, filled with practical examples of common tasks faced by Embedded JavaScript developers. This month adds several new guides:
- HTTP Server. Every project seems to reach a point where it needs an HTTP server. Adding that can be intimidating. It is actually pretty easy. Our guide shows how to create a server, serve web pages, upload and download files, and more.
- WebSocket Server: The WebSocket protocol is usually the most efficient way to have bidirectional conversations between an embedded device and a remote. This is especially true when communicating with a web browser. Adding a WebSocket Server to your project is easy – it builds on the HTTP Server.
- Captive Portal. Configuring Wi-Fi is one of the most challenging aspects of many real Embedded JavaScript projects. Often developers resort to building custom mobile apps for this. Our captive portal module lets users configure Wi-Fi using their phone's browser: no mobile app is required. You can even use the captive portal to configure other device settings like date and time, time zone, daylight savings time offset, and the user's preferred language.
- How Time and Timezone are Initialized. Demystifies how time and timezone are initialzed when debugging and what you need to do in your project to initialize them when not debugging.
In addition to the new guides, there are many updates to the existing guides based on experience using them.
ESP-IDF v6.1
We've upgraded to the latest ESP-IDF v6.1 from Espressif. You probably yawn and stop reading when you hear "IDF update." We do them often, so you can stay up-to-date with the latest fixes, optimizations, and security fixes from Espressif. This update has a very real benefit for Embedded JavaScript developers: differential flashing (aka "fast reflashing").
What's differential flashing? The idea is simple – only reflash what has changed between builds. A small change to a script shouldn't require reflashing the entire firmware. For that to work, the firmware needs to be ordered so the pieces that change the most frequently are located at the end of the firmware image. For Embedded JavaScript, that means putting the preloaded virtual machine and JavaScript bytecode at the end of the firmware. We've updated the Moddable SDK build to do just that, and the results are superb. Reflashing after a script change often takes about a second.
Instructions for updating are in our documentation. If you forget to update, the build will remind you.
Details
- ECMA-419
- TCP Socket
- Mac, Windows, and Linux handle
EAGAINon read - Mac, Windows, and Linux throw on unexpected write error
- lwip
- Manage output buffer in Moddable SDK for better control & reliability
- Reliability improvements for multi-threaded deployments (contributed by @meganetaaan, building on contributions of @xymeow) #1679
- Mac, Windows, and Linux handle
- HTTP Server
- Changed webpage module specifier to static and websocket to ws/handshake - both to match ECMA-419 standard
- Implement connection re-use (keep-alive)
- Fix occasional stall at the end of a request
- Add experimental
onRoute()to simplify routing - Add query to request object to simplify routing
- Don't invoke onReadable with count of 0
- HTTP Client
- Move from
device.network.http.iotodevice.network.http.client.iofor conformance
- Move from
- WebSocket Client
- Handle request headers larger than a TCP buffer (contributed by @meganetaaan) #1678
- BLE Client - show optional callback argument for
GATTServerConnection.notify()(reported by @stc1988) #1680 - GPIO expander - correct initialization of pullups (contributed by @Templarian) #1689
- Files
- POSIX- rewind needed after
dup()when creating new directory iterator - Throw on disk full write errors
- POSIX- rewind needed after
- TCP Socket
- Modules
- TLS
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384andTLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384- Single certificate chains
- Reduce memory use by freeing handshake digest
- fetch() (streaming version)
- use pull source for better buffering
- abort & cancel close http client
- web/console - rename trace to info (reported by @stc1988) #1674
- Commodetto
- FreeType font engine (see above)
- Add manifests for all Commodetto modules for consistency and compatibility with
mcpack - Outline.clone() accepts optional buffer to clone into to minimize memory allocation
- Piu
- Scalable fonts with FreeType (see above)
- Fix obscure bug in
PiuApplicationStartContent()that could corrupt memory (appeared on ESP32 as piu/outline/shapes failing to move two of the four shapes) - More precise shape invalidation (minimizes redraw)
- Wi-Fi
- Simulator support
- Wi-Fi Access Point
- Simulator support
- Clean-up auth mode strings across all platforms
- Captive Portal
- Simulator support
- Uses WebSocketClient instead of WebSocket to avoid pulling in TLS
- Example sends time zone, dst, date, time, and language from phone to device
- New example web page is usable
- Time module in simulator provides getters for timezone and dst
- ECMA-419 style Button driver added, includes debounce support
- ECMA-419 style LED driver added. Supports LEDs driven by Digital, PWM, NeoPixel, and Discrete RGB.
- ECMA-419 style JogDial driver added
- MP3 HTTP Stream (audioout/mp3-http-stream) supports ICY metadata to get song metadata
- MP3 decoder reports sampleRate and channel
- System
- Remove System.resolve()
- Remote System timer APIs
- URL – eliminate unnecessary 64-bit math
- Add
tm16377-segment LED display driver. (contributed by @stc1988) #1677 - MCP2300xx GPIO expander – fix constructor options (contributed by @Templarian) #1684
- Neopixels reserves pin when ECMA-419 enabled (catches conflicts)
- ILI9341_p8 display driver reduces per-band overhead
Timer.repeat()treats interval of 0 as 1 to avoid devolving to a one-shot timer
- TLS
- Devices
- Add
icm42670pIMU foresp32/c3_devkit_rust - Linux build always uses default
DISPLAYwhen launching xsbug - ESP32
- Updated to ESP-IDF v6.1 (see above)
- Updated build to benefit from differential flashing
- Only enable coredump in instrumented builds to reduce firmware size
- Switch to
libc_newlib_nano_format(don't need the feature of the larger library) - Only reserve UART pins if debugging on UART
- ECMA-419 PWM
close()returns pin to uninitialized state - If NVS storage is corrupt at boot, erase it (previously rebooted continuously)
- ESP8266
- Reserve UART pins when debugging
- Don't crash on pbuf allocation failure on ESP8266
- Raspberry Pi Pico
- Instrumentation displays actual system bytes free
- Random number generator is truly random
- Fix runaway event turns
- Switch from background (multitasking) to single-threaded sockets (matches ESP8266 and what implementation expects)
- Bump native stack to 6 KB
- Add
- Tools
- Add
.devcontainersupport for GitHub Codespaces (contributed by @matthewruzzi) #1682 mcconfigno longer creates JSON modules for tsconfig.json, package.json, and package-lock.json.- Add
esp32Configto allow manifest to contribute toSDKCONFIG(like Zephyr). test-examples- More useful reports.
- Exclude logs from successful tests
- Option to build one example against many device targets
- Support testing of packages too (
mcpack)
- ESP8266 builds now use
esptool5.x to eliminate Python 2.x dependency - Use
NAMEenvironment variable to eliminate build artifact collisions between examples with the same directory name.
- Add
- XS JavaScript engine
- No comma after rest in destructuring assignment (reported by @gibson042) #1673
- SetterThatIgnoresPrototypeProperties attributes (reported by @d01c2) #1672
- URI handling functions do not throw when their argument is omitted (reported by @d01c2) #1671
- Set methods do not throw when the value argument is omitted (reported by @d01c2) #1670
- Reflect property-key methods do not throw when propertyKey is omitted (reported by @d01c2) #1669
- Proxy ownKeys trap must return an object (reported by @d01c2) #1668
- Math.atan2 and Math.pow coerce the first argument when the second argument is omitted (reported by @d01c2) #1667
- Map methods do not throw when the key argument is omitted (reported by @d01c2) #1666
- Array.from() throws when its argument is omitted (reported by @d01c2) #1665
- String.raw truncates the raw object's length to 32 bits (reported by @d01c2) #1685
- Next on the String, Map, and Set iterator prototypes is non-configurable (reported by @d01c2) #1686
- Value and done on iterator result objects are non-writable and non-configurable (reported by @d01c2) #1687
- Eliminate C undefined behaviors is
fxPushSubstitutionString()
- TypeScript
- Typings for Wi-Fi Access Point
- Typings for Captive Portal
- httpclient typings for
write()align with ECMA-419 (contributed by @stc1988) #1683 - SMBus constructor options connection (contributed by @stc1988) #1688
- Moved xs.d.ts from xs/includes to typings for easier configuration and maintenance (reported by @stc1988) #1675
Contact Us
If you have questions or suggestions about anything here, please reach out:
- Start a new Discussion on our GitHub repository.
- Drop by our Gitter to chat.
- Contact us on Bluesky at @moddable.bsky.social.
- Contact us on X / Twitter at @moddabletech.