Skip to main content
Logo image

Section 13 Interactive Elements, Authored in Javascript

When outputting Web page versions, it is possible to embed a variety of dynamic interactive elements. In a /PDF version, these will necessarily need to be replaced by some static substitute, such as a screenshot. See Section 3 for the specifics of embedding instances of the Sage Cell Server, which is more elaborate, and not entirely similar.
Interactives in this section are those for which you provide code you have authored. Generally, the libraries involved to support this have open licenses, though the player for GeoGebra may be an exception. Creating these assumes some familiarity with HTML and Javascript. See Section 14 for more interactives that are perhaps simpler to create or use.
(2018-06-22) Almost everything in this section is under active development and not stable yet. Feel free to experiment and make suggestions and requests. This page takes a while to completely load, so be patient.

Subsection 13.1 HTML5 Canvas

HTML5 introduced the <canvas> element, which can be thought of a blank slate, a place to draw or write on. So PreTeXt has the <slate> element for a similar purpose. Generally, but not exclusively, HTML5 writes on a <canvas> using the Javascript language. We demonstrate this approach to interactive diagrams in this subsection.
The following examples are from David Austin’s excellent Understanding Linear Algebra
 1 
merganser.math.gvsu.edu/david/linear.algebra/ula/index.html
textbook, which can be found at
merganser.math.gvsu.edu/david/linear.algebra/ula/index.html
David’s contribution of examples, and assistance designing the PreTeXt elements is greatly appreciated. Alright, let’s learn some linear algebra. Yes, there are some learning opportunities in this subsection.

Instructions.

Let \(\vec{x}\) be represented by the red arrow, and \(A\vec{x}\) by the grey arrow, for some particular \(2\times 2\) matrix \(A\text{.}\) Drag the tip of the red arrow to see the grey arrow change.
Figure 13.1. A simple eigenvector demonstration

Checkpoint 13.2.

The interactive in Figure 13.1 shows a vector \(\vec{x}\) in red, and the matrix-vector product \(A\vec{x}\) in grey, for a particular \(2\times 2\) matrix \(A\text{.}\) The four entries of the matrix \(A\) are coded into the interactive. Can you deduce \(A\) simply by using the interactive? Which theorem is the key?

Instructions.

Let \(\vec{x}\) be represented by the red arrow, and \(A\vec{x}\) by the grey arrow, for a \(2\times 2\) matrix \(A\text{.}\) Drag the tip of the red arrow to see the grey arrow change. Or drag the blue sliders to change the numerical values of the four entries of the \(2\times 2\) matrix \(A\text{.}\) You will not see the grey vector until you change the matrix using one of the two sliders on the left. Why is that? What are the eigenvectors of the initial matrix?
Figure 13.3. Eigenvector demonstration
The next example has ten <slate> elements communicating with each other, and arranged with the layout features of a <sidebyside> (see Section 25).

Flipping Woody

Parameters \(a\text{,}\) \(b\text{,}\) \(d\text{,}\) and \(e\text{,}\) form a \(2\times 2\) matrix \(A\text{,}\) while \(c\) and \(f\) form a vector \(\vec{b}\text{.}\) The two views of Woody shows the effect of the mapping
\begin{equation*} \vec{x}\mapsto A\vec{x} + \vec{b}\text{.} \end{equation*}
Figure 13.4. Affine Transformations

Warning 13.5.

If your <interactive> employs a <slate> with a @surface attribute whose value is html, then you are advised to augment each top-level (HTML) element within the <slate> with the attribute:
xmlns="http://www.w3.org/1999/xhtml"
This will identify all of the elements within the <slate> as HTML elements and not as PreTeXt elements. The danger is that elements with the same name in both languages, such as <li> and <table>, will be mis-identified. This could be harmless, but could also create chaos, such as disrupting numbering of PreTeXt elements.
See the source code of this document for examples: Figure 13.4 Figure 13.11, Figure 13.16.
Note that the HTML that is output can vary slightly from your source in small, harmless ways, such as empty (self-closing) elements being output with both an opening and a closing tag. Please report any significant discrepancies. Soon this requirement will be enforced in the code.
It is also possible to add <script> elements within an interactive that contain properly escaped JS code. These elements will be placed at the end of the document created to hold the interactive content and can interactive with the other elements within the interactive but can not directly interact with the surrounding page.
Authors are strongly discouraged from trying to incorporate complex code in the form of a <script>, but it can be a useful tool to call more complex code that is linked via @source on the <interactive>.
This example uses a <script> to draw “Hello World” to a <slate>
Figure 13.6. A simple embedded script example

