svelte-p5 0.3.0 → 0.4.0

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
@@ -8,6 +8,14 @@ Svelte 5 bindings for p5.js. This package is the primitive layer: a canvas wrapp
8
8
  pnpm add svelte-p5 p5
9
9
  ```
10
10
 
11
+ To test a change that's merged on `main` but not yet released — or any specific commit — install the preview build from [pkg.pr.new](https://pkg.pr.new/):
12
+
13
+ ```bash
14
+ pnpm add https://pkg.pr.new/edw1nzhao/svelte-p5/svelte-p5@main
15
+ # or pin an exact SHA:
16
+ pnpm add https://pkg.pr.new/edw1nzhao/svelte-p5/svelte-p5@<commit-sha>
17
+ ```
18
+
11
19
  ## `<P5Canvas>`
12
20
 
13
21
  Mounts a p5 sketch in instance mode, cleans it up on unmount.
@@ -91,11 +99,42 @@ What each does and when to reach for it lives in the [performance recipe](../../
91
99
  ## Type exports
92
100
 
93
101
  ```ts
94
- import type { SketchFn, P5CanvasProps, P5Bridge } from 'svelte-p5';
102
+ import type { SketchFn, ExtendedP5, P5CanvasProps, P5Bridge } from 'svelte-p5';
95
103
  ```
96
104
 
97
105
  `SketchFn` is `(p: p5) => void`. `SketchFn`, not `Sketch`, because the components package exports a `<Sketch>` component and the collision would force aliased imports.
98
106
 
107
+ ### Typed instance extensions
108
+
109
+ Sketches that install custom members on the instance (`p.myHelper = ...`) can type
110
+ them instead of casting. `SketchFn<Ext>` types the instance inside the sketch as
111
+ `p5 & Ext`, and `ExtendedP5<Ext>` names that same intersection for stores and
112
+ variables that hold the bound instance:
113
+
114
+ ```ts
115
+ interface AppSketchExt {
116
+ resetView(): void;
117
+ zoomLevel: number;
118
+ }
119
+ type AppP5 = ExtendedP5<AppSketchExt>;
120
+
121
+ const sketch: SketchFn<AppSketchExt> = (p) => {
122
+ p.resetView = () => {
123
+ /* ... */
124
+ };
125
+ p.draw = () => {
126
+ /* p.zoomLevel is typed */
127
+ };
128
+ };
129
+
130
+ let instance: AppP5 | null = $state(null);
131
+ ```
132
+
133
+ ```svelte
134
+ <P5Canvas {sketch} bind:instance />
135
+ <!-- instance is inferred as AppP5 | null; instance?.resetView() type-checks -->
136
+ ```
137
+
99
138
  ## License
100
139
 
101
140
  MIT
@@ -1,7 +1,7 @@
1
- <script lang="ts">
1
+ <script lang="ts" generics="Ext = unknown">
2
2
  import { onMount } from 'svelte';
3
3
  import type p5Type from 'p5';
4
- import type { P5CanvasProps } from './types.js';
4
+ import type { ExtendedP5, P5CanvasProps } from './types.js';
5
5
 
6
6
  let {
7
7
  sketch,
@@ -9,7 +9,7 @@
9
9
  class: className = '',
10
10
  style = 'display: block; width: 100%; height: 100%;',
11
11
  onReady
12
- }: P5CanvasProps = $props();
12
+ }: P5CanvasProps<Ext> = $props();
13
13
 
14
14
  let container: HTMLDivElement | null = null;
15
15
 
@@ -24,9 +24,12 @@
24
24
  if (cancelled || !container) return;
25
25
 
26
26
  const p5Ctor = mod.default;
27
- local = new p5Ctor((p: p5Type) => sketch(p), container);
28
- instance = local;
29
- onReady?.(local);
27
+ // The sketch installs its Ext members during construction (p5 calls the
28
+ // sketch function synchronously inside the constructor), so by the time
29
+ // the instance is observable it is already the extended type.
30
+ local = new p5Ctor((p: p5Type) => sketch(p as ExtendedP5<Ext>), container);
31
+ instance = local as ExtendedP5<Ext>;
32
+ onReady?.(local as ExtendedP5<Ext>);
30
33
  })();
31
34
 
32
35
  return () => {
@@ -1,4 +1,25 @@
1
1
  import type { P5CanvasProps } from './types.js';
2
- declare const P5Canvas: import("svelte").Component<P5CanvasProps, {}, "instance">;
3
- type P5Canvas = ReturnType<typeof P5Canvas>;
2
+ declare function $$render<Ext = unknown>(): {
3
+ props: P5CanvasProps<Ext>;
4
+ exports: {};
5
+ bindings: "instance";
6
+ slots: {};
7
+ events: {};
8
+ };
9
+ declare class __sveltets_Render<Ext = unknown> {
10
+ props(): ReturnType<typeof $$render<Ext>>['props'];
11
+ events(): ReturnType<typeof $$render<Ext>>['events'];
12
+ slots(): ReturnType<typeof $$render<Ext>>['slots'];
13
+ bindings(): "instance";
14
+ exports(): {};
15
+ }
16
+ interface $$IsomorphicComponent {
17
+ new <Ext = unknown>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<Ext>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<Ext>['props']>, ReturnType<__sveltets_Render<Ext>['events']>, ReturnType<__sveltets_Render<Ext>['slots']>> & {
18
+ $$bindings?: ReturnType<__sveltets_Render<Ext>['bindings']>;
19
+ } & ReturnType<__sveltets_Render<Ext>['exports']>;
20
+ <Ext = unknown>(internal: unknown, props: ReturnType<__sveltets_Render<Ext>['props']> & {}): ReturnType<__sveltets_Render<Ext>['exports']>;
21
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
22
+ }
23
+ declare const P5Canvas: $$IsomorphicComponent;
24
+ type P5Canvas<Ext = unknown> = InstanceType<typeof P5Canvas<Ext>>;
4
25
  export default P5Canvas;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { default as P5Canvas } from './P5Canvas.svelte';
2
2
  export { createP5Bridge, type P5Bridge } from './createP5Bridge.svelte.js';
3
- export type { SketchFn, P5CanvasProps } from './types.js';
3
+ export type { SketchFn, ExtendedP5, P5CanvasProps } from './types.js';
4
4
  export * from './utils/index.js';
package/dist/types.d.ts CHANGED
@@ -2,20 +2,41 @@ import type p5 from 'p5';
2
2
  /**
3
3
  * A p5 sketch function in instance mode. Called with the p5 instance;
4
4
  * the function should assign `p.setup`, `p.draw`, etc. on it.
5
+ *
6
+ * `Ext` types the members your sketch installs onto the instance
7
+ * (`p.myHelper = ...`). Inside the sketch the instance is typed as
8
+ * already-extended, because the sketch itself is what installs those
9
+ * members before anyone else can observe them:
10
+ *
11
+ * ```ts
12
+ * interface MyExt {
13
+ * resetView(): void;
14
+ * }
15
+ * const sketch: SketchFn<MyExt> = (p) => {
16
+ * p.resetView = () => { ... };
17
+ * p.draw = () => { ... };
18
+ * };
19
+ * ```
5
20
  */
6
- export type SketchFn = (p: p5) => void;
21
+ export type SketchFn<Ext = unknown> = (p: p5 & Ext) => void;
22
+ /**
23
+ * A p5 instance decorated with app-specific members (see {@link SketchFn}).
24
+ * Useful for typing stores or variables that hold the bound instance:
25
+ * `let instance: ExtendedP5<MyExt> | null`.
26
+ */
27
+ export type ExtendedP5<Ext> = p5 & Ext;
7
28
  /**
8
29
  * Props accepted by the `<P5Canvas>` component.
9
30
  */
10
- export interface P5CanvasProps {
31
+ export interface P5CanvasProps<Ext = unknown> {
11
32
  /** Your sketch function - assigns p.setup, p.draw, etc. */
12
- sketch: SketchFn;
33
+ sketch: SketchFn<Ext>;
13
34
  /** Bindable: the p5 instance, available after mount. `null` before mount or after unmount. */
14
- instance?: p5 | null;
35
+ instance?: ExtendedP5<Ext> | null;
15
36
  /** Optional class applied to the container div. */
16
37
  class?: string;
17
38
  /** Optional inline style on the container div. Defaults to `display: block; width: 100%; height: 100%;`. */
18
39
  style?: string;
19
40
  /** Called once, synchronously, when the p5 instance has been created and the sketch function has returned. */
20
- onReady?: (instance: p5) => void;
41
+ onReady?: (instance: ExtendedP5<Ext>) => void;
21
42
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-p5",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Svelte 5 + p5.js integration primitives — <P5Canvas> wrapper, rune bridge, and performance utilities",
5
5
  "keywords": [
6
6
  "svelte",