cubeforge 0.3.10 → 0.3.12

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
@@ -9,6 +9,8 @@ var ECSWorld = class {
9
9
  // Seeded RNG (LCG) for deterministic mode
10
10
  _rngState = 0;
11
11
  _deterministic = false;
12
+ /** Asset manager reference — set by Game, available in Script callbacks via world.assets */
13
+ assets;
12
14
  // Primary storage: archetypes keyed by sorted type string
13
15
  archetypes = /* @__PURE__ */ new Map();
14
16
  // Which archetype each entity lives in
@@ -1146,6 +1148,55 @@ function createSprite(opts) {
1146
1148
  };
1147
1149
  }
1148
1150
 
1151
+ // ../../packages/renderer/src/textureFilter.ts
1152
+ var TextureFilter = {
1153
+ /** Nearest-neighbor — sharp pixels, ideal for pixel art */
1154
+ NEAREST: "nearest",
1155
+ /** Bilinear — smooth interpolation */
1156
+ LINEAR: "linear",
1157
+ /** Nearest on nearest mipmap level */
1158
+ NEAREST_MIPMAP_NEAREST: "nearest-mipmap-nearest",
1159
+ /** Bilinear on nearest mipmap level */
1160
+ LINEAR_MIPMAP_NEAREST: "linear-mipmap-nearest",
1161
+ /** Nearest, blending between two mipmap levels */
1162
+ NEAREST_MIPMAP_LINEAR: "nearest-mipmap-linear",
1163
+ /** Trilinear — bilinear + mipmap blending, smoothest downscaling */
1164
+ LINEAR_MIPMAP_LINEAR: "linear-mipmap-linear"
1165
+ };
1166
+ var DEFAULT_SAMPLING = TextureFilter.NEAREST;
1167
+ function resolveSampling(sampling, fallback = DEFAULT_SAMPLING) {
1168
+ const s2 = sampling ?? fallback;
1169
+ if (typeof s2 === "string") {
1170
+ const mag = s2.startsWith("linear") ? "linear" : "nearest";
1171
+ return { min: s2, mag };
1172
+ }
1173
+ return { min: s2.min, mag: s2.mag };
1174
+ }
1175
+ function toGLMinFilter(gl, filter) {
1176
+ switch (filter) {
1177
+ case "nearest":
1178
+ return gl.NEAREST;
1179
+ case "linear":
1180
+ return gl.LINEAR;
1181
+ case "nearest-mipmap-nearest":
1182
+ return gl.NEAREST_MIPMAP_NEAREST;
1183
+ case "linear-mipmap-nearest":
1184
+ return gl.LINEAR_MIPMAP_NEAREST;
1185
+ case "nearest-mipmap-linear":
1186
+ return gl.NEAREST_MIPMAP_LINEAR;
1187
+ case "linear-mipmap-linear":
1188
+ return gl.LINEAR_MIPMAP_LINEAR;
1189
+ default:
1190
+ return gl.NEAREST;
1191
+ }
1192
+ }
1193
+ function toGLMagFilter(gl, filter) {
1194
+ return filter === "linear" ? gl.LINEAR : gl.NEAREST;
1195
+ }
1196
+ function needsMipmap(filter) {
1197
+ return filter !== "nearest" && filter !== "linear";
1198
+ }
1199
+
1149
1200
  // ../../packages/renderer/src/components/camera2d.ts
