Orbit Achieved

It turns out that if you eject some population with exactly the right velocity, they will enter a stable orbit around the planet...

It turns out that if you eject some population with exactly the right velocity, they will enter a stable orbit around the planet...
Using game engines for LDjam is like bringing a car jack to the gym. Efficient, effective, and vastly more capable. On the other hand, typing in matrix algebra is not a great way to spend a weekend. What's the right balance? Whatever balance we pick, obviously... ;)
We're writing some helper stuff, and maybe it can help you too. Here is a 32-bit floating point linear algebra library designed for 2D (for example, matrices are affine transformations instead of being actual matrices.) 32 bit floats in Javascript, you say? Yes, it turns out that it is possible...
P.S. All untested code is broken, so don't trust anything until you see a commit message that says "Fixed (that specific function.)"
[https://github.com/Atomotron/ld47-prep/blob/master/math32.js]
It turns out that there are many things to think about when you're trying to play music or sound in a web browser. For example, there's an important difference between large files that can be played with high latencies (music tracks), which are best to stream, and low-latency short sound effects, which ought to be downloaded completely before the game starts. Another interesting point is the fact that fading is broken in Firefox. If you want to ramp volume, you've got to implement that yourself.
Here is a work-in-progress sound library that handles these considerations, and more. Hopefully some of you can benefit from it! Even if you don't want to include it, it might be a helpful example.
I am thinking that the fading implementation could use a rework, but IMO the loader and gain node stuff is relatively solid. Hopefully you will see some improvements as we get closer to the jam date. :)
https://github.com/Atomotron/ld47-prep/blob/master/sounds.js
Continuing our series of highly generic game library stuff, here is a class that can compile shaders in WebGl. You can find trillions of examples on the internet, and here is another. It features some degree of error-checking, and it has what I think at least is a nice interface. :)
https://github.com/Atomotron/ld47-prep/blob/master/shadercompiler.js
Instanced rendering: super fast, super hard to get working. So, we wrote a library that lets you forget that sprite instancing is happening at all... Admittedly, this under-commented code might be hard to understand, but it's not as hard as inventing it from scratch... I hope. ;)
Simply call DynamicVAO.acquire to get a handle to an object containing one element from each of the attached vertex attributes. Buffer resizing, and changing references to point to the new buffer, is handled internally: all you need to do is write to the object you're given.
There is also a static/dynamic control, so that you can let some buffers update every frame, while requiring others to only update on first draw. Static buffers only get re-sent to the GPU when refreshes are specially requested, or when sprites are added or removed.
Only one caveat: Be sure that your vertex shader produces nothing but degenerate triangles when all of its instanced attribute inputs are zero!
https://github.com/Atomotron/ld47-prep/blob/master/dynamicvao.js
This jam, we wanted to make a game that would work in the browser. LD is about invention and exprimentation, so we made our own engine. It's designed for 2D, and it has good support for shaders (necessary for those sweet graphical effects). It's based on instanced rendering, so the performance is pretty good. It has a nice sprite class, data loaders, render passes, 32-bit floating point math, and even an audio system. I can definitely say it was a lot of work. Hopefully, it will also be helpful. :)
Demo app: https://atomotron.github.io/ld47-prep/gldemo.html
The repo: https://github.com/Atomotron/ld47-prep

