Repository navigation
Releases: pocket-nexus/pocketjs
Release list
v0.15.0 — One runtime per console runs any game's .pocket, and `pocket` installs the toolchains and selects the target it builds for
One runtime per console runs any game's .pocket, and pocket installs the toolchains and selects the target it builds for.
The PSP, PS Vita, Nintendo 3DS, iPod touch 4 and Android each get a generic
runtime built once, and a TypeScript repack writes a game's console package
from it. The CLI runs on Bun, creates standalone projects and resolves
targets from one catalog. MicroTS gains a site and a playground, and the
Nintendo 3DS gains the Pocket Link to a Mac.
- A generic runtime per console, and repacks in TypeScript.
bun tools/runtime.ts <target>builds a runtime with no game in it;
bun tools/repack.ts --target <target>turns it and a game's.pocket
into a.3dsx, a PSP Memory Stick zip, a.vpk, an.ipaor an APK. At
boot each runtime readsapp.pocket, checks its footer hash, its variant
and its host ABI, and takes the surfaces and raster density from the plan.
The.3dsxand PARAM.SFO writers are byte-identical to3dsxtooland
vita-mksfoexfor the same inputs. The Android repack rewrites the binary
manifest and resource table, aligns aszipalign -p 4does and signs v1 +
v2 with Web Crypto, with no SDK tool.tools/repack/index.tsgives Pocket
Studio's Worker one row per target. pocketselects targets from one catalog.tools/targets/index.ts
lists the eighteen targets by the names commands use. A verb acts on the
first of+<id>,--targetor--host-profile,POCKET_TARGET, a
directory override, the first oftargetsinpocket.config.ts, and the
user default, and prints the target and its source.pocket build --all
builds every project target.pocket target add|list|removeinstalls the pinned toolchains. Pins
live intools/targets/<id>.toolchain.json; each component is checked
against its SHA-256 and stored under its digest, so equal pins share one
entry.pocket doctorchecks the framework's pins instead of the CLI's.- Breaking: the CLI runs on Bun.
@pocketjs/clideclares
#!/usr/bin/env bunandengines.bun; under Node it prints the install
hint and exits.pocket createwrites a standalone project outside a
checkout, with--framework solid|vue-vapor|octane, and derives the
manifest of an ESP-IDF project from its host contract. - Builds write nothing under the framework directory. The style module is
served from memory and copied to<outdir>/<output>.styles.ts; the
transform cache moves totransforms/under the PocketJS cache root. A
read-onlynode_modulesand concurrent builds work. - The guest runtime's dependencies are exact versions.
solid-js,
@solid-primitives/keyed, the Babel presets,opentype.jsand
babel-plugin-jsx-dom-expressionsare pinned to the versions the goldens
use, and the build checks the application's installed copy. - Layout regions and build-time rects.
contain-strict(prop 33) makes a
definite-size node its own solver root, so a change reconciles and solves
only its region.layout-bakedasserts every rect in a subtree is a
build-time constant; MicroTS solves it once in theno_stdcore and emits
the rects into the mount code. Readback rounds with Taffy'sround_layout
on unrounded origins, so a region yields the bits the full tree would. - The compiler reports class literals it drops. Each JSX
classliteral
with unsupported tokens is reported with file, line and column; it is an
error under--strict-classes. The simulator boots any built bundle. - The Nintendo 3DS links to a Mac.
@pocketjs/framework/linkand Pocket
Companion on the Mac carry net requests and the Mac's clock
(companionNow()), beside the Wi-Fi and QR camera modules. Pocket Home and
a Hacker News app run on it, and their lists scroll at 58 to 61 fps on an
Old 3DS through fixed row slots incontain-strictregions. - Pocket3D games ship as content-addressed packs and play in one browser
player. A game's packs are pieces named by their bytes under one
manifest for every device, and a 3DS fetches the pieces it lacks over the
LAN. The browser player shows each handheld in its shell, speaks English
and Japanese, keeps the interface's alpha over the scene, and offers
Download and Remix in a dock a host may draw. Every Pocket3D game shows
the Pocket3D icon in each console's launcher. See
Introducing Pocket3D. - MicroTS has a site and a playground, and drives two more devices.
microts.pocket.nexus carries its docs and a browser playground drawn as the
real devices. The GBA sprite presenter is generated from the layout and
paint plan. MicroTS Hero runs as a Rockbox plugin on the iPod nano 2G. - Breaking: the iPod nano music player is removed (
apps/ipod-nano, the
Pocket Stageaudio-playlist@1service and its tracks); the iPod package
runs Hero. - Android builds one APK for any plan, with a Redmi 1S profile
(360x640 at density 2) carrying armeabi-v7a and arm64-v8a, and a release
build. - The browser realm draws glyphs at runtime.
text.glyphs.runtimedraws
codepoints no atlas holds with the browser and adds them to the atlases. - Device fixes. The PSP's GE display list gets cache lines of its own; a
shared line's write-back had replaced the first commands of the first list
and drawn 16-bit pixels into the 32-bit display. The PS Vita keeps a font
atlas as one byte a texel, 1 MiB instead of 4 MiB for the 36 px page.
npm: @pocketjs/framework@0.15.0 · @pocketjs/cli@0.15.0 · full changelog
v0.14.0 — Pocket3D gets a homepage, a title card and its own license, and the PS Vita and Nintendo 3DS replace native builds over their development connections
Pocket3D gets a homepage, a title card and its own license, and the PS Vita and Nintendo 3DS replace native builds over their development connections.
The repository now names three technologies: PocketJS, Pocket3D and MicroTS.
The core steps 2D physics, builds without std on every target and keeps its
layout tree across structural updates. Pocket Nexus runs on the Old 3DS, the
iPod touch 4 and the Nokia E7.
- Pocket3D has a homepage and entry points in the repository.
3d.pocket.nexus presents it with frames captured
on consoles.pocket3d/README.mdstates its design and maps its code
(devices/,engine/pocket3d/,site/pocket3d/);microts/README.mddoes
the same for MicroTS, and the README gains an "In this repository" table. - A Pocket3D game shows a title card at launch.
pocket3d-titledraws the
mark and the name into a console's frame buffer before the game starts
its renderer, for 144 ticks at 60 Hz, with no GPU:vita::play()on the
PS Vita,play(surface, present)on the PSP,pocket3d_title_play()in a C
header on the Nintendo 3DS andplayTitle()in a browser. The three
drawers produce the same frames; the crate's tests record their hashes and
the C header and the browser module are held to them. - Breaking: Pocket3D moves from the MIT License to the Pocket3D License
1.0.pocket3d/,devices/andengine/pocket3d/keep the MIT License's
grant and add one condition: a distributed product that draws 3D scenes
with Pocket3D shows the title card each time it starts. The PocketJS hosts,
and software that reaches Pocket3D only through them to draw PocketJS
interfaces, are exempt. A separate written license waives the condition
(support@pocket.nexus). PocketJS and MicroTS stay MIT; the npm package's
license is now(MIT AND LicenseRef-Pocket3D-1.0)and ships
pocket3d/LICENSE. Copies published before this release stay MIT. - Breaking: the handheld device kernels are shared, and BSP code moved to
OpenStrike.devices/vita/pocket-vita-gxm,devices/psp/pocket-psp-ge
anddevices/3ds/pocket-3ds-picahold GPU memory, patching and texture
storage for every caller.pocket3d::bsp,pocket3d::collideand
WorldModel::from_bspleft this repository; OpenStrike owns them. The GXM
kernel gains float and normalized data targets and aligns owned GXP storage
on the ARM ABI. - PS Vita development runs in Pocket Devkit. The Devkit app waits for a
build over USB:vita:dev pushreplaces its JS/PAK guest and
vita:dev nativeruns another project's native build from the inactive
slot. Native apps publish renderer telemetry underenginein each status
receipt, and the USB host closes descriptors idle for 30 s, which ends the
"filedescriptor out of range" stop after about 40 minutes. - The Nintendo 3DS installs and starts
.3dsxfiles over the dev
connection. The Runtime stages an upload, checks its length, CRC-32 and
3DSX magic, keeps the replaced file asnative-previous.3dsxand hands the
new one tohb:ldr. ui.physicssteps 2D jelly bodies insideUi::tick. Ops 52..56 run a
fixed-step simulation and write each body's pose into its views as
paint-only props; askewXtransform prop joins rotate and scale. The wasm
core, the 3DS host, the iPod touch 4 host and the Nokia E7 host bind it.- The core builds without
stdon hosts and devices, and keeps its layout
tree. Layout rounding at half boundaries no longer differs by one pixel
between a host test and a device. Inserting, removing or reordering nodes
reconciles a retained Taffy tree: unchanged nodes keep their handles,
styles and text measurements. - Pocket Nexus fits the Old 3DS frame budget and runs on two more
devices. On an Old 3DS it went from 34.6 ms a frame to 16.7 to 17.0 ms.
It ships as a standalone iPod touch 4 app and installs on the Nokia E7
beside Pocket Clear. The iPod touch 4 host runs native games with a depth
buffer and bundled assets. - MicroTS admits imperative code in compiled models. State modules,
assignable places with in-place array operations,while,do-while,
break,continue, generalforloops, numeric conversions, float math
and static constant arrays compile to Rust; element reads of stored arrays
index them in place. - Device sessions take leases. Tools that drive a console take a named
lease, so two sessions do not drive one device, and validation evidence is
bound to the build that produced it. - Breaking: every
pocket-stackidentifier ispocket-nexus. App ids
aredev.pocket-nexus.*, the Android package and its JNI symbols follow,
and the toolchain cache is~/.cache/pocket-nexus. The canonical origin is
pocketjs.pocket.nexus; pocketjs.dev keeps working. - DevTools and touch fixes. Replay input survives a pause, the touch
recorder compacts its history and releases empty pages, retired console
bridges detach on init, guest trace retention is off by default, and
native touch captures are released before new contacts are assigned. - Sites. pocket.nexus is the Pocket Nexus
homepage, and the PocketJS site takes the candy arcade style.
npm: @pocketjs/framework@0.14.0 · @pocketjs/cli@0.14.0 · full changelog
v0.13.0 — MicroTS compiles Solid and Vue TypeScript apps to native Rust, and the PS Vita gains a wired development runtime
MicroTS compiles Solid and Vue TypeScript apps to native Rust, and the PS Vita gains a wired development runtime.
MicroTS turns an admitted TypeScript view and model into a no_std Rust
application that runs without a guest engine, down to a Game Boy Advance
cartridge. The PS Vita reloads JavaScript and native code over USB. Nokia E7
rendering reaches 60 fps in Pocket Shell, and Pocket3D and the PSP arena
carry larger worlds.
- MicroTS compiles Solid TSX and Vue SFC views, plus a TypeScript model, to
Rust. Withapp.aot: trueandapp.model: "compiled", state seeds,
methods, memos, effects and async tasks are generated from the TypeScript
implementation; the default"rust"mode keeps an application-provided
Rust model behind the same generated trait. Solid and Vue share typed View
IR format 1; Model IR format 1 records model bodies, dependencies, schedules
and coroutine states. Admission errors report source locations and there is
no fallback to another implementation. The package exports new
solid/std,vue-vapor/std,solid/reactive,vue-vapor/reactive,
model/tasks,model/animationandnet/modelentries. See the
MicroTS guide. - MicroTS reaches motion sensors and targets without atomic CAS. A native
motion driver publishes one fusedMotionStateper estimate at gravity,
inertial or geomagnetic level;<MotionHandler>in Solid and@updatein
Vue receive it, and board admission rejects a board below the level a value
requires. On targets such as ARMv4T, MicroTS and heapless select
portable-atomic.bun hosts/gba/build.tsbuilds a 656,316-byte Hero ROM
that boots in mGBA with a 60,268-byte peak heap. - The shared Hero runs one view and model in JavaScript guests and
generated Rust. The standalonehero-vue-sfcandhero-vue-vaporapps
are removed; Vue Vapor and Octane variants remain insideapps/hero, and
the npm package ships the Solid Hero sources. - PS Vita builds include a wired development runtime. L + R + SELECT
opens a native menu;bun run vita:devreloads JS and resources over USB,
replaces the native SELF through A/B slots with checksum readback, and
captures the 960 × 544 GXM framebuffer. A failed reload restores the previous
bundle in a fresh realm.--no-usb-debugomits the USB driver. See
docs/VITA-USB.md. - Nokia E7 rendering reaches 60 fps in Pocket Shell. QuickJS builds at
-O2and the Rust core atopt-level=3, both with VFPv2. The GLES backend
drops per-frame error queries, merges adjacent draws, shares glyph coverage
pages between full-size and scaled text, and bounds border masks and text
placement caches. The portrait switcher went from 31.70 to 60.31 fps.
Installed apps stay resident behind a shared return gesture and release
their EGL resources while in the background. - Pocket3D and the PSP carry larger worlds. BSP maps build spatial draw
groups once per map, cache PVS membership, cull cooked faces and collision
hulls, and submit bounded triangle strips; a 28,243-triangle map holds
59.9 fps on a physical PSP.arena::alloc_permanentreserves process-lifetime
buffers without power-of-two rounding, and the PSP host exposes QuickJS
allocator counters and an arena free-space snapshot. - ESP-IDF sets the guest heap limit through Kconfig.
CONFIG_POCKETJS_GUEST_HEAP_LIMITdefaults to 4 MiB; an explicit
config.heap_limittakes precedence. - Breaking: the BlackBerry Classic Android Runtime host and the
blackberry-androidscript are removed; the native QNX host remains. The
earlyvapor/compiler experiment moved to a standalone repository, taking
itsvapor:*scripts with it. - Tape assertions reject malformed, partial and repeated entries, and the
suite covers previously omitted tests. The iPod touch 4 installer rejects
failed digest checks. The site is also served at
pocket.nexus.
npm: @pocketjs/framework@0.13.0 · @pocketjs/cli@0.13.0 · full changelog
v0.12.0 — Whole-text CJK loading, background resources, and device-aware presentations
Whole-text CJK loading, background resources, and device-aware presentations.
PSPMAN's Japanese text feedback helped shape this release's CJK work.
PocketJS can keep common characters in memory, load uncommon characters in
the background, and show an animated skeleton until an entire text is ready.
Dynamic content such as song titles and book chapters can appear together,
without characters arriving a few at a time.
- Prepared text reserves every required glyph before loading begins.
openFontArchiveconfigures common-character residency and memory limits;
prepareTextreturns a resource for the complete text. Live resources pin
their glyphs, including while offscreen, and overlapping texts share cells.
Solid'sTextconsumes the resource through the existing resource boundary
with loading and error fallbacks. A batch that exceeds capacity or contains
an unavailable glyph reports an error instead of displaying partial text. - Font I/O runs through companion or PSP storage workers. Both providers
useio.offloadwith bounded requests, retries and session checks. Streamed
source bitmaps share a 2 MiB native ceiling; closing an archive releases its
allocations, and failed index-page reads cannot poison later cache hits.
The Text Lab demonstrates a music list and chapter reader with animated
skeletons. Regression coverage includes 1,000 runtime song titles, uncommon
characters, eviction, pinned content and reloads; the PSP build was checked
on hardware. The implementation is available on PSP and through WASM host
operations. Other native hosts need the batch operations before enabling it. - External fonts are generated assets with an explicit migration path.
Font tooling builds PJFA archives from application-supplied font files and
can derive coverage from text files or Unicode ranges. Full font sources
and generated archives stay outside Git. Downstream apps using custom
formats, including PSPMAN's PJPF, must regenerate archives and adopt the
prepared-text lifecycle. This release supplies that framework path; it does
not migrate PSPMAN itself. See the
dynamic text guide. - Shared resources and offload queues separate I/O from frame work.
Scoped demand, reactive reads and cache ownership connect visibility to
resource lifetime. Bounded worker mailboxes carry provider requests and
results without socket or storage calls on the UI thread. Shared companion
sessions add reconnect and backpressure for stateful services. A bounded
Rust prediction module reconciles simulation state without rewinding UI or
repeating external effects. - Applications select presentations from device input and display facts.
Manifest presentations can target screen count, touch location and control
availability. Shared actions express confirm, back and media intents;
keyboards choose layouts for buttons or touch surfaces. Classic controls
add shared lists, footers, skeletons and sprite spinners, while the system
sheet exposes application actions and return-to-launcher behavior. - Media and text services cover more application flows. Native 3DS
playback uses the shared media provider with audio-clock timing and bounded
buffering. Media support adds local downloads and timed captions. Clear's
companion input uses reusable glyph resources, revision-checked candidate
windows and text layouts that preserve cached characters across edits. - Desktop rendering and native integrations expand. Desktop hosts gain
portable GPU rendering and offloaded text. ESP-IDF integrations provide
separate package, guest, UI and renderer components for ESP32-P4 and S3.
The 3DS runtime isolates application state, returns to the Homebrew Launcher,
and acquires native sources without PSP dependencies. Legacy iPod touch
installs use removable user applications. - Pocket3D shares geometry across rendering and simulation. Handheld
animation uses shared skin bindings and indexed PICA skinning. Collision
geometry also governs water transport; contact-based locomotion, occluder
fading and themed PocketJS control overlays extend the shared world.
The site adds handheld application demos, updated use cases and restored
mobile documentation navigation.
npm: @pocketjs/framework@0.12.0 · @pocketjs/cli@0.12.0 · full changelog
v0.11.0 — Two more device families run PocketJS, a second backend class paints through gpui and measures text on the host, and a paired Nintendo 3DS takes new guests over Wi-Fi
Two more device families run PocketJS, a second backend class paints through gpui and measures text on the host, and a paired Nintendo 3DS takes new guests over Wi-Fi.
0.11.0 adds the Nintendo 3DS and the BlackBerry Classic to the host set, a
backend class that hands text measurement to the platform instead of a baked
atlas, and a System that supervises several guests behind one compositor on
macOS, Linux and the browser. Both new device profiles remain private
development targets: each records an exact hardware and firmware tuple, and
neither advertises a production capability from a build alone.
- The Nintendo 3DS runs a QuickJS guest on both screens. The split follows
hosts/iphone2grather thanhosts/psp: citro3d is mostlystatic inline,
so C owns the GPU while ano_stdRust staticlib built for the built-in
armv6k-nintendo-3dstarget owns the core and exports the DrawList. The top
screen is a fixed 400×240 viewport and the touch screen a 320×240 auxiliary
surface; touch arrives on the auxiliary surface alone.3ds-devis host ABI
8. The demo splits one classic iPhone Contacts app across the two: a
10,000-row virtual list, its section index and its scrubber below, and the
detail card the phone had to push a navigation level to reach above. Goldens
run the same PICA200 code path under Azahar and match hardware. - Pocket Runtime accepts a new guest over Wi-Fi.
bun run 3ds:dev pair
installs a 32-byte key once through ftpd; after that a paired TCP connection
carries.pocketupdates and dual-screen RGB8 captures as bounded binary
frames that never enter QuickJS, andbun run 3ds:dev devbridges the
existing DevTools protocol to the panel. Updates reuse the Runtime's target
and ABI admission, immutable package storage, retired-frame acceptance and
rollback path.L+R+SELECTopens a Runtime-owned menu on the bottom screen
with the device's IP, pairing and connection state, generation and package
hash. The pairing key authenticates but does not encrypt the LAN connection,
and the channel updates guests only: a new.3dsxor CIA still requires
deployment and a restart. - The BlackBerry Classic runs two hosts over one shared contract.
hosts/blackberry-qnxis a BB10 Core Native host (libscreen, BPS,
EGL/GLES2) built and packaged as an unsigned development BAR inside the
digest-pinned BBNDK image and installed on a rooted Classic;
hosts/blackberry-androidis an Android Runtime (API 18) host whose
v1-signed APK drives the same QuickJS bridge and Rust core through a JNI
armeabi-v7alibrary. Both register at 720×720 physical, 360×360 logical at
density 2, host ABI 9. First device run recorded on an SQC100-4 at
10.3.3.3216; the port follows both routes onto
the same square screen. - A second backend class paints through gpui and measures text on the
host. The portable family (wgpu, software raster, PPA, GLES2) keeps
executing the DrawList against compile-time baked font atlases.
engine/backends/gpuipaints through Zed's gpui/Metal renderer instead, and
text::MeasureFnplusDRAW_OP.TEXT_RUNroute measurement and shaping to
CoreText when an app opts in — astyleHashword keeps identical word
streams pixel-identical, so demand-render hashes stay truthful. The
macos-apptarget ships with it, together with awrapTexthost op and a
Notepad whose word wrap, hit-testing, caret movement, selection and
undo/redo all read one visual-segment layout, so reflow on resize falls out
of the reactive width. - A System supervises several guests behind one compositor. Pocket System
resolution, role-scoped compositor surfaces and isolatedAppInstance
supervision arrive with a product-neutral macOS compositor host, and Linux
and browser System hosts run the same resolved plan. - The manifest and the resolved plan carry companion adapters and viewport
policy.app.companionsnames the exactsvcOpenservice names an app's
adapters speak, and the plan carriescompanionsandviewport.policy, so
a host derives every boot flag from one artifact instead of re-reading the
raw manifest and matching on the application's name. - The gesture layer is framework-neutral and recognizes pinch. The
recognizer machinery and the kinetic scroller move intogesture-core.ts
andkinetics-core.tsbehind per-framework shims, so the Vue Vapor entry
runs the same touch pipeline as Solid: contacts latch with their
host-resolved hit facts, the gesture pump runs before app frame hooks, and
the tap-to-press recognizer installs at mount. A two-contact pinch
recognizer measures span on the locked axis and claims both contacts when
the span change beatspinchSlopand the centroid travel. The legacy UIKit
runtime replaces its single-contact globals with an eight-slot touch table.
Pocket Clear on the iPod touch 4 is the demo the layer was built against. via-*adds a middle gradient stop, and vertical gradients point the
right way on the 3DS. The core draws a three-stop gradient as two ordinary
two-stop boxes, so every backend still seesGRAD_RECTand clipping stays
where it was.hosts/3ds/src/gfx.ccopies the spec'sGradDirordinals
into C by hand and hadToTopandToBottomswapped, which inverted every
vertical gradient on the one backend that does not read the generated Rust
enum. The gpui raster fallback renders the full viewport and composites
transparently, and the compiler's path handling is portable on Windows
again.- PocketJS 98 and a desktop benchmark measure the gpui host.
apps/desk98
is a Windows 98 desktop as one guest — draggable, resizable, z-ordered
windows, taskbar, Start menu, Notepad, Minesweeper and the classic
shortcuts — with window moves riding paint-only transform props so a drag
never relayouts and the idle desktop holds the demand-render governor at a
few frames a second.tools/bench-desktop.tsmeasures byte-identical web
editors shelled by Tauri v2 and Electron against the Pocket note on the same
host; the numbers and their fairness caveats ship with the report. - The site is one design system across a nine-chapter homepage. Shared
tokens, chrome and base stylesheets replace the per-page CSS, the landing
carries compatibility receipts, and an icon family covers every surface from
the favicon to the Safari bookmark and the iOS home screen. A new post
derives the agent-native runtime for embedded
systems.
npm: @pocketjs/framework@0.11.0 · @pocketjs/cli@0.11.0 · full changelog
v0.10.1 — Three more physical phones run PocketJS, Pocket Vapor compiles a smaller reactive graph, and Pocket3D gains a deterministic systemic world
Three more physical phones run PocketJS, Pocket Vapor compiles a smaller reactive graph, and Pocket3D gains a deterministic systemic world.
0.10.1 carries the connected-device work completed after 0.10.0 together with
the compiler, renderer and tooling fixes those devices exposed. The new phone
profiles remain private development targets: each one records an exact
hardware and firmware tuple, and none advertises a production capability from
a build or upload alone.
- Windows CE runs a real Solid guest on the Meizu M8. One ARM executable
embeds QuickJS, the app and its assets, and the Rust software renderer; the
native host copies a 480×720 BGRA framebuffer to the LCD through GDI without
stretching. The host turns WinCE messages into wide touch coordinates,
closes cleanly on Home or Escape, registers a build-qualified MiniOneShell
icon, and deploys over the phone's ActiveSync serial function through PPP
and RAPI. Status requires advancing guest frames, successful GDI composites
and matching logical and physical viewports; acceptance additionally
requires a completed touch and changed application action. The
field report follows the port from the first
clipped 320×480 frame to the native, readable result. - The sixth-generation iPod touch has a transactional native host. The
testediPod7,1on iOS 12.5.8 runs an arm64 UIKit application at a 320×568
logical viewport and density 2. Each deploy re-identifies the device, opens
a fresh UDID-scoped USB tunnel, verifies the staged bundle byte by byte, and
keeps a rollback copy until SpringBoard registration succeeds. Wide touch
words preserve the bottom of the 568-point surface, while the device receipt
proves a live process, advancing frames, completed release andhero_tap. - The iPhone 4S runs the retained UI through OpenGL ES 1.1 at Retina
density. The private iOS 6.1.3 host builds an ARMv7 bundle against locally
derived, hash-pinned linker stubs and requires the physical runtime to report
a 640×960 GLES1 drawable for its 320×480 logical viewport. Transaction leases,
staged file hashes, signature checks and rollback keep a failed install from
replacing the working application; the captured device frame comes from the
actual Retina renderbuffer. - The modern iOS shell's 120 Hz path is complete. Its NativeScript plugin
pin moves to@nativescript/pocketjs0.2.1, whose native bridge publishes the
requested tick rate before guest evaluation. This closes 0.10.0's known
limitation: a 120 Hz bundle and host now establish the same mount invariant
instead of refusing the unpublished 0.2.0 bridge. - Pocket Vapor removes work that static analysis proves unreachable. A
sparse conditional constant-propagation pass folds constant ref reads,
selects decidable branches, and removes their dead dependencies and ROM.
Frame-local view and bounded-string temporaries now share statically colored
overlay slots when their generated owners cannot be live together, reducing
permanent RAM and stack pressure on the NES and Game Boy. Linux parity runs
can supplyMGBA_PREFIXandCC65_LIBwithout changing the macOS defaults. pocket3d-worldis a renderer-independent fixed-step simulation. Stable
entity IDs, seeded randomness and ordered phases cover sphere and capsule
bodies, attachments, structural damage, retained water, heat, fuel and
combustion. Inputs, initial state and configuration replay to a stable state
hash; shared collision and reaction laws are tested as general invariants,
while concrete material recipes remain application-owned. Pocket3D model
sockets and the optional stylized scene path present that state without
moving simulation policy into the renderer.- Font and desktop-host regressions are closed. The font baker now closes
implicitly closed CFF contours before scanline filling, retaining their final
edge, and the Note and widget launchers resolve their Cargo outputs from the
currentengine/workspace rather than the retired nested path. - Release automation runs on the current Node 24-backed GitHub Actions. The
checkout, cache and setup-node upgrades preserve the existing OIDC trusted
publishing, build gates and deployment behavior.
npm: @pocketjs/framework@0.10.1 · @pocketjs/cli@0.10.1 · full changelog
v0.10.0 — Apps reach the network, a database and their own files, and a realm declares the rate its virtual time runs at
Apps reach the network, a database and their own files, and a realm declares the rate its virtual time runs at.
0.10.0 adds three modules — net, db and fs — each behind its own
append-only op spec, a deterministic sim host and a reference Rust core, and
turns the core's fixed 1/60 s step into a per-realm constant chosen before the
first tick. Every default remains 60 and the 60 Hz path is the identical
expression throughout, so existing bundles, tapes and frame-hash goldens are
byte-for-byte unchanged.
net— bounded whole-response HTTP.fetch()andglobalThis.netover
five ops (start,take,cancel,poll,lastError), with the bounds in
the spec rather than in each host: 2 in flight, 64 KB of request,
128 KB of response by default and 256 KB at most, 32 headers. The
transport never calls into QuickJS — completions are staged to tick
boundaries and drained one batch per tick — so a network answer cannot land
in the middle of a frame. Transport adapters stay host-owned; the browser dev
host, the sim andengine/crates/pocket-netexercise the contract without
granting network access to every host.db— SQLite behind five synchronous ops.open,close,exec,
query,lastError, with rows arriving as one JSON line perquery()call
rather than a cursor: at most 4 databases per app, 4096 rows per
result, names matched against a fixed pattern, and storage the host confines
to the app.:memory:is spelled the same as SQLite spells it.fs— a per-app file tree behind nine ops.read,write,remove,
list,stat,mkdir,rename,usage,lastError, plus a
readFileSync/writeFileSyncsurface for code that expects one. Every
path is confined to the app's own data root — apps cannot name, let alone
reach, each other's trees — and the shape of a path is bounded too: 160
bytes, 8 levels, 64 bytes per segment.- No stock target advertises the three capabilities yet.
net.http,
data.sqliteanddata.fsare registered ahead of any console host shipping
them, exactly asaudio.pcmwas: the sim host and the reference cores
implement the whole contract, so an app can declare the requirement today,
run against the sim (and, fornet, the browser dev host), and fail
admission cleanly where the module is absent. A device target appends the id
to its profile when its native host ships the module — not before. - A realm declares its tick rate before its first tick.
Ui::set_tick_rate
threadsdtthrough the spring integrators and every ms-to-frame conversion,
keeping exact integer hz alongside it so frame counts stay integers;
tools/build.ts --hzbakes the same rate into the bundle, and clock,
kinetics, input, deepzoom and the styles.bin ANIM TABLE all derive their
per-tick constants from it. The rate is fixed for the whole run — a
realm's frame content stays a pure function of its frame index, which is what
keeps goldens byte-exact. - A bundle refuses a host that drives another rate. The host publishes its
rate asui.__tickHzand the bundle checks it where it already checks target
and host ABI. An absent__tickHzmeans 60, so every host that predates
per-realm rates keeps mounting every bundle built the ordinary way. Without
this a 120-baked bundle mounted on a 60-stepped core and ran at half speed
silently; it now fails at mount with both rates named. - Modern iOS runs guests, as a transitional target.
pocket ios doctor|build|stage|playbuilds against anios-devplan and launches inside
a NativeScript shell on an arm64 simulator, over thepocket-applecrate:
one guest realm, one UI surface, and the software rasterizer driven
incrementally through a damage tracker behind a small C ABI, with a UIKit
view compositing only what changed. The profile stays out of
POCKET_TARGETSuntil it has device-level acceptance, following the same
convention the iPhone 2G target used. Known limitation: the 120 Hz path
needs@nativescript/pocketjs0.2.1, which is not published yet — against
the current 0.2.0 plugin a 120 Hz bundle refuses to mount (loudly, by the
rule above) while 60 Hz is unaffected. - Hosts choose the guest allocator, so an embedder with its own arena no
longer has to accept the default one. - Site: the landing page leads with a machine collage and per-audience
/for/pages, the in-browser playground reuses the landing PSP model, and
every playground demo is validated and restored on build.
npm: @pocketjs/framework@0.10.0 · @pocketjs/cli@0.10.0 · full changelog
v0.9.3 — The PSP arena no longer strands the memory a QuickJS boot needs
The PSP arena no longer strands the memory a QuickJS boot needs.
A guest whose boot parses a megabyte of JSON could exhaust the heap while
megabytes sat free, because the arena's power-of-two size classes never hand a
block to a different class. 0.9.3 closes that, and
Pocket Voxel boots on a real
PSP-2000 at the default arena size again.
reallockeeps the pointer when the new size stays inside the block's
class. The arena rounds every request up to a power of two, so a grow that
stays in class already owns those bytes. QuickJS grows its string and array
builders geometrically, and the previous allocator answered every one of those
grows with an allocate, a copy, and a free that put the old block into a class
nothing asked for again. A boot parsing 1.15 MB of game data stranded
megabytes this way.arena::allocsplits a larger free block when the bump is spent, halving
down to the class it needs. It runs last on purpose: a heap with room behaves
exactly as it did in 0.9.2, and large blocks stay whole for the callers that
want them.- A null exception object is an out-of-memory signature.
[PocketJS js error] nullfollowed byJS_Eval threwmeans QuickJS could not allocate an
Errorto throw, so the guest source is not the suspect. The same halt line
covers every eval failure, which is what made this one read as a code bug for
a day. globalThis.audiomounts without theuisurface.register_audiois
split out ofregister, so a host that owns its own surface can still offer
theaudio.pcmcapability. The credit mirror also decays with the hardware
stream:poll()never subtracted whatwrite()accepted, so a ring the mixer
drained completely between two polls sent no credit and the guest went
permanently silent after a couple of seconds.
Measured on the hardware that found it. The same guest bundle peaks at
12.3 MB under desktop QuickJS and needed more than 15.5 MB on the device
before this release; it now boots inside the 14.3 MB an XMB launch leaves
after a 32 MB pak, with the emulator journey green at 11 of 11 marks and
frame-hash goldens byte-identical at both quality rungs.
npm: @pocketjs/framework@0.9.3 · @pocketjs/cli@0.9.3 · full changelog
v0.9.2 — A locked 60 fps on a 2007 iPhone, because the composite was the only stage that was never damage-limited
A locked 60 fps on a 2007 iPhone, because the composite was the only stage that was never damage-limited.
PocketJS 0.9.2 makes the software rasterizer scope its screen composite to the
damaged rectangle, which takes the original iPhone from 22–26 fps to 59.99,
and exposes the damage statistics that made the diagnosis possible. The
deep dive has the numbers.
- The composite now follows the damage plan. The rasterizer was always
incremental; the composite was not. The tick calledsetNeedsDisplayon the
whole view anddrawRect:discarded the dirty rectangle UIKit passes, so every
frame rebuilt aCGImageover all 320×480 — 22–27 ms. An empty plan now
invalidates nothing (626 of 961 frames in one sample), and a non-empty plan
goes tosetNeedsDisplayInRect:withdrawRect:clipping to what it is
handed. The composite costs 0.26 ms, and the frame 7.63 ms of a
16.67 ms budget. No preservation guarantee is relied on: when UIKit discards
the backing store it passes full bounds and the full frame is drawn. - Damage is observable.
engine/symbianwas discarding theDamagePlanthe
incremental rasterizer returns. Six new C ABI accessors expose attempts,
failures, policy-chosen full redraws, region count, pixel area and union
bounds, and four of them ride in the device record.damage_failuresis the
one that matters: planning that errors silently draws a complete frame, and
without a counter that is indistinguishable from a slow machine. A
compositescounter sits beside it, because a scoped invalidation that never
fires looks exactly like a very fast one. - The software rasterizer is now the default on this target, and the OpenGL
ES 1.1 backend is opt-in. The GL path is correct and pixel-verified but costs
17.2–19.7 ms and delivers 48.6–50.7 fps, because it re-submits and re-fills
the entire DrawList every frame. This supersedes rather than corrects
0.9.1: the GPU path really was faster than the CPU path as that code stood;
the CPU path then got an optimization the GPU path still lacks. - Both paths can be captured and diffed. The capture works on the software
path too, which is the test that matters for a damage-limited rasterizer —
the framebuffer persists and only damaged spans are rewritten, so
under-reported damage would accumulate as staleness. After 2,581 frames:
mean absolute channel difference 0.039 of 255, with the only residue inside
the animating spinner's own 40×40 box. Note the two captures disagree about
format —glReadPixelsis R,G,B,A bottom-up, the core's ARGB32 words are
B,G,R,A top-down — and comparing the software one unswapped reports a
convincing 9.3/255 failure that is entirely in the comparison.
npm: @pocketjs/framework@0.9.2 · @pocketjs/cli@0.9.2 · full changelog
v0.9.1 — The GPU path on the original iPhone was never losing; three stacked measurement bugs said it was
The GPU path on the original iPhone was never losing; three stacked measurement bugs said it was.
PocketJS 0.9.1 corrects the central performance claim of 0.9.0, fixes the two
real defects that produced it, and adds the instrument that settled it — the
device's own framebuffer, read back and diffed against the reference
rasterizer. The rewritten deep
dive tells it in order.
- Correction to 0.9.0. That release reported the OpenGL ES 1.1 path as
2.4× slower than the software rasterizer on the original iPhone. It is
1.8–2× faster: 46.7–49.4 fps against 21.9–26.5, and 19.4–20.5 ms per
frame against 33.9–40.8. The old comparison timed GL's rasterize and
present against software's rasterize only, because the software
composite runs indrawRect:later in the run loop. - Fixed: the software fallback never composited.
+layerClassreturned
CAEAGLLayerunconditionally, and a GL-backed layer never receives
drawRect:. The documented fallback — the one the host drops to whenever GL
fails — computed frames that could not reach the screen. The layer class now
agrees with the selected renderer. - Fixed: the GPU drew colour blocks. In OpenGL ES 1.1 texturing is a
per-unit enable, andglEnable(GL_TEXTURE_2D)was missing, so every fragment
took only its vertex colour: flat fills looked right while all text, images
and font-atlas content silently vanished. ES 2 has no equivalent, which is
exactly why deriving the ES 1 pipeline from the ES 2 one hid it. Also states
GL_MODULATE,glShadeModel(GL_SMOOTH)and an identity texture matrix, with
a test pinning all four. - Pixel parity, off the device. A one-shot
glReadPixelscapture writes the
phone's framebuffer to a file the host pulls over USB. Against the same guest
rendered by the reference core: mean absolute channel difference 0.04 of
255, no channel off by more than 32, worst single channel 7 — the residue
being antialiased glyph edges. First PocketJS host verified by reading pixels
back off physical hardware. - A frame rate you can trust. The device now reports
window_framesand
window_us, so the rate is computed from exact on-device counters instead of
differencing two status records with one-second timestamps — the ±4 fps of
slop that let the original discrepancy hide.
npm: @pocketjs/framework@0.9.1 · @pocketjs/cli@0.9.1 · full changelog