Hoping to show GLMakie can do something similar to ganja.js in displaying an interactive demonstration of the projective geometric algebra inverse kinematics algorithm (in the demonstration, a user drags around the target and the robot arm follows), I added a function iik() (i.e., interactive inverse kinematics) and it works:
 # pga2d3d_ik.jl
# interactive graphical demo of Inverse Kinematics
using GLMakie
include("ripga3d.jl") 
# translate distance along line
function xlator(line::Vector{Float32},dist::Number) 
#	return 1 - dist/2*(e0*normalize(line)*!e0)
	return ga"1 - dist/2 (e0 normalize(line) e0∗)"
end
# inverse kinematics algorithm; plot of convergence rate
# arguments:
# - coordinates of target
# - number of links in robot arm
function ik(target::Vector{Float64}=[2.5,2.,0.], nLink::Int64=6)
	nEP = nLink + 1	# number of link endpoints
	armLength = 3	# max reach of robot arm
	
	# initialize figure
	fig = Figure(resolution = (1800, 800))
	C = ["red"; "green"; "blue"] # line colors
	LIM = (-2,3, -2.5,2.5)
	YTIC = (-2:1:2)
	AX = [
		Axis(fig[1,1], limits=LIM, yticks=YTIC, aspect=1,
			title = "1. initial endpoints,\n" *
				"the target is separate from robot arm");
		Axis(fig[1,2], limits=LIM, yticks=YTIC, aspect=1,
			title = "2. endpoints after 1st pass\n" *
				"of backward relaxation");
		Axis(fig[1,3], limits=LIM, yticks=YTIC, aspect=1, 
			title = "3. endpoints after 1st pass\n" *
				"of forward relaxation");
		Axis(fig[1,4], limits=LIM, yticks=YTIC, aspect=1,
			title = "4. endpoints after 2nd pass\n" *
				"of backward relaxation");
		Axis(fig[1,5], limits=LIM, yticks=YTIC, aspect=1, 
			title = "5. endpoints after 2nd pass\n" *
				"of forward relaxation");
		Axis(fig[2,2], limits=LIM, yticks=YTIC, aspect=1,
			title = "6. endpoints after 3rd pass\n" *
				"of backward relaxation");
		Axis(fig[2,3], limits=LIM, yticks=YTIC, aspect=1, 
			title = "7. endpoints after 3rd pass\n" *
				"of forward relaxation");
		Axis(fig[2,4], limits=LIM, yticks=YTIC, aspect=1,
			title = "8. endpoints after 4th pass\n" *
				"of backward relaxation");
		Axis(fig[2,5], limits=LIM, yticks=YTIC, aspect=1, 
			title = "9. endpoints after 4th pass\n" *
				"of forward relaxation");
	]
	
	# allocate endpoint PGA expressions
	# (appended endpoint in last column is target)
	PX = Matrix{Float32}(undef, (length(e0),nEP+1))
	
	# define link endpoints
	linkLength::Float32 = armLength / nLink
	for iEP = 1:nEP
#		PX[:,iEP] = !(e0 + (iEP*linkLength - 1.5)*e1)
		PX[:,iEP] = ga"(e0 + (iEP linkLength - 1.5) e1)∗"
	end
	PX[:,nEP+1] = point(target[1], target[2], target[3])
	
	# plot link endpoints and target point
	P = toPlot(PX)
	iAx = 1
	scatterlines!(AX[iAx], P[1:3,1:nEP], color="black")
	scatterlines!(AX[iAx], # target point is at end
		[P[1,end]], [P[2,end]], [P[3,end]],
		color="black")
	
	# plot results of each relaxation loop
	for iRelax = 1:4
		# set tip to target, changing length of last link
		PX[:,nEP] = PX[:,nEP+1]
		P = toPlot(PX)
		
		# restore link lengths from back to front
		iAx += 1
		scatterlines!(AX[iAx],
			P[1:3,1:nEP], color = "light gray")
		for jLink = 1:nEP-2
			i = nEP - jLink
			iColor = mod(jLink-1,3) + 1
#			XL = xlator( # define translation along line
#				PX[:,i+1] & PX[:,i], linkLength)
#			PX[:,i] = XL >>> PX[:,i+1] # perform translation
			XL = xlator(ga"PX[:,i+1] ∨ PX[:,i]", linkLength)
			PX[:,i] = ga"XL PX[:,i+1] ~XL" # perform translation
			P = toPlot(PX)
			if i > 2
				scatterlines!(AX[iAx],
					P[1:3,i:i+1], color = C[iColor])
			else
				scatterlines!(AX[iAx],
					P[1:3,i-1:i+1], color = C[iColor])
			end
		end
		
		# restore link lengths from front to back
		iAx += 1
		scatterlines!(AX[iAx],
			P[1:3,1:nEP], color = "light gray")
		for i = 2:nEP
			iColor = mod(i-2,3) + 1
#			XL = xlator( # define translation along line
#				PX[:,i-1] & PX[:,i], linkLength)
#			PX[:,i] = XL >>> PX[:,i-1] # perform translation
			XL = xlator(ga"PX[:,i-1] ∨ PX[:,i]", linkLength)
			PX[:,i] = ga"XL PX[:,i-1] ~XL" # perform translation
			P = toPlot(PX)
			scatterlines!(AX[iAx],
				P[1:3,i-1:i], color = C[iColor])
		end
	end
	fig
end
function ik_solver(PX::Matrix{Float32},linkLength::Float32)
	nEP = size(PX,2) - 1 # -1 because last column is target
	
	# for each relaxation pass
	for iRelax = 1:4
		# set tip to target, changing length of last link
		PX[:,nEP] = PX[:,nEP+1]
		
		# restore link lengths from back to front
		for jLink = 1:nEP-2
			i = nEP - jLink
