Gravity Programming Language: an embeddable C99 scripting VM for iOS and Android hosts
Gravity Programming Language
At a glance
- What is it?
- Gravity is a dynamically typed, class-based scripting language written in portable C with no external dependencies. It targets hosts that need to ship a small interpreter, and it is maintained by a single author, which shapes what you get.
- Who is it for?
- Adopt Gravity if you are embedding a scripting layer into a C, C++ or Objective-C host and you want a small dependency-free VM with bytecode precompilation and a documented bridging API; the example in examples/example.c and the header gravity_vm.h are the places to start.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 11 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Gravity is for and who actually needs it
Gravity exists to let a native application run portable scripts. The README states it was developed for the Creo project to offer an easy way to write portable code for iOS and Android, and that framing explains most of the design: a C99 codebase with no external dependencies other than its standard library, a compiler and VM that together add less than 200KB to an executable on a 64-bit system, and an embedding API meant to be called from a host program rather than from a terminal.
The audience is therefore narrow and specific. If you are writing a game engine, a mobile app, a plugin host or a tool that needs user-authored logic without a rebuild, Gravity is aimed at you. If you want a general-purpose language to write standalone programs in, Gravity will feel like a scripting layer that escaped its host: the CLI exists, but the README spends most of its length on the compiler, the VM and the embedding API, not on libraries.
The language surface is broad for its size. Classes with inheritance, higher-order functions and classes, lexical scoping, closures, fibers for coroutines, nested classes, operator overriding, string interpolation, enums, modules, structs as value types, switch with ranges, and optional semicolons. Mark-and-sweep garbage collection is built in. That is a lot of feature surface for a VM the README measures at roughly 6.5K lines, and the trade-off is visible in what is absent: there is no package manager, no module registry, and the optional modules list is short.
The pipeline: multipass compiler, bytecode, stack VM
Gravity is not a tree-walking interpreter. The repository layout splits the work into src/compiler and src/runtime, and the README describes the compiler as multipass with an optimizer. The compiler directory holds the lexer, parser, AST, semantic analysis, an intermediate representation, the optimizer and code generation. The runtime directory holds a stack-based VM plus the built-in types and core methods. src/shared carries the pieces both sides need: value representation, opcodes, a hash table, an array, and memory management with the garbage collector.
That split matters for deployment. Because compilation and execution are separate stages, the CLI can compile a source file to bytecode once and execute the precompiled artifact later. The README's usage list shows this directly: -c compiles to bytecode and writes gravity.g by default, -o redirects that output to a named file, and -x executes precompiled bytecode. For an embedded host, that means you can ship bytecode and skip parsing at startup, at the cost of a build step in your pipeline.
The embedding example in the README shows the same two-stage flow in C. A gravity_compiler_t is created with a delegate that carries an error_callback, gravity_compiler_run returns a gravity_closure_t, then a gravity_vm is created separately and gravity_compiler_transfer moves compiler-owned objects into the VM before the compiler is freed. Only then does gravity_vm_runmain execute the closure and gravity_vm_result read the value back. The transfer step is the detail worth noticing: objects are not shared between compiler and VM by default, so the host has to hand them over explicitly. That is a deliberate ownership boundary, and getting it wrong is the kind of mistake the API design is trying to make hard.
Building Gravity and running a first script
There are two build paths. The Makefile covers Linux, macOS and BSD, and the README lists the targets: make builds the CLI, make mode=debug builds with symbols, make lib builds the shared library, make staticlib builds libgravity.a, make example builds the C embedding example, and make clean removes artifacts. A C99 compiler is the only requirement stated.
make
make mode=debug
make lib
make exampleThe shared library name is platform dependent, and the Makefile makes that explicit rather than hiding it: gravity.dll on Windows, libgravity.dylib on Darwin, libgravity.so on Linux and the BSDs, with libgravity.a as the static name everywhere. On Linux the link flags include -lrt; on macOS they do not. If you are cross-compiling, that is the kind of detail you will be reading the Makefile for.
CMake is the path for Windows and for anyone who wants to build the library without the CLI:
cmake -B build
cmake --build build
cmake -B build -DBUILD_CLI=OFF
cmake --build buildThe -DBUILD_CLI=OFF flag is the one to remember if you are embedding Gravity into an application and do not want a command-line binary in your build output.
Once built, the CLI is the fastest way to see the language work. The README's usage section gives these forms:
./gravity file.gravity
./gravity -c file.gravity
./gravity -o out.json -c file.gravity
./gravity -x gravity.g
./gravity -i 'return 2 + 3'The -i form executes inline code, so ./gravity -i 'return 2 + 3' is the shortest path to confirming the VM is alive. The -c form writes bytecode, gravity.g by default or the file named by -o. Note that the -o example in the README uses a .json extension for a bytecode output file; the extension is just a filename, not a format change.
For the embedding path, the README points at examples/example.c and the header files src/runtime/gravity_vm.h and src/compiler/gravity_compiler.h. The repository also contains examples/Executing Gravity from C.md and an examples/GravityCpp/ directory. The example compiles the source string "func main() { return 6 * 7; }", runs it, and calls gravity_value_dump, which the README says prints 42. The teardown order at the end is gravity_vm_free followed by gravity_core_free.
Where Gravity is the wrong choice
The clearest limitation is ecosystem. Gravity ships optional modules for Math, File, JSON and ENV. There is no package manager and no third-party module registry described anywhere in the README. If your project needs an HTTP client, a database driver, a date library or a test framework beyond the built-in unit tests, you are writing it yourself, in C, against the embedding API. For a scripting language, that is a significant gap, and it is the single most likely reason a team evaluates Gravity and then picks something else.
The second constraint is versioning. The most recent release listed is 0.9.8. A pre-1.0 version number is not a defect in itself, but it tells you the language surface is not frozen. The README does not document a stability policy or a deprecation process, and it does not document rollback behaviour for bytecode compiled by an older build. If you ship precompiled .g files to end users, you are depending on an artifact format whose compatibility guarantees the README does not state. Verify that yourself before you build a distribution around it.
The third is the maintenance model. The repository is not archived, and the last push was on 2026-09-19. But the README credits a single author plus one named friend for debugging and testing, and the special-thanks section points to Lua and Wren for closures, fibers, upvalues and parts of the garbage collector. A language runtime is a long-lived dependency. One maintainer is a real risk factor for a component you cannot easily replace once your host application is built around it.
Finally, the language is not a drop-in for anything. It has Swift-like syntax with optional semicolons, which will look familiar to some readers and unfamiliar to others. If your team's scripts are already written in another embedded language, the migration cost is a rewrite, not a port.
How Gravity differs from Lua and Wren
The README names both Lua and Wren as influences, and the differences are worth stating precisely rather than treating them as interchangeable embedding options. From Lua, Gravity takes the closure design, citing the Closures in Lua document by Roberto Ierusalimschy. From Wren, it takes fibers, upvalue handling and parts of the garbage collector, crediting Bob Nystrom.
The practical difference from Lua is the object model. Gravity is class-based with inheritance, operator overriding and string interpolation as language features, and the README shows a Vector class overriding both + and String() in a single example. Lua's table-based model gives you metatables and a smaller core, and its standard library is larger. If your host needs classes and operator overloading expressed in the script itself rather than emulated, Gravity's model is closer to what you want.
The practical difference from Wren is scope and tooling. Wren is also a small class-based embeddable language, and the shared lineage in fibers and GC is visible. Gravity adds a multipass compiler with an optimizer, bytecode precompilation through the CLI's -c and -x flags, and optional modules for Math, File, JSON and ENV. The built-in JSON serializer and deserializer is a concrete convenience if your host exchanges structured data with scripts, and it is listed as a first-class feature rather than an add-on. Neither comparison is a verdict on quality; the deciding factor is which object model and which build pipeline your host already assumes.
Testing, licence and the cost of upgrading
Gravity ships its own test infrastructure, which is unusual enough for a project this size to be worth noting. The README documents three ways to run tests: ./gravity -t test/unittest runs all unit tests through the VM, ./test/unittest/run_all.sh runs them through a shell script with per-test timeouts, and ./gravity test/unittest/somefile.gravity runs a single file. The test directory also contains fuzzy/ for randomised fuzzing inputs and infiniteloop/ for tests that must terminate with a runtime error rather than hang. That last directory is a small but telling detail: the project treats non-termination as a testable failure mode, not an acceptable outcome.
Licensing is MIT, per the repository. That is permissive and short, and it is the licence most hosts want for an embedded runtime because it does not impose copyleft obligations on the surrounding application. Nothing in the README or the repository listing suggests a dual-licence arrangement, a contributor licence agreement, or a commercial exception. Check the LICENSE file itself and your own organisation's policy; this is a description of what the repository states, not legal advice.
The upgrade cost is the part the documentation is thinnest on. The CHANGELOG.md and TODO.md files exist at the repository root, but the README does not describe a migration path between releases, and it does not state whether bytecode produced by one version runs on another. If you embed Gravity, your upgrade procedure has to include recompiling your scripts and re-running your host's integration tests, because the README gives no compatibility guarantee you could rely on instead. The presence of CLAUDE.md at the root is also worth a glance if you want to know how the project describes itself to tooling.
Editorial conclusion
Adopt Gravity if you are embedding a scripting layer into a C, C++ or Objective-C host and you want a small dependency-free VM with bytecode precompilation and a documented bridging API; the example in examples/example.c and the header gravity_vm.h are the places to start. Do not adopt it if you need a large standard library, a package ecosystem, or a language whose syntax and semantics are frozen by a specification, because the repository is at 0.9.8 and the README documents optional modules only for Math, File, JSON and ENV. Before committing, verify two things yourself: that your target platform builds under the Makefile or CMake path you intend to use, and that the bridging API in src/runtime/gravity_vm.h covers the value types your host needs to exchange.
Frequently asked questions
What is the Gravity programming language?
Gravity is a dynamically typed, class-based scripting language written in C with no external dependencies apart from its standard library. The README describes it as embeddable, with a multipass compiler, a stack-based VM, and an embedding API for C hosts.
How do I install and build Gravity?
There is no package to install. The README gives two build paths: make for Linux, macOS and BSD, and cmake -B build followed by cmake --build build for cross-platform builds including Windows. A C99 compiler is the only stated requirement.
How do I run a Gravity script from the command line?
After building, ./gravity file.gravity compiles and executes a source file. The CLI also accepts -c to compile to bytecode, -x to execute precompiled bytecode, -i to execute inline code, and -t to run unit tests.
Can Gravity be embedded in a C application?
Yes, and that is its stated purpose. The API lives in src/runtime/gravity_vm.h and src/compiler/gravity_compiler.h, and examples/example.c shows the flow: create a compiler with a delegate, run it to get a closure, create a VM, transfer the compiler's objects into it, then call gravity_vm_runmain.
What optional modules does Gravity provide?
The README lists Math, File, JSON and ENV as optional modules. JSON serialization and deserialization are also listed among the core features, so structured data exchange with a host does not require an add-on.
What licence is Gravity released under?
The repository states the licence as MIT. The README does not describe a dual-licence arrangement or a commercial exception, so the LICENSE file at the repository root is the document to read.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/marcobambini-gravity)