1150
1201
  function createCamera2D(opts) {
1151
1202
  return {
@@ -1367,10 +1418,17 @@ function createWhiteTexture(gl) {
1367
1418
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1368
1419
  return tex;
1369
1420
  }
1421
+ function getSamplingKey(sampling) {
1422
+ if (!sampling) return "";
1423
+ if (typeof sampling === "string") return sampling;
1424
+ return `${sampling.min}|${sampling.mag}`;
1425
+ }
1370
1426
  function getTextureKey(sprite) {
1371
1427
  const src = sprite.image?.src || sprite.src;
1372
- if (src) return sprite.tileX || sprite.tileY ? `${src}:repeat` : src;
1373
- return `__color__:${sprite.color}`;
1428
+ const samplingKey = getSamplingKey(sprite.sampling);
1429
+ const suffix = samplingKey ? `:s=${samplingKey}` : "";
1430
+ if (src) return sprite.tileX || sprite.tileY ? `${src}:repeat${suffix}` : `${src}${suffix}`;
1431
+ return `__color__:${sprite.color}${suffix}`;
1374
1432
  }
1375
1433
  function getUVRect(sprite) {
1376
1434
  if (!sprite.image || sprite.image.naturalWidth === 0) return [0, 0, 1, 1];
@@ -1528,6 +1586,16 @@ var RenderSystem = class {
1528
1586
  textureCache = /* @__PURE__ */ new Map();
1529
1587
  /** Insertion-order key list for LRU-style eviction. */
1530
1588
  textureCacheKeys = [];
1589
+ // ── Texture sampling ────────────────────────────────────────────────────
1590
+ _defaultSampling = DEFAULT_SAMPLING;
1591
+ /** Set the global default texture sampling mode for all sprites that don't specify their own. */
1592
+ setDefaultSampling(sampling) {
1593
+ this._defaultSampling = sampling;
1594
+ }
1595
+ /** Get the current global default texture sampling mode. */
1596
+ getDefaultSampling() {
1597
+ return this._defaultSampling;
1598
+ }
1531
1599
  // ── Debug overlays ──────────────────────────────────────────────────────
1532
1600
  debugNavGrid = null;
1533
1601
  contactFlashPoints = [];
@@ -1546,16 +1614,18 @@ var RenderSystem = class {
1546
1614
  loadTexture(src) {
1547
1615
  const cached = this.textures.get(src);
1548
1616
  if (cached) return cached;
1549
- const imgSrc = src.endsWith(":repeat") ? src.slice(0, -7) : src;
1617
+ let imgSrc = src;
1618
+ const sampIdx = imgSrc.indexOf(":s=");
1619
+ if (sampIdx !== -1) imgSrc = imgSrc.slice(0, sampIdx);
1620
+ if (imgSrc.endsWith(":repeat")) imgSrc = imgSrc.slice(0, -7);
1550
1621
  const existing = this.imageCache.get(imgSrc);
1551
1622
  if (existing && existing.complete && existing.naturalWidth > 0) {
1552
1623
  const gl = this.gl;
1553
1624
  const tex = gl.createTexture();
1554
1625
  gl.bindTexture(gl.TEXTURE_2D, tex);
1555
1626
  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);
1627
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
1628
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1559
1629
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
1560
1630
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1561
1631
  this.textures.set(src, tex);
@@ -1564,15 +1634,14 @@ var RenderSystem = class {
1564
1634
  if (!existing) {
1565
1635
  const img = new Image();
1566
1636
  img.src = imgSrc;
1567
- const tiled = src.endsWith(":repeat");
1637
+ const tiled = src.includes(":repeat");
1568
1638
  img.onload = () => {
1569
1639
  const gl = this.gl;
1570
1640
  const tex = gl.createTexture();
1571
1641
  gl.bindTexture(gl.TEXTURE_2D, tex);
1572
1642
  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);
1643
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
1644
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1576
1645
  const wrap = tiled ? gl.REPEAT : gl.CLAMP_TO_EDGE;
1577
1646
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrap);
1578
1647
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrap);
@@ -1595,9 +1664,8 @@ var RenderSystem = class {
1595
1664
  const tex = gl.createTexture();
1596
1665
  gl.bindTexture(gl.TEXTURE_2D, tex);
1597
1666
  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);
1667
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
1668
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1601
1669
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
1602
1670
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
1603
1671
  this.parallaxTextures.set(src, tex);
@@ -1640,9 +1708,8 @@ var RenderSystem = class {
1640
1708
  const tex = gl.createTexture();
1641
1709
  gl.bindTexture(gl.TEXTURE_2D, tex);
1642
1710
  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);
1711
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
1712
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1646
1713
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
1647
1714
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1648
1715
  const entry = { tex, w: textW, h: textH };
@@ -1650,13 +1717,23 @@ var RenderSystem = class {
1650
1717
  this.textureCacheKeys.push(key);
1651
1718
  return entry;
1652
1719
  }
1720
+ // ── Texture sampling helper ────────────────────────────────────────────────
1721
+ /** Apply min/mag filter params to the currently bound texture. */
1722
+ applySampling(spriteSampling) {
1723
+ const { gl } = this;
1724
+ const { min, mag } = resolveSampling(spriteSampling, this._defaultSampling);
1725
+ if (needsMipmap(min)) gl.generateMipmap(gl.TEXTURE_2D);
1726
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, toGLMinFilter(gl, min));
1727
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, toGLMagFilter(gl, mag));
1728
+ }
1653
1729
  // ── Instanced draw call ────────────────────────────────────────────────────
1654
- flush(count, textureKey) {
1730
+ flush(count, textureKey, sampling) {
1655
1731
  if (count === 0) return;
1656
1732
  const { gl } = this;
1657
1733
  const isColor = textureKey.startsWith("__color__");
1658
1734
  const tex = isColor ? this.whiteTexture : this.loadTexture(textureKey);
1659
1735
  gl.bindTexture(gl.TEXTURE_2D, tex);
1736
+ this.applySampling(sampling);
1660
1737
  gl.uniform1i(this.uUseTexture, isColor ? 0 : 1);
1661
1738
  gl.bindVertexArray(this.quadVAO);
1662
1739
  gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceBuffer);
@@ -1835,9 +1912,10 @@ var RenderSystem = class {
1835
1912
  });
1836
1913
  let batchCount = 0;
1837
1914
  let batchKey = "";
1915
+ let batchSampling;
1838
1916
  for (let i = 0; i <= renderables.length; i++) {
1839
1917
  if (i === renderables.length) {
1840
- this.flush(batchCount, batchKey);
1918
+ this.flush(batchCount, batchKey, batchSampling);
1841
1919
  break;
1842
1920
  }
1843
1921
  const id = renderables[i];
@@ -1852,9 +1930,8 @@ var RenderSystem = class {
1852
1930
  const tex = gl2.createTexture();
1853
1931
  gl2.bindTexture(gl2.TEXTURE_2D, tex);
1854
1932
  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);
1933
+ gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MIN_FILTER, gl2.NEAREST);
1934
+ gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MAG_FILTER, gl2.NEAREST);
1858
1935
  const wrap = tiled ? gl2.REPEAT : gl2.CLAMP_TO_EDGE;
1859
1936
  gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_WRAP_S, wrap);
1860
1937
  gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_WRAP_T, wrap);
@@ -1871,9 +1948,8 @@ var RenderSystem = class {
1871
1948
  const tex = gl2.createTexture();
1872
1949
  gl2.bindTexture(gl2.TEXTURE_2D, tex);
1873
1950
  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);
1951
+ gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MIN_FILTER, gl2.NEAREST);
1952
+ gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MAG_FILTER, gl2.NEAREST);
1877
1953
  this.textures.set(img.src, tex);
