<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dw="https://www.dreamwidth.org">
  <id>tag:dreamwidth.org,2010-04-27:505737</id>
  <title>The Mandelbear's Musings</title>
  <subtitle>mdlbear</subtitle>
  <author>
    <name>mdlbear</name>
  </author>
  <link rel="alternate" type="text/html" href="https://mdlbear.dreamwidth.org/"/>
  <link rel="self" type="text/xml" href="https://mdlbear.dreamwidth.org/data/atom"/>
  <updated>2018-10-23T00:27:41Z</updated>
  <dw:journal username="mdlbear" type="personal"/>
  <entry>
    <id>tag:dreamwidth.org,2010-04-27:505737:1639781</id>
    <link rel="alternate" type="text/html" href="https://mdlbear.dreamwidth.org/1639781.html"/>
    <link rel="self" type="text/xml" href="https://mdlbear.dreamwidth.org/data/atom/?itemid=1639781"/>
    <title>Further Adventures in Hyperspace</title>
    <published>2018-10-23T00:11:06Z</published>
    <updated>2018-10-23T00:27:41Z</updated>
    <category term="strong-typing"/>
    <category term="hyperviewer"/>
    <category term="programming"/>
    <category term="math"/>
    <category term="curmudgeon"/>
    <category term="javascript"/>
    <category term="4-d"/>
    <dw:mood>didactic</dw:mood>
    <dw:security>public</dw:security>
    <dw:reply-count>1</dw:reply-count>
    <content type="html">&lt;p&gt;You may remember from &lt;a href="2018-10-08-adventures-in-hyperspace.md"&gt;my previous post about
Hyperviewer&lt;/a&gt; that I’d been plagued by
a mysterious bug.  The &lt;em&gt;second&lt;/em&gt; time the program tried to make a simplex (the
N-dimensional version of a triangle (N=2) or tetrahedron (N=3), a whole batch
of “ghost edges” appeared and the program (quite understandably) blew up.  I
didn’t realize it until somewhat later, but there were ghost &lt;em&gt;vertices&lt;/em&gt; as
well, and that was somewhat more fundamental.  Basically, &lt;code&gt;nVertices&lt;/code&gt;, the
field that holds the number of vertices in the polytope, was wildly wrong.&lt;/p&gt;

&lt;h2&gt;Chasing ghosts&lt;/h2&gt;

&lt;p&gt;Eventually I narrowed things down to someplace around here, which is where
things stood at the end of the previous post.&lt;/p&gt;

&lt;div class="language-javascript highlighter-coderay"&gt;&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="line-numbers"&gt;&lt;a href="#n1" name="n1"&gt;1&lt;/a&gt;&lt;/span&gt;        let vertices = [];
&lt;span class="line-numbers"&gt;&lt;a href="#n2" name="n2"&gt;2&lt;/a&gt;&lt;/span&gt;        &lt;span style="color:#777"&gt;/* something goes massively wrong, right here. */&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n3" name="n3"&gt;3&lt;/a&gt;&lt;/span&gt;        &lt;span style="color:#080;font-weight:bold"&gt;for&lt;/span&gt; (let i = &lt;span style="color:#00D"&gt;0&lt;/span&gt;; i &amp;lt; dim; ++i) {
&lt;span class="line-numbers"&gt;&lt;a href="#n4" name="n4"&gt;4&lt;/a&gt;&lt;/span&gt;            vertices.push(&lt;span style="color:#080;font-weight:bold"&gt;new&lt;/span&gt; vector(dim).fill((j) =&amp;gt; i === j? &lt;span style="color:#60E"&gt;1.0&lt;/span&gt; : &lt;span style="color:#00D"&gt;0&lt;/span&gt;));
&lt;span class="line-numbers"&gt;&lt;a href="#n5" name="n5"&gt;5&lt;/a&gt;&lt;/span&gt;        }
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;I found this by throwing an error, with a big data dump, right in the middle
if &lt;code&gt;nVertices&lt;/code&gt; was wrong (it’s supposed to be &lt;code&gt;dim+&lt;/code&gt;), or if the length of the
list of vertices was different from &lt;code&gt;nVertices&lt;/code&gt;.&lt;/p&gt;

