Back to Napcraft
SOURCE / PINNED RELEASE

Made of little things.

Napcraft

Release
ee47ac6a25df…
Author-recorded commit
410dea87e109…
License
LICENSE
Author’s source reference
nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-52f9e22f5ce

Archive hash verified: 9e6e0cabb18d0d46…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

docs/verification.md
# Napcraft verification — 2026-09-25

> Follow-up: [responsive editing and soyLI 0.23.1 verification](responsive-editing.md).
> The original findings below describe the earlier 0.23.0 run.

Built in the existing soyLI workspace. App-owned pastel island and interface;
no host theme dependency. The final self-contained HTML is about 37 KiB.

## Automated checks

| Check | Result |
| --- | --- |
| `pnpm type-check` | Passed |
| `pnpm build` | Passed; one self-contained `dist/index.html` |
| `pnpm test:guidance` | 6 passed |
| `pnpm test:backend` | 3 passed: bounds/support, stale edits, owner lock |
| `pnpm test:conformance` | 5 passed, 0 failed, 5 skipped |
| `soyli backend check` | Compiled `worlds` and all 4 operations |
| Direct-authority scan of src and artifact | No forbidden network, browser-storage, signer or peer APIs |
| `soyli check` | Blocked by the confirmed 0.23.0 backend-copy bug |
| `soyli multiplayer … --latency 50 --jitter 15` | Same tooling bug before scenario execution |
| `soyli publish --dry-run` | Source/destinations plan generated; does not certify public hosting |

The conformance skips are three manifest-event cases, wire envelopes and lifecycle.
They are unmeasured, not passes. Real host interactions below cover actual SDK calls.

## Two independent players in the real soyLI host

Preview used its printed URL, `http://127.0.0.1:51696/`. Independent Chromium
contexts used different host transport identities. A temporary test Nostr signer
in the trusted host created the world; another player joined as a guest. The app
never received signer keys. No selected creator account was changed.

`tests/shared-world.mjs` passed creation/join, guest placement and removal visible
to the other player, forbidden guest ownership changes, owner pause/resume,
retrying the exact committed request without duplicating it, stale-cell rejection,
and simultaneous same-cell writes with exactly one winner. Both browsers were
reloaded and the world reopened with the same code and all edits intact.

`tests/persistence.mjs` also reopened the saved world after the soyLI dev process
and local backend were stopped and restarted. Its three prior edits were intact.
New tests later added a fourth edit; the earlier restart result is retained.

Direct ICE stalled on this machine. A disposable, authenticated loopback coturn
relay established real WebRTC connections through the unchanged soyLI signaling
host. `tests/run-multiplayer.mjs` wraps the host's native data-channel sends with
50 ms of outgoing delay and deterministic ±15 ms jitter, preserving send order.
This changes only test transport configuration; it does not simulate game results.
All nine assertions passed. Guest input reached rendered movement in 12.9 ms,
against a 70 ms budget; the other player saw the movement and all shared edits.
Both players saw each other's avatars, owner lock/unlock synchronized, and the
world survived everyone leaving. Tests clean up their browsers and relay processes.

These are local relay tests, not evidence for deployed TURN, separate networks,
packet loss, long sessions, real iOS/Android performance or public creator admission.

## Responsive and touch checks

Actual iframe inner dimensions were asserted at 200×160, 320×560, 900×600,
1440×900, 390×844, 360×640 and 844×390. Test-only host CSS removed workshop chrome
and the host iframe's normal 300px minimum; the product CSS was unchanged.
The smallest frame shows the useful enlarge notice. All larger frames retain
reachable materials, movement and build/erase controls. Screenshots were inspected.

A touch-enabled mobile context exercised taps and the D-pad, including a second
simultaneous action touch and release without stuck movement. Light/dark browser
color schemes preserve the app palette. Removing optional theme, storage and
identity domains leaves practice building usable. Reduced-motion preferences
stop decorative cloud drift, particle bursts and CSS transitions; core movement
remains interactive. Physical-phone testing remains outstanding.

## Media

- `preview.png`: real 1200×750 shared-world screenshot with two independent players.
- `preview-portrait.png`: actual 390×844 shared-world screenshot.
- `preview.webm`: real 960×600, 7-second silent VP8 gameplay clip showing two players,
  movement, material selection, stacking and removal. Under the 5 MiB host limit.
- Both the PNG and full clip were decoded/played in soyLI's Listing view.
- The clip was captured from artifact
  `1838b6c34ee5b63f660f0f455dfaf0103dfff7a4a2c1fabfe97e0ea0876b6796`.
  Capture checks that the artifact does not change during recording; that exact
  hash is selected in napplet.json. No stale-build check was bypassed.

`tests/capture.mjs` reproduces the real-host capture. It creates a test world,
joins a second player, moves them apart, builds a coral column, saves both image
sizes, then records walking, a butter/glacier stack, a friend's build and removal.
The last seven seconds of the raw Playwright video are encoded as VP8 with FFmpeg.
The cover and full clip were visually reviewed. Raw captures, frame inspection,
Listing review and machine-readable reports are under ignored `.napplet-space/`.
No generated illustration stands in for gameplay. There is no portrait clip.

## Repeat and release

Start one `soyli dev --no-open` process, use its printed URL, and set `NAPCRAFT_URL`
for the scripts if it differs from the address above. `NAPCRAFT_BROWSER` can name
another installed Chromium executable; `NAPCRAFT_TURN` can name coturn. The default
paths reflect this macOS environment. Dependencies are the already pinned
Playwright/nostr-tools transitive test packages; no game runtime package was added.

```sh
pnpm verify
pnpm test:conformance
soyli backend check
NAPCRAFT_URL=http://127.0.0.1:51696/ pnpm verify:host
# After stopping/restarting that preview:
NAPCRAFT_URL=http://127.0.0.1:51696/ node tests/persistence.mjs
```

Publication is intentionally unfinished pending the soyLI patch the creator plans
to implement. See [the exact blocker and suggested regression](soyli-backend-capture-bug.md).
No frontend release or public backend deployment has occurred. After the patch,
rerun the host checks, review media against the current artifact, commit, publish,
deploy `backend/backend.json`, inspect its signed receipt and test public gameplay.