cubeforge 0.3.10 → 0.3.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/dist/index.d.ts CHANGED
@@ -3,6 +3,8 @@ import * as React from 'react';
3
3
  import React__default, { CSSProperties, ReactNode } from 'react';
4
4
  import { Plugin, EntityId, ECSWorld, ScriptUpdateFn, NavGrid, WorldSnapshot, EventBus } from '@cubeforge/core';
5
5
  export { AssetProgress, Component, ECSWorld, Ease, EntityId, GameTimer, HotReloadablePlugin, NavGrid, Plugin, PreloadManifest, ScriptUpdateFn, TransformComponent, TweenHandle, Vec2Like, WorldSnapshot, arrive, createTag, createTimer, createTransform, definePlugin, findByTag, flee, hotReloadPlugin, patrol, preloadManifest, seek, tween, wander } from '@cubeforge/core';
6
+ import { Sampling } from '@cubeforge/renderer';
7
+ export { AnimationStateComponent, MagFilterValue, NineSliceComponent, ParallaxLayerComponent, Particle, ParticlePoolComponent, RenderSystem, Sampling, SpriteComponent, SquashStretchComponent, TextComponent, TextureFilter, TextureFilterValue, TrailComponent, createNineSlice, createSprite } from '@cubeforge/renderer';
6
8
  import { ColliderShape } from '@cubeforge/physics';
7
9
  export { BoxColliderComponent, CapsuleColliderComponent, CircleColliderComponent, ColliderShape, CompoundColliderComponent, RaycastHit, RigidBodyComponent, createCompoundCollider, overlapBox, overlapCircle, raycast, raycastAll, sweepBox } from '@cubeforge/physics';
8
10
  import { InputManager, ActionBindings, InputContextName, PlayerInput, InputRecorderControls } from '@cubeforge/input';
