cubeforge 0.3.13 → 0.3.15

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
@@ -32,8 +32,8 @@ npm install cubeforge react react-dom
32
32
  ## What's included
33
33
 
34
34
  - **ECS** — archetype-based entity-component-system with query caching
35
- - **Physics** — two-pass AABB, capsule colliders, kinematic bodies, one-way platforms, 60 Hz fixed timestep
36
- - **Renderer** — WebGL2 instanced renderer by default; Canvas2D opt-in via `renderer={Canvas2DRenderSystem}`
35
+ - **Physics** — two-pass AABB, kinematic bodies, one-way platforms, 60 Hz fixed timestep
36
+ - **Renderer** — WebGL2 instanced renderer by default
37
37
  - **Input** — keyboard, mouse, gamepad, per-player input maps, input contexts, recording/playback
38
38
  - **Audio** — Web Audio API with volume groups, fade, crossfade, ducking (`useSound`)
39
39
  - **Gameplay hooks** — `usePlatformerController`, `useTopDownMovement`, `useHealth`, `useSave`, `useGameStateMachine`, `useLevelTransition`, `usePathfinding`, `useAISteering`, and more
package/dist/index.d.ts CHANGED
@@ -1,17 +1,18 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
- import React__default, { CSSProperties, ReactNode } from 'react';
3
+ import React__default, { CSSProperties, ReactNode, ReactElement } from 'react';
4
4
  import { Plugin, EntityId, ECSWorld, ScriptUpdateFn, NavGrid, WorldSnapshot, EventBus } from '@cubeforge/core';
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';
5
+ export { AssetProgress, Component, ECSWorld, Ease, EntityId, GameTimer, HotReloadablePlugin, MergedRect, NavGrid, Plugin, PreloadManifest, ScriptUpdateFn, TimelineEntry, TransformComponent, TweenHandle, TweenTimeline, Vec2Like, WorldSnapshot, arrive, createTag, createTimeline, createTimer, createTransform, definePlugin, findByTag, flee, hotReloadPlugin, mergeTileColliders, patrol, preloadManifest, seek, tween, wander } from '@cubeforge/core';
6
+ import { Sampling, BlendMode, PostProcessEffect } from '@cubeforge/renderer';
7
+ export { AnimationStateComponent, BlendMode, MagFilterValue, NineSliceComponent, ParallaxLayerComponent, Particle, ParticlePoolComponent, PostProcessEffect, PostProcessStack, RenderLayer, RenderLayerManager, RenderSystem, Sampling, SpriteComponent, SquashStretchComponent, TextComponent, TextureFilter, TextureFilterValue, TrailComponent, chromaticAberrationEffect, createNineSlice, createPostProcessStack, createRenderLayerManager, createSprite, defaultLayers, scanlineEffect, vignetteEffect } from '@cubeforge/renderer';
8
8
  import { ColliderShape } from '@cubeforge/physics';
9
9
  export { BoxColliderComponent, CapsuleColliderComponent, CircleColliderComponent, ColliderShape, CompoundColliderComponent, RaycastHit, RigidBodyComponent, createCompoundCollider, overlapBox, overlapCircle, raycast, raycastAll, sweepBox } from '@cubeforge/physics';
10
10
  import { InputManager, ActionBindings, InputContextName, PlayerInput, InputRecorderControls } from '@cubeforge/input';
11
11
  export { ActionBindings, AxisBinding, InputContextName, InputManager, InputMap, InputRecorderControls, InputRecording, InputRecording as InputRecordingData, PlayerInput, createInputMap, createInputRecorder, createPlayerInput, globalInputContext } from '@cubeforge/input';
