JavaScript - Library (Available on WebRepo)

Hi All,

I’ve been working with the new ObjC API and have got to a releasable point on a JavaScript library.

I’m sure the code below will demonstrate what it’s capable of better than I can put into words!

WebRepo Link

JavaScript only:

~~~ -- JS only webview (no HTML provided) local webview = WebView()
-- Imported functions made available to JS!
-- (Return values not yet supported)
webview:import("print", function(...)
    print(...)
end)

-- Load JavaScript string
webview:loadJS([[
    // Functions can accept parameters from Lua!
    function main(num1, num2) {

        // You can call imported Lua functions!
        print("Hello JavaScript!");
        
        // Values can be returned to Lua!
        return num1 + num2;
    }
]])

-- Can call a JS function with arguments and get the result!
local result = webview:call("main", 9, 7)
print("Result: ", result)


<h2>Loading a HTML page & calling a JavaScript function defined in the HTML:</h2>
-- Load and show a HTML page from disk
local webview = WebView(asset.core)
webview:show()

-- Imported functions made available to JS!
-- (Return values not yet supported)
webview:import("print", function(...)
    print(...)
end)

-- Call a function defined in the HTML file
webview:call("htmlTest")


<h2>Just displaying a simple web page:</h2>
-- Load and display a simple HTML page
local webview = WebView([[
    <center>
        <br/>
        <br/>
        Hello Codea!
        <br/>
        I came from a string :)
    </center>
]])
webview:show()


<h2>Bulk function imports:</h2>
-- JS only webview (no HTML provided)
local webview = WebView()

-- Imported functions made available to JS!
-- (Return values not yet supported)
local imports = {
    ["print"] = function(...)
        print(...)
    end,
    ["helloWorld"] = function()
        print("Hello Codea!")
    end
}
webview:import(imports)

-- Load JavaScript string
webview:loadJS([[
    // Functions can accept parameters from Lua!
    function main(num1, num2) {

        // Can call imported Lua functions!
        print("Demo! -----");

        // Call another imported function!
        helloWorld();
        
        // Values can be returned to Lua!
        return num1 * num2;
    }
]])

-- Can call a JS function with arguments and get the result!
local result = webview:call("main", 9, 9)
print("Result: ", result)

Note that this entire library relies on some async -> sync magic provided by ‘STLib’ that requires a shift in the normal program flow in Codea.

Rather than use the `setup()` & `draw()` functions, please run your code within a `main()` function (shown in the included project demos). I hope to release this as a separate library soon as it allows for some very useful functionality.

Steppers
o7

Yo this is awesome, but my major questions are:

Does it support css? Does it support SVGs?

@skar It’s just a WKWebView on the backend so I can’t see why not :smile: You can add svgs or css to the project assets and reference them from the HTML.

Very good! Can it support three.js?

@binaryblues Should do!

I’ll note that I’m also working on an additional 3D WebGL based API similar to that of Codea’s that I hope to upload at some point soon :smile: I’ve just got a lot of stuff to plug in & connect up.

Here’s about where I am at the moment (this is JS):

function setup() {
	gl.clearColor(0.4, 0.2, 0.2, 1.0);
	
	print("Listening for touch events...");
	
	viewer.mode = FULLSCREEN;
}

function draw(deltaTime) {
	gl.clear(gl.COLOR_BUFFER_BIT);
}

function touched(t) {
	print(t.pos.x, t.pos.y);
}

@Steppers Great! Looking forward to it!

@Steppers - looks very promising. Will you be incorporating Three.js ?

I’ll keep an eye on this thread. Thanks.

@Bri_G @binaryblues Here we go :smile:

If you run the JavaScript project it provides full documentation directly from a HTML page generated by LDoc!

Three.js 1.0a is currently largely untested but provides enough of a base to render a green cube with the OrbitControls from Three.js

Unfortunately the support for importing ES modules directly in JavaScript like import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; is very limited so you need to use the webview:importJSModule() function from Lua to correctly load them (from what I can tell). This is done already for the OrbitControls module as an example.

The JavaScript 1.1.0 library is also available on WebRepo.

If you have any issues or suggestions do let me know!

Cheers o7

Edit: Downloads removed due to issues (please use WebRepo)

@Steppers - great stuff, will play with this. Not programmed in JavaScript for a while so will be very rusty.
Thanks again.

Great job! I’ve done some experiments, very good!

Thanks a lot!

Btw. We can put the JS code in a long string, then it will be easy to edit, like bellow:

