This update introduces a better folder structure, relocating notebooks, backups, and examples to logical directories like YourDocuments/WLJS Notebooks
and $TemporalDirectory
while preserving current data and streamlining offline documentation access. Improved file synchronization prevents crashes during large uploads by splitting data into smaller parts, while new visualization tools enhance image and vector graphics integration, dynamic tracking, animated image support, and interactive raster editing.
Additionally, shell access for Unix/OSX users allows direct command execution, and ESM JavaScript cells enable seamless integration of NPM libraries like siriwave, providing in-place compilation with esbuild for enhanced development flexibility.
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 '';
Better folder structure
Starting from 2.6.2 we no longe use application data directory for storing notebooks and your backups. Our new structure follows the pattern
YourDocuments/WLJS Notebooks/
examples and your default home folder$TemporalDirectory/wljs_quicknotes
folder for anonimous quick notes$TemporalDirectory/wljs_backups
backups folder
Your current data will not be erased.
Also we moved all offline documentation to a separate system package.
Safer Synchronization and Uploading
If you have a large file added to a cell or heavy objects loaded to the frontend, it could crash the master kernel upon saving due to buffering issues. Now it is split into smaller parts, which prevents buffer overflow and allows for easy progress tracking.
You will notice this indication when saving a notebook with many images.
Better Inset support
A great example of the implicit Inset
usage is HighlightImage
, where raster and vector graphics are combined
(*VB[*)(FrontEndRef["61cd9b03-0523-46b3-938e-c58fc3742f3b"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKmxkmp1gmGRjrGpgaGeuamCUZ61oaW6TqJptapCUbm5sYpRknAQB53hVF"*)(*]VB*); Image[%, "ImageResolution"->Automatic]; HighlightImage[%, {Yellow, ImageCorners[%, 1, .001, 5]}, ImageSize->300]
(*VB[*)(FrontEndRef["7e05198a-a400-4fab-bc39-819f5c74fe38"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKm6camBpaWiTqJpoYGOiapCUm6SYlG1vqWhhappkmm5ukpRpbAACByxWr"*)(*]VB*)
Image tracking example
Here we use a sample video of nanoparticles moving in a fluid
source https://www.azonano.com/nanotechnology-video-details.aspx?VidID=47
video = (* import a video *) With[{frames = VideoExtractFrames[video, {1,2}]}, HighlightImage[frames//First, {Yellow, ImageFeatureTrack[frames, MaxFeatures->25, Tolerance->0.01] // First}] ]
(*VB[*)(FrontEndRef["6a649ca8-23ce-41b6-a15e-aa282e6adae2"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKmyWamVgmJ1roGhknp+qaGCaZ6SYamqbqJiYaWRilmiWmJKYaAQCH6BYl"*)(*]VB*)
Track them in all frames
features = ImageFeatureTrack[VideoExtractFrames[video, All], MaxFeatures->25, Tolerance->0.01]; tracks = Map[DeleteMissing, features // Transpose]; ListLinePlot[tracks, AspectRatio -> 1, PlotRange -> All]
(*VB[*)(FrontEndRef["d64916f5-1fad-4f2d-a2b1-ea316f015524"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKp5iZWBqapZnqGqYlpuiapBml6CYaJRnqpiYaA4UNDE1NjUwAiL0VlQ=="*)(*]VB*)
AnimatedImage support
We added a rough implementation of AnimatedImage
similar to Video
object
Import[FileNameJoin[{"attachments", "character-13952_256-f4d.gif"}]]; AnimatedImage[%]
(*VB[*)(JerryI`Notebook`GraphicsVideo`Internal`origin$120670)(*,*)(*"1:eJy9VNlu4zYUTYsWKPrSX/DoyVEiRE5EWS46A2ihZUvyIlO0Ygd5oLWF0W55VTL/PnKMYFKgD1Og6MvdgEsennt4P63yWfjTxcVF9UtjBnnihz+fst8bA326yddzGuzRH79eXLRZRXlgL9tTkgXJQ5vVT9nLy3u5zc7ffH+dZxuY+bMgfGC6t+Jd0OmGHC8BiRNum4jwPZ7zeM/jidjt3hGBebxss9dNJ8t0/gyMg+OM8ilKx/FCl/NlBNFgFwNzpgbQUPamtJ6ad4MxutM3CPJbCyejYxyP5xE008N2qROPpGVY6AlduFtKdLm/pDZxlfXaUKrMUPIkBduVTtFC9hfeHMqfPzOnux/nCnv5Q0DkYAK0vcPvrCPujZA7UVXbjkGJRTD3ZQVqZcQXNc4rENn1IBvV/G5c451iwgz2Ug/HBx1oT5oym1honcqa6cN843i1VeNNfwShitQq2tW0NupRT8O2JBcCn5HoHaiinNyZbJb9F5AtmI19r9whfaIiO5iD0nbVvby0yqSgBAMDi8aBZIqxxKD0YAQc0UCkeRmK5SNfObH9kauvbfb1lb28PruXD3o4Q4O7INtMVs+Bt3n465UZ+kyL+9JighXp3HYA4DpSKHDCiu9xpCdIXBgCr+N1JUEMQ+a6xQwzuqEkeWvqk6QKmtpJiudTOqAjka7PczzxGl2FfsARIK44IvmheCv27kQ/ZF6//FfK0kFOXIpIcXjOdWqn7hUlhenGIiUkpfeFkZRxYcTLdB6TVHRj2VYHE2Ux/M5Ww9KZq1N4/jCMRjakRatWnrXMYN18Kuaf4dITXBB5SMb3YLmMixJlVwpyl1f3WZ8s9pE6W0TCUg/jvfXk2aYhGCatrQNf3OxNCkU7KjWUjWdUo5pmOVc7Q6O1+ew6qvSkJHYvja6qPhUwTshClQcIDxz8QWtfm0k/6v+T6CQb6uHBdHA2tvFIxvJoU8396G/Ce8fzQ9N1k9FQEW5iOcqP9MZyYDKWkJQfvXpq8uBZhknDn42kjlFn0+F6CAtFz8em1zG1fSN+o1zASrKwLGsUPeGb77Sc9+Rpa862SVD9dgoC4k+y5PhWddbb4BvUTpm4"*)(*]VB*)
Reevaluate an input cell above to see the result
Generate from expressions
AnimatedImage[Rasterize[Style[#, 40]] & /@ Range[0, 9], FrameRate->6 ]
InputRaster - a free drawing tool
We introduce a new input element. Here is how a simple mirror-paint widget might look like
bufferImage = ImageData[ConstantImage[{0,0,0,0}, {350,350}], "Byte"]; EventHandler[InputRaster[ImageSize->{350,350}], Function[img, bufferImage = ImageData[img, "Byte"]; ]] Image[bufferImage // Offload, "Byte"]
You can use it as a masking tool for images
InputRaster["OverlayImage"->(*VB[*)(FrontEndRef["61cd9b03-0523-46b3-938e-c58fc3742f3b"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKmxkmp1gmGRjrGpgaGeuamCUZ61oaW6TqJptapCUbm5sYpRknAQB53hVF"*)(*]VB*)]
(*VB[*)(EventObject[<|"Id" -> "ac41ae57-4081-4cf3-a0a4-78b0e73f3ede", "View" -> "43d18820-cd9e-4ccd-8551-7f0f113a5c28"|>])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKmxinGFpYGBnoJqdYpuqaJCen6FqYmhrqmqcZpBkaGieaJhtZAACAzxVy"*)(*]VB*)
Shell access
==This feature is currently only for Unix/OSX users==
Type .sh
in the first line to run a command
.sh ls
2.5.0.wln 2.5.2.wln 2.5.3.wln 2.5.4.wln 2.5.6.wln 2.5.7.wln 2.5.9.wln 2.6.1.wln 2.6.2.wln attachments
ESM Javascipt cells
==This feature requires NodeJS installed==
It comes handy not only to write Javascript in a cell, but also bundle it with libraries from NPM repositiry. Now it is possible, we use esbuild
to compile Javascript in-place
.sh npm i siriwave --prefix .
added 1 package in 2s
Now import this library and bundle it
.esm import SiriWave from "siriwave"; const dom = document.createElement('div'); this.return(dom); let siriWave; siriWave = new SiriWave({ container: dom, height:300, style: "ios9", width:600 }); siriWave.start(); this.ondestroy = () => { siriWave.dispose(); console.warn('removed'); }
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); // node_modules/siriwave/dist/siriwave.umd.js var require_siriwave_umd = __commonJS({ "node_modules/siriwave/dist/siriwave.umd.js"(exports, module) { (function(global, factory) { typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, global.SiriWave = factory()); })(g0this, function() { "use strict"; var __assign = function() { __assign = Object.assign || function __assign2(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } var ClassicCurve = ( /** @class */ function() { function ClassicCurve2(ctrl, definition) { this.ATT_FACTOR = 4; this.GRAPH_X = 2; this.AMPLITUDE_FACTOR = 0.6; this.ctrl = ctrl; this.definition = definition; } ClassicCurve2.prototype.globalAttFn = function(x) { return Math.pow(this.ATT_FACTOR / (this.ATT_FACTOR + Math.pow(x, this.ATT_FACTOR)), this.ATT_FACTOR); }; ClassicCurve2.prototype.xPos = function(i) { return this.ctrl.width * ((i + this.GRAPH_X) / (this.GRAPH_X * 2)); }; ClassicCurve2.prototype.yPos = function(i) { return this.AMPLITUDE_FACTOR * (this.globalAttFn(i) * (this.ctrl.heightMax * this.ctrl.amplitude) * (1 / this.definition.attenuation) * Math.sin(this.ctrl.opt.frequency * i - this.ctrl.phase)); }; ClassicCurve2.prototype.draw = function() { var ctx = this.ctrl.ctx; ctx.moveTo(0, 0); ctx.beginPath(); var finalColor = this.definition.color || this.ctrl.color; var colorHex = finalColor.replace(/rgb\(/g, "").replace(/\)/g, ""); ctx.strokeStyle = "rgba(".concat(colorHex, ",").concat(this.definition.opacity, ")"); ctx.lineWidth = this.definition.lineWidth; for (var i = -this.GRAPH_X; i <= this.GRAPH_X; i += this.ctrl.opt.pixelDepth) { ctx.lineTo(this.xPos(i), this.ctrl.heightMax + this.yPos(i)); } ctx.stroke(); }; ClassicCurve2.getDefinition = function() { return [ { attenuation: -2, lineWidth: 1, opacity: 0.1 }, { attenuation: -6, lineWidth: 1, opacity: 0.2 }, { attenuation: 4, lineWidth: 1, opacity: 0.4 }, { attenuation: 2, lineWidth: 1, opacity: 0.6 }, { attenuation: 1, lineWidth: 1.5, opacity: 1 } ]; }; return ClassicCurve2; }() ); var iOS9Curve = ( /** @class */ function() { function iOS9Curve2(ctrl, definition) { this.GRAPH_X = 25; this.AMPLITUDE_FACTOR = 0.8; this.SPEED_FACTOR = 1; this.DEAD_PX = 2; this.ATT_FACTOR = 4; this.DESPAWN_FACTOR = 0.02; this.DEFAULT_NOOFCURVES_RANGES = [2, 5]; this.DEFAULT_AMPLITUDE_RANGES = [0.3, 1]; this.DEFAULT_OFFSET_RANGES = [-3, 3]; this.DEFAULT_WIDTH_RANGES = [1, 3]; this.DEFAULT_SPEED_RANGES = [0.5, 1]; this.DEFAULT_DESPAWN_TIMEOUT_RANGES = [500, 2e3]; this.ctrl = ctrl; this.definition = definition; this.noOfCurves = 0; this.spawnAt = 0; this.prevMaxY = 0; this.phases = []; this.offsets = []; this.speeds = []; this.finalAmplitudes = []; this.widths = []; this.amplitudes = []; this.despawnTimeouts = []; this.verses = []; } iOS9Curve2.prototype.getRandomRange = function(e) { return e[0] + Math.random() * (e[1] - e[0]); }; iOS9Curve2.prototype.spawnSingle = function(ci) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; this.phases[ci] = 0; this.amplitudes[ci] = 0; this.despawnTimeouts[ci] = this.getRandomRange((_b = (_a = this.ctrl.opt.ranges) === null || _a === void 0 ? void 0 : _a.despawnTimeout) !== null && _b !== void 0 ? _b : this.DEFAULT_DESPAWN_TIMEOUT_RANGES); this.offsets[ci] = this.getRandomRange((_d = (_c = this.ctrl.opt.ranges) === null || _c === void 0 ? void 0 : _c.offset) !== null && _d !== void 0 ? _d : this.DEFAULT_OFFSET_RANGES); this.speeds[ci] = this.getRandomRange((_f = (_e = this.ctrl.opt.ranges) === null || _e === void 0 ? void 0 : _e.speed) !== null && _f !== void 0 ? _f : this.DEFAULT_SPEED_RANGES); this.finalAmplitudes[ci] = this.getRandomRange((_h = (_g = this.ctrl.opt.ranges) === null || _g === void 0 ? void 0 : _g.amplitude) !== null && _h !== void 0 ? _h : this.DEFAULT_AMPLITUDE_RANGES); this.widths[ci] = this.getRandomRange((_k = (_j = this.ctrl.opt.ranges) === null || _j === void 0 ? void 0 : _j.width) !== null && _k !== void 0 ? _k : this.DEFAULT_WIDTH_RANGES); this.verses[ci] = this.getRandomRange([-1, 1]); }; iOS9Curve2.prototype.getEmptyArray = function(count) { return new Array(count); }; iOS9Curve2.prototype.spawn = function() { var _a, _b; this.spawnAt = Date.now(); this.noOfCurves = Math.floor(this.getRandomRange((_b = (_a = this.ctrl.opt.ranges) === null || _a === void 0 ? void 0 : _a.noOfCurves) !== null && _b !== void 0 ? _b : this.DEFAULT_NOOFCURVES_RANGES)); this.phases = this.getEmptyArray(this.noOfCurves); this.offsets = this.getEmptyArray(this.noOfCurves); this.speeds = this.getEmptyArray(this.noOfCurves); this.finalAmplitudes = this.getEmptyArray(this.noOfCurves); this.widths = this.getEmptyArray(this.noOfCurves); this.amplitudes = this.getEmptyArray(this.noOfCurves); this.despawnTimeouts = this.getEmptyArray(this.noOfCurves); this.verses = this.getEmptyArray(this.noOfCurves); for (var ci = 0; ci < this.noOfCurves; ci++) { this.spawnSingle(ci); } }; iOS9Curve2.prototype.globalAttFn = function(x) { return Math.pow(this.ATT_FACTOR / (this.ATT_FACTOR + Math.pow(x, 2)), this.ATT_FACTOR); }; iOS9Curve2.prototype.sin = function(x, phase) { return Math.sin(x - phase); }; iOS9Curve2.prototype.yRelativePos = function(i) { var y = 0; for (var ci = 0; ci < this.noOfCurves; ci++) { var t = 4 * (-1 + ci / (this.noOfCurves - 1) * 2); t += this.offsets[ci]; var k = 1 / this.widths[ci]; var x = i * k - t; y += Math.abs(this.amplitudes[ci] * this.sin(this.verses[ci] * x, this.phases[ci]) * this.globalAttFn(x)); } return y / this.noOfCurves; }; iOS9Curve2.prototype.yPos = function(i) { return this.AMPLITUDE_FACTOR * this.ctrl.heightMax * this.ctrl.amplitude * this.yRelativePos(i) * this.globalAttFn(i / this.GRAPH_X * 2); }; iOS9Curve2.prototype.xPos = function(i) { return this.ctrl.width * ((i + this.GRAPH_X) / (this.GRAPH_X * 2)); }; iOS9Curve2.prototype.drawSupportLine = function() { var ctx = this.ctrl.ctx; var coo = [0, this.ctrl.heightMax, this.ctrl.width, 1]; var gradient = ctx.createLinearGradient.apply(ctx, coo); gradient.addColorStop(0, "transparent"); gradient.addColorStop(0.1, "rgba(255,255,255,.5)"); gradient.addColorStop(1 - 0.1 - 0.1, "rgba(255,255,255,.5)"); gradient.addColorStop(1, "transparent"); ctx.fillStyle = gradient; ctx.fillRect.apply(ctx, coo); }; iOS9Curve2.prototype.draw = function() { var ctx = this.ctrl.ctx; ctx.globalAlpha = 0.7; ctx.globalCompositeOperation = this.ctrl.opt.globalCompositeOperation; if (this.spawnAt === 0) { this.spawn(); } if (this.definition.supportLine) { return this.drawSupportLine(); } for (var ci = 0; ci < this.noOfCurves; ci++) { if (this.spawnAt + this.despawnTimeouts[ci] <= Date.now()) { this.amplitudes[ci] -= this.DESPAWN_FACTOR; } else { this.amplitudes[ci] += this.DESPAWN_FACTOR; } this.amplitudes[ci] = Math.min(Math.max(this.amplitudes[ci], 0), this.finalAmplitudes[ci]); this.phases[ci] = (this.phases[ci] + this.ctrl.speed * this.speeds[ci] * this.SPEED_FACTOR) % (2 * Math.PI); } var maxY = -Infinity; for (var _i = 0, _a = [1, -1]; _i < _a.length; _i++) { var sign = _a[_i]; ctx.beginPath(); for (var i = -this.GRAPH_X; i <= this.GRAPH_X; i += this.ctrl.opt.pixelDepth) { var x = this.xPos(i); var y = this.yPos(i); ctx.lineTo(x, this.ctrl.heightMax - sign * y); maxY = Math.max(maxY, y); } ctx.closePath(); ctx.fillStyle = "rgba(".concat(this.definition.color, ", 1)"); ctx.strokeStyle = "rgba(".concat(this.definition.color, ", 1)"); ctx.fill(); } if (maxY < this.DEAD_PX && this.prevMaxY > maxY) { this.spawnAt = 0; } this.prevMaxY = maxY; return null; }; iOS9Curve2.getDefinition = function() { return [ { color: "255,255,255", supportLine: true }, { // blue color: "15, 82, 169" }, { // red color: "173, 57, 76" }, { // green color: "48, 220, 155" } ]; }; return iOS9Curve2; }() ); var SiriWave2 = ( /** @class */ function() { function SiriWave3(_a) { var _this = this; var container = _a.container, rest = __rest(_a, ["container"]); this.phase = 0; this.run = false; this.curves = []; var csStyle = window.getComputedStyle(container); this.opt = __assign({ container, style: "ios", ratio: window.devicePixelRatio || 1, speed: 0.2, amplitude: 1, frequency: 6, color: "#fff", cover: false, width: parseInt(csStyle.width.replace("px", ""), 10), height: parseInt(csStyle.height.replace("px", ""), 10), autostart: true, pixelDepth: 0.02, lerpSpeed: 0.1, globalCompositeOperation: "lighter" }, rest); this.speed = Number(this.opt.speed); this.amplitude = Number(this.opt.amplitude); this.width = Number(this.opt.ratio * this.opt.width); this.height = Number(this.opt.ratio * this.opt.height); this.heightMax = Number(this.height / 2) - 6; this.color = "rgb(".concat(this.hex2rgb(this.opt.color), ")"); this.interpolation = { speed: this.speed, amplitude: this.amplitude }; this.canvas = document.createElement("canvas"); var ctx = this.canvas.getContext("2d"); if (ctx === null) { throw new Error("Unable to create 2D Context"); } this.ctx = ctx; this.canvas.width = this.width; this.canvas.height = this.height; if (this.opt.cover === true) { this.canvas.style.width = this.canvas.style.height = "100%"; } else { this.canvas.style.width = "".concat(this.width / this.opt.ratio, "px"); this.canvas.style.height = "".concat(this.height / this.opt.ratio, "px"); } switch (this.opt.style) { case "ios9": this.curves = (this.opt.curveDefinition || iOS9Curve.getDefinition()).map(function(def) { return new iOS9Curve(_this, def); }); break; case "ios": default: this.curves = (this.opt.curveDefinition || ClassicCurve.getDefinition()).map(function(def) { return new ClassicCurve(_this, def); }); break; } this.opt.container.appendChild(this.canvas); if (this.opt.autostart) { this.start(); } } SiriWave3.prototype.hex2rgb = function(hex) { var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; hex = hex.replace(shorthandRegex, function(m, r, g, b) { return r + r + g + g + b + b; }); var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? "".concat(parseInt(result[1], 16).toString(), ",").concat(parseInt(result[2], 16).toString(), ",").concat(parseInt(result[3], 16).toString()) : null; }; SiriWave3.prototype.intLerp = function(v0, v1, t) { return v0 * (1 - t) + v1 * t; }; SiriWave3.prototype.lerp = function(propertyStr) { var prop = this.interpolation[propertyStr]; if (prop !== null) { this[propertyStr] = this.intLerp(this[propertyStr], prop, this.opt.lerpSpeed); if (this[propertyStr] - prop === 0) { this.interpolation[propertyStr] = null; } } return this[propertyStr]; }; SiriWave3.prototype.clear = function() { this.ctx.globalCompositeOperation = "destination-out"; this.ctx.fillRect(0, 0, this.width, this.height); this.ctx.globalCompositeOperation = "source-over"; }; SiriWave3.prototype.draw = function() { this.curves.forEach(function(curve) { return curve.draw(); }); }; SiriWave3.prototype.startDrawCycle = function() { this.clear(); this.lerp("amplitude"); this.lerp("speed"); this.draw(); this.phase = (this.phase + Math.PI / 2 * this.speed) % (2 * Math.PI); if (window.requestAnimationFrame) { this.animationFrameId = window.requestAnimationFrame(this.startDrawCycle.bind(this)); } else { this.timeoutId = setTimeout(this.startDrawCycle.bind(this), 20); } }; SiriWave3.prototype.start = function() { if (!this.canvas) { throw new Error("This instance of SiriWave has been disposed, please create a new instance"); } this.phase = 0; if (!this.run) { this.run = true; this.startDrawCycle(); } }; SiriWave3.prototype.stop = function() { this.phase = 0; this.run = false; if (this.animationFrameId) { window.cancelAnimationFrame(this.animationFrameId); } if (this.timeoutId) { clearTimeout(this.timeoutId); } }; SiriWave3.prototype.dispose = function() { this.stop(); if (this.canvas) { this.canvas.remove(); this.canvas = null; } }; SiriWave3.prototype.set = function(propertyStr, value) { this.interpolation[propertyStr] = value; }; SiriWave3.prototype.setSpeed = function(value) { this.set("speed", value); }; SiriWave3.prototype.setAmplitude = function(value) { this.set("amplitude", value); }; return SiriWave3; }() ); return SiriWave2; }); } }); // <stdin> var import_siriwave = __toESM(require_siriwave_umd()); var dom = document.createElement("div"); g0this.return(dom); var siriWave; siriWave = new import_siriwave.default({ container: dom, height: 300, style: "ios9", width: 600 }); siriWave.start(); g0this.ondestroy = () => { siriWave.dispose(); console.warn("removed"); }; /*! Bundled license information: siriwave/dist/siriwave.umd.js: (*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** *) */
The best thing, the compiled JS is stored in the output cell, so other users do not need even nodejs
installed to use your code.
More customization
We extended available CSS classes for cells
main
main window.ccontainer
cells container.cgroup
a single group of cells: 1 input + outputs + tools.cframe
a single inner group of cells: 1 input + outputs.cborder
a vertical line displayed at the right side from the cell group.cwrapper
an input/output cell wrapper.cseparator
a thin space between cells
.cinit
a class for initialization cells.cin
a class for input cells.cout
a class for output cells
Feel free to adjust it in a way you like. Those styles are not occupied by any default CSS tables.
Ballon animation by Jemima (codepen)