12
+ import { AnimationClip } from '@cubeforge/gameplay';
13
+ export { AISteering, AnimationClip, AnimationControllerResult, BindingControls, CutsceneControls, CutsceneStep, DialogueControls, DialogueLine, DialogueScript, GameState as GameStateDefinition, GameStateMachineResult, HealthControls, HealthOptions, KinematicBodyControls, LevelTransitionControls, ObjectPool, PathfindingControls, PlatformerControllerOptions, RestartControls, SaveControls, SaveOptions, TopDownMovementOptions, TransitionOptions, TransitionType, TweenControls, useAISteering, useAnimationController, useCutscene, useDamageZone, useDialogue, useDropThrough, useGameStateMachine, useGameStore, useHealth, useKinematicBody, useLevelTransition, useObjectPool, usePathfinding, usePersistedBindings, usePlatformerController, useRestart, useSave, useTopDownMovement, useTween } from '@cubeforge/gameplay';
12
14
  import { EngineState } from '@cubeforge/context';
13
- export { EngineState, useCircleEnter, useCircleExit, useCircleStay, useCollisionEnter, useCollisionExit, useCollisionStay, useTriggerEnter, useTriggerExit, useTriggerStay } from '@cubeforge/context';
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';
15
+ export { EngineState, useCircleEnter, useCircleExit, useCircleStay, useCollidingWith, useCollisionEnter, useCollisionExit, useCollisionStay, useTriggerEnter, useTriggerExit, useTriggerStay } from '@cubeforge/context';
15
16
  export { AudioGroup, SoundControls, duck, getGroupVolume, setGroupMute, setGroupVolume, setMasterVolume, stopGroup, useSound } from '@cubeforge/audio';
16
17
  export { DevToolsHandle } from '@cubeforge/devtools';
17
18
 