&lt;div class="language-javascript highlighter-coderay"&gt;&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="line-numbers"&gt; &lt;a href="#n1" name="n1"&gt;1&lt;/a&gt;&lt;/span&gt;        let vertices = [];
&lt;span class="line-numbers"&gt; &lt;a href="#n2" name="n2"&gt;2&lt;/a&gt;&lt;/span&gt;        &lt;span style="color:#777"&gt;/* something goes massively wrong, right here. */&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n3" name="n3"&gt;3&lt;/a&gt;&lt;/span&gt;        &lt;span style="color:#080;font-weight:bold"&gt;if&lt;/span&gt; (&lt;span style="color:#950"&gt;this&lt;/span&gt;.nVertices !== (dim + &lt;span style="color:#00D"&gt;1&lt;/span&gt;) || &lt;span style="color:#950"&gt;this&lt;/span&gt;.nEdges !== ((dim + &lt;span style="color:#00D"&gt;1&lt;/span&gt;) * dim / &lt;span style="color:#00D"&gt;2&lt;/span&gt;) ||
&lt;span class="line-numbers"&gt; &lt;a href="#n4" name="n4"&gt;4&lt;/a&gt;&lt;/span&gt;            &lt;span style="color:#950"&gt;this&lt;/span&gt;.vertices.length !== &lt;span style="color:#00D"&gt;0&lt;/span&gt; || &lt;span style="color:#950"&gt;this&lt;/span&gt;.edges.length !== &lt;span style="color:#00D"&gt;0&lt;/span&gt; ) {
&lt;span class="line-numbers"&gt; &lt;a href="#n5" name="n5"&gt;5&lt;/a&gt;&lt;/span&gt;            &lt;span style="color:#080;font-weight:bold"&gt;throw&lt;/span&gt; &lt;span style="color:#080;font-weight:bold"&gt;new&lt;/span&gt; Error(&lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#D20"&gt;nEdges = &lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + &lt;span style="color:#950"&gt;this&lt;/span&gt;.nEdges + &lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#D20"&gt; want &lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +  ((dim + &lt;span style="color:#00D"&gt;1&lt;/span&gt;) * dim / &lt;span style="color:#00D"&gt;2&lt;/span&gt;) +
&lt;span class="line-numbers"&gt; &lt;a href="#n6" name="n6"&gt;6&lt;/a&gt;&lt;/span&gt;                            &lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#D20"&gt;; nVertices = &lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + &lt;span style="color:#950"&gt;this&lt;/span&gt;.nVertices + &lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#D20"&gt; want &lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + dim +
&lt;span class="line-numbers"&gt; &lt;a href="#n7" name="n7"&gt;7&lt;/a&gt;&lt;/span&gt;                            &lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#D20"&gt;; vertices.length = &lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + &lt;span style="color:#950"&gt;this&lt;/span&gt;.vertices.length +
&lt;span class="line-numbers"&gt; &lt;a href="#n8" name="n8"&gt;8&lt;/a&gt;&lt;/span&gt;                            &lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;span style="color:#D20"&gt; at this point in the initialization, where dim = &lt;/span&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;/span&gt; + dim +
&lt;span class="line-numbers"&gt; &lt;a href="#n9" name="n9"&gt;9&lt;/a&gt;&lt;/span&gt;                            &lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#D20"&gt; in &lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + &lt;span style="color:#950"&gt;this&lt;/span&gt;.dimensions + &lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;span style="color:#D20"&gt;-D &lt;/span&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;/span&gt; + &lt;span style="color:#950"&gt;this&lt;/span&gt;.name 
&lt;span class="line-numbers"&gt;&lt;strong&gt;&lt;a href="#n10" name="n10"&gt;10&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;                           );
&lt;span class="line-numbers"&gt;&lt;a href="#n11" name="n11"&gt;11&lt;/a&gt;&lt;/span&gt;        } 
&lt;span class="line-numbers"&gt;&lt;a href="#n12" name="n12"&gt;12&lt;/a&gt;&lt;/span&gt;        &lt;span style="color:#080;font-weight:bold"&gt;for&lt;/span&gt; (let i = &lt;span style="color:#00D"&gt;0&lt;/span&gt;; i &amp;lt; dim; ++i) {
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;It appeared that &lt;code&gt;nVertices&lt;/code&gt; was wildly wrong at that point.  If I’d looked
carefully and thought about what &lt;code&gt;nVertices&lt;/code&gt; actually &lt;em&gt;was&lt;/em&gt;, I would probably
have found the bug at that point.  Or even earlier.  Instead, what clinched it
was this:&lt;/p&gt;

&lt;div class="language-javascript highlighter-coderay"&gt;&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="line-numbers"&gt; &lt;a href="#n1" name="n1"&gt;1&lt;/a&gt;&lt;/span&gt;        &lt;span style="color:#950"&gt;this&lt;/span&gt;.vertices = vertices;
&lt;span class="line-numbers"&gt; &lt;a href="#n2" name="n2"&gt;2&lt;/a&gt;&lt;/span&gt;        &lt;span style="color:#950"&gt;this&lt;/span&gt;.nVertices = vertices.length;  &lt;span style="color:#777"&gt;// setting this to dim+1 FAILS:&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n3" name="n3"&gt;3&lt;/a&gt;&lt;/span&gt;        &lt;span style="color:#777"&gt;// in other words, this.nVertices is getting changed between these two statements!&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n4" name="n4"&gt;4&lt;/a&gt;&lt;/span&gt;        &lt;span style="color:#080;font-weight:bold"&gt;if&lt;/span&gt; (&lt;span style="color:#950"&gt;this&lt;/span&gt;.vertices.length !== &lt;span style="color:#950"&gt;this&lt;/span&gt;.nVertices || &lt;span style="color:#950"&gt;this&lt;/span&gt;.edges.length !== &lt;span style="color:#00D"&gt;0&lt;/span&gt;) {
&lt;span class="line-numbers"&gt; &lt;a href="#n5" name="n5"&gt;5&lt;/a&gt;&lt;/span&gt;            &lt;span style="color:#080;font-weight:bold"&gt;throw&lt;/span&gt; &lt;span style="color:#080;font-weight:bold"&gt;new&lt;/span&gt; Error(&lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#D20"&gt;expect &lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + &lt;span style="color:#950"&gt;this&lt;/span&gt;.nVertices + &lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#D20"&gt; verts, have &lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + &lt;span style="color:#950"&gt;this&lt;/span&gt;.vertices.length +
&lt;span class="line-numbers"&gt; &lt;a href="#n6" name="n6"&gt;6&lt;/a&gt;&lt;/span&gt;                            &lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#D20"&gt; in &lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + &lt;span style="color:#950"&gt;this&lt;/span&gt;.dimensions + &lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;span style="color:#D20"&gt;-D &lt;/span&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;/span&gt; + &lt;span style="color:#950"&gt;this&lt;/span&gt;.name +
&lt;span class="line-numbers"&gt; &lt;a href="#n7" name="n7"&gt;7&lt;/a&gt;&lt;/span&gt;                            &lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#D20"&gt;; want &lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + &lt;span style="color:#950"&gt;this&lt;/span&gt;.nEdges + &lt;span style="background-color:hsla(0,100%,50%,0.05)"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:#D20"&gt; edges into &lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + &lt;span style="color:#950"&gt;this&lt;/span&gt;.edges.length
&lt;span class="line-numbers"&gt; &lt;a href="#n8" name="n8"&gt;8&lt;/a&gt;&lt;/span&gt;                           );
&lt;span class="line-numbers"&gt; &lt;a href="#n9" name="n9"&gt;9&lt;/a&gt;&lt;/span&gt;        }
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The code that creates the list of vertices produces the right number of
vertices.  If I set &lt;code&gt;nVertices&lt;/code&gt; equal to the length of that list, everything
was fine.&lt;/p&gt;