Subsection 13.2 D3.js

D3 is a Javascript library for “Data-Driven Documents”, which might greatly enhance some data you wish to display. In short, it uses the animation capabilities of SVG. Available examples seem sensitive to the version of the library, so we have examples using different versions. Use the @version attribute on <interactive> to specify the version number. The default is 5.
The first example uses the force layout and collision detection from Version 3. (The necessary commands are very different in Version 4.) Pretend you are a working shepherding dog. Can you separate, and catch, one of the herd?
This is adapted from a block
 2 
bl.ocks.org/mbostock/3231298
by Mike Bostock
 3 
bl.ocks.org/mbostock
with a GPL license. A similar demonstration, only using an HTML5 canvas is at bl.ocks.org/mbostock/3231307.

Instructions.

Place your mouse/pointer at the center of the interactive to repel the 200 circles.
Figure 13.7. Force layout and collision detection
Similar, but different, this demonstration of a graph layout uses Version 4 of the library. Technical notes:
  • We have changed the size of the nodes, and their number, to fit in a smaller space.
  • The Javascript script uses introspection to size itself, which would be a good general practice.
This is adapted from a block
 4 
bl.ocks.org/shimizu/e6209de87cdddde38dadbb746feaf3a3
by shimizu
 5 
bl.ocks.org/shimizu
with a GPL license.

Instructions.

Drag a vertex to a new location to see the graph adjust its layout.
Figure 13.8. Graph Layout

Checkpoint 13.9. Graph Planarity.

Can you move the vertices to new locations such that the resulting graph is planar? (In other words, no edges cross?)
Finally an example that actually uses some data. Here is the description from the original block
 6 
bl.ocks.org/martinjc/7aa53c7bf3e411238ac8aef280bd6581
by Martin Chorley
 7 
bl.ocks.org/martinjc
with an MIT License.
This visualisation uses a D3 force simulation to show the Twitter relationships between the Assembly Members in the Welsh Assembly in terms of the number of times each assembly member has mentioned another assembly member in a tweet.
Twitter relationships were mined on 22/03/2017, and are representative of the conversational relationships on that date. Links between AMs represent a conversational relationship: one AM has mentioned the other. Party colour indicates the direction of the mention.
Hover over the nodes to fade out non-connected nodes.
Rather than using intermediate nodes to create curved links (as in Mike Bostock’s block), this adds curves by adding a calculated control point for each edge.
Technical notes:
  • Once the nodes organize themselves (automatically in the beginning), they cannot be moved.
  • We have adjusted the margins in an attempt to keep names visible on the right side, but without giving up too much space.
  • We have adjust the repelling force, and the collision buffer, to better fit the available space.
  • This example required its own CSS, which we have included as part of the <interactive>.
  • The data collected from the Twitter analysis is contained in a JSON file, mention_network.json, and where the script loads that file, it has a hardcoded path. So this example is a bit brittle, should that file move.

Instructions.

Hover on the name of an Assembly Member to concentrate on their tweet mentions.
Figure 13.10. Tweet mentions within the Welsh Assembly

Subsection 13.3 SVG

Entirely similar to using an HTML5 canvas element (13.1), it is possible to control an SVG element with Javascript. This example is from Mark McClure.
Look carefully at the source and rendering of this example as HTML. The functions to choose from via radio buttons, and the change in \(x\text{,}\) denoted later as \(h\text{,}\) are being rendered as mathematics by the Javascript MathJax library. However, this cannot be accomplished with simply $...$ nor by simply \(...\), but instead by using the \(...\) and then also wrapping that in a <span> element with a @class attribute set to process-math. (The latter is how we instruct MathJax as to which parts of a page to process, or not). So to have MathJax render a nice \(x^2\) in this context (math inside HTML inside a <slate> inside an <interactive>) would be accomplished with
<span class="process-math">x^2</span>

Instructions.

Select a function with the radio buttons, then use the checkbox to add the secant line. The denominator of the difference quotient, \(h\text{,}\) can be adjusted with the slider and the red point will react to the different values. The green point is the point of tangency, and can be dragged with the mouse.
Figure 13.11. Tangent and secant slopes

Checkpoint 13.12. Changing Secant Lines.

