๐ง Features & Enhancements
-
2D Input
- Helper Boxes: Show borders around expressions for easier editing.
- MatrixForm: Updated display style for matrix outputs.
-
Datasets
- Fixed rendering issues with complex datasets (e.g., COโ emissions data).
-
Speech & Audio
Speak
supports conversion toAudio
viaSpeechSynthesize
.
-
Video
- Now supports audio playback and native browser streaming.
-
Graphics & Inset
- Improved
Inset
handling for combining 2D/3D elements, overlays, and interactive views.
- Improved
๐งช Internals
- Welcome Screen: Intro tutorial on first WLJS Notebook launch.
- Watchdog: Micro self-tests for kernel reliability and hot-reload support.
- UI Fixes: Windows scrollbar layout bugs resolved.
๐ On-Demand Licensing
Run WLJS Notebook without device-locked licenses using entitlements. Useful for server use โ but expect slower evaluation speed.
const balloonContainer = document.getElementById("balloon-container"); function random(num) { return Math.floor(Math.random() * num); } function getRandomStyles() { var r = random(255); var g = random(255); var b = random(255); var mt = random(200); var ml = random(50); var dur = random(5) + 5; return ` background-color: rgba(${r},${g},${b},0.7); color: rgba(${r},${g},${b},0.7); box-shadow: inset -7px -3px 10px rgba(${r - 10},${g - 10},${b - 10},0.7); margin: ${mt}px 0 0 ${ml}px; animation: float ${dur}s ease-in infinite `; } function createBalloons(num) { for (var i = num; i > 0; i--) { var balloon = document.createElement("div"); balloon.className = "balloon"; balloon.style.cssText = getRandomStyles(); balloonContainer.append(balloon); } } function removeBalloons() { balloonContainer.style.opacity = 0; setTimeout(() => { balloonContainer.remove() }, 500) } createBalloons(10); setTimeout(removeBalloons, 15000); return '';
2D Input Improvementsโ
Helper boxesโ
We introduced helper boxes that appear when you move your cursor through equations or other decorations, which helps to see the borders of each decoration
Try to focus on different elements
(*FB[*)((A)(*,*)/(*,*)((*SpB[*)Power[w(*|*),(*|*)2](*]SpB*) - (*SpB[*)Power[x(*|*),(*|*)2](*]SpB*) + I g x))(*]FB*) + (*TB[*)Sum[(*|*)x(*|*), {(*|*)x(*|*),(*|*)xmin(*|*),(*|*)xmax(*|*)}](*|*)(*1:eJxTTMoPSmNiYGAoZgMSwaW5TvkVmYwgPguQCCkqTQUAeAcHBQ==*)(*]TB*) + (*TB[*)Integrate[(*|*)x(*|*), {(*|*)x(*|*),(*|*)xmin(*|*),(*|*)xmax(*|*)}](*|*)(*1:eJxTTMoPSmNiYGAo5gESnnklqelFiSWpTvkVmYwgURYgEVJUmgoAvmMJeQ==*)(*]TB*)
MatrixFormโ
MatrixForm
has a new output form!
Table[{i,j/i}, {i,5}, {j,5}] // MatrixForm
(*GB[*){{{1,1}(*|*),(*|*){1,2}(*|*),(*|*){1,3}(*|*),(*|*){1,4}(*|*),(*|*){1,5}}(*||*),(*||*){{2,(*FB[*)((1)(*,*)/(*,*)(2))(*]FB*)}(*|*),(*|*){2,1}(*|*),(*|*){2,(*FB[*)((3)(*,*)/(*,*)(2))(*]FB*)}(*|*),(*|*){2,2}(*|*),(*|*){2,(*FB[*)((5)(*,*)/(*,*)(2))(*]FB*)}}(*||*),(*||*){{3,(*FB[*)((1)(*,*)/(*,*)(3))(*]FB*)}(*|*),(*|*){3,(*FB[*)((2)(*,*)/(*,*)(3))(*]FB*)}(*|*),(*|*){3,1}(*|*),(*|*){3,(*FB[*)((4)(*,*)/(*,*)(3))(*]FB*)}(*|*),(*|*){3,(*FB[*)((5)(*,*)/(*,*)(3))(*]FB*)}}(*||*),(*||*){{4,(*FB[*)((1)(*,*)/(*,*)(4))(*]FB*)}(*|*),(*|*){4,(*FB[*)((1)(*,*)/(*,*)(2))(*]FB*)}(*|*),(*|*){4,(*FB[*)((3)(*,*)/(*,*)(4))(*]FB*)}(*|*),(*|*){4,1}(*|*),(*|*){4,(*FB[*)((5)(*,*)/(*,*)(4))(*]FB*)}}(*||*),(*||*){{5,(*FB[*)((1)(*,*)/(*,*)(5))(*]FB*)}(*|*),(*|*){5,(*FB[*)((2)(*,*)/(*,*)(5))(*]FB*)}(*|*),(*|*){5,(*FB[*)((3)(*,*)/(*,*)(5))(*]FB*)}(*|*),(*|*){5,(*FB[*)((4)(*,*)/(*,*)(5))(*]FB*)}(*|*),(*|*){5,1}}}(*||*)(*1:eJxTTMoPSmNkYGAo5gUSYZmp5S6pyflFiSX5RcFsQBHfxJKizAoAs04KOA==*)(*]GB*)
Dataset Improvementsโ
We fixed many bugs related to poor Dataset
implementation. This one in particular was not rendered correctly
ResourceData["Global and National Annual CO2 Emissions from Fossil Fuel Burning 1751-2014"]
(*VB[*)(Dataset[Join@@CoffeeLiqueur`Extensions`InputsOutputs`Private`store$167774])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKm5okJqVZphrqGhkYJuuamCYn6yamWRjqJiWZWhonW5gYJ1qaAQCKxxXQ"*)(*]VB*)
Speakโ
One of the oldest function from Wolfram Standard Library
Speak[(*VB[*)(RGBColor[1, 0, 0])(*,*)(*"1:eJxTTMoPSmNiYGAo5gUSYZmp5S6pyflFiSX5RcEsQBHn4PCQNGaQPAeQCHJ3cs7PyS8qYgCDD/ZQBgMDnAEA4iUPRg=="*)(*]VB*)]
It can also be converted to Audio
object
SpeechSynthesize[SpokenString[(*VB[*)(RGBColor[1, 0, 0])(*,*)(*"1:eJxTTMoPSmNiYGAo5gUSYZmp5S6pyflFiSX5RcEsQBHn4PCQNGaQPAeQCHJ3cs7PyS8qYgCDD/ZQBgMDnAEA4iUPRg=="*)(*]VB*)], GeneratedAssetLocation -> None]
(*VB[*)(Audio[FrontEndRef["3084d98a-f8fc-4003-b2b6-0adfe3c2edd8"], "SignedInteger16"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKp6UkJRuYGVvqpiYbGOiamCWl6VokGifpJqUkWpimGSalmCQaAQCU3haE"*)(*]VB*)
Improved support for Video objectโ
For quite some time Video
could only show "motion picture" without any audio. Now we have audio playback as well.
UPD: A few seconds before the release. We found a way to stream it to the native browser's video engine. It will work even better
Video["ExampleData/Caminandes.mp4"]
Better Inset
supportโ
It allows to combine multiple different graphics objects in a quite complex way. Here are a few example
Plot[Sin[x], {x, 0, 10}, Epilog -> Inset[Graphics3D[Cylinder[], ImageSize -> 60], {0.5,0.5}]] Graphics[{Circle[], Inset[EditorView[ToString[x^2 + y^2 == 1 // Unevaluated, StandardForm]], {0, 0}, Center, {1,0.7}]}, ImageSize->200]
(*VB[*)(FrontEndRef["5393609c-0f83-4065-880c-9e21d14e9307"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKmxpbGpsZWCbrGqRZGOuaGJiZ6lpYGCTrWqYaGaYYmqRaGhuYAwBtzBSO"*)(*]VB*)
(*VB[*)(Graphics[{Circle[{0, 0}], Inset[EditorView["(*SpB[*)Power[x(*|*),(*|*)2](*]SpB*)+(*SpB[*)Power[y(*|*),(*|*)2](*]SpB*)==1"], {0, 0}, Center, {1, 0.7}]}, ImageSize -> 200])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KWlMIB4HkHAvSizIyEwuhoiA5H0yi0sgqtmAhHNmUXJOKqpsJpBmABNpIKFiViDhmVecCtXGBSRcUzJL8ovCMlPLg32AXA2t4AKnaC3NgPzy1KLoCg2tGi1NHTBpFKuhFQuU1NLURlVUiVWRra0hLrdAnJuaV5JahKYE5KqiNDB4Zo+QCyrNSS3mBLk9NzE9NTizKjXzBJAHAJcsQnQ="*)(*]VB*)
Or combination of overlayed raster images
img = (*VB[*)(FrontEndRef["3404a670-7ee4-478b-9771-8ccfa938b07d"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKG5sYmCSamRvomqemmuiamFsk6VqamxvqWiQnpyVaGlskGZinAAB3QRVU"*)(*]VB*); faces = FindFaces[img]; res = HighlightImage[img, {"Blur", faces}]
(*VB[*)(FrontEndRef["2ed27c25-8a6c-4ad4-80e5-91b2daa99385"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKG6WmGJknG5nqWiSaJeuaJKaY6FoYpJrqWhomGaUkJlpaGluYAgCHkhWo"*)(*]VB*)
Internalsโ
Welcome Screenโ
If WLJS Notebook is launched for the first time, it will guide a user though a short tutorial.
Watchdog ๐ฉผโ
We added a set of self-tests for the Wolfram Kernel, which are performed periodically during the active session and before any evaluation. They take about seconds of computational time; however, they allow for hot-reloading some of the modules that may misbehave due to uncontrollable definition reloads in the Wolfram Language Standard Library.
Yes, this is a sort of workaround. The Wolfram Kernel can clear any custom
FormatValues
of the system symbol, even those that do not interfere with system definitions. This is a big pain, but we can still live with it since it happens rarely and only for particular symbols.
UI bug fixesโ
- Layout scroll bars corrections for mini apps on Windows
On-demand licenseโ
If you want to try WLJS Notebook without binding the free license to your machine, you can issue license entitlement using Wolfram Cloud or a friend. Then
git clone https://github.com/JerryI/wolfram-js-frontend
cd wolfram-js-frontend
wolframscript -f Scripts/start.wls -entitlement XXX-CODE-OF-ENTITLEMENT-XXX
It also would make sense on servers.
In this regime the evaluation kernel works much slower
Ballon animation by Jemima (codepen)