1878
1954
  };
1879
1955
  }
@@ -1881,10 +1957,11 @@ var RenderSystem = class {
1881
1957
  }
1882
1958
  const key = getTextureKey(sprite);
1883
1959
  if (key !== batchKey && batchCount > 0 || batchCount >= MAX_INSTANCES) {
1884
- this.flush(batchCount, batchKey);
1960
+ this.flush(batchCount, batchKey, batchSampling);
1885
1961
  batchCount = 0;
1886
1962
  }
1887
1963
  batchKey = key;
1964
+ batchSampling = sprite.sampling;
1888
1965
  const ss = world.getComponent(id, "SquashStretch");
1889
1966
  const scaleXMod = ss ? ss.currentScaleX : 1;
1890
1967
  const scaleYMod = ss ? ss.currentScaleY : 1;
@@ -1926,9 +2003,10 @@ var RenderSystem = class {
1926
2003
  if (!text.visible) continue;
1927
2004
  const entry = this.getOrCreateTextTexture(text);
1928
2005
  if (!entry) continue;
1929
- this.flush(batchCount, batchKey);
2006
+ this.flush(batchCount, batchKey, batchSampling);
1930
2007
  batchCount = 0;
1931
2008
  batchKey = "";
2009
+ batchSampling = void 0;
1932
2010
  this.writeInstance(
1933
2011
  0,
1934
2012
  transform.x + text.offsetX,
@@ -3788,6 +3866,7 @@ function Game({
3788
3866
  deterministic = false,
3789
3867
  seed = 0,
3790
3868
  asyncAssets = false,
3869
+ sampling,
3791
3870
  onReady,
3792
3871
  plugins,
3793
3872
  style,
@@ -3807,9 +3886,11 @@ function Game({
3807
3886
  const input = new InputManager();
3808
3887
  const events = new EventBus();
3809
3888
  const assets = new AssetManager();
3889
+ ecs.assets = assets;
3810
3890
  const physics = new PhysicsSystem(gravity, events);
3811
3891
  const entityIds = /* @__PURE__ */ new Map();
3812
3892
  const renderSystem = new RenderSystem(canvas, entityIds);
3893
+ if (sampling) renderSystem.setDefaultSampling(sampling);
3813
3894
  const activeRenderSystem = renderSystem;
3814
3895
  let debugSystem = null;
3815
3896
  if (debug) {
@@ -4101,7 +4182,8 @@ function Sprite({
4101
4182
  tileX,
4102
4183
  tileY,
4103
4184
  tileSizeX,
4104
- tileSizeY
4185
+ tileSizeY,
4186
+ sampling
4105
4187
  }) {
4106
4188
  const resolvedFrameIndex = atlas && frame != null ? atlas[frame] ?? 0 : frameIndex;
4107
4189
  const engine = useContext5(EngineContext);
@@ -4126,7 +4208,8 @@ function Sprite({
4126
4208
  tileX,
4127
4209
  tileY,
4128
4210
  tileSizeX,
4129
- tileSizeY
4211
+ tileSizeY,
4212
+ sampling
4130
4213
  });
4131
4214
  engine.ecs.addComponent(entityId, comp);
4132
4215
  if (src) {
@@ -6394,6 +6477,7 @@ export {
6394
6477
  Sprite,
6395
6478
  SquashStretch,
6396
6479
  Text,
6480
+ TextureFilter,
6397
6481
  Tilemap,
6398
6482
  Trail,
6399
6483
  Transform,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cubeforge",
3
- "version": "0.3.10",
3
+ "version": "0.3.12",
4
4
  "description": "React-first 2D browser game engine",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",