Debugging Entity Scripts in a Web Browser (initial tests + brainstorm)


#1

So this weekend I explored the possibility of running Entity script code entirely from a web browser. For example, here is Philip’s hypnotic FlockofFish.js entities script running in two different ways:

left == Interface; right == Chrome

The emulation layer could in theory be made to work with most modern browsers – so maybe a lightweight IDE of sorts could be created around this premise?

Note that in this model the built-in debugging tools of modern browsers become available directly:

inspecting live variables while stepping through edit.js and related entitySelectionTool.js code

Anybody know of other ways to interactively debug Entity scripts at the moment?


Features we don't need?
#2

Ive lost the amount of times I had to put in print(JSON.stringify(object)) in my scripts just to check what some variables contained so I really like this.


#3

What is this sorcery


#4

how does this work!? tell me more!! :slight_smile:


#5

Magic-User Level 5 Spell… must be at least level 9 with 135,001 experience points to even attempt this spell.


#6

One way to explain how it works might be in terms of “mock objects” –

If VR mimics reality we could say virtual interfaces mimic interfaces; here’s a quick example:

> JSON.stringify(MyAvatar.position) ⏎
 `ReferenceError: MyAvatar is not defined`

> MyAvatar = {position:{x:null, y:null, z:null}} ⏎
 `Object {position: Object}`

> JSON.stringify(MyAvatar.position) ⏎
 `"{"x":null,"y":null,"z":null}"`

Taken a little further we could already write Entity scripts that run in Interface and debug (separately) using any modern JavaScript IDE:

print('avatar position: ' + JSON.stringify(MyAvatar.position));

Of course… it’s not quite that simple. In my case it took something like ~3K SLOC of CoffeeScript to emulate enough of the APIs to get defaultScripts.js barely-loading without exceptions.

Just for fun here’s a screen shot taken from old single-core Android / Firefox (whopping ~6fps!). On iPad 2 / Safari it seemed workable though at around 30 fps – which might just be fast enough to tinker with actual objects on a Domain server over WebSockets or something.


#7

Would be good if such mock.js script could be generated from the source code so that each build would generate one.


#8

It looks intressting. especially if you can monitor more easy variables. Still a print is sometimes helpfull to until you always know the figh way to read json :slight_smile:


#9

Yeah totally – static analysis could go a long way here.

Back when generating an Overlays relationship diagram I was able to get by with a handful of grep|sed commands to extract the metadata, but to decipher the whole scripting API might require something more elaborate.

There is also a bit of state emulation needed to keep certain scripts from complaining – for example, returning reasonable results from Entities.getEntityProperties() depends on tracking values passed to earlier .addEntity and .editEntityProperties calls.

I tried loading your Hookgun scripts earlier and it looks like I’m still missing a few core methods like MyAvatar.addThrust, but in principle some unit testing etc. would already be possible on top of the current brute-force emulation.

EDIT: after mocking a few more functions the hook guns are now firing in-browser!


#10

Awesome. Althought the position of the ropes seems off than how its in world.


#11

Yeah I noticed that too – when back at a good computer will have to run some more side-by-side tests to see where my bug is. Maybe I just need to maintain the object’s centroid when applying new dimensions?

Btw, that’s a very clever use of boxes to mock ropes! :wink:

On a different note, when tuning the physics did you ever wish you could rewind and reply time to test new parameters?

Because I keep thinking back to Bret Victor’s Invention on Principle video – especially around 10:30 in, where he leverages time as a free variable and “onion skinning” as part of the development process for physics simulations.


#12

Definitely.

I had to actually test it constantly by using the tools, as I lacked the ability look. So isntead of any complex things I just decided to mix the target vector (GRAVITY) with the current GlobalVelocity with a 10% change per frame towards the target :smiley:

Not the most ideal thing, Id rather have the engine handle the physics than me doing it via constant thrust, but Ill have to dig up on it.


#13

From today’s meetup another potential use case came to mind: How about using this kind of emulation to execute untrusted Entity scripts?

This could give Users the option to sacrifice a degree of performance in favor of locally-managed security measures, which could be maintained as JavaScript modules at the community level.

I imagine this as complementing a certificate-based trust model.

And maybe the same layers could be used by Avatars on the same Domain to begin sharing CPU resources with each other in a reasonably-securable way.


#14

Hmm, just discovered another way – apparently if you hold down the Shift key at just the right moment, Interface will place underlying scripting engines into debuggable mode…

To try for yourself – just hold down Shift when first clicking Edit -> Console. That should cause the JavaScript Console’s engine instance to become debuggable – sending uncaught exceptions into the interactive QtScriptDebugger.


#15

when is “just the right moment”? or is there something I am missing here?


#16

Good question – this SHIFT hack seems to be a temporary kludge, so probably best to stick to the predictable Edit -> Console… case and manually load any particular scripts you want to work with from there.

To do that, hold down SHIFT continuously as you hunt for and click the Console… menu item – releasing SHIFT once the prompt appears. At that point you can type ‘debugger’ + Enter into the prompt and the QtScriptDebugger window should automagically appear.

The JavaScript Console is a no frills command prompt – but you can tinker with the whole API from there. And even load Interface scripts using Script.load('scriptname') , Script.include('scriptname') etc.