
Research
Two Malicious Rust Crates Impersonate Popular Logger to Steal Wallet Keys
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
expo-game-support
Advanced tools
Game support library for Expo/React Native with physics, robust game loop, and optimized touch input.
A complete game-development library for Expo/React Native that adds advanced physics, a robust game loop, and optimized touch input handling.
GLRenderer
) and typed render interfaces (IRenderer
, TextureInfo
, DrawOptions
)AssetManager
for images/spritesheets/textures and audio (via expo-asset
/expo-av
); SpriteAnimator
for sprite animationsnpm install expo-game-support
npm install expo react react-native \
expo-asset expo-av expo-gl \
react-native-gesture-handler react-native-reanimated
import { GameEngine, GameObject, Vector2D } from 'expo-game-support';
// Configure the game engine
const gameEngine = new GameEngine({
width: 400,
height: 600,
gravity: new Vector2D(0, 981), // Gravity pointing down
gameLoop: {
targetFPS: 60,
maxDeltaTime: 0.05,
enableFixedTimeStep: true
}
});
// Initialize and start
gameEngine.initialize();
gameEngine.start();
import React, { useEffect, useRef } from 'react';
import { View, PanResponder } from 'react-native';
import { GameEngine, GameObject, Vector2D } from 'expo-game-support';
export default function GameComponent() {
const gameEngineRef = useRef<GameEngine | null>(null);
useEffect(() => {
const gameEngine = new GameEngine({
width: 400,
height: 600,
gravity: new Vector2D(0, 981),
gameLoop: {
targetFPS: 60,
maxDeltaTime: 0.016,
enableFixedTimeStep: true
}
});
gameEngineRef.current = gameEngine;
gameEngine.initialize();
gameEngine.start();
return () => gameEngine.stop();
}, []);
// Wire PanResponder to touch input
const panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onMoveShouldSetPanResponder: () => true,
onPanResponderGrant: (evt) => {
gameEngineRef.current?.handleTouchStart(evt.nativeEvent);
},
onPanResponderMove: (evt) => {
gameEngineRef.current?.handleTouchMove(evt.nativeEvent);
},
onPanResponderRelease: (evt) => {
gameEngineRef.current?.handleTouchEnd(evt.nativeEvent);
},
});
return (
<View style={{ flex: 1 }} {...panResponder.panHandlers}>
{/* Your game UI here */}
</View>
);
}
// Create a ball with physics
const ball = new GameObject({
id: 'ball',
position: new Vector2D(200, 100),
size: new Vector2D(40, 40),
physics: {
mass: 1,
velocity: new Vector2D(0, 0),
acceleration: new Vector2D(0, 0),
friction: 0.1,
restitution: 0.8, // Bounciness
isStatic: false
}
});
// Add to the engine
gameEngine.addGameObject(ball);
// Touch events
gameEngine.onTouch('player-input', (touchEvent) => {
if (touchEvent.type === 'start') {
console.log('Touch started at:', touchEvent.position);
}
});
// Gestures
gameEngine.onGesture('player-gestures', (gesture) => {
switch (gesture.type) {
case 'tap':
console.log('Tap at:', gesture.position);
break;
case 'swipe':
console.log('Swipe direction:', gesture.direction);
break;
}
});
gameEngine.onUpdate((deltaTime) => {
// Game logic per frame
const ball = gameEngine.getGameObject('ball');
if (ball) {
// Apply forces, check conditions, etc.
}
});
gameEngine.onRender((interpolation) => {
// Rendering (hook into your renderer of choice)
});
This library ships an optional WebGL renderer built on top of expo-gl
. You can use the typed interfaces exported from render/IRenderer
and the concrete GLRenderer
:
import { GameEngine } from 'expo-game-support';
import { GLView } from 'expo-gl';
import { GLRenderer } from 'expo-game-support';
export default function GameWithGL() {
return (
<GLView
style={{ flex: 1 }}
onContextCreate={(gl) => {
const renderer = new GLRenderer(gl);
const engine = new GameEngine({
width: gl.drawingBufferWidth,
height: gl.drawingBufferHeight,
gameLoop: { targetFPS: 60, maxDeltaTime: 0.033, enableFixedTimeStep: true },
});
// Hook engine render to the renderer
engine.onRender(() => {
renderer.beginFrame();
// renderer.drawRect({...}) or draw your textures/sprites here
renderer.endFrame();
gl.endFrameEXP?.();
});
engine.initialize();
engine.start();
}}
/>
);
}
Types you can import:
import type { IRenderer, TextureInfo, DrawOptions, Rect as RenderRect } from 'expo-game-support';
From expo-game-support
root entry:
GameEngine
, GameLoop
, GameObject
PhysicsEngine
, CollisionDetector
TouchInputManager
(web), TouchInputManagerRN
(React Native)BoundaryChecker
, ObjectCleaner
, ScoreZone
, ScoreManager
, ObjectSpawner
AssetManager
, SpriteAnimator
GLRenderer
and render types IRenderer
, TextureInfo
, DrawOptions
, Rect as RenderRect
GameEngineConfig
, GameObjectConfig
, PhysicsBody
, GameTouchEvent
, GameLoopConfig
, CollisionEvent
, and assets types like AssetManifest
, AssetId
, ImageAsset
, TextureAsset
, SoundAsset
, LoadedTexture
, LoadedSpriteSheet
, SoundHandle
Check src/index.ts
for the authoritative export list.
Web-only helpers:
uploadTextureFromImage(image: HTMLImageElement | ImageBitmap)
is intended for web contexts using DOM-compatible image sources.gl.texImage2D
(see uploadTextureFromAssetNative
placeholder). Consider integrating native-assisted decoding or use Expo utilities to obtain a pixel buffer.React Native setup:
react-native-gesture-handler
and react-native-reanimated
properly configured per their docs.expo-gl
, use GLView
and call gl.endFrameEXP()
after each frame.*.web.ts
vs *.native.ts
) to separate implementations.Tree-shaking:
import { GameEngine, GameObject, Vector2D } from 'expo-game-support';
class PongGame {
private gameEngine: GameEngine;
private ball: GameObject;
private paddle: GameObject;
constructor() {
this.gameEngine = new GameEngine({
width: 400,
height: 600,
gravity: new Vector2D(0, 0), // No gravity for Pong
gameLoop: {
targetFPS: 60,
maxDeltaTime: 0.016,
enableFixedTimeStep: true
}
});
this.setupGame();
}
private setupGame() {
// Crear pelota
this.ball = new GameObject({
id: 'ball',
position: new Vector2D(200, 300),
size: new Vector2D(20, 20),
physics: {
mass: 1,
velocity: new Vector2D(200, 150),
acceleration: new Vector2D(0, 0),
friction: 0,
restitution: 1,
isStatic: false
}
});
// Crear paddle
this.paddle = new GameObject({
id: 'paddle',
position: new Vector2D(200, 550),
size: new Vector2D(80, 20),
physics: {
mass: 10,
velocity: new Vector2D(0, 0),
acceleration: new Vector2D(0, 0),
friction: 0.9,
restitution: 0,
isStatic: false
}
});
this.gameEngine.addGameObject(this.ball);
this.gameEngine.addGameObject(this.paddle);
// Handle input to move the paddle
this.gameEngine.onTouch('paddle-control', (touch) => {
if (touch.type === 'move') {
this.paddle.position.x = touch.position.x;
}
});
// Game logic
this.gameEngine.onUpdate((deltaTime) => {
this.updateGame(deltaTime);
});
}
private updateGame(deltaTime: number) {
// Wall bounces
if (this.ball.position.x <= 10 || this.ball.position.x >= 390) {
this.ball.physics!.velocity.x *= -1;
}
if (this.ball.position.y <= 10) {
this.ball.physics!.velocity.y *= -1;
}
// Reset if the ball leaves screen bottom
if (this.ball.position.y > 610) {
this.resetBall();
}
}
private resetBall() {
this.ball.position = new Vector2D(200, 300);
this.ball.physics!.velocity = new Vector2D(200, 150);
}
start() {
this.gameEngine.initialize();
this.gameEngine.start();
}
}
class ParticleSystem {
private gameEngine: GameEngine;
private particles: GameObject[] = [];
constructor(gameEngine: GameEngine) {
this.gameEngine = gameEngine;
}
createExplosion(position: Vector2D, particleCount: number = 20) {
for (let i = 0; i < particleCount; i++) {
const angle = (Math.PI * 2 * i) / particleCount;
const speed = 100 + Math.random() * 200;
const particle = new GameObject({
id: `particle_${Date.now()}_${i}`,
position: position.clone(),
size: new Vector2D(4, 4),
physics: {
mass: 0.1,
velocity: new Vector2D(
Math.cos(angle) * speed,
Math.sin(angle) * speed
),
acceleration: new Vector2D(0, 0),
friction: 0.02,
restitution: 0.3,
isStatic: false
}
});
this.particles.push(particle);
this.gameEngine.addGameObject(particle);
// Destroy particle after 3 seconds
setTimeout(() => {
particle.destroy();
this.particles = this.particles.filter(p => p !== particle);
}, 3000);
}
}
}
new GameEngine(config: GameEngineConfig)
initialize()
: Initialize enginestart()
: Start gamepause()
: Pause gameresume()
: Resume gamestop()
: Stop gameaddGameObject(gameObject: GameObject)
: Add an objectremoveGameObject(id: string)
: Remove an objectgetGameObject(id: string)
: Get by IDgetAllGameObjects()
: Get all objectsonUpdate(callback: (deltaTime: number) => void)
: Update callbackonRender(callback: (interpolation: number) => void)
: Render callbackonTouch(id: string, callback: (event: TouchEvent) => void)
: Touch callbackonGesture(id: string, callback: (gesture: GestureEvent) => void)
: Gesture callbackonCollisionStart(cb)
, onCollisionEnd(cb)
: Physics collision eventsonTriggerEnter(cb)
, onTriggerExit(cb)
: Trigger eventsnew GameObject(config: GameObjectConfig)
id: string
: Unique identifierposition: Vector2D
: World positionsize: Vector2D
: Object sizerotation: number
: Radiansphysics?: PhysicsBody
: Optional rigid bodyupdate(deltaTime: number)
: Per-frame updateapplyForce(force: Vector2D)
: Apply forceapplyImpulse(impulse: Vector2D)
: Apply impulsecontainsPoint(point: Vector2D)
: Point testdestroy()
: Destroy objectnew Vector2D(x: number = 0, y: number = 0)
add(vector: Vector2D)
subtract(vector: Vector2D)
multiply(scalar: number)
divide(scalar: number)
magnitude()
normalize()
dot(vector: Vector2D)
distance(vector: Vector2D)
// Configure for performance
const gameEngine = new GameEngine({
width: 400,
height: 600,
gravity: new Vector2D(0, 981),
gameLoop: {
targetFPS: 30, // Reduce FPS on slower devices
maxDeltaTime: 0.033, // Limit time jumps
enableFixedTimeStep: false // Variable timestep for performance
}
});
// Touch input config
gameEngine.touchInputManager.updateConfig({
deadZone: 10, // Larger dead zone
maxTouchPoints: 2, // Limit touch points
touchSensitivity: 0.8 // Lower sensitivity
});
git checkout -b feature/AmazingFeature
)git commit -m 'Add some AmazingFeature'
)git push origin feature/AmazingFeature
)MIT License - see LICENSE for details.
Note: To minimize tunneling and improve stability, we recommend a fixed time step (enableFixedTimeStep: true
) with targetFPS
60 for physics-heavy scenes. Collision and trigger events are available via GameEngine.onCollisionStart/End
and onTriggerEnter/Exit
.
FAQs
Game support library for Expo/React Native with physics, robust game loop, and optimized touch input.
The npm package expo-game-support receives a total of 34 weekly downloads. As such, expo-game-support popularity was classified as not popular.
We found that expo-game-support demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
Research
A malicious package uses a QR code as steganography in an innovative technique.
Research
/Security News
Socket identified 80 fake candidates targeting engineering roles, including suspected North Korean operators, exposing the new reality of hiring as a security function.