He's a man on a planet.
I thank everyone for participating in the experience of this text.
Our team is using WebGL and Javascript for this jam, and to that end I am writing an improved version of the custom engine we used last time. The spirit of LudumDare is about collaboration and sharing, and in that spirit, we invite you to use our code!
First off, here is some code to pretty-print the content of gl.getShaderInfoLog. Why's it so great to pretty-print compilation errors? Well, the default messages I get from the browser are bare oneliners like ERROR: 0:10: 'x' : syntax error. Last jam, I had to hunt through the line numbers manually, which was inconvenient when the shader source was burred inside a script tag in an HTML file. Having learned that this was a problem, today I wrote a simple regex parser that prints much more helpful messages, like this:
When compiling vertex shader "a":
gl_Position = vec4(vertex,0.0,1.0);
world_coord = (inverse_view * vec3(vertex,1.0)).xy ◀◀◀ MISSING SOMETHING?
daytime = dot(world_coord,solar_vector);
▀▀▀▀▀▀▀
ERROR: 0:10: 'daytime' : syntax error``` It's even so nice as to try and find the line where the semicolon is missing. (Heuristically of course, I am not parsing GLSL.)
If you think that's cool, well, hopefully your driver/browser/whatever produces raw errors that textually look like my computer's. If so, then the following code may help you:
```javascript // WebGL shader compilation errors don't provide a lot of context. // This pretty-printer extracts line numbers from the message, and // formats a helpful report on the site of the issue. // My driver can return several errors on several lines, so first let's split them. function prettyPrintShaderErrors(name,source,message) { const errors = message.split(/ ? /); const readouts = []; for (const error of errors) { if (error.length == 0) continue; readouts.push(prettyPrintShaderError(name,source,error)); } return readouts.join(" "); }
// Pretty-print a single error.
function prettyPrintShaderError(name,source,error) {
const lowEffortMessage = When compiling ${name}: ${error};
const lines = source.split(/
?
/);
// An OpenGL compilation error will look like:
// "ERROR: 0:11: 'daytime' : syntax error"
// So, the first thing we do is split at the :
const errorParts = error.split(":");
if (errorParts[0] !== "ERROR" || errorParts.length < 3) {
// Give up if it doesn't look like we're expecting.
return lowEffortMessage;
}
const [part,line] = [
parseInt(errorParts[1],10),
parseInt(errorParts[2],10) - 1 // OpenGL starts at line 1
];
if (part !== 0) return lowEffortMessage; // 'part' is an OpenGL thing that webGL shouldn't have. If it isn't zero, then we aren't properly parsing the error.
if (line >= lines.length) return lowEffortMessage;
// Attempt to find the error-triggering string in the bad line
// Strip whitespace and wrapping quotes
const triggering = errorParts[3].replace(/^\s+['|"]|['|"]\s+$/g, '');
const triggeringindex = lines[line].search(triggering);
// Probe for missing semicolons, a common error.
// This regex-based heuristic is NOT PERFECT, but it can work sometimes.
let semicolonmissingat = null;
// Semicolons, { and } can all go before a statement.
const goodLine = /[;|{|}]\s*(\/\/.*)?$/;
const emptyLine = /^\s*(\/\/.*)?$/;
for (let i=line-1; i>=0; --i) {
if (goodLine.test(lines[i])) break; // We found line that terminates right.
if (!emptyLine.test(lines[i])) { // If the line has stuff on it...
semicolonmissingat = i; // then since we haven't found a good one...
break; // it must be a bad one. We're done!
}
}
// Decide whether or not we suspect a missing semicolon/brace
let suspectedmissingsemicolon = false;
if (semicolonmissingat !== null && triggeringindex >= 0) {
// If the triggering string appears after nothing but whitespace
if (/\s*/.test(lines[line].slice(0,triggeringindex))) {
suspectedmissingsemicolon = true;
}
}
// Select context for error from source lines
const contextend = line+1; // Our context must include the triggering line!
const contextstart = contextend - 3; // 3 lines of context by default
if (semicolonmissingat !== null && contextstart > semicolonmissingat) {
contextstart = semicolonmissingat; // Always include the suspected line
}
if (contextstart <= 0) contextstart = 0;
const context = lines.slice(contextstart,contextend);
// Assemble the message
if (suspectedmissingsemicolon) {
const locincontext = semicolonmissingat - contextstart;
context[locincontext] += " ◀◀◀ MISSING SOMETHING?";
}
const message = [When compiling ${name}:
].concat(context);
if (triggeringindex >= 0) {
message.push(' '.repeat(triggering_index) + '▀'.repeat(triggering.length));
}
message.push(error);
let longest = 0;
for (const l of message) if (l.length > longest) longest = l.length;
message.unshift('='.repeat(longest+1));
return message.join('
');
}```
Our team is making a custom WebGL engine for this jam, and we hope that you can benefit from our work. Today, I'd like to share a little file that may save you some time if you're working with shaders.
Last jam, I spent a lot of time trying to manually synchronize uniform and attribute names between shaders and my webgl engine code. I was always forgetting names and making typos. So, this time, I would like to auto-generate and auto-verify uniform and attribute types.
With webgl functions like getActiveUniform and getActiveAttrib, you can inspect shaders to find out what types of uniforms and attributes should be attached to them. Unfortunately for anyone planning to use that information, the types of those variables are returned in opaque OpenGL codes like 0x8B51. So, I made a JS file containing an object with entries like this:
javascript
GL_TYPES = {
...
0x8B51:{
TypedArray : Float32Array,
name : "FLOAT_VEC3",
nbytes : 12,
nelements : 3,
uniformv : "uniform3fv",
},
...
}
With GL_TYPES[mysterious_opaque_code], you can get a typed array constructor appropriate for the data type, a human-readable name (which happens to comply with WebGL nomenclature), the number of bytes per item, the number of primitive elements per instance, and the name of the uniform upload function that should be called to upload an instance of the type to a shader. As a bonus, there's another object GL_TYPE_CODES, which maps names to codes (superfluously if you have a webgl context, but helpfully if you don't.) If you're writing code to dynamically read info from shaders, this file might save you a lot of typing, and even more spec-reading. Again, here's a link to the file. I hope that it saves you some time.
From a wellspring of laziness, I wrote a python script to generate the file from some tabular data cut-and-pasted from MDN. Humorously, the code-generating script comes in at 175 lines: producing a 212-line file, saving little typing... and costing a lot of thinking. Now, I'm all for laziness and replacing typing with thinking, but in retrospect it may have been better to generate the object in Javascript on page load. Having a python script that generates javascript code that gets put in the repo alongside the generator seems over-complicated.
Secondly, it turns out that integers can't be used as keys in a Javascript object. Implicitly, they're getting converted to strings. That shouldn't cause any problems (because they will also get implicitly converted on lookup), but it does poke a hole in my plans for a super-efficient lookup table; and it severely weakens the case for static code generation. In retrospect I should have used a Map, or maybe a sparse array.
Writing WebGL engines involves doing a lot of linear algebra. Doing a lot of linear algebra involves making a lot of mistakes. Debugging the many mistakes involves a lot of console.log. So, through the inexorable march of implication, we arrive at the need for nice matrix string formatting.
The following code will produce strings like this:
2×2 Matrix
[ 0.000, -1.000]
[ 1.000, 0.000]
when it is given TypedArrays with lengths that are square numbers. (This is a typical way to store matrices.) If you are writing an engine, this will hopefully save you a little time.
javascript
matrixToString(array) {
// Formats a square TypedArray matrix
const n = Math.sqrt(this.a.length); // It better be a square matrix!
const rows = [];
let longest = 0;
for (let row=0; row<n; ++row) {
const slice = Array.from(array.slice(n*row,n*(row+1)));
rows.push(
slice.map(x => {
const s = x.toFixed(3);
if (longest < s.length) longest = s.length;
return s;
})
);
}
const lines = [`${n}×${n} Matrix`];
for (const row of rows) {
const line = [];
for (const x of row) {
line.push(' '.repeat(1 + longest - x.length) + x);
}
lines.push(`[${line.join(',')}]`);
}
return lines.join('
');
}
Previous Use our Code posts: 1. Better errors for shader compilation 2. WebGL Type Info
Our team is developing a new WebGL enigne for this jam. In the spirit of camaraderie, we hope that you can benefit from our work! Today, I'd like to share some work on the vector math library interface, specifically about the way we harmonize the needs of math routines with javascript's object system. You can see the result of this research in our math module.
Other math libraries like glMatrix implement vector and matrix operations as bare monomorphized functions that take references to input and output locations, like mat4.multiply(out, a, b). That pattern is efficient (JS engines prefer functions with consistent types, and allocation is a bad idea in fast math code), but it leads to routines that look like they're programmed in assembly language. We would rather, when possible, write code that looks like equations.
Let's spend a moment considering the various ways to do math in native JS. Ideally, the methods on our vector types would be as convenient. We have three patterns, two that operate on existing memory and one that has to create a new object.
javascript
c = a + b; // Assignment
a += b; // Updating assignment
console.log(a + b); // An expression (creates a new Number)
We can mirror these three on our Vec class. Suppose that Vec is a class that contains its coordinates. Then,
javascript
let a=new Vec(), b=new Vec(), c=new Vec();
c.eqAdd(a,b); // Overwrites the content of c with the sum of a and b
a.addEq(b); // The equivalent of +=, adding b to a.
console.log(a.add(b)); // Allocates a new vector and sets it to the sum of a and b
Each of these methods has its own use-case. Assignment and updating assignment are useful in high-performance code, and the allocating expression is useful for writing natural, expression-like equations in situations where performance is not as important.
thisTo aid expression chaining, we want all methods to return the object they're writing to. That makes it possible to build expressions that look like the following:
javascript
// Several ways to sum three vectors
d.eqAdd(d.eqAdd(a,b),c));
d.addEq(a).addEq(b).addEq(c);
a.add(b).add(c);
To avoid having to write every method three times, I wrote a wrapper to scan classes for implementations of eq___, and generate variants for all of them that were found. We do this using the fact that you can call toString on functions in order to get their implementations. A little parsing (copied from Angular's implenetation) extracts the function signature, and from there we build source strings, eval them, and assign them to the class. In this way, automatic implementations for addEq and add can come from a manually written eqAdd. The codegen can be triggered like this,
javascript
const Vec2 = generateVariantMethods(
class Vec2 extends AbstractVecN {
...
});
Class method decorators have been proposed, but until they're added, this is the best way I can think of to modify class members dynamically.
In addition to the relationships between operators discussed above, there is also a relationship between assignments and constructors. For example, if we can construct a vector in polar coordinates with Vec2.Polar(r,theta), we will also want to be able to assign a polar coordinate to a vector with a.eqPolar(r,theta). For this reason, the codegen will also produce a static Foo method, that can be used as a constructor, from every eqFoo assignment method it finds. This gives us the primary constructor, Vec2.From(x,y), from the assignment function a.eqFrom(x,y). We get a lot of not-so-useful constructors from this (like Vec2.Add), but that doesn't seem to be a problem.
For a class method eqFoo(self,other), the following functions are generated:
javascript
fooEq(other) {
return this.eqFoo(this,other); // Updating assignment
}
foo(other) {
// the Default static method is expected to allocate a default-value object
return (this.constructor.Default()).eqFoo(this,other);
}
static Foo(self,other) { // Like `foo`, but available on the class like a constructor.
return (this.constructor.Default()).eqFoo(self,other);
}
With these codegen features, our math library will be easier to use than most others, without sacrificing crucial performance. I wrote objects for all WebGL types: vectors from one to four dimensions, matrices, and even integer-valued vectors. They're all based on typed arrays and highly performant. If you'd like to use it, pick it up here!.
Previous Use our Code posts: 1. Better errors for shader compilation 2. WebGL Type Info 3. Matrix pretty printing
Our team is developing a new WebGL enigne for this jam. In the process, I kept running in to cases where I wanted to check types, to provide helpful error messages if a complex data structure was mis-assembled by a caller. The ultimate solution to this problem is to use something like TypeScript, but since we wanted to use pure JS for familiarity's sake, it seemed like a good idea to write a typechecking helper. Hopefully, this can save you a little time in your own project.
The following routine takes object specifications like this:
javascript
const SHAPE = {
name: "string",
shader: "?object",
uniforms: "?object",
draw: "function",
}
The check can be performed with a simple call, which returns a boolean:
javascript
const is_good = shapeCheck(
x, // the untrusted object
SHAPE, // the type schema
);
It supports nullability with the ? prefix, but it does not support multi-level deep introspection. (That would be a natural addition, but it wasn't needed at the time.) Here's the snippet:
javascript
function shapeCheck(x,shape) {
let good = true;
for (const name in shape) {
if (typeof x[name] === "undefined") {
good = false;
console.error(x,"missing",name);
continue;
}
if (shape[name].startsWith("?")) {
if (x[name] === null ||
typeof x[name] === shape[name].slice(1)) continue;
} else {
if (typeof x[name] === shape[name]) continue;
}
console.error(x,`has wrong type on ${name}: should be`,shape[name]);
good = false;
}
return good;
}
It's designed to exit late, so that as many errors are found as possible. Happy coding!
Previous Use our Code posts: 1. Better errors for shader compilation 2. WebGL Type Info 3. Matrix pretty printing 4. Math Library API Design

Need to get a few more ratings in? Well, we all like playing WebGL games. This is a WebGL game. That's all I got, folks. Thanks for coming.
Is our game any better than it was when the jam ended? Nope. Do we have any status updates? Not one. No community discord. No monetization plans. What we have is... a Jam game. Why?
Because when the jam ends... It's Quittin' Time!
If you're a fellow-member of the highly prestigious Quittin'-Time Rotary Club, the unified and formidable People for Putting-Pencils-Down PAC, or the timeless and mysterious Couldn't-Be-Bothered Brotherhood, maybe post your game in the comments so that we can pat each other on the back for our ethically refined forms of laziness.
Check it out here, and be sure to take a look at the tutorial first!
Also, don't use your arrow keys, use WASD or your mouse. I accidentally left left swapped with right right before the jam ended, but I don't plan on fixing it, because when it's quittin' time...