samsaraJS - first look

I have looked at RxJS and Bacon.js. There was a particularly important feature I needed that they couldn’t provide. For merging streams, they wait for all sources to emit an event for them to emit the merged event. In Samsara when you write

new SizeNode({
    size : ...
    margins : ...
});

this is a “merged stream” from two streams: size and margins. Both of them don’t need to be changing at the same time. It may be that only one is changing, and so I needed to come up with a way to still fire a change event on the merged stream (SizeNode). This involves a batching strategy tied to the request animation frame. Unfortunately this is a break to the modularity of the code, because it couples the FRP stuff to the raf cycle. I haven’t yet figured a way around this though. Maybe someone here has some good ideas.

I haven’t yet experimented with web workers. I think it should be relatively straightforward, as there is a clear separation between the purely JS parts and the parts that touch the DOM. Though honestly the JS execution time is quite small. Unlike famous, where the render tree was constructed from scratch each frame, because of the stream nature of samsara, only the subtrees where a change has occurred needs to be recomputed. There is only one way I’ve thought of to make it faster (and indeed optimal), which involves some aggressive caching. But with this method you can actually say that if N objects on the screen are moving, at most N matrix multiplications are happening, which is pretty cool.

I was watching a presentation on ES6/7 async features and someone had a question that was along similar lines:

https://www.youtube.com/watch?v=DqMFX91ToLw#t=60m (60:00 to 61:01)

Not sure if that’s any use for you, but figured I’d mention it.

Nice. While it’s still possible to achieve aggressive caching with a non-FRP approach, I’m sure it’d result in a bunch of messy state everywhere (e.g. dirty flags).

Are renderable nodes can have child nodes (i.e. they aren’t limited to leaf nodes) then we’ll have the sub trees to recalculate for WebGL but we can let nested DOM cache subtree transforms.

Why not just have a Node communicate to the Engine and tell it when it’s “dirty” and only in that case traverse to that Node (and it’s subtree if renderables have children)?

@dmvaldman Nice to have your support! :smile: Would you like to join us in the merge when we put our best ideas from our prototypes into a single project? Feel free to move your project to github.com/infamous if you’d like to (you’ve got access to the org (check email for the invitation)).

Hey @dmvaldman!

Of course we remember you :slight_smile: Very happy to have you here with us in the forums, and thanks for this awesome update… had no idea something like this was in the works. The stream based approach is super cool!

Having said that, you’re in a very different place from the rest of us… 9 months of work on an existing code base, vs from-scratch rewrites of a few weeks. Are you interested in collaborating with us? What kind of collaboration did you have in mind?

As @trusktr said, what’s happening now is that we’re each working on our own engine candidate. I know it kind of sounds crazy at first, but instead of theoretical chats about what will work best, we’re trying to each get a real / practical feel about what’s involved and generate a few different ways of solving the same problem to see what works best. And then ultimately, combine all our efforts into a single code base, a long these lines:

I’m guessing you’d probably want to see some finished candidates before committing to anything, after so much of your own work. (Do you want to share any of your existing plans for samsaraJS?).

Two differences I’d immediately note between your current code base and what we have planned, is:

  1. Web workers - as @oldschooljarvis mentioned - for simultaneous calculations and/or just to keep the UI thread more free in general and specifically for super slow DOM updates which of course can only happen there.

  2. WebGL - we discussed in some other threads here. The general feeling was that we quite liked the idea of mixed mode… and that most devs aren’t interested in it only because it’s a chore, but with low barriers to entry it’s just cheap awesome. Also a few of us felt that it was a 2nd priority, but an important one… i.e. after “a DOM model that feels native everywhere”, but definitely something we wanted to be able to accomodate, probably by leveraging ThreeJS as part of an optional plugin.

Lastly, any input you have about anything is very welcome :smile:

1 Like

@dmvaldman In Famous oh-three there was an issue where even if the user removed a node from the scene graph and lost all references to it, the Engine would still keep a reference to it, so it’d essentially be a memory leak for the end user.

Have you addressed this issue? If not, I guess that a simple solution would be to use WeakMap wherever it is that Engine is keeping the references, so that, when the end user loses all references, the Node is deleted from the WeakMap automatically.

Yes this issue is addressed, though other issues of removing nodes aren’t :wink: It’s what I’m currently working on.