When discussing the derivative as a limit, we think of the point of tangency as being fixed (the green point in 13.11) and the “other” point defining the secant line as changing (the red point in 13.11). Switch it up! Fix a large value of \(h\) (positive or negative) and then change the point of tangency (the green point). Discuss what you observe.

Subsection 13.4 JSXGraph

JSXGraph
 8 
jsxgraph.uni-bayreuth.de
is a “cross-browser JavaScript library for interactive geometry, function plotting, charting, and data visualization in the web browser.” Now a <slate> will be what JSXGraph calls a board. Again, you use Javascript to write onto a <slate>, but have some powerful shortcuts available from the JSXGraph library. For this reason, PreTeXt calls JSXGraph a “language”, similar in may respects to how Sage is a language, but is really a Python library. So realize that the syntax for using JSXGraph is that of Javascript.
Place Javascript inside a file that is specified with the @source attribute of the <interactive> element. Then just be certain that @xml:id of the <interactive> element is passed as the HTML id in an (early) call to JSXGraph’s initBoard() method.
The following example was contributed by Rick Roesler. The <figure> is comprised of four <stack> elements within a <sidebyside>. By varying the time in the top box, the reader can observe the displacement, velocity, and acceleration of a ball thrown upward with an initial velocity of 30 m/s.

Instructions.

Use the time slider in the top panel to vary the time from 0 sec to 6 sec. Observe how the displacement, velocity, and acceleration vary with time.
Figure 13.13. 1-Dimensional Kinematics
The plot below is the curve \(r=a+b\theta\) in polar coordinates, for \(0\leq\theta\leq 8\pi\text{.}\) It may be manipulated with the sliders to control the shape of the curve. Point \(A\) is contrained to the curve, but may be dragged to a new location. At \(A\) the tangent line and normal line are plotted as dashed red lines. Use the controls in the lower left to adjust the viewing window. This Archimedean Spiral
 9 
jsxgraph.uni-bayreuth.de/wiki/index.php/Archimedean_spiral
is taken from the JSXGraph example wiki
 10 
jsxgraph.uni-bayreuth.de/wiki/index.php/Category:Examples
. The code could be written in 7 lines. Width is 80% and aspect ratio is 4:3.

Instructions.

Drag the sliders to change the parameters \(a\) and \(b\text{.}\) Controls in the lower-right will adjust the viewing window.
Figure 13.14. The Archimedian Spiral \(r = a + b\theta\text{,}\) \(0\leq\theta\leq 8\pi\)
Here is a more elaborate example, from the JSXGraph Showcase
 11 
jsxgraph.uni-bayreuth.de/showcase/
, titled Infinity
 12 
jsxgraph.uni-bayreuth.de/showcase/infinity.html
.
There are two active sliders to control the shape and shading of the graphic, and hovering the mouse near one of the edges will highlight the entirety of one of the 30 quadrangles. Finally, each of the four red corners may be dragged to a new location. Code is 47 lines. Width is 60% and aspect ratio is the default, 1:1, i.e. a square.

Instructions.

Drag the sliders to change the pattern, and drag any of the four red corners to change the overall shape.
Figure 13.15. Infinity, from the JSXGraph Showcase
Here are the two new examples. They have been included in a sidebyside layout element with equal widths (see Section 25) so they can be placed horizontally across the page. They are not wrapped as figures, so cannot be cross-referenced. These are again from the JSXGraph example wiki
 13 
jsxgraph.uni-bayreuth.de/wiki/index.php/Category:Examples
, the left being Fermat’s Spiral and the right being a demonstration of B-splines.

Instructions.

Drag the slider to change the curve.

Instructions.

Any of the 8 red control points may be moved anywhere.
Finally, a piecewise function you can control, with traces of the domain values and range values in two other JSXGraph boards. Boards and HTML buttons have been laid out using the sidebyside layout element.

Instructions.

The slider of the left panel will trace out the piecewise function. Simultaneously, the domain will be traced in the middle panel, and the range in the right panel.
Figure 13.16. Piecewise Function
Generally, we load an interactive into an HTML iframe to sandbox (isolate) it from other interactives. We does this for your own protection. So, for example, one interactive cannot talk to another. If two <slate> need to communicate, then they are related, and should be placed into a single <interactive>, allowed to layout themselves, or grouped within a <sidebyside> allowing finer control. Even if we have this under control, you might still enjoy reading Your JS is a Mess
 14 
mikecavaliere.com/your-js-is-a-mess-javascript-namespacing/
at mikecavaliere.com/your-js-is-a-mess-javascript-namespacing/.