#			XL = xlator( # define translation along line
#				PX[:,i+1] & PX[:,i], linkLength)
#			PX[:,i] = XL >>> PX[:,i+1] # perform translation
			XL = xlator(ga"PX[:,i+1] ∨ PX[:,i]", linkLength)
			PX[:,i] = ga"XL PX[:,i+1] ~XL" # perform translation
		end
		
		# restore link lengths from front to back
		for i = 2:nEP
#			XL = xlator( # define translation along line
#				PX[:,i-1] & PX[:,i], linkLength)
#			PX[:,i] = XL >>> PX[:,i-1] # perform translation
			XL = xlator(ga"PX[:,i-1] ∨ PX[:,i]", linkLength)
			PX[:,i] = ga"XL PX[:,i-1] ~XL" # perform translation
		end
	end
end
# interactive inverse kinematics
# arguments:
# - coordinates of target of robot arm
# - number of links in robot arm
function iik(target::Vector{Float64}=[2.5,2.,0.], nLink::Int64=6)
	nEP = nLink + 1	# number of link endpoints
	armLength = 3	# max reach of robot arm
	# initialize figure
	fig = Figure(resolution = (800, 800))
	LIM = (-2,3, -2.5,2.5)
	YTIC = (-2:1:2)
	ax1 = Axis(fig[1,1], limits=LIM, yticks=YTIC, aspect=1,
		title = "Interactive demonstration of inverse kinematics algorithm.\n" *
			"(The target point is initially separated from the robot arm.\n" *
			"Drag that target point around to see how the robot arm reacts.)")
	# allocate and define endpoint PGA expressions
	# (appended endpoint in last column is target)
	PX = Matrix{Float32}(undef, (length(e0),nEP+1))
	linkLength::Float32 = armLength / nLink
	ANCHOR = [-1; 0; 0]
	for iEP = 1:nEP
#		PX[:,iEP] = !(e0 + ((iEP-1)*linkLength + ANCHOR[1])*e1)
		PX[:,iEP] = ga"(e0 + ((iEP-1) linkLength + ANCHOR[1]) e1)∗"
	end
	PX[:,nEP+1] = point(target[1], target[2], target[3])
	# calculate inverse kinematics
	ik_solver(PX, linkLength)
	P = toPlot(PX) # convert PGA expressions to Euclidean coordinates
	# define observables for plotting
	RDATA = Observable(P[1:3,1:nEP]) # robot coordinates
	TDATA = Observable([ANCHOR P[1:3,end]]) # target coordinates
	# plot robot and target coordinates
	scatterlines!(ax1, RDATA, color="black")
	scatter!(ax1, TDATA, color="red")
	deregister_interaction!(ax1, :rectanglezoom)
	register_interaction!(ax1, :my_mouse_interaction) do event::MouseEvent, axis
		if Makie.is_mouseinside(ax1.scene)
			if event.type === MouseEventTypes.leftdrag
				PX[:,end] = point(event.data[1], event.data[2], 0)
				ik_solver(PX,linkLength)
				P = toPlot(PX)
				RDATA[] = P[1:3,1:nEP] # update the plotted observables to 
				TDATA[] = [ANCHOR P[1:3,end]] # automatically update the plot
			end
		end
	end
	fig
end
However, after reading this recent post, I realized that I too was unknowingly using a very old version (0.4.4) of GLMakie:
(@v1.8) pkg> status GLMakie
Status `C:\Users\gsgm2\.julia\environments\v1.8\Project.toml`
⌃ [e9467ef8] GLMakie v0.4.4
julia> Pkg.update()
    Updating registry at `C:\Users\gsgm2\.julia\registries\General.toml`
   Installed GR_jll ─ v0.71.3+0
   Installed PyCall ─ v1.95.0
   Installed Plots ── v1.38.1
   Installed GR ───── v0.71.3
  Downloaded artifact: GR
    Updating `C:\Users\gsgm2\.julia\environments\v1.8\Project.toml`
  [91a5bcdd] ↑ Plots v1.38.0 ⇒ v1.38.1
    Updating `C:\Users\gsgm2\.julia\environments\v1.8\Manifest.toml`
  [28b8d3ca] ↑ GR v0.71.2 ⇒ v0.71.3
  [91a5bcdd] ↑ Plots v1.38.0 ⇒ v1.38.1
  [438e738f] ↑ PyCall v1.94.1 ⇒ v1.95.0
  [d2c73de3] ↑ GR_jll v0.71.2+0 ⇒ v0.71.3+0
    Building PyCall → `C:\Users\gsgm2\.julia\scratchspaces\44cfe95a-1eb2-52ea-b672-e2afdf69b78f\b32c4b415f41f10c671cba02ae3275027dea8892\build.log`
Precompiling project...
  5 dependencies successfully precompiled in 44 seconds. 262 already precompiled.
[ Info: We haven't cleaned this depot up for a bit, running Pkg.gc()...
      Active manifest files: 2 found
      Active artifact files: 115 found
      Active scratchspaces: 13 found
     Deleted no artifacts, repos, packages or scratchspaces
julia> Pkg.status("GLMakie")
Status `C:\Users\gsgm2\.julia\environments\v1.8\Project.toml`
⌃ [e9467ef8] GLMakie v0.4.4
Info Packages marked with ⌃ have new versions available and may be upgradable.
julia>
What is the best practice for updating to a newer version of the GLMakie package?