An experimentation to use jweb
object for developing Max for Live devices.
jweb
object is an option for modern ECMAScript (JavaScript) in Cycling '74 Max before 9.
Also, jweb
can be used to create UI with various APIs.
However, as the author has researched, HTML files in frozen Max for Live devices cannot be loaded into jweb
.
Node for Max (N4M) is another option, however, there are difficulties in using N4M in Max for Live. It is necessary to execute manually npm install
to use external modules, it has to be executed only the first time.
executejavascript
message is a way to inject some scripts to jweb
.
You can handle long injection messages by js
object as follows.
// jweb script injection by js object
autowatch = 1;
inlets = 1;
outlets = 1;
var SCRIPT = "let label = document.createElement('label');";
SCRIPT = SCRIPT + "label.textContent = 'Hello World!';";
SCRIPT = SCRIPT + "window.document.body.appendChild(label);";
SCRIPT = SCRIPT + "window.max.bindInlet('execute', function() {";
SCRIPT = SCRIPT + " window.max.outlet('output', 42)";
SCRIPT = SCRIPT + "});";
SCRIPT = SCRIPT + "window.max.outlet('ready');";
function inject() {
outlet(0, 'executejavascript', SCRIPT);
}
Yeah, it is too hard to debug in development.
It would be useful to have an intermediate HTML as a template for development and extracting JavaScript like the above for the frozen M4L device from the template.
Among of ways to implement that demand, Python is a better tool because you would have prepared the environment for Max diff tool.
- Max 8.1 or later (see this section for Max 9)
- Python 3.8 or later
$ python3 jweb-inject.py [-i input-file] -o [output-file]
input-file
: the HTML template file. If not specified, it will bejweb-template.html
.output-file
: the name of the JavaScript file. If not specified, it will bejweb-inject.js
.
-o
flag is necessary for the extract function.
See the sample directory.
The workflow is as follows.
stateDiagram-v2
state "HTML Template" as template
state "M4L Device<br>(un-frozen)" as patch
state "jweb-inject.py" as py
state "JavaScript" as js
state "M4L Device<br>(frozen)" as m4l
[*] --> template: 1 Prepare HTML Template
template --> patch: modify<br>3 Prepare Max Patch
patch --> template: 4 Test/Fix Script in HTML
template --> py
py --> js : 5 Extract Injection JavaScript for jweb
patch --> m4l: 7 Freeze M4L Device
js --> m4l: 6 Import JavaScript to M4L
m4l --> [*] : Release!
The Python script jweb-inject.py
and HTML Template are the main factors.
We will discusses each steps.
Just checkout this repository or download the raw jweb-inject.py file.
Copy the HTML file or just copy and paste from below.
<!DOCTYPE html>
<html>
<head></head>
<body>
<script>
window.onload = function() {
/* @@@SOS@@@ */
// insert your code here
/* @@@EOS@@@ */
}
</script>
<body>
</html>
Do not remove the comments /* @@@SOS@@@ */
and /* @@@EOS@@@ */
. Those indicate the start and end of your codes when generating the inject script.
Send readfile [file name]
message to open the template HTML.
If you the HTML template in sample, ready
message will be output and it can be a trigger to send initialize parameter to jweb
or disable hidden
attribute.
As you can see in 3. Prepare the Max Patch,
You can only write ECMAScript between indicators @@@SOS@@@
and @@@EOS@@@
and cannot add any tags of HTML.
To display elements like text or input boxes, you have to write codes in WebAPI.
let label = document.createElement('label');
label.textContent = 'Hello World!';
window.document.body.appendChild(label);
Also, you need to add handler functions for inlets of jweb
object.
window.max.bindInlet('execute', function() {
window.max.outlet(42);
});
It is good to output a message at the end of the script to indicate if the injection succeeded.
<script>
/* @@@SOS@@@ */
// ...
// jweb outputs 'ready' message when injection succeeded.
window.max.outlet('ready');
/* @@@EOS@@@ */
</script>
It can trigger initializations in your patch such as sending hidden 0
message showing jweb
itself.
Again, do not remove the comments /* @@@SOS@@@ */
and /* @@@EOS@@@ */
.
Import HTML file to Max for Live device.
You can make any changes to the HTML for jweb
while your *.amxd
file is not frozen.
Execute Python script to generate JavaScript file that injects scripts for jweb
.
$ python3 jweb-inject.py -i jweb-template.html -o jweb-inject.js
If you have not modified HTML template from the sample, the generated JavaScript is like below.
// generated by jweb-inject.py
// based on jweb-template.html
autowatch = 1;
inlets = 1;
outlets = 1;
var SCRIPT = "let label = document.createElement('label');";
SCRIPT = SCRIPT + "label.textContent = 'Hello World!';";
SCRIPT = SCRIPT + "window.document.body.appendChild(label);";
SCRIPT = SCRIPT + "window.max.bindInlet('execute', function() {";
SCRIPT = SCRIPT + " window.max.outlet(42)";
SCRIPT = SCRIPT + "});";
SCRIPT = SCRIPT + "window.max.outlet('ready');";
function inject() {
outlet(0, 'executejavascript', SCRIPT);
}
Import the extracted JavaScript into your Max patch.
You have a few steps to inject to jweb
.
about:blank
is the URL for a blank tab/page. In chromium, it is not completely blank but it has HTML elements like below.
<html>
<head></head>
<body></body>
</html>
jweb
outputs onloadend about:blank
message when the load is completed.
Route onloadend
message to js
to execute inject
function.
Then <script>
will be injected into loaded HTML body of jweb
.
Modified patch is like below.
When the device is loaded, live.thisdevice
sends read about:blank
message except readfile
.
Then jweb
object sends onloadend
when a blank page is loaded and
route
object fires inject
function in js
object.
jweb-sample-release.amxd is the actual result.
Just freeze as usual.
Et voilà, you have a M4L device which has jweb
content within itself.
Good luck!
- The extracted JavaScript will not be minified.
- You must use single quot
'
for string literals in your HTML template.jweb-inject.py
uses double quot"
to inject scripts. - As far as the author knows, there are no way to
import
other JavaScript in frozen M4L into the script injweb
.
You can import modules from the Web like CDN, but be aware if your M4L device will always be used with the Internet and the license of external modules, off course. - The author has not reported to the official that frozen M4L devices cannot load HTML files within themselves because it might be not the desired behavior.
- You can use
jweb
in MIDI Transform/Generate Tools, however, you cannot output dictionaries of transformed/generated notes tolive.miditool.out
directly. Because input and output within the apply cycle of MIDI Tool must be synchronized like Node for Max.
Also, see details in Memorandum of M4L development for MIDI Tools.
Max 9 introduced v8
object which can run modern ECMAscript.
You may write directly ECMAscript with linter.
This means you can inject it into jweb
without intermediate templates as follows.
// this code is not confirmed to work
autowatch = 1;
inlets = 1;
outlets = 1;
targetFunction.local = 1;
function targetFunction() {
let label = document.createElement('label');
label.textContent = 'Hello World!';
window.document.body.appendChild(label);
window.max.bindInlet('execute', function() {
window.max.outlet(42)
});
window.max.outlet('ready');
}
function inject() {
outlet(0, 'executejavascript', targetFunction.toString());
}
It is not confirmed if Max 9 could handle HTML files in freezed M4L devices.