Subsection 13.5 JessieCode

JessieCode
 15 
jsxgraph.uni-bayreuth.de/wp/docs_jessiecode/
is a scripting language for JSXGraph. It provides the core geometric and graphing features of JSXGraph without accessing the underlying JavaScript. In order to use JessieCode, you simply create the HTML <div> element as you would for any other JSXGraph interactive plot and then provide the JessieCode script, which focuses on the geometric elements.
Because JessieCode is provided by JSXGraph, the interactive platform is jsxgraph. The <slate>, however, uses @surface with value jessiecode. The script can be embedded directly in your code. As usual, you would need to remember to escape the special characters. JessieCode uses < and > for inequalities as well as for declaring objects used to style geometric elements, and && is the boolean AND operator. Alternatively, you can provide the file as a separate resource, providing the URL with a @source attribute. Attributes defining the JSXBoard at the time it is created should be included as attributes of the <slate>, including @boundingbox, @axis, and @grid.
For this first example, the JessieCode was included directly in the XML source as the contents of the associated slate.

Instructions.

Use the sliders to set the parameters of the quadratic \(f(x)=ax^2+bx+c\text{.}\) Drag the point \(A\) on the graph and the point \(P\) to define a line. Try to make the line tangent at the point at \(A\) and observe the resulting slope of the tangent line.
Figure 13.17. Finding the Tangent Line of a Quadratic Function
For this second example, the JessieCode was included through an associated script file, loaded by the browser.

Instructions.

Drag the point \(B\) to move the point on the graph and change the secant line. Notice that there is no well-defined limiting tangent line as \(x \to 0\text{.}\)
Figure 13.18. Graph of a function that is continuous but not differentiable at \(x=0\) because the slope of the secant line has no limit.

Subsection 13.6 Sage Interacts

Sage, and the Sage Cell Server, support interactive demonstrations, called interacts.
  • The interactive elements are nearly trivial to construct.
  • An interact is simply a single Python function (acted on by a decorator).
  • You have the full mathematical power of Sage at your disposal, so can do some very powerful computations with high precision (or exactly).
  • The interface is not as polished as what you can achieve with Javascript libraries.
  • Graphics refresh with a round-trip to the server, so are not nearly as fluid as with other tools.
Note that each interact is insulated from the others, unlike our other employment of the Sage Cell Server.
This example is by Marshall Hampton, taken from the Sage interact wiki
 16 
wiki.sagemath.org/interact/calculus
, specifically Numerical integrals with the midpoint rule
 17 
wiki.sagemath.org/interact/calculus#Numerical_integrals_with_the_midpoint_rule
.
Figure 13.19. Numerical integrals using the midpoint rule

Subsection 13.7 Geogebra

To embed a GeoGebra applet as-is from GeoGebra’s Classroom Resources site (by material ID), see Subsection 14.1. To design your own applet (either from scratch, or modifying something that already exists in one of those three forms) you may use one of Geogebra’s “Apps” to embed the material in your document. (But note, use of the App comes with licensing restrictions.) PreTeXt will handle most of the technical details for you.
Do one of the following:
  1. Identify a material ID from GeoGebra’s Classroom Resources site. You might even make the material yourself on that site.
  2. Obtain a .ggb file from GeoGebra. You might construct something on a desktop installation of GeoGebra and save it. If you have a base64-encoded string for a GeoGebra applet, but you don’t have a .ggb file, you can decode the string and save the result. For example, at https://www.opinionatedgeek.com/codecs/base64decoder.
  3. Obtain a base64 encoded string for a GeoGebra applet. You might first open a .ggb file in a desktop installation of GeoGebra, and push ctrl-shift-B (command-shift-B on a Mac) and then the string will be in your clipboard.
  4. None of the above, with the intention to make an applet from scratch.
Then mimic the examples that follow, using GeoGebra API commands documented at Geogebra API Manual
 18 
wiki.geogebra.org/en/Reference:GeoGebra_Apps_API
, but do not include the ggbApplet. or applet. used in examples to prefix the functions—that part of the code will be provided automatically by PreTeXt.
Jack Green created an applet on the Classroom Resources site with ID D4s2v4ft, which you may view at www.geogebra.org/m/D4s2v4ft. Suppose you would like to use this in your project, but change something about it. We will change something trivial, making the \(y\)-axis ticks be separated \(5\) apart instead of \(10\) apart. We also decide we want a different aspect ratio and overall width. One gotcha: the original applet is loaded and then PreTeXt uses @width and @aspect attributes to resize the viewing window using the top left corner as an anchor. This does not rescale axes and that may leave you with important elements missing from the viewing window. So here we reset the viewing window to return to values that are in the original. Lastly, we disable zooming, which is not helpful for this applet. To do each of these things, we rely on the GeoGebra API manual at Geogebra API Manual
 19 