&lt;p&gt;If instead I set&lt;/p&gt;

&lt;div class="language-javascript highlighter-coderay"&gt;&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="line-numbers"&gt;&lt;a href="#n1" name="n1"&gt;1&lt;/a&gt;&lt;/span&gt;        &lt;span style="color:#950"&gt;this&lt;/span&gt;.nVertices = dim+&lt;span style="color:#00D"&gt;1&lt;/span&gt;;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;it was wrong.  Huh?  For example, in four dimensions, the number of vertices
is supposed to be five, and that was the length of the list.  When is &lt;code&gt;4+1&lt;/code&gt;
not equal to &lt;code&gt;5&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;At this point a light bulb went off, because it was clear that &lt;code&gt;dim+1&lt;/code&gt; was
coming out equal to 41.  In three dimensions it was 31.  When is &lt;code&gt;4+1&lt;/code&gt; not
equal to 5?  When it’s actually &lt;code&gt;"4"+1&lt;/code&gt;.  In other words, &lt;code&gt;dim&lt;/code&gt; was a string.
JavaScript “helpfully” converts a string to a number when you do anything
arithmetical to it, like multiply it by something or raise it to a power.  But
&lt;code&gt;+&lt;/code&gt; isn’t always an arithmetic operation!  In JavaScript (and many other
languages) it’s also used for &lt;em&gt;string concatenation&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;What went wrong, and a rant&lt;/h2&gt;

