
Agent
FRENZYPhyXion
About this agent
Physics Game for Android
PhyX — Physics Sandbox
1. Project Overview
Type: 2D physics sandbox / destruction simulator
Engine: LÖVE2D (Lua)
Platform: Android (mobile-first), desktop playable
Core concept: place objects made of voxels with material properties. Apply forces (gravity, down-force, explosions, player input). Watch structures fracture, collapse, and interact. ML handles the majority of simulation — stress prediction, fracture propagation, and debris dynamics — working alongside a lightweight traditional physics engine.
Inspired by: People Playground, Garry's Mod, Powder Game, N-Body simulations.
2. Visual & Rendering
World
- Background: Dark scientific grid (subtle
#0D1117base with#1E3A5Fgrid lines, 40px spacing) - Camera: Scrollable, pinch-to-zoom on mobile; mouse wheel on desktop
- World bounds: Large play area (e.g., 4000×3000 units), walls on all sides
Voxels
- Default size: 8×8 pixels (adjustable per object)
- Each voxel rendered as layered geometric shape:
- Outer glow — faint pulsing halo matching material color at 30% opacity
- Primary fill — solid material color
- Inner detail — material-specific geometric pattern (grain lines for wood, crosshatch for metal, clean glass, etc.)
- Connected voxel groups share a subtle outline at the boundary
- Stress visualization — voxels shift from base color toward red as stress increases
Post-processing (lightweight)
- Screen-edge vignette
- Scanline overlay (subtle, for "scientific readout" aesthetic)
- Particle effects for fractures and debris
UI / HUD
- Toolbar (left side, mobile-friendly large touch targets): material selector (wood, metal, glass, rubber, concrete, explosives)
- Tool mode selector: place / delete / apply force / explode / drag
- Top bar: FPS counter, voxel count, ML status indicator, pause button
- Bottom: force magnitude slider (drag gesture length maps to force)
3. Physics Engine Architecture
Traditional Layer (LÖVE2D + Box2D)
Handles core dynamics: gravity, collision detection, rigid body movement, joints.
- PhysicsWorld: wraps
love.physics, manages gravity vector, timestep - Gravity: default
(0, 980)— strong downward pull. Configurable per material. - Down-force: special force mode where player drags down on an object to apply a crushing force
- Collision groups: voxels in the same object share a group (don't collide with each other, but collide with world and other objects)
- Boundary walls: static bodies at world edges
Voxel Grid System
Each object is a grid of voxels:
LUAObject { id, material, voxels[Row][Col] = Voxel | nil, body = love.physics.Body, -- unified rigid body for connected voxels fracture_level = 0, -- current subdivision depth stress = 0 -- 0..1, drives fracture } Voxel { x, y, -- world position (top-left of voxel) state = "intact" | "fractured" | "removed", neighbors = {up, down, left, right}, stress = 0, -- accumulated stress connections = {}, -- physics joints to neighboring intact voxels }
Layered Hex-Pixel Discretization (Material Model)
Materials define their fracture depth:
| Material | Depth | Voxel HP | Fracture behavior |
|---|---|---|---|
| Rubber | 0 | 30 | Bounces, deforms, rarely breaks |
| Wood | 1 | 15 | Splits into individual pixels |
| Glass | 1 | 5 | Shatters into many small shards |
| Concrete | 2 | 25 | Cracks into chunks, chunks further crack |
| Metal | 3 | 40 | Bends, then micro-fractures into fine debris |
| Explosive | 0 | — | Triggers area fracture on detonation |
At depth 0: a voxel is the atomic unit — breaks into debris particles.
At depth N: a voxel breaks into a 3×3 grid of sub-voxels (each inherits parent stress).
Fracture Mechanics
- Stress accumulation: each frame, ML system computes stress across the voxel grid
- Threshold check: if a voxel's stress > material threshold, it enters "cracking" state
- Propagation: cracking voxel applies stress to neighbors (cascading for brittle materials)
- Separation: intact connections are removed, fractured voxels become independent physics bodies
- Debris: sub-voxels become small rigid bodies with randomized velocity based on impact force
ML Integration Points
The ML system is called from the physics loop at strategic points:
| Hook | Input | Output |
|---|---|---|
predictStress(object) | Voxel grid state, applied forces, material map | Stress heatmap across all voxels |
predictFracture(voxel, stress) | Single voxel state + stress | Probability of fracture / next break point |
propagateFracture(object) | Stressed object | Set of voxels to fracture this frame |
predictDebris(voxel, force) | Breaking voxel + force vector | Initial velocity/rotation for debris fragments |
adaptPhysics(dt) | Frame timing, object count | Suggested timestep adjustment |
4. Neural Network Architecture
Pure Lua implementation, no external dependencies.
Network 1: Stress Predictor
- Input: Voxel grid state — for each voxel: material type (one-hot), intact/fractured (binary), stress value, neighbor count, distance from force application point. Flattened, ~20 features per voxel × N voxels.
- Output: Stress value per voxel (regression, 0..1)
- Architecture: 2 hidden layers, (input/4, input/8) neurons, tanh activation
- Training: Online — collect (grid_state, stress_map) samples from simulation, batch train every N frames
- Use case: Replaces expensive iterative spring-damper stress calculation
Network 2: Fracture Propagator
- Input: Single voxel features + stress + neighbor stress values
- Output: Fracture probability (0..1)
- Architecture: Small MLP, 16-8-1
- Training: Binary labels from simulation ground truth (voxel broke / didn't break)
- Use case: Determines which stressed voxel breaks next (instead of threshold comparison)
Network 3: Debris Trajectory
- Input: Voxel position, material, fracture force magnitude + direction
- Output: Debris velocity (vx, vy) and angular velocity
- Architecture: 8-4-2 regression
- Training: Collect actual debris motion from Box2D simulation, distill to NN
- Use case: Fast approximate debris without full physics for small fragments
Training Pipeline
- Start with zero training samples
- Every 100 frames, record grid states and outcomes
- When a fracture occurs, record the input state and label (which voxels broke)
- Train networks when sample buffer > threshold (e.g., 200 samples)
- Networks persist to file (JSON serialization) across sessions
5. Materials
Definition (consts.lua)
LUAMATERIALS = { wood = { color = {0.6, 0.4, 0.2}, density = 0.6, strength = 15, fracture_depth = 1, elasticity = 0.3, friction = 0.5, ml_weight = 1.0, icon_shape = "rect" }, metal = { color = {0.7, 0.7, 0.8}, density = 1.5, strength = 40, fracture_depth = 3, elasticity = 0.1, friction = 0.4, ml_weight = 2.0, icon_shape = "hex" }, glass = { color = {0.4, 0.8, 1.0}, density = 0.4, strength = 5, fracture_depth = 1, elasticity = 0.05, friction = 0.2, ml_weight = 0.5, icon_shape = "diamond" }, rubber = { color = {0.2, 0.2, 0.2}, density = 0.3, strength = 30, fracture_depth = 0, elasticity = 0.9, friction = 0.8, ml_weight = 1.5, icon_shape = "circle" }, concrete = { color = {0.5, 0.5, 0.5}, density = 1.2, strength = 25, fracture_depth = 2, elasticity = 0.05, friction = 0.7, ml_weight = 1.2, icon_shape = "square" }, explosive = { color = {1.0, 0.2, 0.1}, density = 0.5, strength = 1, fracture_depth = 0, elasticity = 0.0, friction = 0.3, ml_weight = 0.0, -- no stress prediction, instant detonation icon_shape = "triangle" } }
Reactions
- Metal + Wood: standard collision, metal transfers more stress
- Glass + anything: high stress transfer, glass shatters on impact above threshold
- Rubber + anything: absorbs force, high elasticity bounce
- Concrete + Metal: high compression strength, slow fracture
- Explosive + any: radius-based fracture, force = explosive.power × (1 / distance²)
6. Controls (Mobile-First)
All input is processed through screenToGame() coordinate conversion for proper letterboxing.
Touch Gestures
| Gesture | Action |
|---|---|
| Tap toolbar icon | Select material or tool |
| Tap on world | Place object at grid-snapped position |
| Long press on world | Delete object under finger |
| Drag on world | Apply force (direction + magnitude from drag vector) |
| Drag down (force mode) | Down-force crushing |
| Two-finger drag | Pan camera |
| Pinch | Zoom camera |
| Tap pause button | Pause simulation |
Tool Modes
- Place — tap to place a 3×3 or 5×5 voxel block of selected material
- Delete — long press to remove objects
- Push — drag to apply impulse force to objects in drag path
- Explode — tap to detonate explosives under cursor radius
- Grab — drag to pick up and move an object
Visual Feedback
- Press highlight: button pulses with material color
- Drag line: shows force vector with arrow
- Placement preview: ghost voxel grid follows finger before tap
Desktop
- Left click: place / select
- Right click: delete
- Middle drag: pan
- Scroll: zoom
- Space: pause
- R: reset world
7. Project Structure
PhyX/
├── SPEC.md
├── conf.lua ← LÖVE2D window config (1080×1920, mobile-safe)
├── main.lua ← entry: love.load/udpate/draw/quit, global input handlers
├── src/
│ ├── consts.lua ← ALL numbers: display dims, material defs, ML params, world size
│ ├── core/
│ │ ├── PhysicsWorld.lua ← LÖVE2D Box2D wrapper, gravity, boundaries, timestep
│ │ ├── VoxelGrid.lua ← 2D grid of voxels, spatial hash, neighbor queries
│ │ ├── Material.lua ← material property definitions + fracture logic
│ │ └── FractureManager.lua ← manages fracture propagation across voxel grids
│ ├── objects/
│ │ ├── Object.lua ← object: collection of voxels, unified physics body
│ │ ├── Voxel.lua ← single voxel state + connections
│ │ └── ObjectFactory.lua ← creates pre-built structures (tower, bridge, wall, etc.)
│ ├── ml/
│ │ ├── NeuralNetwork.lua ← pure Lua MLP: forward, train, serialize
│ │ ├── StressNet.lua ← stress prediction network
│ │ ├── FractureNet.lua ← fracture propagation network
│ │ ├── DebrisNet.lua ← debris trajectory network
│ │ └── MLManager.lua ← owns all nets, trains on simulation data, prediction interface
│ ├── ui/
│ │ ├── Toolbar.lua ← left-side material/tool selection
│ │ ├── HUD.lua ← top bar: FPS, voxel count, ML status
│ │ ├── ForceSlider.lua ← bottom force magnitude indicator
│ │ └── PauseMenu.lua ← pause overlay
│ ├── world/
│ │ ├── World.lua ← world state: objects, boundaries, ambient particles
│ │ └── Camera.lua ← pan + zoom, handles input
│ └── render/
│ ├── Renderer.lua ← main draw loop: background, objects, UI, effects
│ └── Effects.lua ← vignette, scanlines, particles, stress coloring
├── lib/
│ ├── Font.lua ← geometric font (from previous project)
│ ├── Haptics.lua ← mobile vibration feedback
│ └── Serializer.lua ← JSON save/load for worlds + ML model weights
└── assets/
└── (no external assets — all procedural/geometric)
8. Performance Targets
- Target FPS: 60 on mid-range Android (2020+)
- Max voxels: ~2000 active before degradation
- ML inference budget: <1ms per frame (runs on CPU via pure Lua)
- Physics timestep: fixed 1/120s with accumulator pattern
- Rendering: canvas-based batching, no per-voxel draw calls
9. Development Phases
Phase 1: Engine Core (this session)
- Project scaffold
- PhysicsWorld: LÖVE2D gravity, boundaries, bodies
- VoxelGrid: grid data structure, spatial queries
- Material system: definitions, voxel creation
- Object: voxel collection → physics body
- Basic rendering: grid background, voxel drawing with material colors
- Camera: pan + zoom
- Mobile controls: tap to place, drag to apply force
- MLManager: NeuralNetwork base + 3 networks + training pipeline
Phase 2: Fracture System
- FractureManager: stress propagation, voxel separation
- ML stress prediction → fracture triggers
- Debris particle system
- Material-specific fracture behaviors
Phase 3: Sandbox Features
- Pre-built structure templates (bridge, tower, wall)
- Explosive tool
- Save/load worlds
- Particle effects for destruction
Phase 4: Polish
- Sound (optional)
- Performance optimization
- UI polish
- APK build
10. Success Criteria (Phase 1)
- World renders with grid background
- Player can tap to place voxel blocks of different materials
- Objects fall under gravity and collide with boundaries
- Drag applies force to objects
- ML networks train on simulation data (stress/fracture/debris)
- Runs at 60fps on desktop
- Touch controls work on mobile
Chart
Loading chart...
Comments & Discussion
Scroll to load comments...
Share
Loading recommendations...