function main()
    
    -- Load the Three.js page
    webview = WebView(asset.index)
    
    -- Import initial global values
    importGlobals(webview)
    
    -- Load Three.js ES modules
    print("Loading modules...")
    -- We're currently limited to Three.js 0.136.0 due to a lack of import map
    -- support on iOS.
    -- https://caniuse.com/import-maps
    webview:importJSModule('https://cdn.skypack.dev/three@0.136.0', nil, 'THREE')
    webview:importJSModule('https://cdn.skypack.dev/three@0.136.0/examples/jsm/controls/OrbitControls.js', { 'OrbitControls' })
    print("Done loading modules.")
    
    -- Load the user code
    -- webview:loadJS(asset.user)
    webview:loadJS(JSCode2)
    
    -- Display once the engine has initialised
    webview:show()
end

JSCode = [[

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight);
renderer.setSize( window.innerWidth * ContentScaleFactor, window.innerHeight * ContentScaleFactor, false );
document.body.appendChild( renderer.domElement );

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );

const controls = new OrbitControls( camera, renderer.domElement );

//controls.update() must be called after any manual changes to the camera's transform
camera.position.set( 0, 0, 5 );
controls.update();

function animate() {
	requestAnimationFrame( animate );

	cube.rotation.x += 0.01;
	cube.rotation.y += 0.01;
	
	// required if controls.enableDamping or controls.autoRotate are set to true
	controls.update();

	renderer.render( scene, camera );
}

animate();

viewer.mode = FULLSCREEN;
]]

JSCode2 = [[
var scene = new THREE.Scene();
var flat ={flatShading: true};
var light = new THREE.AmbientLight('white',0.8);
scene.add(light);

var aspectRatio = window.innerWidth/window.innerHeight;
var camera = new THREE.PerspectiveCamera(75,aspectRatio,1,10000);
camera.position.z = 350;
scene.add(camera);

var renderer=new THREE.WebGLRenderer({antialias:true});
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);

var shape = new THREE.SphereGeometry(100);
var cover = new THREE.MeshNormalMaterial(flat);
var ball = new THREE.Mesh(shape,cover);
scene.add(ball);

renderer.render(scene,camera);
]]

Here is my snapshot:

Avatar demo:

https://youtu.be/YB2levjndck

Shadow demo:

https://youtu.be/p78fu2v1f34

@binaryblues Nice work! The long text was just an option because I know people may prefer it (Personally I use textastic to edit the JS file directly).

I’ve got a more extensive example working from the official Three.js examples too but it’s a little too large (3.7MB) for the forum so is only available on WebRepo I’m afraid.

I’ll point out that it’s using a currently undocumented feature of the JavaScript lib to grab the model file; using codea:// which is a custom url handler to load Codea project assets from the JS.

@binaryblues - looks good but doesn’t run, fails on first line loading WebView.

@Bri_G This line? ~local webview = WebView(asset.doc.index)~

If so you can delete it as that’s just something from the JavaScript project demo

@Bri_G Which one you can not run? For me, the Three.js_1_0a.zip can run normally, but the JavaScript_1.1.0.zip can not show anything. I copied the project to CODEA’s Documents directory before it started running.

@Steppers Very good! I will check the WebRepo to dowload the newest one. Thanks!

I have 2 questions:

  1. How to use the Codea project assets from the JS?
  2. How to use the internet assets from the JS?

In my Codea Documents? there is a pic named grass.png.

I tried use it like bellow, but it does not work:

var texture = new THREE.TextureLoader().load("codea://asset.Documents.grass.png");

Or I want to use a asset on a website, like bellow:

  var texture = new THREE.TextureLoader().load("https://code3dgames.com/textures/hardwood.png");

but nothing happened.

@binaryblues The codea:// url doesn’t work exactly like Codea’s asset system (it uses normal file paths) and has the root in the project bundle. This should work though I think: codea://../grass.png (Edit: this certainly works for me)

As for the online ones, I’m not entirely sure what’s going on there yet. I have tried similar with the Model in the Three.js project on WebRepo but couldn’t get it working just yet so included the model. I’ll take a look

@binaryblues @steppers - couldn’t get the original post you made to run. Deleted the line you sugested and the project ran but was just a blank screen.

Loaded @steppers demo in from webrepo and that worked fine. That is some impressive demo. Pad ran out of power so will recharge then dig a little deeper. Thanks for your posts.

@Bri_G You may be better off downloading both the Three.js & JavaScript projects from WebRepo tbh, they’ll be the most up to date ones. Not sure what went wrong with the ones on the forum.

@Steppers It works! Thanks!

Put the texture grass.png into Codea’s Documents, then using this line:

var texture = new THREE.TextureLoader().load("codea://../grass.png");

https://youtu.be/o6p-wwiHI2o

@binaryblues Nice job! Looks great