&lt;p&gt;The problem was that, the &lt;em&gt;second&lt;/em&gt; time I tried to create a simplex, the
number of dimensions was coming from the user interface.  From an &lt;code&gt;&amp;lt;input&lt;/code&gt;
element in a web form.  And every value that you get from a web form is a
string.  HTML knows nothing about numbers, and it has no way to know what
you’re going to do with the input you get.&lt;/p&gt;

&lt;p&gt;So the fix was simple (and you can see it &lt;a href="https://github.com/ssavitzky/hyperviewer/commit/8bef087648d403a9ba432058fc4641e582b27250"&gt;here on
GitHub&lt;/a&gt;:
convert the value from a string to a number right off before trying to use it
as a number of dimensions.  But… But…  But cubes and octohedrons were
&lt;em&gt;right!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That’s because the number of vertices in a N-cube is &lt;code&gt;2**N&lt;/code&gt;, and in an
N-orthoplex (octohedron in three dimensions) it’s &lt;code&gt;N*2&lt;/code&gt; (and multiplication is
always an arithmetic operator in JavaScript).  And it worked when I
was creating the simplex’s vertices because it was being compared against in a
&lt;code&gt;for&lt;/code&gt; loop.  And so on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If I’d been using a strongly-typed language, the compiler would have found
this two weeks ago.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are two main ways of dealing with data in a programming language, called
“strong typing” and “dynamic typing”.  In a strongly-typed language, both
values and variables (the boxes you put values into) have types (like “string”
or “integer”), and the types have to match.  You can’t put a string into a
variable with a type of integer.  Java is like that (mostly).&lt;/p&gt;

&lt;p&gt;Some people find this burdensome, and they prefer dynamically-typed languages
like JavaScript.  In JavaScript, &lt;em&gt;values&lt;/em&gt; have types, but variables don’t.
It’s called “dynamic” typing because a variable can hold anything, and its
type is that of the last thing that was put into it.&lt;/p&gt;

&lt;p&gt;You can write code very quickly in a language where you don’t have to declare
your variables and make sure they’re the right type for the kind of values you
want to put into them.  You can also shoot yourself in the foot much more
easily.&lt;/p&gt;

&lt;p&gt;There are a couple of strongly-typed variants on JavaScript, for example
CoffeeScript and TypeScript, and a type-checker called “Flow”.  I’m going to
try one of those next.&lt;/p&gt;

&lt;h2&gt;There was one more problem with simplexes&lt;/h2&gt;

&lt;p&gt;(simplices?) … but that was purely geometrical, and just because I was
trying to do all the geometry in my head instead of on paper, and wasn’t
thinking things through.&lt;/p&gt;

&lt;p&gt;If you’re in N dimensions, you can create an N-1 dimensional simplex by simply
connecting the points with coordinates like &lt;code&gt;[1,0,0]&lt;/code&gt;, &lt;code&gt;[0,1,0]&lt;/code&gt;, and
&lt;code&gt;[0,0,1]&lt;/code&gt; (in three dimensions – it’s pretty easy to see that that gives you
an equilateral triangle).  Moreover, all the vertices are on the unit sphere,
which is where we want them.  The last vertex is a bit of a problem.&lt;/p&gt;

&lt;p&gt;A fair amount of googling around (or DuckDuckGoing around, in my case) will
eventually turn up &lt;a href="mathoverflow.net/questions/38724/coordinates-of-vertices-of-regular-simplex"&gt;this answer on
mathoverflow.net&lt;/a&gt;,
which says that in N dimensions, the last vertex has to be at &lt;code&gt;[x,...,x]&lt;/code&gt;
where &lt;code&gt;x=-1/(1+sqrt(1+N))&lt;/code&gt;.  Cool!  And it works.  Except that it’s not
centered – that last vertex is a lot closer to the origin than the others.
It took me longer than it should have to get this right, but the center of the
simplex is its “center of mass”, which is simply the average of all the
vertices.  So that’s at &lt;code&gt;y=(1+x)/(N+1)&lt;/code&gt; because there are N+1 vertices.  Now
we just have to subtract y from all the coordinates to shift it over until the
center is at the origin.&lt;/p&gt;

&lt;p&gt;Then of course we have to scale it so that all the vertices are back on the
unit sphere.  You can find the code &lt;a href="https://github.com/ssavitzky/hyperviewer/blob/794f406d8de7af4dd55ded5f21d46237bf76a5bd/src/polytopes.js#L128-L140"&gt;here, on
GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Another fine post from &lt;a href="https://computer-curmudgeon.com"&gt;The Computer Curmudgeon&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mdlbear&amp;ditemid=1639781" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2010-04-27:505737:1638548</id>
    <link rel="alternate" type="text/html" href="https://mdlbear.dreamwidth.org/1638548.html"/>
    <link rel="self" type="text/xml" href="https://mdlbear.dreamwidth.org/data/atom/?itemid=1638548"/>
    <title>Adventures in Hyperspace (and Javascript)</title>
    <published>2018-10-09T04:01:55Z</published>
    <updated>2018-10-09T15:13:54Z</updated>
    <category term="math"/>
    <category term="hyperviewer"/>
    <category term="programming"/>
    <category term="4-d"/>
    <category term="javascript"/>
    <category term="curmudgeon"/>
    <category term="development"/>
    <dw:mood>didactic</dw:mood>
    <dw:security>public</dw:security>
    <dw:reply-count>2</dw:reply-count>
    <content type="html">&lt;p&gt; (This will be something of an experiment.  The original was written in
    markdown and posted on &lt;a href="https://computer-curmudgeon.com/2018/10/08/adventures-in-hyperspace.html"&gt;Computer-Curmudgeon.com&lt;/a&gt;.  We'll see whether the process made a hash
    of it.  I may have to do some cleaning up.

&lt;p&gt;This post is about &lt;a href="http://github.com/ssavitzky/hyperviewer"&gt;Hyperviewer&lt;/a&gt;, an update of a &lt;a href="https://github.com/ssavitzky/ncube/"&gt;very old demo program of mine&lt;/a&gt; from 1988 that displays wireframe objects rotating in hyperspace. (Actually, anywhere between four and six dimensions.) Since this is 2018, I naturally decided to write it in JavaScript, using &lt;a href="https://infernojs.org/"&gt;Inferno&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG"&gt;SVG&lt;/a&gt;, and put it on the web. It was a learning experience, in more ways than one.&lt;/p&gt;

&lt;h2&gt;Getting started&lt;/h2&gt;
&lt;p&gt;I had been doing a little work with &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt;, which is pretty good an very popular, and had recently read about &lt;a href="https://infernojs.org/"&gt;Inferno&lt;/a&gt;, which is a lighter-weight, faster framework that's almost completely interchangeable with React. Sounded good, especially since I wanted high performance for something that's going to be doing thousands of floating-point matrix multiplies per second. (A hypercube in N dimensions has 2^N vertices, and a rotation matrix has N^2 entries -- do the math). (It turns out I really didn't have to worry -- Moore's Law over three decades gives a speedup by a factor of a million, give or take a few orders of magnitude, so even using an partially-interpreted language speed isn't a problem. Perhaps I'm showing my age.)&lt;/p&gt;
&lt;p&gt;To keep things simple -- and make it possible to eventually save pictures -- I decided to use SVG: the web standard for &lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG"&gt;Scalable Vector Graphics&lt;/a&gt;, rather than trying to draw them out using an HTML5 &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API"&gt;Canvas&lt;/a&gt; tag. It's a perfect match for something that's nothing but a bunch of vectors. SVG is XML-based, and you can simply drop it into the middle of an HTML page. SVG is also &lt;em&gt;really&lt;/em&gt; easy to generate using the new JSX format, which is basically XML tags embedded in a JavaScript file.&lt;/p&gt;
&lt;p&gt;Modern JavaScript uses a program called a &amp;quot;transpiler&amp;quot; -- the most common one is &lt;a href="https://babeljs.io/"&gt;Babel&lt;/a&gt; -- that compiles shiny new JavaScript constructs (and even some new languages like TypeScript and CoffeeScript, which I want to learn soon) into the kind of plain old JavaScript that almost any browser can understand. (There are still some people using Microsoft Exploiter from the turn of the &lt;del&gt;century&lt;/del&gt; &lt;em&gt;millennium&lt;/em&gt;; if you're reading this blog it's safe for me to assume that you aren't one of them.)&lt;/p&gt;
&lt;p&gt;Anyway, let's get started:&lt;/p&gt;
&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://mdlbear.dreamwidth.org/1638548.html#cutid1"&gt;cut tag added to protect your sanity&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;
&lt;p&gt; (Not too bad of a formatting job, though of course the color didn't come through.  Cut tag added because it's over 2000 words.)




&lt;p&gt; &lt;em&gt;Another fine post from
    &lt;a href="https://mdlbear.dreamwidth.org/tag/curmudgeon"&gt;The Computer Curmudgeon&lt;/a&gt;.
&lt;br /&gt; Cross-posted on &lt;a href="https://computer-curmudgeon.com/2018/10/08/adventures-in-hyperspace.html"&gt;computer-curmudgeon.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mdlbear&amp;ditemid=1638548" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
</feed>
