Back to Impact Yard
SOURCE / PINNED RELEASE

Made of little things.

Impact Yard

Release
09fe6aebec3c
Author-recorded commit
0696a4211733…
License
LICENSE
Author’s source reference
nostr://npub1n8ga89w8h6tvwamxusfyzexw8gjy84yxu9rxgnmk955cxtml4ujswzxydd/wss%3A%2F%2Fgit.napplet.soy%2F/n-0b3d7b60562

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

README.md
## Napplet Space workspace

Read [docs/napplet-space.md](docs/napplet-space.md) first for this project's CLI commands, installed skills and host capabilities. Use the upstream guidance below with those tooling mappings.

# Impact Yard

A compact 3D driving playground with a suspension-equipped car and 157 movable
crates, masonry blocks, barrels, timbers and giant dominoes. Drive into seven
freestanding structures, launch off the ramp, switch camera views, or slow the
simulation to inspect impacts.

The west side has a domino run with grippy feet, the east side has a timber tower
with alternating layers, and the back of the yard has a crate-loaded masonry
arch. Strike a pier to bring down its lintel and cargo. The ramp's wedge starts
flush with the ground, so the car can climb it from a standing start.

Click the yard to focus the keyboard controls. Use **WASD / arrows** to drive,
**Space** to brake, **R** to recover the car, **C** to cycle cameras and **P** to
pause. The on-screen buttons support touch and keyboard operation. Drag in orbit
view to rotate the camera. **Rebuild yard** restores every piece and clears telemetry.

The simulation uses cannon-es rigid-body dynamics at 120 physics steps per second:
mass, gravity, friction, angular momentum, spring/damper suspension and contact
impulses. Collapse comes from individual pieces moving under those forces.
It approximates solid bodies; it does not simulate splintering, material fracture
or vehicle body deformation. Three.js renders all procedural geometry locally.

No runtime domains are required. The optional theme domain colors the whole
surface; optional storage saves only the camera preference. Without them the game
uses its fallback theme and keeps preferences in memory. There are no relay calls,
remote models, textures or fonts. The build is one self-contained HTML file.

Preview in the actual host:

```bash
napplet-space dev --port 4184 --no-open
```

Checks specific to this game:

```bash
pnpm test:physics
pnpm test:browser  # requires the runtime preview on port 4184
napplet-space check
```

The browser test writes screenshots and its report to `/tmp/impact-yard-checks`.
Set `SIM_PREVIEW_URL` to test another local runtime URL. See
[the build spec](docs/driving-simulator.md) for physics assumptions and boundaries.

Napplets are sandboxed iframe apps. The shell/runtime injects `window.napplet`
before app code runs; the app uses `@napplet/sdk` to call available NAP domains
such as outbox, identity, storage, resource, and notify.

## Start

```bash
pnpm install
napplet-space dev --no-open
```

Build and verify the production artifact:

```bash
pnpm verify
```

`pnpm build` uses `@napplet/vite-plugin` to produce one inlined `index.html` and,
when `VITE_DEV_PRIVKEY_HEX` is set, write a local napplet manifest JSON file for
hash workflow testing. That file uses NIP-5D kinds with the NIP-5A tag schema.

## Conformance Testing

Verify the napplet conforms to the NAP protocol before publishing. Two variants,
mirroring `vitest` vs `vitest --ui`:

```bash
pnpm test:conformance      # headless: build + check; non-zero exit on failure (CI)
pnpm test:conformance:ui   # live web runtime; re-runs on every source change
```

It loads the build into a real `sandbox="allow-scripts"` iframe and drives the
protocol with a reference shell. Boot, forbidden-global, and degradation checks
run for a local directory; manifest, wire, and lifecycle checks report `SKIP`
unless the invocation supplies the evidence they require.

Exacting requirements for a passing build:

- Build to a **single self-contained `index.html`** (`@napplet/vite-plugin`
  `artifactMode: 'single-file'` in `vite.config.ts`). NIP-5D loads a napplet via
  `iframe.srcdoc` with
  `sandbox="allow-scripts"` and no `allow-same-origin` (an opaque origin) — there
  is no served origin from which to fetch an external `<script src>`, so the JS
  must be inlined into the one file. External-asset builds do not boot.
- Do not import `@napplet/shim` from app code. The runtime injects
  `window.napplet`; conformance verifies boot and emitted envelopes through the
  reference runtime.
- Emit only well-formed envelopes via `@napplet/sdk`. Declare only hard NAP
  requirements in `vite.config.ts`; guard optional domains with
  `window.napplet?.domain` checks and a graceful fallback.
- Do not reference `window.nostr` or use direct `fetch`/`WebSocket`/`localStorage`.

The executable `index.html` does **not** carry its own aggregate hash. Before
execution, the runtime verifies manifest path blobs and recomputes the NIP-5A
aggregate carried by the manifest `x` tag.

This game declares no hard domains. Theme and storage are optional enhancements.
Add `requires` only for a core task that cannot run without the requested domain.

## Included

- Vanilla Vite + TypeScript napplet app.
- Typed `@napplet/sdk` helpers over the runtime-injected `window.napplet`
  namespace.
- Build-time `@napplet/vite-plugin` wiring for the single-file artifact and
  optional local manifest generation.
- Default app-chrome text selection disabled in `src/styles.css`, with
  opt-in controls for copyable or editable regions.
- Context documents for NIP-5D, shell boundaries, package surfaces, and authoring
  patterns.
- Guidance for handling missing NAP interfaces or numbered wire formats without
  submitting unnecessary protocol PRs.
- An applet-shaped starter layout: no title header (the runtime shows the
  name), compact density, container-query tiers from a tiny widget to a
  full-screen pane, and whole-surface runtime theming.
- A pointer to the current `napplet-*` agent skills (installed with the
  skills.sh CLI) instead of forked local skill bodies.

## Authoring Context

Read these before changing protocol-facing behavior:

- `docs/nip-5d.md`
- `docs/boundaries.md`
- `docs/design-patterns.md`
- `docs/package-surfaces.md`
- `docs/new-nap-proposals.md`
- `docs/authoring-checklist.md`

The living NIP-5D source is referenced from `docs/nip-5d.md`; this template does
not treat its local notes as normative protocol text.

For agent-driven work, install the official `napplet-*` skills with the open
skills CLI; it detects your coding agents and places the skills where each one
reads them:

```bash
npx skills add napplet/napplet
```

Then ask the agent to use `napplet-make` (end to end) or `napplet-ui` (layout
only). The skills are non-normative guidance; living NIP-5D and NAP documents
remain protocol truth.

## Text Selection

The starter disables accidental text selection by default. To change the whole
napplet, set `--napplet-text-selection: text` in `src/styles.css`. To opt in one
region, add `data-napplet-select="text"` or `data-napplet-select="all"`.

## Package Scripts

```bash
pnpm dev          # local Vite dev server
pnpm type-check   # TypeScript strict-mode check
pnpm build        # Vite production build
pnpm preview      # preview dist/
pnpm test:guidance       # stale-guidance and optional-domain regression checks
pnpm verify       # guidance test + type-check + build
pnpm test:conformance     # headless NAP conformance (build + check, CI exit code)
pnpm test:conformance:ui  # live conformance web runtime, re-runs on change
```