@@ -109,6 +110,7 @@ interface SpriteProps {
109
110
  zIndex?: number;
110
111
  visible?: boolean;
111
112
  flipX?: boolean;
113
+ flipY?: boolean;
112
114
  anchorX?: number;
113
115
  anchorY?: number;
114
116
  frameIndex?: number;
@@ -123,8 +125,12 @@ interface SpriteProps {
123
125
  tileSizeY?: number;
124
126
  /** Texture sampling mode — controls filtering when the sprite is scaled */
125
127
  sampling?: Sampling;
128
+ /** Blend mode used when drawing this sprite */
129
+ blendMode?: BlendMode;
130
+ /** Render layer name — sprites are sorted by layer order first, then zIndex */
131
+ layer?: string;
126
132
  }
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;
133
+ declare function Sprite({ width, height, color, src, offsetX, offsetY, zIndex, visible, flipX, flipY, anchorX, anchorY, frameIndex, frameWidth, frameHeight, frameColumns, atlas, frame, tileX, tileY, tileSizeX, tileSizeY, sampling, blendMode, layer, }: SpriteProps): null;
128
134
 
129
135
  interface TextProps {
130
136
  text: string;
@@ -153,8 +159,16 @@ interface RigidBodyProps {
153
159
  lockX?: boolean;
154
160
  /** Prevent any vertical movement — velocity.y is zeroed every frame (disables gravity) */
155
161
  lockY?: boolean;
162
+ /** Enable continuous collision detection to prevent tunneling through thin colliders */
163
+ ccd?: boolean;
164
+ /** Angular velocity in radians per second */
165
+ angularVelocity?: number;
166
+ /** Angular damping (0–1): fraction of angular velocity removed each fixed step */
167
+ angularDamping?: number;
168
+ /** Linear damping (0–1): velocity reduction applied every fixed step (air resistance) */
169
+ linearDamping?: number;
156
170
  }
157
- declare function RigidBody({ mass, gravityScale, isStatic, bounce, friction, vx, vy, lockX, lockY, }: RigidBodyProps): null;
171
+ declare function RigidBody({ mass, gravityScale, isStatic, bounce, friction, vx, vy, lockX, lockY, ccd, angularVelocity, angularDamping, linearDamping, }: RigidBodyProps): null;
158
172
 
159
173
  interface BoxColliderProps {
160
174
  width: number;
@@ -261,6 +275,107 @@ interface AnimationProps {
261
275
  }
262
276
  declare function Animation({ frames, fps, loop, playing, onComplete, frameEvents }: AnimationProps): null;
263
277
 
278
+ /** Shared sprite props used by both API forms */
279
+ interface SpriteOptions {
280
+ width: number;
281
+ height: number;
282
+ src: string;
283
+ color?: string;
284
+ offsetX?: number;
285
+ offsetY?: number;
286
+ zIndex?: number;
287
+ visible?: boolean;
288
+ flipX?: boolean;
289
+ flipY?: boolean;
290
+ anchorX?: number;
291
+ anchorY?: number;
292
+ frameWidth?: number;
293
+ frameHeight?: number;
294
+ frameColumns?: number;
295
+ atlas?: SpriteAtlas;
296
+ frame?: string;
297
+ tileX?: boolean;
298
+ tileY?: boolean;
299
+ tileSizeX?: number;
300
+ tileSizeY?: number;
301
+ sampling?: Sampling;
302
+ blendMode?: BlendMode;
303
+ }
304
+ /** Simple form — single animation clip (like Sprite + Animation) */
305
+ interface SimpleAnimatedSpriteProps extends SpriteOptions {
306
+ frames: number[];
307
+ fps?: number;
308
+ loop?: boolean;
309
+ playing?: boolean;
310
+ onComplete?: () => void;
311
+ frameEvents?: Record<number, () => void>;
312
+ animations?: never;
313
+ current?: never;
314
+ }
315
+ /** Multi-clip form — named animation states with typed clip names */
316
+ interface MultiAnimatedSpriteProps<S extends string = string> extends SpriteOptions {
317
+ /** Map of named animation clips (use `defineAnimations()` for type-safe names) */
318
+ animations: AnimationSet<S>;
319
+ /** Which animation clip is currently playing — typed to the clip names */
320
+ current: S;
321
+ frames?: never;
322
+ fps?: never;
323
+ loop?: never;
324
+ playing?: never;
325
+ onComplete?: never;
326
+ frameEvents?: never;
327
+ }
328
+ type AnimatedSpriteProps<S extends string = string> = SimpleAnimatedSpriteProps | MultiAnimatedSpriteProps<S>;
329
+ /** A typed set of animation clips. Created by `defineAnimations()`. */
330
+ type AnimationSet<S extends string = string> = Record<S, AnimationClip>;
331
+ /**
332
+ * Define a reusable, type-safe set of animation clips.
333
+ *
334
+ * The returned object can be shared across components and provides
335
+ * autocomplete on `current` when used with `<AnimatedSprite>`.
336
+ *
337
+ * @example
338
+ * ```tsx
339
+ * const playerAnims = defineAnimations({
340
+ * idle: { frames: [0], fps: 1 },
341
+ * walk: { frames: [1, 2, 3, 4], fps: 10 },
342
+ * run: { frames: [5, 6, 7, 8], fps: 14 },
343
+ * jump: { frames: [9], fps: 1, loop: false },
344
+ * attack: { frames: [10, 11, 12], fps: 16, loop: false, next: 'idle' },
345
+ * })
346
+ *
347
+ * // `current` is typed as 'idle' | 'walk' | 'run' | 'jump' | 'attack'
348
+ * <AnimatedSprite animations={playerAnims} current={state} ... />
349
+ * ```
350
+ */
351
+ declare function defineAnimations<S extends string>(clips: Record<S, AnimationClip>): AnimationSet<S>;
352
+ /**
353
+ * Convenience wrapper that combines `<Sprite>` and `<Animation>` into a
354
+ * single component. Must be placed inside an `<Entity>`.
355
+ *
356
+ * Supports two API forms:
357
+ *
358
+ * **Simple** — single clip:
359
+ * ```tsx
360
+ * <AnimatedSprite src="/hero.png" width={32} height={32}
361
+ * frameWidth={32} frameHeight={32} frameColumns={8}
362
+ * frames={[0, 1, 2, 3]} fps={10} />
363
+ * ```
364
+ *
365
+ * **Multi-clip** — named animation states, switch via `current`:
366
+ * ```tsx
367
+ * const anims = defineAnimations({
368
+ * idle: { frames: [0], fps: 1 },
369
+ * walk: { frames: [1, 2, 3, 4], fps: 10 },
370
+ * })
371
+ *
372
+ * <AnimatedSprite src="/hero.png" width={32} height={48}
373
+ * frameWidth={32} frameHeight={48} frameColumns={8}
374
+ * animations={anims} current={state} />
375
+ * ```
376
+ */
377
+ declare function AnimatedSprite<S extends string>(props: AnimatedSpriteProps<S>): ReactElement;
378
+
264
379
  interface SquashStretchProps {
265
380
  /** How much to squash/stretch (default 0.2) */
266
381
  intensity?: number;
@@ -293,8 +408,18 @@ interface ParticleEmitterProps {
293
408
  gravity?: number;
294
409
  /** Maximum live particles, default 100 */
295
410
  maxParticles?: number;
411
+ /** Emit this many particles in one frame then deactivate (one-shot burst) */
412
+ burstCount?: number;
413
+ /** Emission shape: 'point' (default), 'circle', or 'box' */
414
+ emitShape?: 'point' | 'circle' | 'box';
415
+ /** Radius for 'circle' emission shape */
416
+ emitRadius?: number;
417
+ /** Width for 'box' emission shape */
418
+ emitWidth?: number;
419
+ /** Height for 'box' emission shape */
420
+ emitHeight?: number;
296
421
  }
297
- declare function ParticleEmitter({ active, preset, rate, speed, spread, angle, particleLife, particleSize, color, gravity, maxParticles, }: ParticleEmitterProps): null;
422
+ declare function ParticleEmitter({ active, preset, rate, speed, spread, angle, particleLife, particleSize, color, gravity, maxParticles, burstCount, emitShape, emitRadius, emitWidth, emitHeight, }: ParticleEmitterProps): null;
298
423
 
299
424
  interface VirtualJoystickProps {
300
425
  /** Diameter of the joystick base in pixels (default 120) */
@@ -435,8 +560,15 @@ interface TilemapProps {
435
560
  * can filter them by `layer.name === spawnLayer` inside the callback.
436
561
  */
437
562
  spawnLayer?: string;
563
+ /**
564
+ * When true (default), adjacent solid tiles in collision/trigger layers
565
+ * are merged into larger rectangles using a 2D greedy algorithm, reducing
566
+ * the number of collider entities. Set to false to create one collider per
567
+ * row-run (legacy behaviour).
568
+ */
569
+ mergeColliders?: boolean;
438
570
  }
439
- declare function Tilemap({ src, onSpawnObject, layerFilter, zIndex, collisionLayer, triggerLayer: triggerLayerName, onTileProperty, navGrid, }: TilemapProps): React__default.ReactElement | null;
571
+ declare function Tilemap({ src, onSpawnObject, layerFilter, zIndex, collisionLayer, triggerLayer: triggerLayerName, onTileProperty, navGrid, mergeColliders, }: TilemapProps): React__default.ReactElement | null;
440
572
 
441
573
  interface ParallaxLayerProps {
442
574
  /** Image URL to use as the background layer */
@@ -960,4 +1092,59 @@ interface PauseControls {
960
1092
  */
961
1093
  declare function usePause(): PauseControls;
962
1094
 
963
- export { Animation, AssetLoader, type BoundInputMap, BoxCollider, Camera2D, type CameraControls, CameraZone, CapsuleCollider, Checkpoint, CircleCollider, CompoundCollider, type CoordinateHelpers, Entity, Game, type GameControls, type GamepadState, type InputContextControls, MovingPlatform, NineSlice, ParallaxLayer, ParticleEmitter, type ParticlePreset, type PauseControls, type PreloadState, RigidBody, ScreenFlash, type ScreenFlashHandle, Script, type SnapshotControls, Sprite, type SpriteAtlas, SquashStretch, Text, type TiledLayer, type TiledObject, Tilemap, Trail, Transform, type VirtualInputState, VirtualJoystick, type VirtualJoystickProps, World, createAtlas, useCamera, useCoordinates, useDestroyEntity, useEntity, useEvent, useEvents, useGame, useGamepad, useInput, useInputContext, useInputMap, useInputRecorder, useLocalMultiplayer, usePause, usePlayerInput, usePreload, useSnapshot, useVirtualInput };
1095
+ interface ProfilerData {
1096
+ fps: number;
1097
+ frameTime: number;
1098
+ entityCount: number;
1099
+ systemTimings: Map<string, number>;
1100
+ }
1101
+ /**
1102
+ * Returns live performance data from the engine: FPS, frame time, entity count,
1103
+ * and per-system timings. Updates at most every 500 ms to avoid excessive re-renders.
1104
+ *
1105
+ * Must be used inside a `<Game>` component.
1106
+ */
1107
+ declare function useProfiler(): ProfilerData;
1108
+
1109
+ /**
1110
+ * Registers a post-processing effect for the lifetime of the component.
1111
+ * The effect runs in screen space after all scene rendering is complete.
1112
+ *
1113
+ * @example
1114
+ * ```tsx
1115
+ * import { vignetteEffect } from 'cubeforge'
1116
+ *
1117
+ * function Atmosphere() {
1118
+ * usePostProcess(vignetteEffect(0.5))
1119
+ * return null
1120
+ * }
1121
+ * ```
1122
+ */
1123
+ declare function usePostProcess(effect: PostProcessEffect): void;
1124
+
1125
+ /**
1126
+ * Define a reusable entity prefab with default props.
1127
+ *
1128
+ * Returns a memoized React component that merges caller-supplied props
1129
+ * over the provided defaults, so every prop becomes optional at the call site.
1130
+ *
1131
+ * @example
1132
+ * ```tsx
1133
+ * const Crate = definePrefab('Crate', {
1134
+ * width: 32, height: 32, color: '#8B4513', mass: 1,
1135
+ * }, (props) => (
1136
+ * <Entity tags={['crate']}>
1137
+ * <Transform x={0} y={0} />
1138
+ * <Sprite width={props.width} height={props.height} color={props.color} />
1139
+ * <RigidBody mass={props.mass} />
1140
+ * <BoxCollider width={props.width} height={props.height} />
1141
+ * </Entity>
1142
+ * ))
1143
+ *
1144
+ * // Usage — all defaults applied, override only what you need:
1145
+ * <Crate width={64} />
1146
+ * ```
1147
+ */
1148
+ declare function definePrefab<D extends Record<string, unknown>>(name: string, defaults: D, render: (props: D) => ReactElement): React__default.FC<Partial<D>>;
1149
+
1150
+ export { AnimatedSprite, type AnimatedSpriteProps, Animation, type AnimationSet, AssetLoader, type BoundInputMap, BoxCollider, Camera2D, type CameraControls, CameraZone, CapsuleCollider, Checkpoint, CircleCollider, CompoundCollider, type CoordinateHelpers, Entity, Game, type GameControls, type GamepadState, type InputContextControls, MovingPlatform, NineSlice, ParallaxLayer, ParticleEmitter, type ParticlePreset, type PauseControls, type PreloadState, type ProfilerData, RigidBody, ScreenFlash, type ScreenFlashHandle, Script, type SnapshotControls, Sprite, type SpriteAtlas, SquashStretch, Text, type TiledLayer, type TiledObject, Tilemap, Trail, Transform, type VirtualInputState, VirtualJoystick, type VirtualJoystickProps, World, createAtlas, defineAnimations, definePrefab, useCamera, useCoordinates, useDestroyEntity, useEntity, useEvent, useEvents, useGame, useGamepad, useInput, useInputContext, useInputMap, useInputRecorder, useLocalMultiplayer, usePause, usePlayerInput, usePostProcess, usePreload, useProfiler, useSnapshot, useVirtualInput };