# glemy

A small 2D circle-physics/game engine for [Gleam](https://gleam.run),
targeting both the Erlang and JavaScript runtimes. Follows a
[Functional Core, Imperative Shell](https://kennethlange.com/functional-core-imperative-shell/)
split: `glemy/physics` and its submodules are pure Gleam (entities, an
axis-aligned bounding box, gravity, integration, and a pairwise
collision sweep with a caller-supplied interaction rule), fully tested
with plain `gleam test` on both targets; `render`/`io` are the thin,
`@target(javascript)`-gated Shell that draws entities to a real WebGPU
canvas and polls keyboard/mouse input.

glemy itself ships no game — see
[glemy-games](https://github.com/recregt/glemy-games) for three
reference games (Tiers, Breakout, Platformer) built on it, and the
[live demo](https://recregt.github.io/glemy-website/play/) to try them
in a browser.

## Installing

Not yet published to Hex. Until then, depend on it directly from
GitHub, pinned to a commit (Gleam's own recommended practice over a
branch or tag):

```toml
[dependencies]
glemy = { git = "https://github.com/recregt/glemy", ref = "<commit-sha>" }
```

## Usage

```gleam
import glemy/physics
import glemy/physics/bounds.{Bounds}
import glemy/physics/collision_sweep.{Bounce}
import glemy/physics/entity.{Entity}
import glemy/physics/vector2.{Vector2}

pub fn main() {
  let bounds = Bounds(min: Vector2(0.0, 0.0), max: Vector2(100.0, 100.0))

  let model =
    physics.Model(entities: [], bounds: bounds, gravity: Vector2(0.0, -9.8))
    |> physics.spawn_entity(Entity(
      position: Vector2(50.0, 90.0),
      velocity: vector2.zero,
      radius: 5.0,
      kind: 0,
      resting_time: 0.0,
    ))

  // Advance one frame: integrate under gravity, bounce off `bounds`,
  // and resolve any overlaps as plain elastic bounces (`Bounce`) --
  // pass your own function instead of `fn(_a, _b) { Bounce }` to merge,
  // destroy, or otherwise react to a specific pair of entities.
  let #(next_model, _events) =
    physics.update(model, 1.0 /. 60.0, bounds.bounce, fn(_a, _b) { Bounce })

  physics.entity_count(next_model)
}
```

See `ARCHITECTURE.md` for where new code goes and why, and
`docs/technical-architecture.md` for the project-level architecture
spanning this repo, `glemy-games`, and `glemy-website`.

## Developing

```sh
gleam test --target erlang
gleam test --target javascript
deno task check-warnings
```

See `CLAUDE.md` for the full verification checklist this project holds
every change to.
