The bivector.net ganja.js origami application example is now ported to Julia and GLMakie in example 3.4 of the Julia and Projective Geometric Algebra essay. (On my laptop computer, Julia and GLMakie generated the 66 second .mp4 video in 10.3 seconds.)

The example’s “REPL sandwich” starts with the following REPL session demonstrating the application’s fundamental rotation operation and that the direction of rotation depends upon the orientation of the rotor’s pivot line.

```
julia> include("ripga3d.jl"); # REPL 1 origami
julia> P = point(Float32.([ # PGA points
0 0 1;
0 0 0;
0 1 0]));
julia> PL = P[:,1] & P[:,2]; # Pivot Line
julia> R = rotor(pi/2, PL);
julia> result = toCoord(R >>> P[:,3])
3-element Vector{Float32}:
0.0
0.99999994
0.0
julia> PL2 = P[:,2] & P[:,1]; # Pivot Line 2
julia> R2 = rotor(pi/2, PL2); # Rotor 2
julia> result2 = toCoord(R2 >>> P[:,3])
3-element Vector{Float32}:
0.0
-0.99999994
```

A common argument against using PGA is that it inefficiently takes 16 floats to store a 3D point instead of just three. However in many PGA applications, only a small portion of the 3D points are converted to PGA points at any one time. For example in this origami application, all the vertices are stored in a Makie mesh and only the vertices in that mesh currently being rotated during a fold are temporarily converted to PGA points. Therefore the second REPL session in the origami example’s REPL sandwich shows how to construct a Makie mesh directly from 3D points (e.g., after being rotated using PGA).

```
julia> include("ripga3d.jl"); # REPL 2 origami
julia> using GLMakie;
julia> using GeometryBasics;
julia> PC = Float32.([ # Point Coordinates
0 0 1;
0 0 0;
0 1 0]);
julia> V = Point{3, Float32}[]; # mesh Vertices
julia> push!(V,PC[:,1]); push!(V,PC[:,2]); push!(V,PC[:,3]);
julia> F = TriangleFace{Int64}[]; # mesh Faces
julia> push!(F,[1,2,3]);
julia> result = GeometryBasics.Mesh(V,F)
Mesh{3, Float32, Triangle}:
Triangle(Float32[0.0, 0.0, 0.0], Float32[0.0, 0.0, 1.0], Float32[1.0, 0.0, 0.0])
```