Skip to main content

Release notes *2.6.3*

· 3 min read

This update brings significant improvements, including autocomplete enhancements that dynamically load suggestions for symbols from external packages by rescanning $ContextPath. The UI for Windows and Linux has been simplified with a redesigned main menu to resemble native apps more closely.

Additionally, a new approach for dynamically adding graphics primitives to existing canvas objects is introduced, bypassing immutability through FrontInstanceReference. Enhanced Manipulate support now includes implicit selection forms and localized symbols.

Download original notebook

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 '';

Autocomplete improvements

We extended the support of providing suggestions for symbols loaded from external packages at runtime. If you load something Kernel will rescan added contextes from $ContextPath and populate the suggestion panel.

UI changes on Windows & Linux

We moved towards the simplity of the native apps and redesigned the main menu

New way of adding things on canvas

Wolfram Language is mostly immutable by the design, the same is true for all graphics primitives. To add new primitives on the canvas, you would need to reevalaute an expression again.

We can violate this rule, by injecting new expressions into existing one dynamically and evaluate them in-place. Since our frontend (browser) actually has OOP structure behind the curtains, we can refer to the particular instance of some object FrontInstanceReference

scene = FrontInstanceReference[];
Plot[x, {x,0,1}, Epilog->{scene}]
(*VB[*)(FrontEndRef["d537799a-7ff7-4567-a82f-795b86ad5817"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKp5gam5tbWibqmqelmeuamJqZ6yZaGKXpmluaJlmYJaaYWhiaAwB+NhVA"*)(*]VB*)

Then we can evaluate any expression in the context of our Plot like if it was there before

FrontSubmit[{RandomColor[], Disk[{.5,.5}, 0.1]}, scene];

To make a removable object, one need to wrap it into a special group, which allows to cancel the sideffects caused by evaluation

group = FrontInstanceGroup[];
FrontSubmit[{RandomColor[], Disk[{.7,.7}, 0.1]} // group, scene];

Then you can simply delete it

Delete[group];

Manipulate improvements

We trying to close a gap between Mathematica's Manipulate and WLJS version. We added the support of implicit selection form, i.e.

Manipulate[Plot3D[f[x] f[y], {x,-10,10}, {y,-10,10}], {f, {Sin, Tanh}}]

Now this form is also valid (take a previous output), it localizes symbols only if one of them is occupied already

(*SpB[*)Power[x(*|*),(*|*)2](*]SpB*) - 2;
Manipulate[%, {x,-1,1}]

Experimental feature FrontProxy

The idea is to efficently store, update and delete things on the screen. For this purpose we invent FrontProxyObject, which an emulation of OOP paterns aka KirillBelov/Objects package, but much more limited.

ClearAll[hue, pos, vel, text];

proxy = CreateFrontProxy[{hue, pos, vel, text}, {
  RGBColor[With[{h = hue}, {1-h, 0, h}]], Text[text, pos, {0,0}]
}, {hue, pos, vel}];

Now you can use it to spawn as many instances as you want. It uses linear buffers for each property under the hood to maximize the performance on updates and minimize footprint in memory.

primitives = Table[proxy[0.8, RandomReal[{-1,1}, 2], {0.,0.}, RandomWord[]//Capitalize], {30}];

Graphics[Show @@ primitives, ImageSize->{500,300}, PlotRange->{{-1,1}, {-1,1}}, TransitionType->None]
(*VB[*)(FrontEndRef["8daa118f-f213-42e0-a4ab-025ff05f58ff"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKW6QkJhoaWqTpphkZGuuaGKUa6CaaJCbpGhiZpqUZmKaZWqSlAQCIaRX3"*)(*]VB*)

Now you can update all properties and then dispatch all changes at once

EventHandler[InputRange[0.03,0.5,0.02, "Label"->"Spread"], recalculate]
(*VB[*)(EventObject[<|"Id" -> "c17297bb-15f7-4e93-9968-9c2c7a32195a", "Initial" -> 0.26, "View" -> "ad8605b0-a27b-48a7-98d1-23aebb2c9dba"|>])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKJ6ZYmBmYJhnoJhqZJ+maWCSa61papBjqGhknpiYlGSVbpiQlAgCGERYn"*)(*]VB*)

Evaluate this handler to see the effect

Module[{
  hue, pos, vel, gradient
}, recalculate[sigma_] := Do[ Do[
  
    {hue, pos, vel} = FrontProxyGet[i];
  
    gradient = Sum[If[i===j, {0.,0.}, With[{neib = FrontProxyGet[j][[2]], \[Sigma] = sigma},
  
      ( (*FB[*)((((*SpB[*)Power[E(*|*),(*|*)-(*FB[*)((SquaredEuclideanDistance[pos, neib])(*,*)/(*,*)(2. ((*SpB[*)Power[\[Sigma](*|*),(*|*)2](*]SpB*))))(*]FB*)](*]SpB*)) )(*,*)/(*,*)(((*SqB[*)Sqrt[2. \[Pi]](*]SqB*)) ((*SpB[*)Power[\[Sigma](*|*),(*|*)3](*]SpB*))))(*]FB*)  - 0.1) (pos - neib) // N
  
    ]], {j, primitives}];

    vel = gradient;
    pos = pos + 0.01 vel;
    hue = Clip[20.0 Norm[gradient]/Length[primitives], {0,1}];

    FrontProxySet[i, {hue, pos, vel}];
  
  , {i, primitives}];

  FrontProxyDispatch[proxy];

  , {2}]
];

New documentation will come soon on them.

Ballon animation by Jemima (codepen)