A decorator for numbers that outputs their bit pattern for both print() and show(). E.x. "0b00111011".

The number type TNum must support the following:

* `sizeof() * 8` to determine the max number of bits.
    * If your type doesn't do this, overload `binary_size(n::TNum)`
        or `binary_size(::Type{TNum})`.
* To check individual bits: bitwise `&` and `<<`;
    `zero(TNum)` that makes a value with all bits set to `0`;
    `one(TNum)` that makes a value with all bits set to `0` *except* the lowest bit.
    * If your type doesn't do this, overload `is_bit_one(a::TNum, bit_idx::Int)::Bool`

An immutable version of PRNG, to avoid heap allocations. Any calls to rand() with this PRNG will return a tuple of 1) the result, and 2) the new 'mutated' ConstPRNG.

This is a break from the typical AbstractRNG interface, so it only supports a specific set of rand() calls.

You can construct a PRNG with its fields (UInt32 and NTuple{3, UInt32}). You can also construct it with any number of scalar data parameters, to be hashed into seeds. If no seeds are given, one is generated with rand(UInt32).

When constructing it, you can optionally pass a 'mixing' strength as the first argument, wrapped in the compile-time type Val. Weaker strengths result in better performance, but risk creating artifacts. The default is Val(PrngStrength.strong), and with more seed values you can get away with weaker ones.


An immutable alternative to Vector, using tuples. The size is a type parameter, but you can omit it so that it's 'resizable'.


Wraps an iterator so that it can be unwrapped by calling pairs(). Each element's key in the pair is an index, using enumerate().

This is needed to use iterators/generators in functions like findfirst().


Returns nothing if the expression doesn't look like a valid function definition (i.e. it's wrapped by an unexpected macro, or not even a function in the first place).

Pass false for check_function_grammar to ignore the actual function inside the macros.


Information that can be part of a function definition but isn't handled by MacroTools. For example, @inline, @generated, and doc-strings.

Turn this back into code with MacroTools.combinedef(::FunctionMetadata).


Combines a Julia UTF-8 string with a null-terminated C-string buffer.

Use update!() to set the Julia string or recompute it from the C buffer.


A fast, strong PRNG, taken from http://burtleburtle.net/bob/rand/smallprng.html. Normally outputs 32-bit numbers; other sizes require extra ops.


A Union of types that can be serialized/deserialized through StructTypes. Any types that can individually be handled by StructTypes should also be usable in this union. It is not super efficient, as it uses try/catch to find the first type that successfully deserializes.


A data represenation of an argument declaration (a.k.a. the output of MacroTools.splitarg()). Also handles the whole argument declaration being wrapped in an esc(), which splitarg() does not.


A data representation of the output of MacroTools.splitdef(), plus the ability to recognize meta-data like doc-strings and @inline.

For convenience, it can also represent function signatures (i.e. calls), by setting the body to nothing (not to be confused with :nothing).

It can also represent lambdas by setting the name to nothing.

It is not valid to set both the body and the name to nothing.


A data representation of a macro invocation, analogous to SplitDef and SplitArg. The constructor returns nothing if the expression isn't a macro invocation.

Turn this struct back into a macro call with combinemacro().


A data representation of a type declaration, such as C{R, T<:Integer} <: B. Analogous to SplitDef and SplitArg.

The constructor returns nothing if the expression isn't a macro invocation.

If you want to skip type checking (such as the name being a Symbol), pass false in the constructor.


Provides append!() for sets, which is missing from Julia for some reason


Computes one of the modifying assignments (*=, &=, etc) given it and its inputs. Also implements = for completeness.


Wraps an iterator so that it can be unwrapped by calling pairs(). Each element's key in the pair is an index, using enumerate(). This is needed to use iterators/generators in functions like findfirst().


The inner logic of @bp_enum. Also takes a block of "definitions", in case something needs to be imported into the enum's module.


Checks that an expression is a Symbol, possibly nested within . operators. For example, Base.empty.

Optionally allows type parameters at the end of the expression, like :( A.B{C} ).


Checks if an expression is a short-form function declaration (like f() = 5). Note that MacroTools' version of this function accepts things that are not actually functions.

If check_components is true, then the checks become a little stricter, such as checking that the function name is a valid expression.


A facade for using unordered collections in functions that don't normally accept them (like map)


Picks a random element from an ntuple. Unfortunately, Random.rand(::ConstPRNG, ::NTuple) has unavoidable type ambiguity.


Converts between two data representations by reinterpreting the bytes. For example:

  • Get the individual bytes of a uint with (a, b, c, d) = reinterpret_bytes(0xaabbccdd, NTuple{4, UInt8})
  • Copy a struct into a Vector{UInt8} with reinterpret_bytes(my_struct, my_vector).
  • Read the first 4 bytes of an array-view as a Float32: f = reinterpret_bytes(@view(my_byte_array[i*4 : end]), Float32)

When deserializing a union of types, this determines the order that the types are tried in. Lower-priority values are tried first.


Takes a zipped piece of data and unzips into the original iterators.

Anything that behaves like the output of zip() can be similarly unzipped; however this general implementation will iterate on zipped several times, and may not even be type-stable (we have to test it).

If the number of zipped iterators can't be deduced statically, you should feed it in as the second argument.


Walks through an expression depth-first, invoking your lambda on every sub-expression with the following arguments:

1 .A list of integers representing the path to this sub-expression (for each Expr along the way, the index of its argument)

  1. A list of the parents to this sub-expression, from the root down to the current expr.

For example, you could pass a lambda of the form (path, exprs) -> let e = exprs[end] ... end.


Anonymous enums, implemented with Val. A stricter alternative to passing symbols as parameters. @ano_enum(ABC, DEF, GHI) == Union{Val{:ABC}, Val{:DEF}, Val{GHI}} Note that this creates some overhead if the user can't construct the Val at compile-time.


Combines the features of @bp_enum with the bitfield behavior of @bitflag from BitFlags.jl. Along with the usual @bp_enum definitions, you also get:

  • Power-of-two element numbering by default (if you want a 0 element, put it at the beginning).
  • Aggregate elements with the syntax @element_name a|b|c. Note that these are not enumerated in instances().
  • a | b to combine two bitflags.
  • a & b to filter bitflags.
  • a - b to remove bitflags (equivalent to a & (~b)).
  • Subsets: a <= b means "a is a subset of b", and >= means vice-versa.
  • Base.contains(haystack, needle)::Bool as a short-hand for (haystack & needle) == needle
  • ALL as a value representing all elements of the bitfield enabled
  • Pretty printing of combination values.

An alternative to the @enum macro, with the following differences:

  • Keeps the enum values in a module to prevent name collisions.
  • Provides an overload of base.parse() to parse the enum from a string.
  • Provides MyEnum.from(i::Integer) to convert from int to enum.
  • Provides MyEnum.from_index(i::Integer) to get an enum value from its index in the original declaration.
  • Provides MyEnum.to_index(e) to get the index of an enum value in the original declaration.
  • Provides MyEnum.instances() to get a tuple of the elements.
  • Provides an alias for the enum type, E_MyEnum.

If you wish to add definitions inside the enum module (e.x. import a package), make your own custom macro that returns generate_enum(). put a begin ... end block just after the enum name, containing the desired code.

If you want your enum to act like a bitfield, use @bp_bitflag instead.


Implements a module's init function by delegating it to a list of callbacks. This allows multiple independent places in your module to register some initialization behavior. The callback list will be named RUN_ON_INIT.


Game math is mostly done with 32-bit floats, especially when interacting with computer graphics. This is a quick short-hand for making a 32-bit float.


This is an alternative to ToggleableAsserts.jl. That package allows you to call asserts which can be toggled on or off by the JIT compiler; however all projects using the package must respect a single global flag.

This macro generates ToggleableAsserts-style code, so that you can have multiple separate instances of ToggleableAsserts. B+ uses this to give each sub-module its own debug flag, and you can use it to give your project its own debug flag as well.

Invoking @make_toggleable_asserts X_ generates the following:

  • @X_assert(condition, msg...) performs a check if X_asserts_enabled(), and throws an error if the check fails.
  • @X_debug() evaluates to a boolean for whether or not asserts are enabled.
  • @X_debug a [b], to evaluate 'a' if asserts are enabled, and optionally 'b' otherwise.
  • X_asserts_enabled() represents the debug flag; it's a function that returns the constant false.
    • For debug mode, your scripts can redefine it to return true instead.

These generated items are not exported by default. Additionally, it's configured for "release" mode by default so that release builds don't pay the extra JIT cost. When running tests, redefine X_asserts_enabled() = true.

Note that constants are not part of JIT recompilation, so a const global should never be defined in terms of the above macros.


A value (or values) that may or may not exist, based on a condition. Useful for conditionally passing something into a collection or function. E.x. print(a, " : ", b, @optional(i>0, " i=", i))


A keyword parameter to a function that may or may not exist. Example usage:

my_func(; @optionalkw(a>10, my_func_arg, a))

Prints the current file and line, along with any data you pass in. Helps pin down crashes that don't leave a clear stack trace.


Union of some outer type, specialized for many inner types. Examples:

  • @unionspec(Vector{_}, Int, Float64) == Union{Vector{Int}, Vector{Float64}}
  • @unionspec(Array{Bool, _}, 2, 4) == Union{Array{Bool, 2}, Array{Bool, 4}}

Any kind of contiguous data, suitable for passing into a C function as a raw pointer. Includes everything from a single bare element, to something like Vector{NTuple{4, v3f}}.

It's not actually possible to explicitly list the infinite variety of possible nestings, so this union currently supports up to 3 levels, which should be enough.


Collections which can be contiguous in memory, even when nested arbitrarily-many times. Includes the type itself, i.e. Int <: ContiguousRaw{Int}.

The length of these containers can be determined with only the type information.


A flat, contiguous collection of some type T. Includes the type itself, i.e. Int <: ContiguousSimple{Int}. A Ref{T} is assumed to have length 1.


An axis-aligned bounding box of some number of dimensions.

Can be deserialized through StructTypes using almost any pair of properties – 'min' + 'size'; 'min' + 'max'; 'max' + 'size'; 'center' + 'size', etc.


Constructs a Box covering the given range. Ignores the step size.


Ref to a contiguous set of data, possibly nested (e.x. Float32s in a Vector{NTuple{4, v3f}}). Note that the index is in terms of the individual contiguous elements.


The type for a matrix with the given rows, columns, and component type. The last parameter must be the number of elements (a.k.a. R*C).


Quaternions are great for representing 3D rotations. It is assumed to always be normalized, to optimize the math when reversing Quaternions and rotating vectors.


Indexes an array using the vector's reversed elements, so that for example the y component of a 2D index points to a row rather than a column. This is more intuitive when working with texture pixel arrays.

Also see the true_order argument for vsize().


A vector math struct. You can get its data from:

  • The field "data", e.x. v.data::NTuple
  • Individual XYZW or RGBA components, e.x. v1.x == v1.r
  • Swizzling, e.x. v.yyyz == Vec(v.y, v.y, v.y, v.z).

Swizzles can also use 0 for a constant 0, 1 for a constant 1, (\increment) for the max finite value, and (\nabla) for the min finite value. For example, Vec{UInt8}(128, 4, 200).rgb∆ results in Vec{UInt8}(128, 4, 200, 255).

Vec has an efficient implementation of AbstractVector, including map, foldl, etc, except for broadcasting because I don't know how to do it yet.

You can use the colon operator to iterate between two values (e.x. Vec(1, 1) : Vec(10, 10)).

To change how many digits are printed in the REPL and Base.show(), set VEC_N_DIGITS or call use_vec_digits() do ... end.

NOTE: Comparing two vectors with == or != returns a boolean as expected, but other comparisons (<, <=, >, >=) return a component-wise result.


Chain Quaternion rotations in the order signified by the arrow. E.x. a << b means "Rotate by b, then rotate by a".


Chain Quaternion rotations in the order signified by the arrow. E.x. a >> b means "Rotate by a, then rotate by b".


Gets whether the first box contains the second


Finds the minimum component which passes a given predicate


Calculate the intersection of two or more boxes. If they don't intersect, it will have 0 or negative size (see is_empty()).


Changes the dimensionality of the box. By default, new dimensions are given the size 1 (both for integer and float boxes).


Gets the total length of a contiguous array of T data, regardless of how deeply it's nested.

Note that there's an implementation limit on how deeply-nested the array can really be; see Contiguous{T} if you get MethodErrors.


Gets a Ptr{T} to an element of a contiguous array of T data, regardless of how deeply it's nested. Takes an index into the element (defaulting to 1), but be aware that this is on top of the Ref itself! If the Ref wasn't generated with contiguous_ref(), then it may already be offsetting from the first element.

Note that there's an implementation limit on how deeply-nested the array can really be; see Contiguous{T} if you get MethodErrors.


Gets the fractional part of f.

Negative values wrap around; for example fract(-0.1) == 0.9 (within floating-point error). This matches the behavior of GLSL's fract(), and I believe HLSL's frac() too.


Gets whether coordinate math is right-handed. By default, is true.

