Home

Awesome

famous-views v1.x series Build Status

PROJECT STATUS: Please see http://forums.famous-views.org/t/with-much-regret-the-final-update/102/. Note that a few posts down, you'll see that some really awesome stuff is happening in the community (that I'm involved in too), so this project isn't dead yet. But I'll no longer be using official Famous and it might be a while until there is some news. Follow there for updates.


Oh look, it's a new major number. That means I can break the API :)

You're on the master branch, where work is in development for the totally unstable famous-views v1.x series, which works with famous v0.5 (mixed mode).

For the stable (but deprecated) famous-views v0.x, which works with famous v0.3.5, please see the v0 branch.

Forums.Famous-Views.Org and Join the chat at https://gitter.im/gadicc/meteor-famous-views

To learn the basics through an interactive tutorial with live, editable code, check out https://fview-lab2.meteor.com/gadicc.

API

The v1 series is a rewrite. A good opportunity for code househeeping. Code from v0 will be copied in and adapted on a per unit bases, after inspection and ideally tests.

Please read this README in it's entirety to understand what's going on :) Also, the v1.0.0 -- it's semver, we're bumping the major version to indicate an API change. Please don't draw any conclusions about being "production ready".

To learn the basics through an interactive tutorial with live editable code, check out https://fview-lab2.meteor.com/gadicc.

Quick start:

# Please check History.md on updates
meteor add gadicohen:famous gadicohen:famous-views

gadicohen:famous is a temporary package until our regular options are available again. It exports everything to a global famous var, e.g. famous.core.FamousEngine, etc. When we reach stable, we'll have a recommended pattern that works with all packages, which may involve wrapping famous-requiring-code with FView.ready() like last time, we'll see. But for now just use the globals.

The new markup structure looks like this:

<body>
  {{#Scene}}
    {{#Node}}
      {{#DOMElement}}
        <p>Yo!</p>
      {{/DOMElement}}
    {{/Node}}
  {{/Scene}}
</body>

Or a "full" example: (in Jade... use Jade!)

body
  +Scene
    +Node id="baseNode"
      +Node size="absolute: 100; renderSize" rotation="[1,1]"
        +DOMElement style="background: red" class="domEl" dir="rtl"
          p Howzit!
      +Node size="A:100; RS" rotation=reactiveRotationHelper
        +DOMElement
          p Shalom!

Scene

Node

Supported non-reactive attributes:

Supported reactive attributes:

Sizing

See http://famous.org/learn/sizing.html for the sizing types. We believe in minimal typing, so we have a proprietary string format that looks as follows (spaces are optional, names may be shortened and case is insensitive, so the following two groups are equivalent):

size="50%, -10"
size="proportional: 0.5; differential: -10"
size="P:0.5; D:-10"

size="150, RS, 50% - 10"
size="absolute: 150; renderSize; relative: 0.5,-10"
size="A:150; RS; R:0.5,-10"

The second group would do the following in famous:

var size = fview.size = new Size(node);
size.setMode(Node.ABSOLUTE_SIZE, Node.RENDER_SIZE, Node.RELATIVE_SIZE)
size.setAbsolute(150);
size.setProportional(undefined, undefined, 0.5);
size.setDifferential(undefined, undefined, -10);

The "natural" sizing works like this: "x, y, z" where these can be (spaces optional):

Everything else (including position, rotation, etc)

String decoding similar to famous-views 0.x, e.g. position="[100,100]", JSON and some other stuff. You should return an exact value (e.g. an Array of Numbers) from reactive helpers.

Notes:

For animations, you can return a special object ala famous-views v0:

Template.body.helpers({
  reactiveRotate: function() {
    return {
      value: [0, 1],
      transition: { duration: 1000, curve: 'inBounce' }
      halt: true,                   // optional (TODO)
      callback: function() { ... }  // optional
    };
  }
});

To keep switching between two values, we provide a shortcut to infinity:

+Node rotation='{ "value1": [0,-3.14], "value2": [0,3.14], "transition": { "duration": 1000 } }'

To reset the loop on each iteration (for a continuous animation "in the same direction", given appropriate values) add: _loopFromBeginning: true.

You can also simply manipulate the fview directly and return '__FVIEW_SKIP__', e.g.:

Template.body.helpers({
  reactiveRotate: function() {
    FView.current().node.setRotation(x,y,z);
    return '__FVIEW_SKIP__';
  },
  reactiveRotate2: function() {
    var fview = FView.current();
    if (!fview.rotate)
      fview.rotate = new famous.components.Rotation(fview.node);
    fview.rotate.set(1,2,3, transition, callback);
    fview.rotate.setX(1, transition, callback);
    return '__FVIEW_SKIP__';
  }
});

Special Attributes:

_onRender:

Specify the name (by string) of a helper function that we should run after adding the node to the Scene Graph.

body
  +Node _onRender="renderFunc" // note, String name
Template.body.helpers({
  renderFunc: function() {
    // this = fview
  }
});

DOMElement

This is a component that is added to the enclosing node, it's not a real node on it's own, it simply attaches a DOMElement component to the enclosing node, and the augments that node's fview with:

Template attributes:

The {{>Surface template="x"}} format is gone, just put {{>x}} inside.

If using RENDER_SIZE, you have to let us know if you do anything that could change the size of the rendered content, using one of the Methods above. Here's an example for a reactive helper:

Template.body.helpers({
  something: function() {
    FView.current().updateSizeDeferred();
    return variableSizedStuff;
  }
});

Others

Mesh, Camera, PointLight are all very simple wrappers and work how you'd expect. See the live demos for some examples.

Components in general with attributes ending with [cC]olor, i.e. color, baseColor, can parse values like "white", "white, 0.2" (for opacity 0.2), "#ffffff".

famousEach

Use this instead of Meteor's built-in #each inside the Scene graph. This is required to maintain ordering and allows wrapped code to capitalize on ordered insertions/removals/reorders.

FView (global)

FV (global)

jQuery inspired short-cut to get the fview, e.g.

You can also set up onRender events for nodes in a class, e.g. (included by default):

FView.defineClass('center', {
  onRender: function() {
    this.node.setMountPoint(0.5, 0.5, 0.5);
    this.node.setAlign(0.5, 0.5, 0.5);
    this.node.setOrigin(0.5, 0.5, 0.5);
  }
});

Which means you can:

+Node class="center"
  +Node class="center"

etc.

fview (node/etc instance)

Properties

Methods

Wrap your Own

Just as with v0, famous-views is primarily a low-level wrapper around Famous, to make it fit in naturally with Meteor. We don't aim to provide a comprehensive library of community components, instead, we realy on other developers to provide fview-* plugin packages. It's not so hard to do, and we'll have some example patterns for v1 available soon.

But what about stuff you don't want to publish, or isn't already published? How can you wrap simple things? Well, like this:

FView.wrap('Node', famous.core.Node);  // silly example, already included
FView.wrapComponent('Mesh', famous.webglRenderables.Mesh);

This will give you {{#Node}} and {{#Mesh}} helpers to use in your templates. Adding children / attaching components all work as you'd expect. Admittedly it's not always this simple, but a 3rd parameter, options can provide a dictionary of overrides to adapt as necessary. You may find some more useful examples here:

https://github.com/gadicc/meteor-famous-views/tree/master/lib/wrappers

Logging

Package['jag:pince'].Logger.setLevel('famous-views', 'info');

Levels are: trace, debug, info, warn, error

In a later release I'll enable to change this before load, for those who hate anything on console :)

Events

Might add something to do this in a Meteor way again. For now, either set these up famous-style _onRender (in famous style, see their docs) or do something like this:

<template name="outer">
  {{#DOMElement}}
    {{>inner}}
  {{/DOMElement}}
</template>

<template name="inner">
  <!-- NB: Critical to have one element in here to receive the event -->
  <!-- depending on your needs, maybe style="width: 100%; height: 100%" -->
  <div>Blah blah blah</div>
</template>
Template.inner.events({
  'click': function(event, templateInstance) {
    var fview = FView.current();
    // `this` is data context; regular Meteor event, etc.
  }
});

What's missing / TODO / Roadmap

Differences from v0

Besides the underlying Famous API and how we deal with it: