{"id":49412442,"url":"https://github.com/ctotheameron/pdphyzx","last_synced_at":"2026-04-29T01:10:54.570Z","repository":{"id":287212059,"uuid":"963802600","full_name":"ctotheameron/pdphyzx","owner":"ctotheameron","description":"Lightweight STB-style single header physics library for the Playdate","archived":false,"fork":false,"pushed_at":"2025-11-21T02:19:11.000Z","size":222,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-21T04:15:55.850Z","etag":null,"topics":["physics","physics-2d","physics-2d-framework","physics-engine","playdate","playdate-sdk"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ctotheameron.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"ctotheameron"}},"created_at":"2025-04-10T08:25:55.000Z","updated_at":"2025-11-21T02:19:13.000Z","dependencies_parsed_at":"2025-04-10T15:48:44.939Z","dependency_job_id":"d61fa371-4f72-44b1-8287-932bab3e04f5","html_url":"https://github.com/ctotheameron/pdphyzx","commit_stats":null,"previous_names":["ctotheameron/pdphyzx"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/ctotheameron/pdphyzx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctotheameron%2Fpdphyzx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctotheameron%2Fpdphyzx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctotheameron%2Fpdphyzx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctotheameron%2Fpdphyzx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ctotheameron","download_url":"https://codeload.github.com/ctotheameron/pdphyzx/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctotheameron%2Fpdphyzx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32406009,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-28T19:38:08.556Z","status":"ssl_error","status_checked_at":"2026-04-28T19:37:55.688Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["physics","physics-2d","physics-2d-framework","physics-engine","playdate","playdate-sdk"],"created_at":"2026-04-29T01:10:53.846Z","updated_at":"2026-04-29T01:10:54.561Z","avatar_url":"https://github.com/ctotheameron.png","language":"C","funding_links":["https://github.com/sponsors/ctotheameron"],"categories":[],"sub_categories":[],"readme":"# pdphyzx\n\n![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/ctotheameron/pdphyzx/build-and-release.yml?branch=main\u0026style=flat-square)\n![GitHub Release](https://img.shields.io/github/v/release/ctotheameron/pdphyzx?style=flat-square\u0026color=%23fac852\u0026link=https%3A%2F%2Fgithub.com%2Fctotheameron%2Fpdphyzx%2Freleases%2Flatest)\n\nA lightweight, impulse-based 2D physics engine designed specifically for the\nPlaydate console. Handle up to 256 physics bodies at smooth framerates while\nstaying within Playdate's performance constraints.\n\n\u003cimg alt=\"demo\" src=\"https://github.com/user-attachments/assets/e95b98b2-1cad-465f-acf3-9fb916498335\" width=\"48%\" /\u003e\n\u003cimg alt=\"demo\" src=\"https://github.com/user-attachments/assets/d700fb58-636e-4bab-97bc-d4912f8cf29b\" width=\"48%\" /\u003e\n\n## ✨ Features\n\n- **📦 Lightweight**: STB-style single-header library with no external dependencies\n- **🚀 Performance-Focused**: Optimized for Playdate's hardware\n- **🧩 Multiple Shape Types**: Circles, boxes, and convex polygons\n- **🎮 Simple API**: Direct integration with Playdate's C SDK\n\n## 📋 Quick Start\n\n### Installation\n\n```bash\n# 1. Download the single header file\ncurl -O https://github.com/ctotheameron/pdphyzx/releases/latest/download/pdphyzx.h\n\n# 2. Add to your project and include it\n```\n\n```c\n// In your source file\n#define PDPHYZX_IMPLEMENTATION\n#include \"pdphyzx.h\"\n```\n\n### Basic Usage\n\n#### Setup and configure world constants\n\n```c\n#include \"pd_api.h\"\n\n// STB-style - only add the #define before the first include.\n// Note that this must be included **after** the Playdate API header.\n#define PDPHYZX_IMPLEMENTATION\n\n// (optional)\n// Define the unit system before including the library:\n// PDPHYZX_UNIT_MM, PDPHYZX_UNIT_CM, or PDPHYZX_UNIT_M\n//\n// Default is PDPHYZX_UNIT_M\n#define PDPHYZX_UNIT PDPHYZX_UNIT_MM // 1 unit = 1 mm\n\n#include \"pdphyzx.h\"\n#include \"pdphyzx.h\"\n\n// These don't have to be global, but for example...\nextern PlaydateAPI *pd;\nPdPhyzxAPI *px = NULL;\nPxWorld *world = NULL;\n\n// Should match your target refresh rate\nfloat targetFps = 50\n```\n\n#### Initialize simulation\n\n```c\nint eventHandler(PlaydateAPI *playdate, PDSystemEvent event, uint32_t arg) {\n  switch (event) {\n    case: kEventInit:\n      pd = playdate;\n      pd-\u003edisplay-\u003esetRefreshRate(targetFps);\n      pd-\u003esystem-\u003esetUpdateCallback(update, NULL);\n\n      px = registerPdPhyzx(playdate);\n      world = px-\u003eworld-\u003enew(targetFps);\n\n      // Number of constraint solving iterations\n      // (higher = more accurate but slower)\n      px-\u003eworld-\u003esetIterations(world, 10);\n\n      // Set the gravity vector (m/s^2)\n      // This can change at runtime\n      px-\u003eworld-\u003esetGravity(world, 0, 9.8);\n\n      // Create a bouncing ball\n      PxShape ballShape = {.circle = {.radius = 10.0f}};\n      float ballDensity = 0.5f;\n      PxVec2 ballPos = pxVec2(200, 100);\n      ball = px-\u003eworld-\u003enewDynamicBody(world, ballShape, ballDensity, ballPos);\n\n      // Configure physics properties\n      ball-\u003erestitution = 0.5f;        // Bounciness\n      ball-\u003edynamicFriction = 0.5f;    // Friction while moving\n      ball-\u003estaticFriction = 0.7f;     // Friction while still\n\n      // Create a static ground platform\n      PxShape groundShape = {.box = {.width = 200.0f, .height = 10.0f};\n      PxVec2 groundPos = pxVec2(200, 200);\n      ground = px-\u003eworld-\u003enewStaticBody(world, groundShape, groundPos);\n      break;\n\n    case kEventTerminate:\n      px-\u003eworld-\u003efree(world);\n      break;\n  }\n\n  return 0;\n}\n```\n\n#### Event loop\n\n```c\n\nint handleInput(void) {\n  PDButtons current, pressed;\n  pd-\u003esystem-\u003egetButtonState(\u0026current, \u0026pressed, NULL);\n\n  if (current \u0026 kButtonA) {\n    // Apply impulse (x,y components for both impulse and contact point)\n    float impulseX = 0, impulseY = -100.0f;  // negative y is up\n    float contactX = 0, contactY = 0;        // center of body\n    px-\u003ebody-\u003eapplyImpulse(ball, impulseX, impulseY, contactX, contactY);\n  }\n}\n\nint update(void *userdata) {\n  // Game logic\n  handleInput();\n  // ...\n\n  // Step physics simulation\n  px-\u003eworld-\u003estep(world);\n\n  // Rendering can be handled manually or using Playdate's sprite system.\n  // See `examples/` for more details.\n  //\n  // For manual rendering:\n  // pd-\u003egraphics-\u003eclear(kColorWhite);\n  // pd-\u003egraphics-\u003efillRect(...);\n  // ...\n  //\n  // When using sprites, simply:\n  // pd-\u003esprite-\u003eupdateAndDrawSprites();\n\n  return 1;\n}\n```\n\n## 🎮 Example Code\n\nCheck out the [examples directory](examples/) for complete demos:\n\n- **[draw](examples/draw/)** - Manual rendering without sprites\n- **[sprites](examples/sprites/)** - Integration with Playdate's sprite system\n\n## 📚 API Overview\n\nThe API is organized into logical domains for easier usage:\n\n```c\n// Core physics domains\npx-\u003eworld     // World creation and management\npx-\u003ebody      // Body manipulation and forces\n```\n\nSee the [source code](src/) for detailed API documentation.\n\n## 🔍 Unit System\n\npdphyzx supports multiple unit scales to make it easier to work with different\nsized objects:\n\n- `PDPHYZX_UNIT_MM`: 1 unit = 1 millimeter\n- `PDPHYZX_UNIT_CM`: 1 unit = 1 centimeter\n- `PDPHYZX_UNIT_M`: 1 unit = 1 meter (default)\n\nDefine this before including the library:\n\n```c\n#define PDPHYZX_UNIT PDPHYZX_UNIT_MM  // Choose your preferred scale\n#include \"pdphyzx.h\"\n```\n\nWhen using `PDPHYZX_UNIT`, sizes and positions are in the specified scale, and\nphysical quantities like gravity and forces are automatically scaled to match.\n\nUnder the covers, this macro tunes internal constants and thresholds to work with\nthe selected unit system.\n\nIf you need further tuning for rendering, you'll need to convert positions and\ndimensions manually.\n\n## 🔧 Local Development Setup\n\n### Prerequisites\n\n- [Playdate SDK](https://play.date/dev/) (latest version recommended)\n- Clang compiler (currently only supports MacOS + Linux)\n\n### Using the Custom Build System\n\nThis project uses a custom build system based on [nob.h](https://github.com/tsoding/nob).\n\n#### Bootstrap the build system\n\n```bash\ncc -o nob .nob/nob.c\n```\n\n#### Build \u0026 Run\n\n```bash\n./nob build # build all examples\n./nob run sprites # run any project in examples/\n./nob help # show available commands\n```\n\n## 🛠️ Development Status\n\nThis library is under active development. Key features being worked on:\n\n- Performance vs accuracy tuning\n- Tunneling prevention for fast-moving objects\n- Collision callbacks system\n- Additional shape types (ellipses, capsules)\n- Kinematic bodies for manual positioning\n\n## 🔬 Under the Hood\n\n### Performance Optimizations\n\n- **No Dynamic Memory Allocation**: Fixed-size arrays and memory pools eliminate\n  runtime allocations\n- **Sweep and Prune Algorithm**: Efficient broad-phase collision detection using\n  sorted AABBs along x-axis\n- **Baumgarte Stabilization**: Position correction bias to prevent sinking\n  without excessive jitter\n- **Sleeping Bodies System**: Inactive objects enter sleep state to save CPU\n  cycles\n- **Fast Math Approximations**: Optimized sqrt (Quake III), sin/cos using lookup\n  tables, and reciprocal calculations\n\n### Collision Detection\n\n- **GJK Algorithm**: For polygon-polygon collision detection using support functions\n- **Clipping Algorithm**: For contact point generation between convex polygons\n- **Voronoi Region Analysis**: For precise circle-polygon collision detection\n- **AABB Overlap Tests**: Quick rejection tests before detailed collision checks\n\n### Physics Solver\n\n- **Sequential Impulse Resolution**: Multi-iteration constraint solver for stability\n- **Coulomb Friction Model**: Static and dynamic friction handling with\n  realistic transitions\n- **Mixed Restitution**: Collision response with coefficient of restitution\n  determined by material properties\n- **Resting Contact Detection**: Uses velocity thresholds to identify and\n  optimize stacking scenarios\n- **Separate Linear/Angular Resolution**: Independent handling of linear and\n  rotational motion\n\n## 🙌 Acknowledgements\n\nThis project wouldn't be possible without these excellent resources:\n\n- **[Randy Gaul's Impulse Engine](https://github.com/RandyGaul/ImpulseEngine)**\n- **[Box2D Lite](https://github.com/erincatto/box2d-lite)**\n- **[Chipmunk2D](https://github.com/slembcke/Chipmunk2D)**\n- **[nob.h](https://github.com/tsoding/nob)**\n\n## 📄 License\n\nMIT License - see the [LICENSE](LICENSE) file for details.\n\n---\n\nBuilt with 💛 for the [Playdate console](https://play.date)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fctotheameron%2Fpdphyzx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fctotheameron%2Fpdphyzx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fctotheameron%2Fpdphyzx/lists"}