@@ -12,7 +14,6 @@ export { EngineState, useCircleEnter, useCircleExit, useCircleStay, useCollision
12
14
  export { AISteering, AnimationClip, AnimationControllerResult, BindingControls, CutsceneControls, CutsceneStep, DialogueControls, DialogueLine, DialogueScript, GameState as GameStateDefinition, GameStateMachineResult, HealthControls, HealthOptions, KinematicBodyControls, LevelTransitionControls, PathfindingControls, PlatformerControllerOptions, RestartControls, SaveControls, SaveOptions, TopDownMovementOptions, TransitionOptions, TransitionType, useAISteering, useAnimationController, useCutscene, useDamageZone, useDialogue, useDropThrough, useGameStateMachine, useGameStore, useHealth, useKinematicBody, useLevelTransition, usePathfinding, usePersistedBindings, usePlatformerController, useRestart, useSave, useTopDownMovement } from '@cubeforge/gameplay';
13
15
  export { AudioGroup, SoundControls, duck, getGroupVolume, setGroupMute, setGroupVolume, setMasterVolume, stopGroup, useSound } from '@cubeforge/audio';
14
16
  export { DevToolsHandle } from '@cubeforge/devtools';
15
- export { AnimationStateComponent, NineSliceComponent, ParallaxLayerComponent, Particle, ParticlePoolComponent, RenderSystem, SpriteComponent, SquashStretchComponent, TextComponent, TrailComponent, createNineSlice, createSprite } from '@cubeforge/renderer';
16
17
 
17
18
  interface GameControls {
18
19
  pause(): void;
@@ -48,13 +49,19 @@ interface GameProps {
48
49
  * shown is fully rendered with real assets.
49
50
  */
50
51
  asyncAssets?: boolean;
52
+ /**
53
+ * Default texture sampling for all sprites (default 'nearest').
54
+ * Individual sprites can override via their own `sampling` prop.
55
+ * Use `TextureFilter.NEAREST` for pixel art or `TextureFilter.LINEAR` for smooth scaling.
56
+ */
57
+ sampling?: Sampling;
51
58
  /** Custom plugins to register after core systems. Each plugin's systems run after Render. */
52
59
  plugins?: Plugin[];
53
60
  style?: CSSProperties;
54
61
  className?: string;
55
62
  children?: React__default.ReactNode;
56
63
  }
57
- declare function Game({ width, height, gravity, debug, devtools, scale, deterministic, seed, asyncAssets, onReady, plugins, style, className, children, }: GameProps): react_jsx_runtime.JSX.Element;
64
+ declare function Game({ width, height, gravity, debug, devtools, scale, deterministic, seed, asyncAssets, sampling, onReady, plugins, style, className, children, }: GameProps): react_jsx_runtime.JSX.Element;
58
65
 
59
66
  interface WorldProps {
60
67
  /** Gravitational acceleration in pixels/s² (default inherited from Game) */
@@ -114,8 +121,10 @@ interface SpriteProps {
114
121
  tileY?: boolean;
115
122
  tileSizeX?: number;
116
123
  tileSizeY?: number;
124
+ /** Texture sampling mode — controls filtering when the sprite is scaled */
125
+ sampling?: Sampling;
117
126
  }
118
- declare function Sprite({ width, height, color, src, offsetX, offsetY, zIndex, visible, flipX, anchorX, anchorY, frameIndex, frameWidth, frameHeight, frameColumns, atlas, frame, tileX, tileY, tileSizeX, tileSizeY, }: SpriteProps): null;
127
+ declare function Sprite({ width, height, color, src, offsetX, offsetY, zIndex, visible, flipX, anchorX, anchorY, frameIndex, frameWidth, frameHeight, frameColumns, atlas, frame, tileX, tileY, tileSizeX, tileSizeY, sampling, }: SpriteProps): null;
119
128
 
120
129
  interface TextProps {
121
130
  text: string;
package/dist/index.js CHANGED
@@ -1146,6 +1146,55 @@ function createSprite(opts) {
1146
1146
  };
1147
1147
  }
1148
1148
 
1149
+ // ../../packages/renderer/src/textureFilter.ts
1150
+ var TextureFilter = {
1151
+ /** Nearest-neighbor — sharp pixels, ideal for pixel art */
1152
+ NEAREST: "nearest",
1153
+ /** Bilinear — smooth interpolation */
1154
+ LINEAR: "linear",
1155
+ /** Nearest on nearest mipmap level */
1156
+ NEAREST_MIPMAP_NEAREST: "nearest-mipmap-nearest",
1157
+ /** Bilinear on nearest mipmap level */
1158
+ LINEAR_MIPMAP_NEAREST: "linear-mipmap-nearest",
1159
+ /** Nearest, blending between two mipmap levels */
1160
+ NEAREST_MIPMAP_LINEAR: "nearest-mipmap-linear",
1161
+ /** Trilinear — bilinear + mipmap blending, smoothest downscaling */
1162
+ LINEAR_MIPMAP_LINEAR: "linear-mipmap-linear"
1163
+ };
1164
+ var DEFAULT_SAMPLING = TextureFilter.NEAREST;
1165
+ function resolveSampling(sampling, fallback = DEFAULT_SAMPLING) {
1166
+ const s2 = sampling ?? fallback;
1167
+ if (typeof s2 === "string") {
1168
+ const mag = s2.startsWith("linear") ? "linear" : "nearest";
1169
+ return { min: s2, mag };
1170
+ }
1171
+ return { min: s2.min, mag: s2.mag };
1172
+ }
1173
+ function toGLMinFilter(gl, filter) {
1174
+ switch (filter) {
1175
+ case "nearest":
1176
+ return gl.NEAREST;
1177
+ case "linear":
1178
+ return gl.LINEAR;
1179
+ case "nearest-mipmap-nearest":
1180
+ return gl.NEAREST_MIPMAP_NEAREST;
1181
+ case "linear-mipmap-nearest":
1182
+ return gl.LINEAR_MIPMAP_NEAREST;
1183
+ case "nearest-mipmap-linear":
1184
+ return gl.NEAREST_MIPMAP_LINEAR;
1185
+ case "linear-mipmap-linear":
1186
+ return gl.LINEAR_MIPMAP_LINEAR;
1187
+ default:
1188
+ return gl.NEAREST;
1189
+ }
1190
+ }
1191
+ function toGLMagFilter(gl, filter) {
1192
+ return filter === "linear" ? gl.LINEAR : gl.NEAREST;
1193
+ }
1194
+ function needsMipmap(filter) {
1195
+ return filter !== "nearest" && filter !== "linear";
1196
+ }
1197
+
1149
1198
  // ../../packages/renderer/src/components/camera2d.ts
1150
1199
  function createCamera2D(opts) {
1151
1200
  return {
@@ -1367,10 +1416,17 @@ function createWhiteTexture(gl) {
1367
1416
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1368
1417
  return tex;
1369
1418
  }
1419
+ function getSamplingKey(sampling) {
1420
+ if (!sampling) return "";
1421
+ if (typeof sampling === "string") return sampling;
1422
+ return `${sampling.min}|${sampling.mag}`;
1423
+ }
1370
1424
  function getTextureKey(sprite) {
1371
1425
  const src = sprite.image?.src || sprite.src;
1372
- if (src) return sprite.tileX || sprite.tileY ? `${src}:repeat` : src;
1373
- return `__color__:${sprite.color}`;
1426
+ const samplingKey = getSamplingKey(sprite.sampling);
1427
+ const suffix = samplingKey ? `:s=${samplingKey}` : "";
1428
+ if (src) return sprite.tileX || sprite.tileY ? `${src}:repeat${suffix}` : `${src}${suffix}`;
1429
+ return `__color__:${sprite.color}${suffix}`;
1374
1430
  }
1375
1431
  function getUVRect(sprite) {
1376
1432
  if (!sprite.image || sprite.image.naturalWidth === 0) return [0, 0, 1, 1];
@@ -1528,6 +1584,16 @@ var RenderSystem = class {
1528
1584
  textureCache = /* @__PURE__ */ new Map();
1529
1585
  /** Insertion-order key list for LRU-style eviction. */
1530
1586
  textureCacheKeys = [];
1587
+ // ── Texture sampling ────────────────────────────────────────────────────
1588
+ _defaultSampling = DEFAULT_SAMPLING;
1589
+ /** Set the global default texture sampling mode for all sprites that don't specify their own. */
1590
+ setDefaultSampling(sampling) {
1591
+ this._defaultSampling = sampling;
1592
+ }
1593
+ /** Get the current global default texture sampling mode. */
1594
+ getDefaultSampling() {
1595
+ return this._defaultSampling;
1596
+ }
1531
1597
  // ── Debug overlays ──────────────────────────────────────────────────────
1532
1598
  debugNavGrid = null;
1533
1599
  contactFlashPoints = [];
@@ -1546,16 +1612,18 @@ var RenderSystem = class {
1546
1612
  loadTexture(src) {
1547
1613
  const cached = this.textures.get(src);
1548
1614
  if (cached) return cached;
1549
- const imgSrc = src.endsWith(":repeat") ? src.slice(0, -7) : src;
1615
+ let imgSrc = src;
1616
+ const sampIdx = imgSrc.indexOf(":s=");
1617
+ if (sampIdx !== -1) imgSrc = imgSrc.slice(0, sampIdx);
1618
+ if (imgSrc.endsWith(":repeat")) imgSrc = imgSrc.slice(0, -7);
1550
1619
  const existing = this.imageCache.get(imgSrc);
1551
1620
  if (existing && existing.complete && existing.naturalWidth > 0) {
1552
1621
  const gl = this.gl;
1553
1622
  const tex = gl.createTexture();
1554
1623
  gl.bindTexture(gl.TEXTURE_2D, tex);
1555
1624
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, existing);
1556
- gl.generateMipmap(gl.TEXTURE_2D);
1557
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
1558
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
1625
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
1626
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1559
1627
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
1560
1628
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1561
1629
  this.textures.set(src, tex);
@@ -1564,15 +1632,14 @@ var RenderSystem = class {
1564
1632
  if (!existing) {
1565
1633
  const img = new Image();
1566
1634
  img.src = imgSrc;
1567
- const tiled = src.endsWith(":repeat");
1635
+ const tiled = src.includes(":repeat");
1568
1636
  img.onload = () => {
1569
1637
  const gl = this.gl;
1570
1638
  const tex = gl.createTexture();
1571
1639
  gl.bindTexture(gl.TEXTURE_2D, tex);
1572
1640
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
1573
- gl.generateMipmap(gl.TEXTURE_2D);
1574
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
1575
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
1641
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
1642
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1576
1643
  const wrap = tiled ? gl.REPEAT : gl.CLAMP_TO_EDGE;
1577
1644
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrap);
1578
1645
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrap);
@@ -1595,9 +1662,8 @@ var RenderSystem = class {
1595
1662
  const tex = gl.createTexture();
1596
1663
  gl.bindTexture(gl.TEXTURE_2D, tex);
1597
1664
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
1598
- gl.generateMipmap(gl.TEXTURE_2D);
1599
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
1600
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
1665
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
1666
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1601
1667
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
1602
1668
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
1603
1669
  this.parallaxTextures.set(src, tex);
@@ -1640,9 +1706,8 @@ var RenderSystem = class {
1640
1706
  const tex = gl.createTexture();
1641
1707
  gl.bindTexture(gl.TEXTURE_2D, tex);
1642
1708
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, offscreen);
1643
- gl.generateMipmap(gl.TEXTURE_2D);
1644
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
1645
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
1709
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
1710
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1646
1711
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
1647
1712
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1648
1713
  const entry = { tex, w: textW, h: textH };
@@ -1650,13 +1715,23 @@ var RenderSystem = class {
1650
1715
  this.textureCacheKeys.push(key);
1651
1716
  return entry;
1652
1717
  }
1718
+ // ── Texture sampling helper ────────────────────────────────────────────────
1719
+ /** Apply min/mag filter params to the currently bound texture. */
1720
+ applySampling(spriteSampling) {
1721
+ const { gl } = this;
1722
+ const { min, mag } = resolveSampling(spriteSampling, this._defaultSampling);
1723
+ if (needsMipmap(min)) gl.generateMipmap(gl.TEXTURE_2D);
1724
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, toGLMinFilter(gl, min));
1725
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, toGLMagFilter(gl, mag));
1726
+ }
1653
1727
  // ── Instanced draw call ────────────────────────────────────────────────────
1654
- flush(count, textureKey) {
1728
+ flush(count, textureKey, sampling) {
1655
1729
  if (count === 0) return;
1656
1730
  const { gl } = this;
1657
1731
  const isColor = textureKey.startsWith("__color__");
1658
1732
  const tex = isColor ? this.whiteTexture : this.loadTexture(textureKey);
1659
1733
  gl.bindTexture(gl.TEXTURE_2D, tex);
1734
+ this.applySampling(sampling);
1660
1735
  gl.uniform1i(this.uUseTexture, isColor ? 0 : 1);
1661
1736
  gl.bindVertexArray(this.quadVAO);
1662
1737
  gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceBuffer);
@@ -1835,9 +1910,10 @@ var RenderSystem = class {
1835
1910
  });
1836
1911
  let batchCount = 0;
1837
1912
  let batchKey = "";
1913
+ let batchSampling;
1838
1914
  for (let i = 0; i <= renderables.length; i++) {
1839
1915
  if (i === renderables.length) {
1840
- this.flush(batchCount, batchKey);
1916
+ this.flush(batchCount, batchKey, batchSampling);
1841
1917
  break;
1842
1918
  }
1843
1919
  const id = renderables[i];
@@ -1852,9 +1928,8 @@ var RenderSystem = class {
1852
1928
  const tex = gl2.createTexture();
1853
1929
  gl2.bindTexture(gl2.TEXTURE_2D, tex);
1854
1930
  gl2.texImage2D(gl2.TEXTURE_2D, 0, gl2.RGBA, gl2.RGBA, gl2.UNSIGNED_BYTE, sprite.image);
1855
- gl2.generateMipmap(gl2.TEXTURE_2D);
1856
- gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MIN_FILTER, gl2.LINEAR_MIPMAP_LINEAR);
1857
- gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MAG_FILTER, gl2.LINEAR);
1931
+ gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MIN_FILTER, gl2.NEAREST);
1932
+ gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MAG_FILTER, gl2.NEAREST);
1858
1933
  const wrap = tiled ? gl2.REPEAT : gl2.CLAMP_TO_EDGE;
1859
1934
  gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_WRAP_S, wrap);
1860
1935
  gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_WRAP_T, wrap);
@@ -1871,9 +1946,8 @@ var RenderSystem = class {
1871
1946
  const tex = gl2.createTexture();
1872
1947
  gl2.bindTexture(gl2.TEXTURE_2D, tex);
1873
1948
  gl2.texImage2D(gl2.TEXTURE_2D, 0, gl2.RGBA, gl2.RGBA, gl2.UNSIGNED_BYTE, img);
1874
- gl2.generateMipmap(gl2.TEXTURE_2D);
1875
- gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MIN_FILTER, gl2.LINEAR_MIPMAP_LINEAR);
1876
- gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MAG_FILTER, gl2.LINEAR);
1949
+ gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MIN_FILTER, gl2.NEAREST);
1950
+ gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MAG_FILTER, gl2.NEAREST);
1877
1951
  this.textures.set(img.src, tex);
1878
1952
  };
1879
1953
  }
