Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

JavaScript - Library (Available on WebRepo)

edited March 7 in Code Sharing Posts: 412

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)

Loading a HTML page & calling a JavaScript function defined in the HTML:

    -- 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")

Just displaying a simple web page:

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

Bulk function imports:

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

«1

Comments

  • Posts: 308

    Yo this is awesome, but my major questions are:

    Does it support css? Does it support SVGs?

  • edited February 26 Posts: 412
    @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?

  • edited February 27 Posts: 412

    @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);
    }
    
  • Posts: 297

    @Steppers Great! Looking forward to it!

  • Posts: 2,689

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

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

  • edited March 8 Posts: 412

    @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)

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

    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:

  • Posts: 412

    @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.

  • Posts: 2,689

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

  • edited March 7 Posts: 412
    @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
  • Posts: 297

    @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.

  • edited March 7 Posts: 412

    @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

  • Posts: 2,689

    @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.

  • edited March 7 Posts: 412
    @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.
  • Posts: 297

    @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

  • Posts: 412
    @binaryblues Nice job! Looks great
  • edited March 8 Posts: 412

    @binaryblues Loading from a web url seems to work just fine if you use the Three.js project from WebRepo and replace the JS with this:

    // Black texture workaround for iOS
            // https://discourse.threejs.org/t/textures-in-gltf-sometimes-display-black-but-only-on-ios/30520/28
            window.createImageBitmap = undefined;
    
            let camera, scene, renderer;
                let mesh;
    
                init();
                animate();
    
                function init() {
    
                    camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
                    camera.position.z = 400;
    
                    scene = new THREE.Scene();
    
                    const texture = new THREE.TextureLoader().load( 'https://www.code3dgames.com/textures/hardwood.png');
    
                    const geometry = new THREE.BoxGeometry( 200, 200, 200 );
                    const material = new THREE.MeshBasicMaterial( { map: texture } );
    
                    mesh = new THREE.Mesh( geometry, material );
                    scene.add( mesh );
    
                    renderer = new THREE.WebGLRenderer( { antialias: true } );
                    renderer.setPixelRatio( window.devicePixelRatio );
                    renderer.setSize( window.innerWidth, window.innerHeight );
                    document.body.appendChild( renderer.domElement );
                }
    
                function animate() {
    
                    requestAnimationFrame( animate );
    
                    mesh.rotation.x += 0.005;
                    mesh.rotation.y += 0.01;
    
                    renderer.render( scene, camera );
    
                }
    

    It may have been an issue with an older version of the JavaScript lib from the forum.

    I’ll also point out that any texture loaded from the internet needs to support Cross-Origin-Resource-Sharing CORS. If the server doesn’t return an access-control-allow-origin: * header then WebGL will allow the image to be used.

  • edited March 8 Posts: 297

    @Steppers Yes! It works! very well!

    It looks like you've made some modifications to three.js. Do all the modules you need to import do the same In that case? suppose I want to import these modules:

    https://code3dgames.com/controls/FlyControls.js
    https://code3dgames.com/controls/OrbitControls.js
    https://code3dgames.com/physi.js
    https://code3dgames.com/tween.js
    https://code3dgames.com/sounds.js
    https://code3dgames.com/noise.js
    https://code3dgames.com/scoreboard.js
    

    What Should I do? Thank you!

    This is the video:

    https://youtu.be/Twh9Ch3LIos

  • Posts: 412

    @binaryblues I’m assuming you’re using the book by Chris Strom?

    If you are then the examples appear to not be using ES modules at all as it’s a far older version of Three.js so it can just be loaded like a normal JS script.

    You’ll need to add the latest ‘JavaScript’ 1.1.1 lib (on WebRepo) as a dependency but this should work just fine once you add some user code :smile:

    function main()
    
        -- Create a webview
        webview = WebView()
    
        -- Import initial global values
        importGlobals(webview)
    
        -- Load Three.js
        webview:loadJS('https://code3dgames.com/three.js', true)
        webview:loadJS('https://code3dgames.com/controls/FlyControls.js', true)
        webview:loadJS('https://code3dgames.com/controls/OrbitControls.js', true)
        webview:loadJS('https://code3dgames.com/physi.js', true)
        webview:loadJS('https://code3dgames.com/tween.js', true)
        webview:loadJS('https://code3dgames.com/sounds.js', true)
        webview:loadJS('https://code3dgames.com/noise.js', true)
        webview:loadJS('https://code3dgames.com/scoreboard.js', true)
    
        -- Load the user code
        webview:loadJS([[
            — Your user code here…
        ]], true)
    
        -- Display once the engine has initialised
        webview:show()
    end
    
  • edited March 8 Posts: 297

    @Steppers Yes, you guessed it, I Learned javascript from this book and found it to be a particularly good introduction to javascript.

    Now there is a new problem, It showed error when I install the project from WebRepo:

    the error of WebRepo:

    DB:231: attempt to index a nil value (local 'file')
    stack traceback:
        DB:231: in field 'installApp'
        AppWindow:151: in upvalue 'callback'
        _dep_Documents:Oil:655: in local 'handler'
        _dep_Documents:Oil:1944: in method 'internal_handle_event'
        _dep_Documents:Oil:1936: in method 'handle_event'
        _dep_Documents:Oil:1954: in method 'children_handle_event'
        _dep_Documents:Oil:938: in method 'handle_event'
        _dep_Documents:Oil:1954: in method 'children_handle_event'
        _dep_Documents:Oil:1932: in method 'handle_event'
        _dep_Documents:Oil:1954: in method 'children_handle_event'
        _dep_Documents:Oil:1932: in method 'handle_event'
        _dep_Documents:Oil:429: in upvalue 'dispatch_event'
        _dep_Documents:Oil:527: in field 'touch'
        Main:173: in function 'touched'
    

    the error of JavaScript:

    _dep_Documents:STLib:158: Main:3: attempt to index a nil value (field 'doc')
    stack traceback:
        [C]: in function 'error'
        _dep_Documents:STLib:158: in upvalue 'callback'
        _dep_Documents:STLib:88: in field 'callback'
        _dep_Documents:STLib:63: in upvalue 'finishTween'
        ...in pairs(tweens) do
        c = c + 1
      end
      return c
    end
    
    :589: in function <...in pairs(tweens) do
        c = c + 1
      end
      return c
    end
    
    :582>
    
  • edited March 8 Posts: 412
    @binaryblues That looks like you have an old version of WebRepo which means project subdirectories won't work. Does WebRepo not offer an update for itself? You'll need the latest version (2.1.2).

    Also available here: https://github.com/steppers/codea-community-repo/releases/tag/2.1.1
  • Posts: 297

    @Steppers Yes, I used an old WebRepo. When I get the new one(2.1.1) from github, it can install the JavaScript and the Three.js, and the Three.js need to modify the line:

    function main()
        local webview = WebView(asset.doc.index)
        webview:show()
        viewer.mode = FULLSCREEN
    end
    

    to

     local webview = WebView(asset.threejs_demo.index)
    

    then it will show the model scene like the video:

    https://youtu.be/xWKYbNthA3g

    Btw. a very interesting scene! I like it.

  • Posts: 297

    In Three.js there is another error, this line:

    function demo2()
    
        -- Load and show a HTML page from disk
        local webview = WebView(asset.core)
        webview:show()
    

    In the project, I can not find the file core.

  • edited March 9 Posts: 297

    And it works! Need to comment this line in the main():

    importGlobals(webview)
    

    Using the Three.js from https://www.code3dgames.com/

    Only in one example, these lines, I modified it from:

    // Physics settings
    Physijs.scripts.ammo = '/ammo.js';
    Physijs.scripts.worker = '/physijs_worker.js';
    

    to

    // Physics settings
    //Physijs.scripts.ammo = '/ammo.js';
    //Physijs.scripts.worker = '/physijs_worker.js';
    Physijs.scripts.ammo = 'https://www.code3dgames.com/ammo.js';
    Physijs.scripts.worker = 'https://www.code3dgames.com/physijs_worker.js';
    

    It returned this:

    393:28 SecurityError: The operation is insecure.
    

    Here is the whole code of myJS:

    -- MyJS
    
    function main()
    
        -- Create a webview
        webview = WebView()
    
        -- Import initial global values
        -- importGlobals(webview)
    
        -- Load Three.js
        print("Loading modules...")
        webview:loadJS('https://code3dgames.com/three.js', true)
        webview:loadJS('https://code3dgames.com/controls/FlyControls.js', true)
        webview:loadJS('https://code3dgames.com/controls/OrbitControls.js', true)
        webview:loadJS('https://code3dgames.com/physi.js', true)
        webview:loadJS('https://code3dgames.com/tween.js', true)
        webview:loadJS('https://code3dgames.com/sounds.js', true)
        webview:loadJS('https://code3dgames.com/noise.js', true)
        webview:loadJS('https://code3dgames.com/scoreboard.js', true)
        print("Done loading modules.")
    
        -- Load the user code
        webview:loadJS(JSCode4, true)
    
        -- Display once the engine has initialised
        webview:show()
    end
    
    
    JSCode4 = [[
    
    // Physics settings
    //Physijs.scripts.ammo = '/ammo.js';
    //Physijs.scripts.worker = '/physijs_worker.js';
    Physijs.scripts.ammo = 'https://www.code3dgames.com/ammo.js';
    Physijs.scripts.worker = 'https://www.code3dgames.com/physijs_worker.js';
    
    // The "scene" is where stuff in our game will happen:
    var scene = new Physijs.Scene();
    scene.setGravity(new THREE.Vector3( 0, -100, 0 ));
    var flat = {flatShading: true};
    var light = new THREE.AmbientLight('white', 0.2);
    scene.add(light);
    
    
    
    // The "camera" is what sees the stuff:
    var aspectRatio = window.innerWidth / window.innerHeight;
    var camera = new THREE.PerspectiveCamera(75, aspectRatio, 1, 10000);
    camera.position.z = 500;
    camera.position.y = 200;
    camera.lookAt(new THREE.Vector3(0, 0, 0));
    scene.add(camera);
    
    // The "renderer" draws what the camera sees onto the screen:
    var renderer = new THREE.WebGLRenderer({antialias: true});
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    document.body.appendChild(renderer.domElement);
    
    // ******** START CODING ON THE NEXT LINE ********
    function addGround() {
    var w = window.innerWidth;
    var h = window.innerHeight;
    var shape = new THREE.BoxGeometry(2*w, h ,1);
    var cover = new THREE.MeshBasicMaterial({color: 'lawngreen'});
    var ground = new Physijs.BoxMesh(shape, cover, 0)
    ground.position.y = -h/2;
    ground.receiveShadow.enabled = true;
    scene.add(ground);
    return ground;
    }
    
    var ground = addGround();
    
    function addLight() {
    var light = new THREE.PointLight('white', 0.4);
    light.position.set(50,200,-100);
    light.castShadow = true;
    scene.add(light);
    return light;
    }
    
    var light1 = addLight();
    
    function Launcher() {
    this.angle = 0;
    this.power = 0;
    this.draw();
    }
    
    Launcher.prototype.draw = function() {
    var direction = new THREE.Vector3(0, 1, 0);
    var position = new THREE.Vector3(0, -100, 250);
    var length = 100;
    this.arrow = new THREE.ArrowHelper(
    direction,
    position,
    length,
    'yellow'
    );
    scene.add(this.arrow);  
    };
    
    Launcher.prototype.vector = function() {
    return new THREE.Vector3(
    Math.sin(this.angle),
    Math.cos(this.angle),
    0
    );
    }
    
    Launcher.prototype.moveLeft = function() {
    this.angle = this.angle - Math.PI/100;
    this.arrow.setDirection(this.vector());
    }
    
    Launcher.prototype.moveRight = function() {
    this.angle = this.angle + Math.PI/100;
    this.arrow.setDirection(this.vector());
    }
    
    Launcher.prototype.powerUp = function() {
    if (this.power >= 100) return;
    this.power = this.power + 5;
    this.arrow.setLength(this.power);
    }
    
    Launcher.prototype.launch = function() {
    var shape = new THREE.SphereGeometry(10);
    var material = new THREE.MeshPhongMaterial({color: 'yellow'});
    var ball = new Physijs.SphereMesh(shape, material, 1);
    ball.name = "Game Ball";
    ball.position.set(0, 0, 300);
    ball.castShadow = true;
    scene.add(ball);
    
    var speedVector = new THREE.Vector3(
    2.5*this.power * this.vector().x,
    2.5*this.power * this.vector().y,
    -80
    );
    ball.setLinearVelocity(speedVector);
    this.power = 0;
    this.arrow.setLength(100);
    };
    
    
    function Basket(size, points) {
    this.size = size;
    this.points = points;
    this.height = 100/Math.log10(size);
    var r = Math.random;
    this.color = new THREE.Color(r(), r(), r());
    
    this.draw();
    }
    
    Basket.prototype.draw = function() {
    var cover = new THREE.MeshPhongMaterial({
    color: this.color,
    shininess: 50,
    specular: 'white'
    });
    
    var shape = new THREE.CubeGeometry(this.size, 1, this.size);
    var goal = new Physijs.BoxMesh(shape, cover, 0);
    goal.position.y = this.height/100;
    scene.add(goal);
    
    var halfSize = this.size/2;
    var halfHeight = this.height/2;
    
    shape = new THREE.CubeGeometry(this.size, this.height, 1);
    var side1 = new Physijs.BoxMesh(shape, cover, 0);
    side1.position.set(0, halfHeight, halfSize);
    scene.add(side1);
    
    var side2 = new Physijs.BoxMesh(shape, cover, 0);
    side2.position.set(0, halfHeight, -halfSize);
    scene.add(side2);
    
    shape = new THREE.CubeGeometry(1, this.height, this.size);
    var side3 = new Physijs.BoxMesh(shape, cover, 0);
    side3.position.set(halfSize, halfHeight, 0);
    scene.add(side3);
    
    var side4 = new Physijs.BoxMesh(shape, cover, 0);
    side4.position.set(-halfSize, halfHeight, 0);
    scene.add(side4);
    
    this.waitForScore(goal);
    }
    
    Basket.prototype.waitForScore = function(goal) {
    goal.addEventListener('collision', this.score.bind(this));
    }
    
    Basket.prototype.score = function(ball) {
    if (scoreboard.getTimeRemaining() == 0) return;
    scoreboard.addPoints(this.points);
    scene.remove(ball);
    }
    
    function Wind() {
    this.draw();
    this.change();
    }
    
    Wind.prototype.draw = function() {
    var dir = new THREE.Vector3(1, 0, 0);
    var start = new THREE.Vector3(0, 200, 250);
    this.arrow = new THREE.ArrowHelper(dir, start, 1, 'lightblue');
    scene.add(this.arrow);
    }
    
    Wind.prototype.change = function() {
    if (Math.random() < 0.5) this.direction = -1;
    else this.direction =1;
    this.strength = 20 * Math.random();
    
    this.arrow.setLength(5*this.strength);
    this.arrow.setDirection(this.vector());
    
    setTimeout(this.change.bind(this), 10000);
    }
    
    Wind.prototype.vector = function() {
    var x = this.direction * this.stength;
    return new THREE.Vector3(x, 0, 0);
    }
    
    function allBalls(){
    var balls = [];
    for (var i=0; i<scene.children.length; i++) {
    if (scene.children[i].name.startsWith('Game Ball')) {
    balls.push(scene.children[i]);
    }
    }
    return balls;
    }
    var goal1 = new Basket(200,10);
    var goal2 = new Basket(40, 100);
    
    var launcher = new Launcher();
    var wind = new Wind();
    
    var scoreboard = new Scoreboard();
    scoreboard.countdown(60);
    scoreboard.score(0);
    scoreboard.help(
    '使用左右方向键调整发射方向.' +
    '按住向下方向键不放给发射器蓄力.' +
    '松开向下方向键发射.' +
    '小心有风!!!'
    );
    scoreboard.onTimeExpired(timeExpired);
    function timeExpired() {
    scoreboard.message("Game Over!");
    }
    
    // Animate motion in the game
    function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
    }
    
    animate();
    
    // Run physics
    function gameStep() {
    scene.simulate();
    
    var balls = allBalls();
    for (var i=0; i<balls.length; i++) {
    balls[i].applyCentralForce(wind.vector());
    if (balls[i].position.y < -100) scene.remove(balls[i]);
    }
    // Update physics 60 times a second so that motion is smooth
    setTimeout(gameStep, 1000/60);
    }
    gameStep();
    
    document.addEventListener('keydown', sendKeyDown);
    function sendKeyDown(event) {
    var code = event.code;
    if (code == 'ArrowLeft') launcher.moveLeft();
    if (code == 'ArrowRight') launcher.moveRight();
    if (code == 'ArrowDown') launcher.powerUp();
    //if (code == 'Arrow')
    }
    
    document.addEventListener('keyup', sendKeyUp);
    function sendKeyUp(event) {
    var code = event.code;
    if (code == 'ArrowDown') launcher.launch();
    }
    
    ]]
    
  • Posts: 412

    @binaryblues Those issues should be resolved in the latest Three.js project on WebRepo. Though even with those errors in the editor it still ran for me.

    I’ll also point out that the _dep_ tabs are auto included dependencies generated during an upload to WebRepo and should usually be ignored and not modified at all.

  • edited March 9 Posts: 412

    @binaryblues Try the same script as you had above with Three.js 1.0.3 (on WebRepo). Seems to work for me now.

    Turns out JavaScript Worker threads aren’t perfect in a WKWebView but 1.0.3 has a workaround included automatically now :smile:

  • Posts: 297

    @Steppers I got the new version:

    • three.js : 1.0.3
    • javascript: 1.1.2

    Now all work! Thank you! Very well!

    Have you ever wondered how to use a virtual keyboard in Codea Javascript code ?

  • Posts: 412

    @binaryblues With the latest ‘JavaScript’ lib from WebRepo (v1.1.3):

        local webview = WebView()
    
        -- Alias console.log to Lua's print function
        webview:import("console.log", print)
    
        webview:import({
            showKeyboard = function()
                print("Showing keyboard")
                showKeyboard();
            end,
            hideKeyboard = function()
                print("Hiding keyboard")
                hideKeyboard();
            end,
        })
        webview:loadJS([[
            // Show the keyboard
            showKeyboard();
    
            // Function to be called on key events
            function keyboard(key) {
    
                // Print the key!
                console.log(key);
            }
        ]], true)
    
        _G.keyboard = function(key)
            ST.runAsync(function()
                webview:callAsync("keyboard", key)
            end)
        end
    
  • Posts: 297

    @Steppers Get the JavaScript 1.1.3 and it works very well!

    The only thing that matters now is how to distinguish between keydown and keyup, the two states of pressing a key and releasing a key, but this seems to be handled by Codea's keyboard() function.

    Other than that, everything's great. Thank you for your work.

  • Posts: 412

    @binaryblues Check out 'MKInput' on WebRepo :smile: It does exactly that in Lua (not JS).

    However, doing this from within JS is preferable (you need to tap or click first for key events to work):

    function main()
        local webview = WebView()
        webview:show()
    
        webview:import("console.log", print)
        webview:loadJS([[
            window.addEventListener("keydown", (event) => {
                if (event.repeat) return;
                console.log(`Key pressed: ${event.code}`);
            });
    
            window.addEventListener("keyup", (event) => {
                console.log(`Key released: ${event.code}`);
            });
        ]], true)
    end
    
  • Posts: 297

    @Steppers In case I didn't make myself clear, I'm talking about the iPad's virtual keyboard, not the external physical Bluetooth keyboard.

    In my example code, I have these lines:

    document.addEventListener('keydown', sendKeyDown);
    function sendKeyDown(event) {
    var code = event.code;
    if (code == 'ArrowLeft') launcher.moveLeft();
    if (code == 'ArrowRight') launcher.moveRight();
    if (code == 'ArrowDown') launcher.powerUp();
    //if (code == 'Arrow')
    }
    
    document.addEventListener('keyup', sendKeyUp);
    function sendKeyUp(event) {
    var code = event.code;
    if (code == 'ArrowDown') launcher.launch();
    }
    

    But on a virtual keyboard, they don't work.

  • Posts: 412

    @binaryblues Ah, I see what you mean.
    As far as I know, the iOS virtual keyboard doesn’t support that at all I’m afraid.

  • Posts: 297

    @Steppers I got it, Thank you for explaining that.

    I'll try to check the iOS documentation to see if there's a clear indication of support.

  • Posts: 1,795
    Couldn’t download from WebRepo.

    Error message attached.

    Project was created but it only had two tabs.
  • Posts: 412
    @UberGoober You'll want the latest update from the WebRepo GitHub page :smile:
  • Posts: 1,795
    @Steppers WebRepo won’t update itself correctly anymore?
  • Posts: 297

    @UberGoober You can try these file, I packed from my Codea

  • edited March 22 Posts: 1,795
    @binaryblues thanks!

    JavaScript seems to work well but Three.is won’t run, it just gives an error message.

    I don’t fully get what this is doing—could it, for example, run ProcTree:

    https://github.com/supereggbert/proctree.js/blob/master/proctree.js
  • edited March 22 Posts: 297

    @UberGoober I looked at the code you provided and found that it used a special representation that was different from my usual javascript code because I was a javascript beginner myself, so it wasn't clear, how does this form need to be transformed in three.js works within a common code framework.

  • Posts: 297

    I looked up that syntax:

    (function(window){
    var Tree=function(data){
            for(var i in data){
                if(this.properties[i]!==undefined){
                    this.properties[i]=data[i];
                }
            }
            this.properties.rseed=this.properties.seed;
            this.root=new Branch([0,this.properties.trunkLength,0]);
            this.root.length=this.properties.initalBranchLength;
            this.verts=[];
            this.faces=[];
            this.normals=[];
            this.UV=[];
            this.vertsTwig=[];
            this.normalsTwig=[];
            this.facesTwig=[];
            this.uvsTwig=[];
            this.root.split(null,null,this.properties);
            this.createForks();
            this.createTwigs();
            this.doFaces();
            this.calcNormals();     
        };
    
        ......
    
    Tree.flattenArray=function(input){
    var retArray=[];
        for(var i=0;i<input.length;i++){
            for(var j=0;j<input[i].length;j++){
                retArray.push(input[i][j]);
            }
        }
        return retArray;
    }
    
        window.Tree=Tree;
    })(window);
    

    and it turns out that you define an anonymous function and then call it immediately after.

    In other words, it's a form of closure.

    Define an anonymous function:

    (function(window){...})
    

    Call this anonymous function:

    (window)
    
  • Posts: 1,795

    …sorry, but does that mean that it can run ProcTree or that it can’t?

  • edited March 23 Posts: 297

    @UberGoober I looked at Proctree.js and found that it didn't call three.js, nor any other drawing-related statements, and it looked like a separate module that needed to be called through other modules.

    Can you elaborate on how you got it to work?

    The only thing that might be relevant is the window parameter, which I guess is the key to getting proctree to run, but that happens to be my knowledge blind spot

  • edited March 23 Posts: 308

    The window parameter here is only used to make Tree a global variable that you can call anywhere with “ Tree” you could pass any object to have Tree assigned to it.

    The problem I see is this call this.root=new Branch( “Branch” has to exist in this scope. actually it’s there in the full file on GitHub

  • edited March 23 Posts: 297

    @skar Thank you for explaining the window parameters.

    In fact, I found that this code should be native webgl, not using three.js, but using vertices, uv, normals, which looks like Codea mesh, but without shader.

  • edited March 24 Posts: 1,795
    Attached is my own project where I clumsily tried to port the JavaScript procTree to lua.

    Didn’t get far, as you’ll see.

    Also here’s the link I got this code from, it’s different than the one I gave before:

    https://github.com/jarikomppa/proctree
  • Posts: 1,795

    So in case it isn’t clear—in my project I tried to turn JavaScript code into lua code, but the project itself still contains the JavaScript code as reference.

    My conversion of the js code didn’t work, but if I could run the js code itself I should be able to use it to make a nice little tree.

    So if someone could tell me how to use the JavaScript project from this thread to run the js code in the above project, it could be really cool.

  • Posts: 1,795

    Okay in attached file I’ve tried to use WebView to load the JavaScript but when I hit play I get an error about not having stlib.

Sign In or Register to comment.