wiki.geogebra.org/en/Reference:GeoGebra_Apps_API
. It is important to use one command per line.
Figure 13.20. GeoGebra: modified material ID
The same can be done with a .ggb file. Here we use two provided by David Rosoff, and one provided by Tevian Dray. The path to the file needs to be relative. First, David’s original.
Figure 13.21. GeoGebra: .ggb file
Now we modify David’s applet in a few ways.
Figure 13.22. GeoGebra: modified from .ggb file
Figure 13.23. GeoGebra: modified from .ggb file
In this one provided by Tevian Dray, we make no modifications (except for those imposed by the scaling). You will need to zoom out a bit, and then pan over some, to see all the pieces.

Instructions.

Drag some of the points and some of the circles to change them, and watch the remainder react.
Figure 13.24. GeoGebra: a constructive “proof” that SAS congruence holds in Euclidean geometry (from Tevian Dray)
You could also use a base64-encoded string of the .ggb file. You might come across such a string somewhere, or you might generate one by opening a .ggb file in a desktop installation of GeoGebra, and pushing ctrl-shift-B (command-shift-B on a Mac) to get the string in your clipboard. If you do this, you could use a @base64 attribute in place of the @source attribute in the previous example. We don’t do that here because such a string is generally over 5000 characters long and we are keeping the sample article source a bit cleaner.
The next example shows how you can communicate between a GeoGebra applet and a <slate> contained in the interactive. The process is mediated by javascript code specified in the @source attribute of the interactive. Event listeners in the code update the HTML when the diagram changes or vice-versa. MathJax is also notified when it needs to update math.
Note that this example has a <slate> whose @surface is pretext and a <slate> whose @surface is html, the latter requiring a namespace declaration. The former produces HTML according to the PreTeXt templates, which is fairly predictable, but never guaranteed to always be identical over time. A PreTeXt slate uses familiar syntax, produces results styled consistently, but might break in the future. While an HTML slate is similar, the results will not be styled, but it does allow for a wider range of HTML elements (a button element here) and will not change over time.
The indefinite integral in the last row of the table is a gratuitious test that aurhors’ macros from <docinfo> are available to MathJax. Finally, a PreTeXt slate will only recognize <p>, <tabular>, <sidebyside>, and <sbsgroup> as children. Make a feature request if you have a good case for more.

Instructions.

This interactive shows \(\vec{r}_{AB}\text{,}\) the displacement vector from \(\vec{A}\) to \(\vec{B}\) and the corresponding unit displacement vector \(\lambda_{AB}\text{.}\)
You may change \(\vec{A}\) and \(\vec{B}\) by moving the red and blue dots. Click the dot to switch between \(x\)-\(y\) mode and \(z\) mode. Coordinates of \(\vec{A}\) and \(\vec{B}\) can also be entered into the table directly.
Figure 13.25. Geogebra/PreTeXt Communications
Lastly, you may just wish to build something from scratch using GeoGebra API. Note that for accessibilty reasons, some objects are rendered unselectable with the setFixed command. Perhaps this should have been done with the previous examples, but that is more difficult when you do not know all of their names. Note that the GeoGebra scripting command setAttribute also changes the webpage’s focus, so it is better to set the perspective using an attribute of the slate.
Figure 13.26. GeoGebra: from scratch

Subsection 13.8 CircuitJS

CircuitJS
 20 
www.falstad.com/circuit
is an electronic circuit simulator. A circuit can be described by a language, which PreTeXt will interpret and submit for rendering. The next two examples are identical, but provided in slightly different ways, see the PreTeXt source for more. Preview images for PDF will be added later.
Figure 13.27. CircuitJS Example (source via an encoded attribute)
Figure 13.28. CircuitJS Example (source authored directly)

Subsection 13.9 IFrames from Files