@@ -1881,10 +1955,11 @@ var RenderSystem = class {
1881
1955
  }
1882
1956
  const key = getTextureKey(sprite);
1883
1957
  if (key !== batchKey && batchCount > 0 || batchCount >= MAX_INSTANCES) {
1884
- this.flush(batchCount, batchKey);
1958
+ this.flush(batchCount, batchKey, batchSampling);
1885
1959
  batchCount = 0;
1886
1960
  }
1887
1961
  batchKey = key;
1962
+ batchSampling = sprite.sampling;
1888
1963
  const ss = world.getComponent(id, "SquashStretch");
1889
1964
  const scaleXMod = ss ? ss.currentScaleX : 1;
1890
1965
  const scaleYMod = ss ? ss.currentScaleY : 1;
@@ -1926,9 +2001,10 @@ var RenderSystem = class {
1926
2001
  if (!text.visible) continue;
1927
2002
  const entry = this.getOrCreateTextTexture(text);
1928
2003
  if (!entry) continue;
1929
- this.flush(batchCount, batchKey);
2004
+ this.flush(batchCount, batchKey, batchSampling);
1930
2005
  batchCount = 0;
1931
2006
  batchKey = "";
2007
+ batchSampling = void 0;
1932
2008
  this.writeInstance(
1933
2009
  0,
1934
2010
  transform.x + text.offsetX,
@@ -3788,6 +3864,7 @@ function Game({
3788
3864
  deterministic = false,
3789
3865
  seed = 0,
3790
3866
  asyncAssets = false,
3867
+ sampling,
3791
3868
  onReady,
3792
3869
  plugins,
3793
3870
  style,
@@ -3810,6 +3887,7 @@ function Game({
3810
3887
  const physics = new PhysicsSystem(gravity, events);
3811
3888
  const entityIds = /* @__PURE__ */ new Map();
3812
3889
  const renderSystem = new RenderSystem(canvas, entityIds);
3890
+ if (sampling) renderSystem.setDefaultSampling(sampling);
3813
3891
  const activeRenderSystem = renderSystem;
3814
3892
  let debugSystem = null;
3815
3893
  if (debug) {
@@ -4101,7 +4179,8 @@ function Sprite({
4101
4179
  tileX,
4102
4180
  tileY,
4103
4181
  tileSizeX,
4104
- tileSizeY
4182
+ tileSizeY,
4183
+ sampling
4105
4184
  }) {
4106
4185
  const resolvedFrameIndex = atlas && frame != null ? atlas[frame] ?? 0 : frameIndex;
4107
4186
  const engine = useContext5(EngineContext);
@@ -4126,7 +4205,8 @@ function Sprite({
4126
4205
  tileX,
4127
4206
  tileY,
4128
4207
  tileSizeX,
4129
- tileSizeY
4208
+ tileSizeY,
4209
+ sampling
4130
4210
  });
4131
4211
  engine.ecs.addComponent(entityId, comp);
4132
4212
  if (src) {
@@ -6394,6 +6474,7 @@ export {
6394
6474
  Sprite,
6395
6475
  SquashStretch,
6396
6476
  Text,
6477
+ TextureFilter,
6397
6478
  Tilemap,
6398
6479
  Trail,
6399
6480
  Transform,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cubeforge",
3
- "version": "0.3.10",
3
+ "version": "0.3.11",
4
4
  "description": "React-first 2D browser game engine",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",