@weft-js/plugin-surface-keel 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,9 +1,318 @@
1
- # @weft-js/plugin-surface-keel
1
+ <p align="center">
2
+ <a href="https://github.com/Ravonus/weft">
3
+ <img src="https://raw.githubusercontent.com/Ravonus/weft/main/site/public/logo.svg" width="88" height="88" alt="Weft">
4
+ </a>
5
+ </p>
2
6
 
3
- > **Early release (0.1.1).** APIs will change between minor versions.
7
+ <h1 align="center">@weft-js/plugin-surface-keel</h1>
4
8
 
5
- The `keel-pixel` surface kind (surface.renderer@1): KEEL's WebGL2 pixel renderer and theme recipes..
9
+ <p align="center">
10
+ <strong>KEEL's WebGL2 pixel renderer as a Weft surface kind: <code>kind: 'keel-pixel'</code>.</strong><br>
11
+ A fixed low-resolution target scaled up with nearest sampling, plus KEEL's seeded theme recipes as palettes and CSS variables.
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://www.npmjs.com/package/@weft-js/plugin-surface-keel"><img src="https://img.shields.io/npm/v/@weft-js/plugin-surface-keel?color=145c3c&label=npm" alt="npm version"></a>
16
+ <a href="https://github.com/Ravonus/weft/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-145c3c" alt="MIT license"></a>
17
+ <a href="https://github.com/Ravonus/weft/actions"><img src="https://img.shields.io/github/actions/workflow/status/Ravonus/weft/quality.yml?branch=main&label=checks" alt="checks"></a>
18
+ </p>
19
+
20
+ <p align="center">
21
+ <a href="#quick-start">Quick start</a> ·
22
+ <a href="https://github.com/Ravonus/weft/tree/main/docs">Docs</a> ·
23
+ <a href="https://github.com/Ravonus/weft/tree/main/examples">Examples</a> ·
24
+ <a href="https://github.com/Ravonus/weft/blob/main/CHANGELOG.md">Changelog</a> ·
25
+ <a href="https://github.com/Ravonus/weft">GitHub</a>
26
+ </p>
27
+
28
+ > [!IMPORTANT]
29
+ > **Early release (0.1.x).** APIs can change between minor versions. Pin the version and read the
30
+ > [changelog](https://github.com/Ravonus/weft/blob/main/CHANGELOG.md) before you upgrade.
31
+
32
+ Weft's surfaces (`@weft-js/core/surface`) are canvas or WebGL views that sit in layout like any other child: `setup`
33
+ runs once on the client, props stay live, and nothing around them re-renders. Core has two built-in kinds, `canvas2d`
34
+ and `webgl2`. This plugin adds a third, `keel-pixel`, through the `surface.renderer@1` slot. A `keel-pixel` surface gets
35
+ `s.px`, KEEL's `PixelRenderer`, which owns the GL context and draws a palette-indexed 3D world into a small fixed
36
+ target. It also exports KEEL's theme recipes, which turn a seed into palette ramps and `--keel-*` CSS variables.
37
+
38
+ The renderer and theme code are vendored from KEEL's engine (keel-engine) at a pinned commit; see
39
+ [Vendored code](#vendored-code).
40
+
41
+ ## Highlights
42
+
43
+ - **A new surface kind, nothing else to wire.** `keel()` in `plugins` registers `keel-pixel`; `defineSurface({ kind:
44
+ 'keel-pixel', pixel: { width, height } })` uses it.
45
+ - **Loaded only where it's used.** The renderer sits behind the slot's `import()`, so only pages that mount a
46
+ `keel-pixel` surface download it.
47
+ - **Fixed pixel target.** `pixel: { width, height }` renders at that resolution and scales up by an integer with nearest
48
+ sampling.
49
+ - **Seeded themes.** `recipeTheme({ seed, culture })` gives the same theme every time for the same recipe: palette ramps,
50
+ frame, type, spacing and motion. `themeTokens(theme, scale)` turns it into CSS variables.
51
+ - **KEEL's UI styles.** `@weft-js/plugin-surface-keel/styles.css` styles `[data-keel-theme]`, `.keel-panel` and
52
+ `.keel-button` from those variables, and drops animation under `prefers-reduced-motion`.
53
+ - **Typed `s.px`.** The package augments `@weft-js/core/surface`'s `SurfaceKinds`, so `s.px` is typed inside `setup`.
54
+ - **Clean teardown.** When the surface goes, the WebGL context is released with `WEBGL_lose_context`.
55
+
56
+ ## Install
6
57
 
7
58
  ```bash
59
+ # npm
8
60
  npm install @weft-js/plugin-surface-keel
61
+
62
+ # pnpm
63
+ pnpm add @weft-js/plugin-surface-keel
64
+
65
+ # bun
66
+ bun add @weft-js/plugin-surface-keel
67
+ ```
68
+
69
+ Or let the `weft` CLI install it and add it to `weft.config.ts` in one step:
70
+
71
+ ```bash
72
+ npx weft add surface-keel
73
+ ```
74
+
75
+ The
76
+ package has no `/plugin` entry and no default export, so `weft add` writes `import { keel } from
77
+ '@weft-js/plugin-surface-keel'` and adds `keel()` to `plugins`.
78
+
79
+ **What it needs:** a browser with WebGL2. There's no server or build-time dependency. If you draw canvas text with
80
+ `s.text()` on a surface, add `text()` from `@weft-js/text` too (the `text.measure` slot), as the demo does.
81
+
82
+ ## Quick start
83
+
84
+ ```ts
85
+ // weft.config.ts
86
+ import { defineConfig } from '@weft-js/core/config'
87
+ import { text } from '@weft-js/text'
88
+ import { keel } from '@weft-js/plugin-surface-keel'
89
+
90
+ export default defineConfig({ plugins: [text(), keel()] })
91
+ ```
92
+
93
+ ```tsx
94
+ // src/routes/scene.tsx
95
+ import { defineSurface, Surface } from '@weft-js/core/surface'
96
+ import {
97
+ recipeTheme,
98
+ themeTokens,
99
+ } from '@weft-js/plugin-surface-keel/theme'
100
+ import '@weft-js/plugin-surface-keel/styles.css'
101
+
102
+ const theme = recipeTheme({
103
+ seed: 'keel/react-demo',
104
+ culture: 'clean',
105
+ })
106
+ const css = Object.entries(themeTokens(theme, 2))
107
+ .map(([k, v]) => `${k}:${v}`)
108
+ .join(';')
109
+
110
+ // Palette ramps are packed RGB numbers; the renderer takes [r, g, b]
111
+ // triples and named ranges.
112
+ const colours = [
113
+ ...theme.palette.surface,
114
+ ...theme.palette.accent,
115
+ ].map((c: number) => [c & 255, (c >>> 8) & 255, (c >>> 16) & 255])
116
+ const ramps = {
117
+ surface: [0, theme.palette.surface.length],
118
+ accent: [theme.palette.surface.length, theme.palette.accent.length],
119
+ }
120
+
121
+ export const Scene = defineSurface({
122
+ name: 'keel-scene',
123
+ kind: 'keel-pixel',
124
+ pixel: { width: 256, height: 144 },
125
+ fps: 30,
126
+ setup(s) {
127
+ s.px.setPalette(colours, ramps)
128
+ s.px.setMaterials([{ ramp: 'surface' }, { ramp: 'accent' }])
129
+ s.px.setWorld({
130
+ boxes: [
131
+ { c: [0, -0.5, 0], h: [5, 0.5, 5], mat: 0 },
132
+ { c: [0, 1, 0], h: [0.75, 1, 0.75], mat: 1 },
133
+ ],
134
+ })
135
+ s.px.setStyle({ screen: 4 })
136
+ s.frame((t) =>
137
+ s.px.render({
138
+ eye: [Math.sin(t.seconds) * 5, 3, Math.cos(t.seconds) * 5],
139
+ target: [0, 1, 0],
140
+ time: t.seconds,
141
+ }),
142
+ )
143
+ },
144
+ })
145
+
146
+ export default function Page() {
147
+ return (
148
+ <div
149
+ data-keel-theme={theme.key}
150
+ style={css}
151
+ >
152
+ <Surface
153
+ use={Scene}
154
+ label="A box on a floor, orbited by the camera"
155
+ style="max-width:640px"
156
+ />
157
+ </div>
158
+ )
159
+ }
9
160
  ```
161
+
162
+ This is the package's own demo (`demo/KeelDemo.tsx`, a port of keel-engine's React scaffold demo), trimmed. The camera
163
+ orbits on the shared surface clock, so `clock.pause()` from `@weft-js/core/surface` stops it, and under
164
+ `prefers-reduced-motion: reduce` it starts paused.
165
+
166
+ ## How it plugs into Weft
167
+
168
+ | Piece | Detail |
169
+ | --- | --- |
170
+ | Slot | `surface.renderer@1`, keyed, client side only. This plugin provides the key `keel-pixel`. |
171
+ | Provider | `renderer` from `@weft-js/plugin-surface-keel/runtime`. Its `context(canvas, def)` creates the `PixelRenderer` and returns `{ fields: { px }, dispose }`. |
172
+ | Loading | Core's surface mount handles `canvas2d` and `webgl2` itself; any other kind is loaded through `import('weft:slot/surface.renderer')`. If loading fails, the error is logged and the host element gets `data-surface-error="keel-pixel"`. |
173
+ | Namespace | `surface-keel/`. |
174
+ | Agent notes | `kind: 'keel-pixel'` needs `pixel: { width, height }`; `s.px` is KEEL's `PixelRenderer`; palettes come from `recipeTheme()`. |
175
+
176
+ Everything else about a surface is core's: `<Surface>` takes `use`, your props, `aspect` (default `2/1`), `label`
177
+ (required) or `decorative`, `class` and `style`, and the server renders a sized placeholder so nothing shifts when the
178
+ canvas mounts. `weft docs surface` covers it.
179
+
180
+ ## `defineSurface` with `kind: 'keel-pixel'`
181
+
182
+ | Field | Type | Default | What it does |
183
+ | --- | --- | --- | --- |
184
+ | `kind` | `'keel-pixel'` | | Selects this renderer. |
185
+ | `pixel` | `{ width: number, height: number }` | required | The fixed render target. Without it, mounting throws ``surface `<name>`: `keel-pixel` needs `pixel: { width, height }` ``. |
186
+ | `fps` | `number` | `60` | Core's frame cap for `s.frame`. |
187
+ | `setup(s, props)` | function | | Runs once on the client. `s.px` is the renderer; `s.frame`, `s.draw`, `s.size`, `s.el` and `s.text` work as for any surface. |
188
+
189
+ ### `s.px`: the renderer
190
+
191
+ The typed part of KEEL's `PixelRenderer` (`src/vendor-types.d.ts`). The rest of the vendored API is reachable but
192
+ untyped.
193
+
194
+ | Method | What it takes |
195
+ | --- | --- |
196
+ | `setPalette(colours, ramps)` | `colours`: `[r, g, b]` triples. `ramps`: named `[start, length]` ranges into `colours`. |
197
+ | `setMaterials(materials)` | `{ ramp: string }[]`: material `i` shades from the named ramp. |
198
+ | `setWorld(world)` | The scene, for example `{ boxes: [{ c, h, mat }] }` (centre, half-extents, material index). |
199
+ | `setStyle(style)` | Render style, for example `{ screen: 4 }`. |
200
+ | `render(view)` | One frame: `{ eye, target, time }`. Call it from `s.frame`. |
201
+
202
+ ## Themes
203
+
204
+ ```ts
205
+ import {
206
+ recipeTheme,
207
+ themeTokens,
208
+ } from '@weft-js/plugin-surface-keel/theme'
209
+ ```
210
+
211
+ | Function | Signature | What it returns |
212
+ | --- | --- | --- |
213
+ | `recipeTheme(recipe?)` | `{ seed?, culture?, pins? }` | A theme: `key`, `palette`, and frame, type, spacing and motion. The same recipe gives the same theme. |
214
+ | `themeTokens(theme, scale?)` | theme, integer scale | `--keel-*` CSS variables at that scale; at scale 2, `--keel-px` is `2px`. |
215
+
216
+ `palette` (type `Palette`) has `tone`, ramps `surface`, `ink`, `accent`, `good`, `warn`, `bad` (packed RGB numbers),
217
+ `team`, `outline`, `onAccent`, and `hues: { surface, accent }`.
218
+
219
+ `styles.css` reads `--keel-font`, `--keel-body`, `--keel-ink`, `--keel-surface`, `--keel-border`, `--keel-outline`,
220
+ `--keel-pad`, `--keel-on-accent`, `--keel-accent` and `--keel-px`, and sets `image-rendering: pixelated` on canvases inside
221
+ `.keel-canvas`.
222
+
223
+ ## API reference
224
+
225
+ | Export | Entry | What it is |
226
+ | --- | --- | --- |
227
+ | `keel()` | `@weft-js/plugin-surface-keel` | The plugin for `weft.config.ts`. |
228
+ | `recipeTheme`, `themeTokens` | `@weft-js/plugin-surface-keel/theme` | KEEL's theme recipes (types come from the main entry's declarations). |
229
+ | `renderer` | `@weft-js/plugin-surface-keel/runtime` | The `surface.renderer@1` provider. Loaded by the slot; you don't import it yourself. |
230
+ | `styles.css` | `@weft-js/plugin-surface-keel/styles.css` | KEEL's UI styles, driven by the theme's CSS variables. |
231
+ | `SurfaceKinds['keel-pixel']` | type augmentation of `@weft-js/core/surface` | Makes `s.px` a `PixelRenderer` in `setup`. |
232
+
233
+ ## Recipes
234
+
235
+ **A play/pause button beside the scene.** The clock is shared, and `clock.playing` is a box the button reads:
236
+
237
+ ```tsx
238
+ import { clock } from '@weft-js/core/surface'
239
+
240
+ export function Controls() {
241
+ return (
242
+ <section
243
+ class="keel-panel"
244
+ aria-label="Scene controls"
245
+ >
246
+ <button
247
+ class="keel-button"
248
+ type="button"
249
+ onClick={() =>
250
+ clock.playing.value ? clock.pause() : clock.play()
251
+ }
252
+ >
253
+ {clock.playing.value ? 'PAUSE' : 'PLAY'}
254
+ </button>
255
+ </section>
256
+ )
257
+ }
258
+ ```
259
+
260
+ **A deterministic frame for a screenshot.** `clock.seek(seconds)` paints every animated surface at that time.
261
+
262
+ ## Limits
263
+
264
+ - Client only, and WebGL2 only. The server renders the sized placeholder.
265
+ - `pixel` is required: there is no resolution-following mode for this kind.
266
+ - Only the five `PixelRenderer` methods above are typed.
267
+ - The vendored engine is a snapshot. New KEEL features arrive only when the vendor files are regenerated from a newer
268
+ pin.
269
+
270
+ ## Troubleshooting
271
+
272
+ | Symptom | Cause and fix |
273
+ | --- | --- |
274
+ | The surface stays a placeholder and has `data-surface-error="keel-pixel"` | The renderer failed to load or set up; the browser console has the error. Check that `keel()` is in `plugins`, and that the browser has WebGL2. |
275
+ | ``surface `<name>`: `keel-pixel` needs `pixel: { width, height }` `` | Add `pixel` to the definition. |
276
+ | P101 for `text.measure` | `s.text()` on a canvas surface needs `text()` from `@weft-js/text` in `plugins`. |
277
+ | Blurry pixels | Put the canvas inside `.keel-canvas` and import `styles.css`, or set `image-rendering: pixelated` yourself. |
278
+
279
+ ## Vendored code
280
+
281
+ `vendor/` is generated by `scripts/vendor.mjs` from keel-engine commit `4bcccc7` and must not be edited by hand:
282
+
283
+ | File | From keel-engine |
284
+ | --- | --- |
285
+ | `keel-render.mjs` (and `keel-render/`) | `createPixelRenderer` from `packages/render` |
286
+ | `keel-theme.mjs` (and `keel-theme/`) | `recipeTheme` and `themeTokens` from `packages/react/src/design.ts` |
287
+ | `keel-styles.css` | `packages/react/src/styles.css` |
288
+
289
+ The checked patches in `scripts/vendor/` move the pinned bundles into local modules. `pnpm --filter
290
+ @weft-js/plugin-surface-keel vendor` regenerates them from a keel-engine checkout: `~/dev/keel-engine`, or a path
291
+ passed as its argument. It refuses a source without the pinned commit. The test that regenerates them reads
292
+ `KEEL_ENGINE`, and skips without a checkout.
293
+
294
+ ## Related packages
295
+
296
+ | Package | What it is |
297
+ | --- | --- |
298
+ | [`@weft-js/core`](https://www.npmjs.com/package/@weft-js/core) | `defineSurface`, `<Surface>` and the clock (`@weft-js/core/surface`). |
299
+ | [`@weft-js/text`](https://www.npmjs.com/package/@weft-js/text) | The `text.measure` slot that `s.text()` on a canvas needs. |
300
+ | [`@weft-js/cli`](https://www.npmjs.com/package/@weft-js/cli) | `weft add surface-keel`, `weft docs surface`, `weft surfaces --json`. |
301
+
302
+ ## Contributing
303
+
304
+ See [CONTRIBUTING.md](https://github.com/Ravonus/weft/blob/main/CONTRIBUTING.md). From the repository root:
305
+
306
+ ```bash
307
+ # Plugin contract, themes, vendor checks
308
+ pnpm --filter @weft-js/plugin-surface-keel test
309
+ # Builds demo/ and checks pixels in Chrome and WebKit
310
+ pnpm --filter @weft-js/plugin-surface-keel test:e2e
311
+ ```
312
+
313
+ The end-to-end run builds `demo/` with `@weft-js/core/vite` and needs `@weft-js/text` built first.
314
+
315
+ ## License
316
+
317
+ [MIT](https://github.com/Ravonus/weft/blob/main/LICENSE). The vendored KEEL code is MIT too; its licence is kept
318
+ byte-for-byte in [`vendor/LICENSE`](https://github.com/Ravonus/weft/blob/main/packages/plugin-surface-keel/vendor/LICENSE).
package/package.json CHANGED
@@ -1,8 +1,17 @@
1
1
  {
2
2
  "name": "@weft-js/plugin-surface-keel",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "@weft-js/plugin-surface-keel: the `keel-pixel` surface kind (surface.renderer@1): KEEL's WebGL2 pixel renderer and theme recipes.",
5
5
  "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Ravonus/weft.git",
9
+ "directory": "packages/plugin-surface-keel"
10
+ },
11
+ "homepage": "https://github.com/Ravonus/weft/tree/main/packages/plugin-surface-keel#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/Ravonus/weft/issues"
14
+ },
6
15
  "type": "module",
7
16
  "exports": {
8
17
  ".": {
@@ -17,7 +26,7 @@
17
26
  "./styles.css": "./vendor/keel-styles.css"
18
27
  },
19
28
  "peerDependencies": {
20
- "@weft-js/core": "^0.1.1"
29
+ "@weft-js/core": "^0.1.3"
21
30
  },
22
31
  "engines": {
23
32
  "node": ">=26"
@@ -34,4 +43,4 @@
34
43
  "publishConfig": {
35
44
  "access": "public"
36
45
  }
37
- }
46
+ }
package/src/index.d.ts CHANGED
@@ -5,7 +5,11 @@ import type { Palette, PixelRenderer } from './vendor-types'
5
5
  export declare const keel: () => PluginEntry
6
6
 
7
7
  /** `{ seed, culture, pins }` → KEEL's theme: palette ramps, frame, type, spacing and motion. */
8
- export declare function recipeTheme(recipe?: { seed?: string; culture?: string; pins?: Record<string, unknown> }): { key: string; palette: Palette; [k: string]: unknown }
8
+ export declare function recipeTheme(recipe?: {
9
+ seed?: string
10
+ culture?: string
11
+ pins?: Record<string, unknown>
12
+ }): { key: string; palette: Palette; [k: string]: unknown }
9
13
  /** A theme as `--keel-*` CSS variables at an integer scale. */
10
14
  export declare function themeTokens(theme: unknown, scale?: number): Record<string, string>
11
15
 
package/src/index.mjs CHANGED
@@ -1,8 +1,12 @@
1
- // keel() for weft.config.ts (PLAN §5, research 33 §5): the `keel-pixel` surface kind. KEEL's renderer is ~27 KB br, so it
2
- // stays behind the slot's `import()` and only pages that mount a `keel-pixel` surface load it.
1
+ // KEEL's renderer stays behind the slot's `import()` so only pages that mount it load it.
3
2
  import { definePlugin, defineSlot, provide } from '@weft-js/core/plugin'
4
3
 
5
- const renderer = defineSlot({ id: 'surface.renderer', version: 1, cardinality: 'keyed', sides: ['client'] })
4
+ const renderer = defineSlot({
5
+ id: 'surface.renderer',
6
+ version: 1,
7
+ cardinality: 'keyed',
8
+ sides: ['client'],
9
+ })
6
10
 
7
11
  export const keel = definePlugin({
8
12
  name: '@weft-js/plugin-surface-keel',
@@ -10,11 +14,22 @@ export const keel = definePlugin({
10
14
  weft: '*',
11
15
  namespace: 'surface-keel/',
12
16
  contribute: () => ({
13
- provides: [provide(renderer, { key: 'keel-pixel', sides: { client: { module: '@weft-js/plugin-surface-keel/runtime', export: 'renderer' } } })],
17
+ provides: [
18
+ provide(renderer, {
19
+ key: 'keel-pixel',
20
+ sides: { client: { module: '@weft-js/plugin-surface-keel/runtime', export: 'renderer' } },
21
+ }),
22
+ ],
14
23
  agents: {
15
24
  title: 'KEEL surfaces (@weft-js/plugin-surface-keel)',
16
25
  text: "- `kind: 'keel-pixel'` needs `pixel: { width, height }`. `s.px` is KEEL's `PixelRenderer`: `setPalette`, `setMaterials`, `setWorld`, `render`. Palettes come from `recipeTheme()` in `@weft-js/plugin-surface-keel/theme`.",
17
26
  },
18
- catalog: [{ name: 'keel', import: '@weft-js/plugin-surface-keel', summary: 'surface.renderer: keel-pixel' }],
27
+ catalog: [
28
+ {
29
+ name: 'keel',
30
+ import: '@weft-js/plugin-surface-keel',
31
+ summary: 'surface.renderer: keel-pixel',
32
+ },
33
+ ],
19
34
  }),
20
35
  })
package/src/runtime.mjs CHANGED
@@ -4,8 +4,12 @@ import { createPixelRenderer } from '../vendor/keel-render.mjs'
4
4
  /** The surface.renderer@1 provider: `context` makes the surface's `s.px` and undoes it when the surface goes. */
5
5
  export const renderer = {
6
6
  context(canvas, def) {
7
- if (!def.pixel) throw new Error(`surface \`${def.name}\`: \`keel-pixel\` needs \`pixel: { width, height }\``)
7
+ if (!def.pixel)
8
+ throw new Error(`surface \`${def.name}\`: \`keel-pixel\` needs \`pixel: { width, height }\``)
8
9
  const px = createPixelRenderer(canvas, def.pixel)
9
- return { fields: { px }, dispose: () => canvas.getContext('webgl2')?.getExtension('WEBGL_lose_context')?.loseContext() }
10
+ return {
11
+ fields: { px },
12
+ dispose: () => canvas.getContext('webgl2')?.getExtension('WEBGL_lose_context')?.loseContext(),
13
+ }
10
14
  },
11
15
  }
package/vendor/README.md CHANGED
@@ -1,8 +1,11 @@
1
1
  # vendor
2
2
 
3
- Built by `scripts/vendor.mjs` from keel-engine 4bcccc7 (MIT, Copyright (c) 2026 ravonus; see LICENSE).
4
- Don't edit these files: fix KEEL and run the script again.
3
+ Built by `scripts/vendor.mjs` from keel-engine 4bcccc7 (MIT; see LICENSE).
4
+ The checked patches move the pinned bundles into local modules. Don't edit generated modules directly.
5
5
 
6
- - `keel-render.mjs`: `createPixelRenderer` from `packages/render`, with what it needs of `packages/core`.
7
- - `keel-theme.mjs`: `recipeTheme` and `themeTokens` from `packages/react/src/design.ts`.
6
+ The existing LICENSE is preserved byte-for-byte. At the pinned commit, upstream's LICENSE names
7
+ Chad Koslovsky and contributors; the preserved vendored copy names ravonus.
8
+
9
+ - `keel-render.mjs`: `createPixelRenderer` from `packages/render` and its local modules.
10
+ - `keel-theme.mjs`: `recipeTheme` and `themeTokens` from `packages/react/src/design.ts` and their local modules.
8
11
  - `keel-styles.css`: `packages/react/src/styles.css`.