An iframe is an HTML element that allows embedding of a complete web page within another one. Here we use this device to provide interactive 3D diagrams built with other tools.
We begin with a Jupyter notebook hosted on CoCalc.com. News of success on other hosts for Jupyter notebook servers will allow us to expand this description. We use a Sage kernel and create a 3D surface suggested by Juan Carlos Bustamante:
var('x,y')
plot3d(x^2 - y^2, (x,-1,1), (y,-1,1), color="orange", mesh=true)
News of other computational engines that produce similar graphics will also allow us to further expand this description. Note that for the case of Sage 3D plots, support for the <sageplot> element makes this even easier. For example, see 9.25.
A button in the lower right allows for several options, one is Save as HTML, which will produce a complete self-contained web page we can recycle. We save this file with our other externally-created images, in a directory that we choose to name iframe—you can use another name. Then we make an <interactive> with an @iframe attribute that has the filename, starting from iframe/ (in other words, do not include the name of your managed directory of external images).
Figure 13.29. Sage+Jupyter iframe
Note that the downloaded file has links to specific versions of the three.js library, which are beyond our control, and beyond your control. So there is a future where these images may need updating. You could put your source code into a (large) comment with your project’s source for safe-keeping in the future. See Subsection 14.4 for the server version.

Subsection 13.10 threejs

Once upon a time there was an example here using the threejs 3D Javascript library. It was one of the project’s examples
 21 
threejs.org/examples/#webgl_geometry_extrude_splines
, licensed with an MIT License, with minimal modifications.
But it would seem to have become a bit more complicated to embed and our example was not rendering. As of 2022-08-08, we have removed it. Of course, you can find it in the git repository, perhaps searching on the date string just mentioned. It woulld be interesting to see if our <interactive> framework could still support the changes.
The following two examples are meant to be instructive (only). The end result is accomplished in a much more straightforward way be the method in Subsection 13.9. We illustrate a way to get a three.js image out of an HTML page as a Javascript file and render it on a PreTeXt <slate>. We follow the second method in a blog post from the \(n\)-Category Cafe
 22 
golem.ph.utexas.edu/category/2017/12/sagemath_and_3d_models_in_webp.html
.
  1. Open a Jupyter Notebook that utilizes a Sage kernel. This can be done easily at CoCalc
     23 
    cocalc.com
    (and for free initially).
  2. Sketch a surface using Sage code. We recycle the suggestion from Juan Carlos Bustamante in Subsection 13.9:
    var('x,y')
    plot3d(x^2 - y^2, (x,-1,1), (y,-1,1), color="orange", mesh=true)
    
  3. Look for a button (in the lower-right) which will provide a menu option Save as HTML. Save the resulting HTML file, and open a copy in a text editor.
  4. You are now looking for two HTML script elements. One will tell you just which version of three.js is being used, vis a @src attribute. For the second example below we located
    https://cdn.jsdelivr.net/gh/sagemath/threejs-sage@r122/build/three.min.js
    
    The @r122 will likely be a version number, which is a good thing for the longevity of your work. This will get used in the @source attribute of your <interactive>, which will have @platform set to javascript.
    The second script element is likely huge and has many generic functions defined it. There may be a huge variable full of data points computed by Sage. Copy the contents of this script element into a new Javascript file (so use a .js extension). Do not edit in any way until you read further. Once adjusted, this file too gets specified in the @source attribute of your <interactive>.
  5. Your <interactive> needs a <slate> element for the graphic to draw on, and you will need to give it a proper @xml:id attribute, plus teh @surface will be set to div. Then you need to edit the Javascript file to connect the graphic with the slate, via IDs in your PreTeXt source and on teh HTML div created by the slate. Look at the provided examples to see how. Do not make any other edits to this file, even if tempted.
  6. Study the two examples below, and mimic how they were constructed.
First, the example given in the blog post referenced above.
Figure 13.30. threejs catenoid surface, from \(n\)-Category Cafe
Second, the example from JC Bustamante.
Figure 13.31. threejs saddle by Sage

Subsection 13.11 DoenetML

DoenetML
 24 
doenet.org
is a markup language inspired by PreTeXt for semantically describing interactive mathematics applets for the web. Use interactive[@platform="doenetml"] with a slate[@surface="doenetml"] to include DoenetML content within your document.
Since DoenetML is similar to, but not completely compatible with, XML, it cannot be authored directly within a PreTeXt document without painstakingly escaping every < as &lt; and every & as &amp;. However, a convenient workflow to avoid this is to author your DoenetML in a separate file like example.doenetml, then include this file within your PreTeXt document using <xi:include parse="text" href="path/to/example.doenetml"/>.
Figure 13.32. DoenetML example