In famous 0.3 there was a list of “entities”. This is taken from the entity/component architecture of game engines. Nothing was removed from this list. This was not ideal, but it was intentional, because you could always add a Surface back in, even if all references to it were lost.

Looking forward to seeing your merge strategy :wink: Looking through the projects, they’re all quite different. Though I think the “explore first” attitude is a good one.

For Samsara, I don’t plan on including any WebGL support. Looking forward to seeing what you are planning there.

1 Like

Hi @dmvaldman ,
I started to explore samsaraJS - this looks very promising!
Do you have a code snippet / example how to connect a ‘resize-Stream’ (or something like that) to a LayoutNode/Transform.translate ?
The demo for connecting GestureInput-streams to the LayoutNode work very well, but I want to resize/translate a surface when the browser window size changes.
Thanks in advance!
Ansgar

1 Like

Yep!

var size = new ResizeStream();

var layout = new LayoutNode({
    transform : size.map(function(size){
        //size = [100,100]
        return Transform.translate(size);
    })
})

size.emit('resize', [100,100]);

All SceneGraph (to be renamed RenderTree) nodes and Views have a .size property (which is an instance of a RenderStream) built in, so it’s rare to need to create your own. That way if your layout is dependent on knowing your containing size the components are already there for you.

Here we are taking a single source of input (size) and mapping it to a transform. If you are interested in taking several sources of input before returning a transform, you’ll need to use Stream.lift. Which has the API

Stream.lift(function(data1,data2,...){
    ...
}, [stream1, stream2, ...]);

Hope this helps. I’ll make a google group soon, I think that will be a better place for questions.

2 Likes

Thanks for the quick reply - that helps a lot!
But I am afraid my question was a little bit misleading: I was looking for a browser-windowsize-stream as an input for transform.
Usecase: Window size changes => Position of surface changes (dependent on window size).
Thanks!
(I’ll wait with further discussion until your google group will open)

Yep, you can do that too. Unfortunately I should expose a small change to make this easier (expose Engine.size or Context.size), but for now if you extend a View it will have a .size property. If you don’t specify a size it will default to the parent size, which is this case will be the entire screen. So…

//kinda like Backbone.View.extend
var MyView = View.extend({
    initialize : function(){
        //this.size is implicitly created in a View
        var layout = new LayoutNode({
            transform : this.size.map(function(size){
                return Transform.translate(size);
            })
        })
        this.add(layout).add(more stuff)
    }
});

var myView = new MyView();
var context = Engine.createContext();
context.add(myView);

Also, Google Group created! https://groups.google.com/forum/#!forum/samsarajs

2 Likes

Pushed up a change (on master) for Engine to have a size property, so now it’s just

var layout = new LayoutNode({
    transform : Engine.size.map(function(size){
        return Transform.translate(size);
    })
})
2 Likes

Works like a charm - thanks a lot!

Been a little bit of time since I’ve talked more about samsaraJS. Check out the examples! http://samsarajs.org/examples

Very impressive!
Just wish you get more support… Do you have any timeline for a BETA version suitable for developing more serious projects?

The code is about 80% stable. I may move things around a bit file structure wise, and bundle it into a single file under the Samsara namespace.

There are some important missing pieces however, that make it unsuitable for serious projects as of now. For one, there’s no ability to remove any content yet, which is pretty darn important. I’d also like to add things, like a physics engine. I was the original author of famous’, but would like to rewrite it and have it be a smaller footprint. The other big thing is to have examples of integrating with Backbone and React, and I have some interesting ideas here to make this integration pleasant, and incredibly easy to maintain. Essentially a small shim layer that associates a Samsara surface with a Backbone (jQuery/zepto) referenced element, or a React component.

The biggest thing right now is documentation. I had reference docs up (http://samsaraJS.org/docs) but there’s a huge nothingness when it comes to prose and high level documentation. So that will be my current focus, followed by the pieces above.

And yes, I suck at marketing. Help spread the word! Even if Samsara isn’t production ready, it’s currently “play” ready!

2 Likes

Definitely will help spread the word and I like Backbone integration!!!

I gave a talk about SamsaraJS at jsConf EU a few weeks ago. The video just came online, thought I’d put it here. Would love some feedback.

3 Likes