drawnui-react 0.1.0-preview.10 → 0.1.0-preview.11

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
@@ -6,6 +6,8 @@ through a custom `react-reconciler` renderer.
6
6
 
7
7
  Check out latest playbook: [helloreact.drawnui.net](https://helloreact.drawnui.net/) 👈
8
8
 
9
+ Playground to use and test live: [drawfiddle.com](https://drawfiddle.com/) 👈
10
+
9
11
  *Work in progress*: the goal is same API surface and semantics as DrawnUi (.NET) — same control names, same PascalCase
10
12
  property names, same measure/arrange/paint contract — so knowledge and docs transfer 1:1.
11
13
 
@@ -65,6 +67,15 @@ accessibility all live in the engine and would work identically under Vue, Svelt
65
67
  That is also why the demo pages describe DrawnUi features, not React ones: the same pages are meant to be reused as
66
68
  the showcase for other frameworks on this engine.
67
69
 
70
+ ## Games
71
+
72
+ `DrawnGame` (from DrawnUi.Gaming) is ported: a layout with a game loop. Subclass it, build your sprites in the
73
+ constructor, call `StartLoop()`, and override `GameLoop(deltaSeconds)` and `OnKeyDown` / `OnKeyUp` (DOM `event.code`
74
+ names). Move sprites with `Left` / `Top` on cached controls, as in C#. The demo's `#/pong` page is the .NET Pong
75
+ sample (`src/Shared/Samples/Pong.Shared`) ported line for line: the game classes are plain TypeScript in
76
+ `samples/demo/pages/pong`, mounted from `PongPage.tsx` with `AddSubView`, and a small `RescalingLayout` fits the
77
+ 360×640 field to any screen by changing the children's rendering scale.
78
+
68
79
  ## Context menu (right click)
69
80
 
70
81
  A right click on the canvas normally opens the browser's own menu ("Save image as…"). Every mouse button goes
package/SKIPPED.md CHANGED
@@ -31,7 +31,9 @@ DrawnUi name and semantics; nothing here is a redesign, only an omission.
31
31
  | `FillGradient`, `SkiaShape.StrokeGradient` | ported | `SkiaGradient` as a plain object: `Type` Linear (Start/End ratios or CSS `Angle`), Circular / Conical (radius = half the smaller side), Oval (radial scaled to the box), Sweep (around the center, `Value1`/`Value2` angles), `ColorPositions`, `TileMode`, `Light` (< 1 darker, > 1 lighter — HSL lightness, C# uses `MakeDarker/MakeLighter`, exact curve unverified), `Opacity`, `BlendMode`; C# `SetupGradient` paint setup (white base); shaders cached per gradient object and rect (C# `Version` cache: a new React literal replaces the old shaders). `SkiaLabel.FillGradient` paints the glyphs (`GradientByLines` default true = per line bounds, false = the text block) and the background only when `BackgroundColor` is set, like the C# label override. `SkiaLabel` text stroke (`StrokeColor`, `StrokeWidth` points, `StrokeGradient`) and drop shadow (`DropShadowColor`, `DropShadowSize`, `DropShadowOffsetX/Y`) in the C# order shadow → stroke → fill, measurement inflated by stroke × 2 and shadow size + offset like C#. Not ported: `Background` MAUI brushes, `FillBlendMode`. |
32
32
  | `SkiaShell` | partial (React-level) | `Routes` (route -> JSX page factory), `GoToAsync(route, animated)` / `GoBackAsync(animated)` / `PopToRootAsync` with the SkiaViewSwitcher slide (`PagesAnimationSpeed` 200 ms, pushed pages opaque over the page below, lower pages hidden when idle), `NavigationStack`, `CanGoBack`, `Route`, nav bar with Back + title, `useShell()`; `OpenPopupAsync(content, { animated, closeWhenBackgroundTapped, showOverlay, backgroundColor })` (C# PopupWrapper: dimmed backdrop, scale 0.5→1 + fade over `PopupsAnimationSpeed`, tap outside the content closes), `ClosePopupAsync`, `CloseAllPopups`; `PushModalAsync(content, { useGestures, animated, freezeBackground })` (C# ModalWrapper: full-screen `SkiaDrawer` FromBottom HeaderSize 0, drag-to-close with `useGestures`), `PopModalAsync`; `ShowToast(text | content, ms)` (C# layout: bottom banner, slide + fade 300/250 ms, `ShellDefaults.Toast*`), `CloseAllToasts`; `PopupsCount`/`ModalsCount`/`ToastsCount`; `ShellDefaults` = the C# statics (`PopupBackgroundColor`, `PopupsBackgroundBlur`, `PopupsAnimationSpeed`, `PopupsCancelAnimationsAfterMs`, `ZIndex*`, `Toast*`, tab colors); popups/modals sit on a `SkiaBackdrop` (blur + tint); `Tabs` (C# SkiaViewSwitcher tabs: bottom tab bar, per-tab page stacks, `SelectedTab`, `SelectTabAsync`, `PopTabToRootAsync`); `GoBackAsync` follows C# `GoBackDefault` (top popup, then modal, then page); React extension `UseBrowserHistory` (default true): pages in the URL hash `#/a/b`, one history entry per page / popup / modal, browser Back unwinds in the same order, deep links restore the page stack. Not ported: engine-level shell / `NavigationLayout` view switcher, frozen-screenshot backgrounds, `pixelsScaleInFrom`, `Navigating`/`Navigated`/`RouteChanged` events, `RegisterRoute` by type with arguments, `IHandleGoBack`, insets, `PushAsync(page instance)`; `AnimateTabs` + `TabsAnimationSpeed` (150) ported with the C# SelectLeftTab/SelectRightTab slide (0.75 width, fade, back-ease 0.55) — only the tab roots animate, pages pushed inside the leaving tab drop instantly. Browser history: a `popstate` at the same depth with another hash (a plain `<a href="#/route">` link, a typed hash) rebuilds the stack like a forward navigation. |
33
33
  | Styles / `ConfigureStyles` | ported | `Super.UseDrawnUi().ConfigureStyles(styles => styles.AddStyle({ TargetType, ApplyToDerivedTypes, Setters }))`, the C# `Style` shape with the `Setter` list written as a plain object (`Setters: { FontFamily: "FontText" }`) because controls hold plain properties instead of BindableProperty. Per-class resolution cached, base-type styles applied furthest-first so the nearest wins, exact type last (C# `ResolveStylesForType`). Applied by the reconciler between `new` and the JSX props, so props override; a control built in code-behind is styled on its first `Measure` and keeps values that differ from its class defaults (the React stand-in for C# `ExplicitPropertiesSet`, which needs BindableProperty). Not ported: `BasedOn`, `Class`, `Triggers`, `Behaviors`, the per-control `Style` property, `ConditionalStyle`. |
34
- | Animators core: `AnimatorBase` / `SkiaValueAnimator` / `RenderingAnimator` (`IOverlayEffect`), `Canvas.RegisterAnimator`/`AnimatingControls`, `PostAnimators` + `ExecutePostAnimators`, `Easing` (Linear/Cubic*) | ported | Frame-driven: a running animator keeps frames coming, idle canvas draws nothing. |
34
+ | Animators core: `AnimatorBase` / `SkiaValueAnimator` / `RenderingAnimator` (`IOverlayEffect`), `Canvas.RegisterAnimator`/`AnimatingControls`, `PostAnimators` + `ExecutePostAnimators`, `Easing` (Linear/Cubic*) | ported | Frame-driven: a running animator keeps frames coming, idle canvas draws nothing. An animator started before its control is attached waits in `PendingUnattachedAnimators` and starts on the control's first arrange (C# starts it in `SuperViewChanged`). Frame time = the frame's vsync timestamp, see PARITY "Animators run on vsync time". |
35
+ | `ActionOnTickAnimator` | ported | Runs an action with the frame time on every frame until stopped. |
36
+ | `DrawnGame` (DrawnUi.Gaming) | ported | `SkiaLayout` subclass: `StartLoop(delayMs)` / `StopLoop`, override `GameLoop(deltaSeconds)`, `OnKeyDown` / `OnKeyUp` (DOM `event.code` names, subscribed through `KeyboardManager` for the game's lifetime), `Pause` / `Resume` / `IsPaused` / `OnPaused` / `OnResumed`, `LastFrameTimeNanos`. Not ported: `FrameTimeInterpolator` (C# disables it on BROWSER too), `IGame`, the `IsPaused` property-changed notification. Demo: `#/pong`, the .NET Pong.Shared sample. |
35
37
  | Touch feedback: `AnimationTapped="Ripple"` + `TouchEffectColor` + `AnimationTappedSpeed` on any control, `SkiaButton.ApplyEffect="Ripple"` (on Down), `PlayRippleAnimation`, `RippleAnimator`, `ClipEffects`/`CreateClip` | ported | Same numbers as C#: 500ms CubicIn, radius 300pt, opacity 0.20 fading over 1.15x progress. |
36
38
  | `Shimmer` touch animation, `ShimmerAnimator`, `ClippedEffectsWith`, `TransformView`, `DelayCallbackMs`, `removePrevious`, `Pause`/`Resume`, `UseInterpolator`, spring/deceleration timing, `AnimateExtensions` (`FadeToAsync`, `TranslateToAsync`, ...) | skipped | |
37
39
  | `VisualEffects` + `SkiaEffect` / `IPostRendererEffect` / `ISkiaGestureProcessor` | partial | `VisualEffects` array on every control (assign a new array; effects attach / detach, dispose with the control, `DisableEffects`, `GetEffectMargin` aggregated into the effects margin); post renderers run after the direct paint (C# `DrawDirectInternal`) or instead of the Image cache blit (C# `DrawRenderObject`, the effect samples `CachedImage`); effects with `ProcessGestures` see the parent's gestures first (C# `EffectsGestureProcessors`). Not ported: `IRenderEffect` chain (`ChainEffectResult`, `Draw(ctx, drawControl)`), `IColorEffect` / `IImageEffect` on VisualEffects (`BlurEffect`, `DropShadowEffect`, `OuterGlowEffect`, `ColorPresetEffect`, `AdjustRGBEffect`, `ChainAdjust*`, `Chain*`), `IStateEffect.UpdateState`, `Tag` lookup. |
@@ -0,0 +1,37 @@
1
+ import { type InputKey } from "../core/KeyboardManager";
2
+ import { SkiaLayout } from "./SkiaLayout";
3
+ /**
4
+ * Mirrors DrawnUi.Gaming DrawnGame (SharedGame/DrawnGame.cs + Game.Input.cs): a layout that runs a game loop.
5
+ * `StartLoop()` / `StopLoop()`, override `GameLoop(deltaSeconds)` for the game and `OnKeyDown` / `OnKeyUp` for keys
6
+ * (DOM `event.code` names, e.g. "ArrowLeft", "Space"). The loop is an `ActionOnTickAnimator`, ticked once per drawn
7
+ * frame; started before the game is attached it waits for the first layout, like C#.
8
+ * Not ported: `FrameTimeInterpolator` (C# disables it on BROWSER too, the raw frame delta is used).
9
+ */
10
+ export declare class DrawnGame extends SkiaLayout {
11
+ private appLoop?;
12
+ protected LastFrameTimeNanos: number;
13
+ private isPaused;
14
+ private readonly onKeyDown;
15
+ private readonly onKeyChar;
16
+ private readonly onKeyUp;
17
+ constructor();
18
+ protected OnDisposing(): void;
19
+ protected OnResumed(): void;
20
+ protected OnPaused(): void;
21
+ /** Override this for your game. `deltaSeconds` is the time elapsed between the previous frame and this one. */
22
+ GameLoop(_deltaSeconds: number): void;
23
+ /** Stops the game loop. */
24
+ StopLoop(): void;
25
+ /** Starts the game loop. */
26
+ StartLoop(delayMs?: number): void;
27
+ /** Internal, override `GameLoop` for your game. Frame time is in nanoseconds. */
28
+ protected GameTick(frameTimeNanos: number): void;
29
+ get IsPaused(): boolean;
30
+ set IsPaused(value: boolean);
31
+ Pause(): void;
32
+ Resume(): void;
33
+ /** Override this to process game keys. */
34
+ OnKeyDown(_key: InputKey): void;
35
+ /** Override this to process game keys. */
36
+ OnKeyUp(_key: InputKey): void;
37
+ }
@@ -0,0 +1,60 @@
1
+ import { ActionOnTickAnimator } from "../core/Animators";
2
+ import { KeyboardManager } from "../core/KeyboardManager";
3
+ import { SkiaLayout } from "./SkiaLayout";
4
+ /**
5
+ * Mirrors DrawnUi.Gaming DrawnGame (SharedGame/DrawnGame.cs + Game.Input.cs): a layout that runs a game loop.
6
+ * `StartLoop()` / `StopLoop()`, override `GameLoop(deltaSeconds)` for the game and `OnKeyDown` / `OnKeyUp` for keys
7
+ * (DOM `event.code` names, e.g. "ArrowLeft", "Space"). The loop is an `ActionOnTickAnimator`, ticked once per drawn
8
+ * frame; started before the game is attached it waits for the first layout, like C#.
9
+ * Not ported: `FrameTimeInterpolator` (C# disables it on BROWSER too, the raw frame delta is used).
10
+ */
11
+ export class DrawnGame extends SkiaLayout {
12
+ appLoop;
13
+ LastFrameTimeNanos = 0;
14
+ isPaused = false;
15
+ onKeyDown = (key) => this.OnKeyDown(key);
16
+ onKeyChar = () => { };
17
+ onKeyUp = (key) => this.OnKeyUp(key);
18
+ constructor() {
19
+ super();
20
+ KeyboardManager.Subscribe(this.onKeyDown, this.onKeyChar, this.onKeyUp);
21
+ }
22
+ OnDisposing() {
23
+ KeyboardManager.Unsubscribe(this.onKeyDown, this.onKeyChar, this.onKeyUp);
24
+ this.appLoop?.Dispose();
25
+ this.appLoop = undefined;
26
+ super.OnDisposing();
27
+ }
28
+ OnResumed() { }
29
+ OnPaused() { }
30
+ /** Override this for your game. `deltaSeconds` is the time elapsed between the previous frame and this one. */
31
+ GameLoop(_deltaSeconds) { }
32
+ /** Stops the game loop. */
33
+ StopLoop() { this.appLoop?.Stop(); }
34
+ /** Starts the game loop. */
35
+ StartLoop(delayMs = 0) {
36
+ this.appLoop ??= new ActionOnTickAnimator(this, (t) => this.GameTick(t));
37
+ this.appLoop.Start(delayMs);
38
+ }
39
+ /** Internal, override `GameLoop` for your game. Frame time is in nanoseconds. */
40
+ GameTick(frameTimeNanos) {
41
+ const deltaSeconds = (frameTimeNanos - this.LastFrameTimeNanos) / 1_000_000_000;
42
+ this.LastFrameTimeNanos = frameTimeNanos;
43
+ this.GameLoop(deltaSeconds);
44
+ }
45
+ get IsPaused() { return this.isPaused; }
46
+ set IsPaused(value) { this.isPaused = value; }
47
+ Pause() {
48
+ this.IsPaused = true;
49
+ this.OnPaused();
50
+ }
51
+ Resume() {
52
+ this.LastFrameTimeNanos = Math.round(performance.now() * 1_000_000);
53
+ this.IsPaused = false;
54
+ this.OnResumed();
55
+ }
56
+ /** Override this to process game keys. */
57
+ OnKeyDown(_key) { }
58
+ /** Override this to process game keys. */
59
+ OnKeyUp(_key) { }
60
+ }
@@ -29,6 +29,15 @@ export declare class AnimatorBase {
29
29
  Dispose(): void;
30
30
  private SetRunning;
31
31
  }
32
+ /**
33
+ * DrawnUi ActionOnTickAnimator: runs `action(frameTimeNanos)` on every frame until stopped, a game loop for
34
+ * DrawnGame or any per-frame work.
35
+ */
36
+ export declare class ActionOnTickAnimator extends AnimatorBase {
37
+ private readonly action;
38
+ constructor(parent: SkiaControl, action: (frameTimeNanos: number) => void);
39
+ TickFrame(frameTimeNanos: number): boolean;
40
+ }
32
41
  /** DrawnUi SkiaValueAnimator: drives mValue from mMinValue to mMaxValue over Speed ms with Easing. */
33
42
  export declare class SkiaValueAnimator extends AnimatorBase {
34
43
  mValue: number;
@@ -29,7 +29,14 @@ export class AnimatorBase {
29
29
  if (!parent.PostAnimators.includes(effect))
30
30
  parent.PostAnimators.push(effect);
31
31
  }
32
- const ok = parent.Superview?.RegisterAnimator(this) ?? false;
32
+ const superview = parent.Superview;
33
+ const ok = superview?.RegisterAnimator(this) ?? false;
34
+ // C# SkiaControl.RegisterAnimator: not attached yet, queue it; the parent starts it on its first arrange
35
+ if (!superview && !parent.IsDisposed) {
36
+ const pending = parent.PendingUnattachedAnimators ??= [];
37
+ if (!pending.includes(this))
38
+ pending.push(this);
39
+ }
33
40
  parent.Repaint();
34
41
  return ok;
35
42
  }
@@ -42,6 +49,9 @@ export class AnimatorBase {
42
49
  if (i >= 0)
43
50
  parent.PostAnimators.splice(i, 1);
44
51
  }
52
+ const pending = parent.PendingUnattachedAnimators?.indexOf(this) ?? -1;
53
+ if (pending >= 0)
54
+ parent.PendingUnattachedAnimators.splice(pending, 1);
45
55
  parent.Superview?.UnregisterAnimator(this.Uid);
46
56
  }
47
57
  Start(delayMs = 0) {
@@ -96,6 +106,21 @@ export class AnimatorBase {
96
106
  this.OnStop?.();
97
107
  }
98
108
  }
109
+ /**
110
+ * DrawnUi ActionOnTickAnimator: runs `action(frameTimeNanos)` on every frame until stopped, a game loop for
111
+ * DrawnGame or any per-frame work.
112
+ */
113
+ export class ActionOnTickAnimator extends AnimatorBase {
114
+ action;
115
+ constructor(parent, action) {
116
+ super(parent);
117
+ this.action = action;
118
+ }
119
+ TickFrame(frameTimeNanos) {
120
+ this.action(frameTimeNanos);
121
+ return super.TickFrame(frameTimeNanos);
122
+ }
123
+ }
99
124
  /** DrawnUi SkiaValueAnimator: drives mValue from mMinValue to mMaxValue over Speed ms with Easing. */
100
125
  export class SkiaValueAnimator extends AnimatorBase {
101
126
  mValue = 0;
@@ -135,7 +135,12 @@ export class Canvas {
135
135
  Draw(canvas) {
136
136
  const started = performance.now();
137
137
  this.ProcessPendingGestures();
138
- const executed = this.ExecuteAnimators(Math.round(started * 1_000_000));
138
+ // Animators run on the frame's vsync time (inside a rAF callback document.timeline.currentTime is the frame
139
+ // timestamp), not on when this callback happened to start: callback starts drift by several ms around vsync
140
+ // (measured 12..23 ms between frames shown 16.7 ms apart), and a game loop moving by speed * delta then
141
+ // jumps unevenly on screen.
142
+ const frameTime = Number(document.timeline?.currentTime ?? started);
143
+ const executed = this.ExecuteAnimators(Math.round(frameTime * 1_000_000));
139
144
  const canRender = this.CanRender;
140
145
  if (canRender && !this.WasRendered)
141
146
  this.WillFirstTimeDraw?.(this, { Canvas: canvas, Surface: this.surface });
@@ -1,6 +1,6 @@
1
1
  import type { Canvas as SkCanvas, Image, Path, SkPicture, Surface } from "canvaskit-wasm";
2
2
  import { type Color, type LayoutOptions, SKRect, ScaledSize, type SkiaCacheType, type SkiaGradient, type SkiaTouchAnimation, Thickness } from "./Types";
3
- import { type IOverlayEffect } from "./Animators";
3
+ import { type AnimatorBase, type IOverlayEffect } from "./Animators";
4
4
  import { Easing } from "./Easing";
5
5
  import type { Canvas } from "./Canvas";
6
6
  import { ContextMenuEventArgs, ControlTappedEventArgs, GestureEventProcessingInfo, type LockTouch, SKPoint, SkiaGesturesInfo, SkiaGesturesParameters } from "./Gestures";
@@ -164,6 +164,11 @@ export declare class SkiaControl {
164
164
  AnimationTappedSpeed: number;
165
165
  /** Overlay effects drawn above this control's content every frame (ripple etc). */
166
166
  readonly PostAnimators: IOverlayEffect[];
167
+ /**
168
+ * C# PendingUnattachedAnimators: animators started while no Canvas was above this control yet (e.g. a game loop
169
+ * started in a constructor). They start on the control's first arrange, where C# starts them in SuperViewChanged.
170
+ */
171
+ PendingUnattachedAnimators?: AnimatorBase[];
167
172
  private visualEffects;
168
173
  /** Post-renderer effects among VisualEffects (C# EffectPostRenderers). */
169
174
  EffectPostRenderers: (SkiaEffect & IPostRendererEffect)[];
@@ -220,6 +225,8 @@ export declare class SkiaControl {
220
225
  protected MeasureAbsolute(_widthConstraint: number, _heightConstraint: number, scale: number): ScaledSize;
221
226
  /** Places MeasuredSize inside destination per Margin + Horizontal/VerticalOptions -> DrawingRect. */
222
227
  Arrange(destination: SKRect, _widthRequest: number, _heightRequest: number, scale: number): void;
228
+ /** C# SuperViewChanged: starts the animators queued before this control was attached. */
229
+ private StartPendingAnimators;
223
230
  private static nextAccessibilityId;
224
231
  /** Stable identity for the DOM overlay. */
225
232
  readonly AccessibilityId: number;
@@ -199,6 +199,11 @@ export class SkiaControl {
199
199
  AnimationTappedSpeed = 0;
200
200
  /** Overlay effects drawn above this control's content every frame (ripple etc). */
201
201
  PostAnimators = [];
202
+ /**
203
+ * C# PendingUnattachedAnimators: animators started while no Canvas was above this control yet (e.g. a game loop
204
+ * started in a constructor). They start on the control's first arrange, where C# starts them in SuperViewChanged.
205
+ */
206
+ PendingUnattachedAnimators;
202
207
  // ---- visual effects (C# VisualEffects: attached SkiaEffect objects) ----
203
208
  visualEffects = [];
204
209
  /** Post-renderer effects among VisualEffects (C# EffectPostRenderers). */
@@ -363,10 +368,21 @@ export class SkiaControl {
363
368
  const y = availT + SkiaControl.Align(this.VerticalOptions, fullH, h);
364
369
  this.DrawingRect = SKRect.Create(x, y, w, h);
365
370
  this.OnLayoutChanged();
371
+ if (this.PendingUnattachedAnimators)
372
+ this.StartPendingAnimators();
366
373
  // DrawnUi OnLayoutReady: an accessible control registers itself on its first layout
367
374
  if (!this.registeredWithAccessibility && this.IsAccessibilityElement)
368
375
  this.NotifyAccessibility();
369
376
  }
377
+ /** C# SuperViewChanged: starts the animators queued before this control was attached. */
378
+ StartPendingAnimators() {
379
+ if (!this.Superview)
380
+ return;
381
+ const pending = this.PendingUnattachedAnimators;
382
+ this.PendingUnattachedAnimators = undefined;
383
+ for (const animator of pending)
384
+ animator.Start();
385
+ }
370
386
  // ---- accessibility (DrawnUi ISkiaAccessibilityNode) ----
371
387
  static nextAccessibilityId = 1;
372
388
  /** Stable identity for the DOM overlay. */
@@ -1038,6 +1054,7 @@ export class SkiaControl {
1038
1054
  this.ownAnimations.clear();
1039
1055
  for (const e of [...this.PostAnimators])
1040
1056
  e.Stop?.();
1057
+ this.PendingUnattachedAnimators = undefined;
1041
1058
  this.PostAnimators.length = 0;
1042
1059
  this.DestroyRenderingObject();
1043
1060
  this.compositeSurface?.delete();
package/dist/index.d.ts CHANGED
@@ -40,6 +40,7 @@ export * from "./controls/SkiaBackdrop";
40
40
  export * from "./controls/SkiaEditor";
41
41
  export * from "./controls/SkiaSprite";
42
42
  export * from "./controls/SkiaSpriteSet";
43
+ export * from "./controls/DrawnGame";
43
44
  export * from "./core/KeyboardManager";
44
45
  export * from "./controls/AnimatedFramesRenderer";
45
46
  export * from "./controls/SkiaLottie";
package/dist/index.js CHANGED
@@ -40,6 +40,7 @@ export * from "./controls/SkiaBackdrop";
40
40
  export * from "./controls/SkiaEditor";
41
41
  export * from "./controls/SkiaSprite";
42
42
  export * from "./controls/SkiaSpriteSet";
43
+ export * from "./controls/DrawnGame";
43
44
  export * from "./core/KeyboardManager";
44
45
  export * from "./controls/AnimatedFramesRenderer";
45
46
  export * from "./controls/SkiaLottie";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drawnui-react",
3
- "version": "0.1.0-preview.10",
3
+ "version": "0.1.0-preview.11",
4
4
  "description": "DrawnUi for React: the DrawnUi (.NET) drawn-UI engine in TypeScript on CanvasKit (Skia WASM). Same controls, same PascalCase API as DrawnUi.Net.",
5
5
  "license": "MIT",
6
6
  "author": "Nick Kovalsky (AppoMobi)",