- App Integrity: Core packages/modules moved from
AppData
into the app folder (immutable); only small personal settings stored outside. Initialization simplified and several hundred LOC removed. Updates now occur globally (no per-module local updates). - Excalidraw Images: Whiteboards in markdown/slide cells now support drag-and-drop image files; images are embedded as base64 in notebook storage.
- Event-Driven Animations: New pattern for
AnimationFrameListener
makes it easier to attach handlers and frame triggers for interactive graphics. - Pattern Matching on Slides (WLX): Introduced a new XML-like pattern design for WLX components
- Subscripts in Manipulate: Fixed pipeline so
Subscript
parameters work in Manipulate/Animate expressions (e.g.,Subscript[f, C]
). - 2D Graphics: Improved rendering/behavior
- Graphics3D: Broader support for 3D plots
App Integrity
We moved all modules and core packages from AppData
to the application folder (as they should be!), making them immutable. In this sense, we only store a few kilobytes of your personal settings outside the main application. It significantly simplified the initialization stage and removed a few hundred lines of code from the repository.
This also means that there will be no more local updates of the individual modules; rather, there will be a global update of the entire app.
Excalidraw Images
As you know, you can add a virtual whiteboard to markdown and slide cells by typing
Now it also supports dropping any image file directly to the whiteboard. An image will be uploaded directly as base64 encoded string to the notebook storage.
Like this one above.
Easier event-driven animations
We added a new pattern to AnimationFrameListener
to make it easier for hooking up handlers and frame triggers:
Module[{p=RandomReal[{-1,1}, {100,2}]}, Graphics[{ (*VB[*)(RGBColor[0.368417, 0.506779, 0.709798])(*,*)(*"1:eJxTTMoPSmNiYGAo5gUSYZmp5S6pyflFiSX5RcEsQBHn4PCQNGaQPAeQCHJ3cs7PyS8qKpg26anKlOv2RYbTXk7vMH9gX3S8ZYb3qm3P7AF5kRs6"*)(*]VB*), Point[p//Offload], EventHandler[AnimationFrameListener[p//Offload], Function[Null, p = (# + Norm[#] 0.01 {#[[2]], -#[[1]]}) &/@ p; ]] }, ImageSize->Small] ]
Pattern matching on slides
It is new pattern design for making WLX components. Let's make a cards system like this one below:
.slide ## Cards layout <div style=" display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; justify-content: center; align-content: space-evenly; align-items: end; justify-items: center; "> <Card> <CardTitle>Electron Density in a Metal</CardTitle> <CardCredits>John Doe et al. <b>Physical Review Letters</b> 125 2020</CardCredits> </Card> <Card> <CardTitle>Quantum Entanglement Demonstration</CardTitle> <CardImage Link={"https://upload.wikimedia.org/wikipedia/commons/f/f3/Entanglement.PNG"} /> <CardCredits>Jane Smith et al. <b>Journal of Quantum Physics</b> 39 2022</CardCredits> </Card> <Card> <CardTitle>Graphene's Unique Properties</CardTitle> <CardImage Link={"https://upload.wikimedia.org/wikipedia/commons/9/96/Basic_Graphene.png"} /> <CardCredits>Emily Johnson et al. <b>Advanced Materials</b> 31 2019</CardCredits> </Card> </div>
<dummy > ## Cards layout <div style=" display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; justify-content: center; align-content: space-evenly; align-items: end; justify-items: center; "><div ><h5 >Electron Density in a Metal</h5><span style="font-size:smaller">John Doe et al. <b >Physical Review Letters</b> 125 2020</span></div><div ><img src="https://upload.wikimedia.org/wikipedia/commons/f/f3/Entanglement.PNG" width="300"/><br /><h5 >Quantum Entanglement Demonstration</h5><span style="font-size:smaller">Jane Smith et al. <b >Journal of Quantum Physics</b> 39 2022</span></div><div ><img src="https://upload.wikimedia.org/wikipedia/commons/9/96/Basic_Graphene.png" width="300"/><br /><h5 >Graphene's Unique Properties</h5><span style="font-size:smaller">Emily Johnson et al. <b >Advanced Materials</b> 31 2019</span></div></div></dummy>
By the default all arguments passed to any WLX
component are converted to strings for the convience. We need to disable that to take advantage of pattern matching:
CardTitle /: ToString[c_CardTitle, WLXForm] := c CardCredits /: ToString[c_CardCredits, WLXForm] := c CardImage /: ToString[c_CardImage, WLXForm] := c
Now use the power of WL to build our cards
.wlx Card[__] := ""; SetAttributes[Card, Orderless]; Card[ CardTitle[Title_], CardCredits[credits__] ] := With[{Text = ToStringRiffle[{credits}]}, <div> <h5><Title/></h5> <span style="font-size:smaller"><Text/></span> </div> ] Card[ CardTitle[Title_], CardCredits[credits__], CardImage[Rule["Link", url_]] ] := With[{Text = ToStringRiffle[{credits}]}, <div> <img src="{url}" width="300"/> <br/> <h5><Title/></h5> <span style="font-size:smaller"><Text/></span> </div> ]
And we are ready to use it.
Subscripts in Manipulate
We fixed our pipeline to support Subscript
as parameters in Manipulate-like and Animate-like expressions:
ManipulatePlot[With[{carrier = Sin[2 Pi (*SbB[*)Subscript[f(*|*),(*|*)C](*]SbB*) t], data = Sin[2 Pi f t]}, {carrier, data, carrier * data}], {t, 0, 1}, {{(*SbB[*)Subscript[f(*|*),(*|*)C](*]SbB*), 10}, 10, 20,1}, {{f, 1}, 1, 2,0.2}]
(*VB[*)(FrontEndRef["a2df318e-bcfa-4b85-be33-94f4daba5502"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKJxqlpBkbWqTqJiWnJeqaJFmY6ialGhvrWpqkmaQkJiWamhoYAQCXdRZY"*)(*]VB*)
Better Support of 2D Graphics
Yes! We made it work a little better again, particularly on these examples:
RiemannBar[box : {{x0_, x1_}, {y0_, y1_}}, {x_, y_}, _] := Block[{area = (y1 + y0) (x1 - x0)}, Sow[area]; {ChartElementData["Rectangle"][box, {}, {}], {Opacity[1], Black, Point[{x, y}]}, If[Abs[area] < 10^-2, {}, {Opacity[1], Black,Text[Rotate[NumberForm[area, {Infinity, 2}], Pi/2], Mean /@ box]}]}] RiemannPlot[f_, {x_, x0_, x1_, dx_: 1.}, opts___] := Block[{plot, areas, extent, points, curve}, extent = OptionValue[Flatten[{opts}], ExtentSize]; points = If[IntegerQ[dx], RandomReal[{x0, x1}, dx], Switch[extent, Full, Range[x0, x1, dx], Left, Range[x0 + dx, x1, dx], Right, Range[x0, x1 - dx, dx]]]; {plot, areas} = Reap[DiscretePlot[f, Evaluate@{x, points}, opts, ImageSize -> 475, ExtentElementFunction -> RiemannBar, FillingStyle -> Opacity[0.5], PlotStyle -> PointSize[Small]]]; Show[plot, Plot[f, {x, x0, x1}], PlotLabel -> Style[Row[{"Estimated Area: ", Total[Flatten@areas], Spacer[10], "Actual Area: ", NIntegrate[f, {x, x0, x1}]}], FontSize->8], Frame -> True, PlotRange -> All, Axes -> {True, False}] ] RiemannPlot[BesselJ[5, x], {x, 0, 10, 0.5}, ExtentSize -> Full]
(*VB[*)(FrontEndRef["3b8ff2d6-2f46-4e8e-8b68-2ba50f84ec30"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKGydZpKUZpZjpGqWZmOmapFqk6lokmVnoGiUlmhqkWZikJhsbAACLFhXf"*)(*]VB*)
More legend positions are supported:
Plot[(*VB[*)(Uncompress["1:eJxTTMoPSuNmYGAoZgESPpnFJWlMIB4rkAjIL08tKjp7BgQ+2BczAoUq0GXXuT+sEln3FYfshENfNWL6f+GQLbTlur644D8OWc2YfqBuJgfssrNmggALDlmQubZc7Dhkq0VArubEIfsmcIdc62tuHLJgR8Xw4ZBNAwMBqCwAi2ZcYw=="])(*,*)(*"1:eJxTTMoPSmNmYGAo5gUSYZmp5S6pyflFiSX5RcEcQBHP5Py8zKrUlMwZQEVpTCCFLEAiqDQnNZgVyPBJTErNCQYJ+eXnpQIA8K4Slg=="*)(*]VB*)//Evaluate, {x, -6, 6}, AspectRatio -> 7/12, PlotStyle -> (*VB[*)(Uncompress["1:eJxTTMoPSuNmYGAoZgESPpnFJWnMIB4HkAhyd3LOz8kvKtrXPN+ioe69fZH8reNcdbOBDCHhKx90dd7aY1F89dXq1UxbgWoOWJ6YwLEJyDB9/mDmhSUvsSl+ravPdeYKUI3vtCU1QduBjFdTw4P/RT3FpphBc4G98nGgmo1vLEykZwEZRZ+do1sk7mNTvPJ+69qbXkA1yeZK5yr/vLUvmnTkzn/B6dexKZb+snS7/fR39kXWf0wjF897bV+UPat8ziLlS9gUZ9/uPvxlBtDA5iMXNxSve25ftK9wbWBW1wVsitPeRgdFLXljX/TN1Nw7b+dj+yKeB7oTFvw4i03xzhCG5wqHgba3fI6/VlV6376oouJ841OO09gUKxk+C875+Mq+6Jbqqu1s264AFbNtcl7IdQKbYtETb3Sq1IGKRaIdLwtpH7QvcuTfmivBetQeAKNExKQ="])(*,*)(*"1:eJxTTMoPSmNmYGAo5gUSYZmp5S6pyflFiSX5RcEcQBHP5Py8zKrUlMwAVgaGNCaQQhYgEVSakxoMFGHwSUxKzQkGCfnl56UCAOaOElA="*)(*]VB*), PlotLegends -> Placed[(*VB[*)(Uncompress["1:eJxTTMoPSuNmYGAoZgESPpnFJWlMIB4rkAjIL08tKjp7BgQ+2BczAoUq0GXXuT+sEln3FYfshENfNWL6f+GQLbTlur644D8OWc2YfqBuJgfssrNmggALDlmQubZc7Dhkq0VArubEIfsmcIdc62tuHLJgR8Xw4ZBNAwMBqCwAi2ZcYw=="])(*,*)(*"1:eJxTTMoPSmNmYGAo5gUSYZmp5S6pyflFiSX5RcEcQBHP5Py8zKrUlMwZQEVpTCCFLEAiqDQnNZgVyPBJTErNCQYJ+eXnpQIA8K4Slg=="*)(*]VB*), Right], PlotRange -> {-1, 6}]
(*VB[*)(Legended[ToExpression[FrontEndRef["f56b6d11-bd0d-4cc3-88a1-4d2d9e100414"], InputForm], Placed[LineLegend[{Directive[Opacity[1.], AbsoluteThickness[2], RGBColor[0.984192, 0.987731, 0.911643]], Directive[Opacity[1.], AbsoluteThickness[2], RGBColor[0.990846, 0.9904826, 0.8013689999999999]], Directive[Opacity[1.], AbsoluteThickness[2], RGBColor[0.9947262, 0.9911282, 0.6673576000000001]], Directive[Opacity[1.], AbsoluteThickness[2], RGBColor[0.9930588, 0.9875618, 0.48587139999999984]], Directive[Opacity[1.], AbsoluteThickness[2], RGBColor[0.9778870000000001, 0.9370698000000001, 0.3685956]], Directive[Opacity[1.], AbsoluteThickness[2], RGBColor[0.955963, 0.863115, 0.283425]], Directive[Opacity[1.], AbsoluteThickness[2], RGBColor[0.9249214, 0.7400454, 0.2584482]], Directive[Opacity[1.], AbsoluteThickness[2], RGBColor[0.8950625999999999, 0.6163855999999999, 0.23414999999999997]], Directive[Opacity[1.], AbsoluteThickness[2], RGBColor[0.8675693999999999, 0.4915453999999999, 0.21120899999999998]], Directive[Opacity[1.], AbsoluteThickness[2], RGBColor[0.8419706, 0.32361000000000006, 0.1878244]], Directive[Opacity[1.], AbsoluteThickness[2], RGBColor[0.817319, 0.134127, 0.164218]]}, {1.05^HoldForm[x], 1.355^HoldForm[x], 1.6600000000000001^HoldForm[x], 1.965^HoldForm[x], 2.27^HoldForm[x], 2.575^HoldForm[x], 2.88^HoldForm[x], 3.185^HoldForm[x], 3.49^HoldForm[x], 3.795^HoldForm[x], 4.1^HoldForm[x]}, LegendMarkers -> None, LabelStyle -> {}, LegendLayout -> "Column"], Right, Identity]])(*,*)(*"1:eJxTTMoPSmNmYGAo5gUSYZmp5S6pyflFiSX5RcHsQBGf1PTUvBSjNCaQEi4g4ZqSCZQDKUxjBIkJAQm3ovy8Ete8FNeK1OTSksSknNRgFaBwmqlZklmKoaFuUopBiq5JcrKxroVFoqGuSYpRimWqoYGBiaEJxGAWIBFUCtTGAWKkJqb45+VUgkVDikpTIe5jAxIBOYnJqSlprDDH+GTmpUJcmMYNM8cns7gEooMTSLhkFqUml2SWpUJcC/KSf0FicmZJZREDGHywh8gIAgnHpOL8nNKS1JCMzOTsvNTi4kyQ6yCGgV3m7uScn5NfVLSveb5FQ917+yL5W8e56mYDGULCVz7o6ry1p7XNV1+tXs20FWjhAcsTEzg2ARmmzx/MvLDkJc1tfq2rz3XmCtBC32lLaoK2AxmvpoYH/4t6SnObGTQX2CsfB1q48Y2FifQsIKPos3N0i8R9mtu88n7r2pteQAuTzZXOVf55a1806cid/4LTr9PcZukvS7fbT39nX2T9xzRy8bzX9kXZs8rnLFK+RHObs293H/4yA+jV5iMXNxSve25ftK9wbWBW1wWa25z2Njooaskb+6JvpubeeTsf2xfxPNCdsODHWZrbvDOE4bnCYWAgt3yOv1ZVet++qKLifONTjtM0t1nJ8FlwzsdX9kW3VFdtZ9t2BWgz2ybnhVwnaG6z6Ik3OlXqQJtFoh0vC2kftC9y5N+aK8F61B6tLAWX0KAiNyC/PLWo6OwZEIBZCTLSIz8nxS2/KLcYJFKBrn6d+8MqkXVfiVY/4dBXjZj+X0SrL7Tlur644D/R6jVj+oE2MDkQq37WTBBgIVo9yDW2XOxEq68WAYUQJ9Hq3wTukGt9zU20erB3Y/iIVp8GBgIE1MNqbHCzAVIF+yYWZacWFYOl/PLzUtEUguvrxKTUnOCSypzUNAbMNAZXygM30yexMr+0JBhU9wNTbWluHtihQZnpGSVgp3mmpOaVADMCAO0lZyU="*)(*]VB*)
Better support of Graphics3D
We now support more 3D plot types compared to 2.8.4:
DiscretePlot3D[ PDF[MultivariatePoissonDistribution[3, {1, 1}], {t, u}], {t, 0, 10}, {u, 0, 10}]
(*VB[*)(FrontEndRef["0dd4659f-a428-4c56-993d-12c89c5bf808"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKG6SkmJiZWqbpJpoYWeiaJJua6VpaGqfoGholW1gmmyalWRhYAAB/cBVa"*)(*]VB*)
DiscretePlot3D[{ PDF[MultivariatePoissonDistribution[2, {2, 2}], {t, u}]}, {t, 0, 10}, {u, 0, 10}, ExtentSize -> Full, PlotStyle->Opacity[1], Lighting->Automatic]
(*VB[*)(FrontEndRef["deae24b1-4916-4c3e-999b-7db5c939a5b4"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKp6QmphqZJBnqmlgamumaJBun6lpaWibpmqckmSZbGlsmmiaZAACL5hXh"*)(*]VB*)