Redefine this (get_right_handed() = false) to make your project left-handed. Julia's JIT will allow it to act as a compile-time constant after the initial overhead of recompilation.

For example, you might want to do this if your game is primarily rendered through Dear ImGUI.


Gets the vertical axis – 1=X, 2=Y, 3=Z. By default, uses Z as the up-axis.

Redefine this (e.x. get_up_axis() = 2) to change the vertical axis for your project. Julia's JIT will allow it to act as a compile-time constant after the initial overhead of recompilation.


Gets the sign of the "Upward" direction of the vertical axis. For example, if get_up_axis()==3 && get_up_sign()==-1, then the "Up" direction is pointing in the -Z direction.

By default, points in the positive direction (i.e. returns -1).

Like get_up_axis(), you can redefine this to configure coordinate math for your project.


Finds the intersection(s) of a ray passing through a shape. Intersections are represented as distances along the ray. They are returned in ascending order (first intersection is the closest one).

Optional parameters:

  • min_t: the beginning of the ray. Defaults to 0.
  • max_t: the end of the ray. Defaults to the largest finite value.
  • atol: margin of error for various calculations.

For 3D shapes, you may pass an optional type param to add the first intersection's surface normal to the return value. The normal is undefined if there are no intersections.


The inverse of lerp(). Given a min, max, and value, finds the interpolant for that value.


Gets whether the point is fully inside the box, not touching the edges. This is primarily for integer boxes.


Linear interpolation: a smooth transition from a to b based on a t. t=0 results in a, t=1.0 results in b, t=0.5 results in the midpoint between them.

You may also pass a bool (or Vec of bools) for t.


Interpolation between two quaternions. It's simple (and fast) linear interpolation, which can lead to strange animations when tweening. Use q_slerp() instead for smoother rotations.


Builds the world-space matrix for an object with the given position, rotation, and scale.


Applies a transform matrix to the given coordinate, assuming the homogeneous component stays at 1.0 and does not need to be processed. This is generally true for world and view matrices, but not projection matrices.


Applies a transform matrix to the given vector (i.e. ignoring translation), assuming the homogeneous component stays at 1.0 and does not need to be processed. This is generally true for world and view matrices, but not projection matrices.


Highly customizable, N-dimensional Perlin noise. Output range is 0 - 1.

The seeds tuple provides extra seed data to the perlin gradient calculation.

prng_strength is a compile-time flag for the strength of the PRNG. Stronger ones require more warm-up time.

filter_pos can be used to implement wrapping or clamping.

t_curve can be used to change the smoothness of the noise by taking a linear t value and converting it to a smoother one. Best results come from a function with first- and second-derivatives of 0 at t=0 and t=1.


Interpolation between two rotations. The interpolation is nonlinear, following the surface of the unit sphere instead of a straight line from rotation 1 to rotation 2, but is a bit expensive to compute. The quaternions' 4 components must be normalized.


Normalizes a quaternion. You normally don't need to do this, but floating-point error can accumulate over time, causing quaternions to "drift" away from length 1.


Picks a random position within a unit radius sphere centered at the origin.

Requires 3 uniform-random values.


Rounds a value up to the nearest multiple of another value. Works with both integers and Vecs of integers (Vec{<:Integer}).

Behavior with float inputs is not defined, because I haven't bothered to think about it (feel free to do it yourself and update this comment!)

Behavior with negative inputs is not defined, because I haven't bothered to think about it (feel free to do it yourself and update this comment!)


An even smoother version of smoothstep(), at the cost of a little performance. Again, unlike lerp(), this function clamps t to the range (0, 1), as its behavior outside this range is not intuitive.


Smooth interpolation: a non-linear version of lerp that moves faster around 0.5 and slower around the ends (0 and 1), creating a more organic transition. Unlike lerp(), this function clamps t to the range (0, 1), as its behavior outside this range is not intuitive.


Does a cross product in the correct way to get a rightward vector from forward and upward ones


Constructs an orthogonal 3D vector basis as similar as possible to the input vectors. If the vectors are equal, then the up axis will usually be calculated with the global up axis. Returns the new forward and up vectors.


Converts a multidimensional array index to a flat one, assuming X is the innermost component


Converts a flat array index to a multidimensional one, assuming X is the innermost component


Like a binary version of lerp, or like step(). Returns components of a when t is false, or b when t is true.


Gets the size of an array as a Vec, rather than an NTuple.

If you pass true_order=true, then the elements of the vector will be reversed, so that for example y measures the number of rows in a 2D array rather than columns. Also see TrueOrdering.