Lively cheat sheet.
Morphic
// Halo API
morph = this
morph.showHalos(); // open halos
morph.removeHalos(); // remove halos
X
Halos
Basic halo interaction: Open a halo via CMD+click. When a halo is already open, CMD+click will open a halo for the morph stacked beneath the morph that is the current halo target. Repeat this cycling through all morphs beneath the hand.
Multi selection: You can open halos ("multi selection") for more than one morph by SHIFT-CMD-click on multiple morphs.
Keyboard Shortcuts: When pressing CMD+h a halo will appear for the morph that currently has keyboard focus. If this morph is inside a window then a halo for the window will be opened.
When a halo is open you can use the arrow keys to move the morph (1-pixel). Arrow key + CMD - move 10 pixel. Arrow key + ALT - move 100 pixel. SHIFT + arrow key - resize morph SHIFT + CMD + arrow key - resize morph 10 pixel SHIFT + arrow key - resize morph 100 pixel
browse halo implementation
Morphic composition and scene graph
// Morphic composition / hierarchy interface
morph.addMorph(submorph) // add a submorph
morph.remove() // remove morph from its owner and the scene graph, morph won't be rendered anymore
morph.removeAllMorphs() // remove all submorphs of morph
// helpful shortcut methods
morph.openInWindow();
morph.openInWorld(pos)
morph.openInWorldCenter();
X
Morphic composition
browse morphic core implementation
<
start
>
clear
save as:
0
Morphs: Direct Composition and Manipulation
Lively interfaces are build out of morphs. You can see some basic morphs below. They react on clicks. To grab these morphs click on them, hold this click and move the cursor.
These morphs are primitive. That is, they are not composed out of other morphs.
Use the '<' and '>' buttons below to navigate between pages in this tutorial.
The example below shows how a very simple world (in this example the "world" is just another rectangle) can look like and how the corresponding scene graph is be structured:
More infos are here - documentation/Rendering.xhtml
Each morph has a transformation that is defined by its position, rotation, and scale. Transformations are applied to all submorphs as well so when the scale
Morphic rendering
Morphic transformations
Morphic naming / enumeration
Each morph has a name, defined in its `name` property. Names can be used to get direct references to a morph through name lookup. Note: This only works for morphs that are currently in the scene graph! For this purpose, the methods `get` and `getMorphNamed can be used.
// Morphic naming example
this.get("nameDescriptionText").show() // starting from this (the editor morph
                                       // containing the code you are reading)
                                       // try to find a morph named "nameDescriptionText"
                                       // and highlight it
// alternatively you can use the $morph helper function:
$morph('nameDescriptionText').show(); // == $world.get('nameDescriptionText').show();
X
More infos: documentation/livedoc/Morphic/Scenegraph/ExtentAndBounds.xhtml livedoc/Morphic/Scenegraph/PositionAndOrigin.xhtml
Note: get will first try to find a matching morph in its submorphs. If nothing was found then the siblings of the morph's owner will be searched. This continues for all owners until the world morph is searched.
For iterating through all submorphs or access owners use these methods:
morph.owner // attribute: the current owner of the morph
morph.ownerChain() // get all the owners of morph
morph.withAllSubmorphsDo(func) // iterator that will recursively go through
                               // morph and all its direct and indirect submorphs
morph.world() // gets the morph's world or null if morph not in scene graph
X
"World"
Rectangle
Ellipse1
Ellipse2
$morph('PseudoWorld').show();
// Printed tree of the Morphic scene graph:
Strings.printTree(
    $morph('PseudoWorld'),
    function(morph) { return morph.name; },
    function(morph) { return morph.submorphs; });
// PseudoWorld
// |-PseudoWorldLabel
// \-Rectangle
//   |-RectangleLabel
//   |-Ellipse1
//   | \-Ellipse1Label
//   \-Ellipse2
//     \-Ellipse2Label
X
Please note that users/robertkrahn/Lively-101.html provides extended content and examples.
Key and mouse events are the main abstractions for user inputs in Lively. This text explains how event dispatch in Lively works and how to define new event behavior, The current Lively implementation ties into the DOM event system but also provides an abstraction to it since events are handled on a per morph level. You can find the implementation of events in the module lively.morphic.Events. Event handlers for texts are implemented in lively.morphic.TextCore (in the lively.morphic.Text class).
world
morph1
morph3
p2
p3
morph2
p1
scene
world morph1 morph2 morph3
scene graph
The figure below shows a simple Morphic scene and the logical morph composition hierarchy. Three morphs are placed in a world. Morph1 and morph2 are top-level morphs. Morph3 is a submorph of morph2 and its bounds stick out and overlap with morph1.
Event handling is done on the morph level, i.e. morphs implement event handlers that are triggered in a certain order (see event dispatch below to learn more about the order of event handler activation). Event handlers are normal methods that are automatically called and get an event object as parameter. For mouse events the following event handlers exist (as of 08/10/2011):
A.onMouseOut A.onMouseMove A.onMouseMove A.onMouseOver A.onMouseOut A.onMouseMove A.onMouseOver A.onMouseOut A.onMouseMove A.onMouseMove
reset
A
B
Handlers for browser-specific drag and drop. Quite complicated (see quirksmode). Currently only implemented by lively.morphic.World for uploading files like pictures and videos.
We implement custom dragging event handling that is not related to DOM drag event handlers. These handlers will only be active if morph.draggingEnabled === true. Call morph.enableDragging() or morph.applyStyle({enableDragging: true}). You can overwrite the event handlers to implement custom event logic. However, please note that certain features (e.g. halo invocation and grabbing) depend on the default behavior. If you do not want to disable that, then include a super call to activate the base behavior.
Lively partly overwrites the browser standard event behavior, e.g. for executing modified behavior when the BACKSPACE key is pressed in a text. Stopping the default event behavior should not be confused with canceling the event dispatch to a submorph! Default behavior is canceled by calling evt.stop() in an event handler. To avoid that submorphs can dispatch events also return a truthy value from the morph event handler method.
It is possible to cancel the event dispatch so that morphs deeper in the scene graph will not receive an event by returning true as the result of the event handler method. Example: If morph2 in the example above overwrites onMouseDown like
morph2.addScript(function onMouseDown(evt) { $super(evt); return true; })
then morph3.onMouseDown will not be called (onMouseUp will, however, unless being modified itself).
Lively uses capturing events, i.e. events are dispatched top-down.
Click on p1: world>>onMouseDown morph2>>onMouseDown - - - - - - world>>onMouseUp morph2>>onMouseUp Click on p2: world>>onMouseDown morph2>>onMouseDown morph3>>onMouseDown - - - - - - world>>onMouseUp morph2>>onMouseUp morph3>>onMouseUp Click on p3: world>>onMouseDown morph2>>onMouseDown morph3>>onMouseDown - - - - - - world>>onMouseUp morph2>>onMouseUp morph3>>onMouseUp
Note that the event dispatch is the same as for p2!. This is because the DOM events are dispatched depending on the scene graph not only click position. You can still find out what morphs are placed under the mouse cursor by asking the world for all its submorphs that contain a certain position:
// return a list of the morphs under the hand, independent of the composition hierarchy $world.morphsContainingPoint($world.firstHand().getPosition())

Morphic – events
Mouse Event Dispatch
Event handler methods
onHTML5DragEnter, onHTML5DragOver, onHTML5Drag, onHTML5Drop
Key events
Dragging
Canceling default event behavior
Modifying the Event Dispatch
Modifying the Event Dispatch
onMouseDown(evt): Mouse button is pressed.
onMouseUp(evt): Mouse button is released.
onClick(evt): When mouse was pressed and released. Currently not used. To use: re-initialize event handlers.
onDoubleClick(evt): When mouse was pressed and released twice in a certain (OS specific) time period.
                    Currently not used. To use: re-initialize event handlers.
onSelectStart(evt): OS specific select (mouse down and move). Implemented to disable default behavior.
onContextMenu(evt): OS specific context menu activation. Implemented to disable default behavior.
onMouseWheel(evt): Horizontal and vertical scroll. Also for two finger scrolling.
onMouseOver(evt): Triggered when the mouse cursor enters a morph. Currently not used.
onMouseMove(evt): The mouse cursor (hand) moves.
onMouseOut(evt): Triggered when the mouse cursor leaves a morph. 
X
Just implementing onMouseOver, onMouseMove, onMouseOut:
Event hovering examples
B hovered out A hovered out A hovered out A hovered out A hovered out B hovered out A hovered out B hovered out A hovered out A hovered out
reset
A
B
Just implementing onMouseMove and onMouseOut with state tracking
onKeyDown(evt): For any key
onKeyUp(evt): For any key
onKeyPress(evt): For events producing printable characters. Browser specific
X
onDragStart(evt): Triggered when drag is initiated. Mouse was clicked and moved morph.dragTriggerDistance
                  (by default 5).
onDragEnd(evt): Mouse was released after dragging.
onDrag(evt): Between drag start and end. Morph gets dragged. (Actually triggered by mouse move).
X
what's missing
X

Menu
Morphic
  - BuildSpec
CodeEditor
  - editor / text API
  - text modes
System code browser
  - module system
    - how to create new modules
  - supported objects
  - http://lively-kernel.org/repository/webwerkstatt/documentation/livedoc/Tools/SCB.xhtml
Subservers
Shell integration
X
FAQ
X

Menu
Q: how to allow a morph (just a simple morph, that is used as a drag handle) to receive 
keyPress events (while being grabbed).
A:
morph.addScript(function grabByHand(hand) { hand.addMorph(this); this.focus() });
morph.addScript(function onBlur() { this.setFill(Color.red) });;
morph.addScript(function onFocus() { this.setFill(Color.green) });;
morph.addScript(function onKeyDown(evt) { show('key!'); });
X
IDE / Shortcuts
Lively defines (user extendable) interactive commands that make navigating and developing a lot easier. You can get a list of available commands by pressing ALT+x. This will open a selection narrower like this:
The narrower lets you quickly filter a big list, simply by typing parts of the item's name. Press enter to execute that command.
There are several useful commands that you will repeatedly use:
ALT-T: browse modules and files (this displayed in a narrower), When you have selected a module/file you can press ENTER to open it inside a SCB or press tab to get a list of alternative actions to run in the module/file.
CMD-SHIFT-C: search through the source code (accepts string or regexp as search term) CMD-SHIFT-F: string search using the runtime objects
Inside a SCB: ALT-SHIFT-T to see a list of all the entities (classes, objects, methods) of the currently selected module.
CMD-` (backtick): get a list all windows. Press ENTER make the selected window be focused.
browse keybindings of interactive commands
When the world is focused (click into the background) CMD+B to open a system code browser CMD+P open PartsBin
CodeEditor / Shortcuts
The code editor is based in the AJAX/ace editor. Its default keyboard bindings are listed here: https://github.com/ajaxorg/ace/wiki/Default-Keyboard-Shortcuts
In Lively we add several other key bindings, some of the often used are: ALT-space - show completions CMD-D - doit CMD-P - print it CMD-Shift-P - evaluate expression and browse protocol of object being returned (dynamic completion) CMD-S - save CMD-I - print inspect CMD-Shift-I - open inspector window CMD-[ - indent left CMD-] - indent right CMD-L - select current line Alt-/ - comment line Shift-CMD-Space - extend selection to AST item that containes the current selection Ctrl-CMD-space - shirink selection to AST item contained by the current selection
Lively keyboard shortcuts
You can customize the keyboard handling.
browse example for customization
Modules
JavaScript library extensions: lively.lang.Array lively.lang.CharSet lively.lang.Closure lively.lang.Date lively.lang.Function lively.lang.LocalStorage lively.lang.Number lively.lang.Object lively.lang.String lively.lang.UUID lively.lang.Worker lively.morphic.Graphics - Graphic primitives such as Point, Rectangle, similitude bootstrap: lively.bootstrap lively.Main Lively JavaScript language extensions: lively.Base - class system lively.ModuleSystem lively.Traits networking: lively.Network - HTTP networking lively.net.WebSockets lively.net.SessionTracker - Lively2Lively PartsBin / scripting lively.PartsBin lively.morphic.ScriptingSupport - morphic PartsBin extensions server interface: lively.ide.CommandLineInterface lively.ide.CommandLineSearch data bindings: lively.bindings.Core - base data binding implementation lively.bindings.GeometryBindings - morphic specific data bindings Serialization: lively.persistence.Serializer - core serialization logic lively.persistence.BuildSpec - Buildspec implementation lively.morphic.Serialization - morphic serialization hookup Morphic: lively.morphic.Core - morphic interface lively.morphic.Events - binding morphic to user events (mouse keyboard) lively.morphic.TextCore - core text implementation lively.morphic.Lists lively.morphic.Widgets - "higher level morphs" such as windows lively.morphic.Layout - set of often used layout strategies lively.morphic.AdditionalMorphs - more morphs lively.morphic.MorphAddons - convenience methods that extend the base morphic interface lively.morphic.Halos lively.morphic.StyleSheets - Morphic CSS interface lively.morphic.Rendering, lively.morphic.HTML - core morphic rendering logic ide: lively.ide.CodeEditor, lively.ide.codeeditor.Keyboard lively.ide.SourceDatabase, lively.ide.FileParsing, lively.ast.Parser, lively.ast.acorn lively.ide.BrowserFramework, lively.ide.SystemCodeBrowser lively.ide.WindowNavigation - window narrower lively.ide.commands.default - interactive commands + their shortcuts lively.ide.tools.SelectionNarrowing - core narrower implementation user config: users.YOURUSERNAME.config
Lively uses a module system to isolate parts of its implementation. Here are the most important modules.
Morphic methods you should now
lively.morphic.connect
/*animation*/
startStepping(stepTime, scriptName, argIfAny) // repeatedly execute a method `scriptName`
stopStepping() // stop repeated method execution
moveByAnimated(delta, time, callback) // smooth transition
withCSSTransitionDo(morphModifyFunc, duration, whenDone)
/*buildpsec*/
buildSpec() // generate buildSpec from morph
/*css*/
addStyleClassName(classNameOrNames) // add css class
setStyleClassNames(classNames) // set css class(es)
getStyleClassNames()
getStyleSheet()
setStyleSheet(styleSheet) // set css def
/*debugging*/
show() // highlight a morph
/*DOM access*/
jQuery() // returns jQuery object for the morph/shape's DOM node
renderContext().morphNode // the DOM node of the morph
renderContext().shapeNode // the DOM node of the morph's shape
/*events*/
focus() // set keyboard focus to morph
lively.morphic.Morph.focusedMorph() // retrieve Morph which currently has kbd focus
getScroll() // scroll of clipped morphs
setScroll(horiz, vert)
ignoreEvents() // disable processing all events in morph
onKeyDown(evt) 
onMouseDown(evt)
onMouseMove(evt)
onMouseUp(evt)
onScroll(evt)
/*halos*/
disableHalos()
enableHalos()
/*layout*/
applyLayout()
getLayouter()
/*menus*/
this.morphMenuItems() // should return menu item lists that define what's in the menu
/*partsbin*/ 
copyToPartsBin(optPartsSpaceNamed) // publish into partsbin
copyToPartsBinWithUserRequest()
/*positioning / transformations / visuals*/
align(p1, p2) // change position of morph so that its position p1 is aligned with the position p2
bounds() // get the bounding box (in owner coordinates of the morph)
copy() // returns a copy of the morph
getExtent() // morph extent
getFill() // background color
getPosition()
getPositionInWorld() // global position = transform local position with transforms of all owners
getRotation()
getScale()
getTransform()
innerBounds() // local bounding box
localize(point)
moveBy(point)
setExtent(newExtent)
setFill(value)
setPosition(value)
setVisible(bool) // hide/show morph
/*direct styling*/
applyStyle(spec)
/*halos*/
that.showHalos()
that.removeHalos()
/*scripting*/ 
addScript(namedFunction) // attach function as new method to morph object
get(name) // lookup morph with name, returns only one match
/*windows*/ 
getWindow() // get the window of the current morph or null if morph not inside a window
openInWindow(); // open morph in window (morph becomes window.targetMorph)
X
Traits
Example
// class and trait definition
Object.subclass("FooClass",
"initializing", {
    initialize: function()  {
        this.state = Numbers.random()
    }
});
Trait('lively.CopyTrait', {
    copy: function() {
        return lively.persistence.Serializer.copy(this);
    }
}).applyTo(FooClass);
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// use in a class
foo = new FooClass()
foo2 = foo.copy()
foo2.state === foo.state; // true
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// usage with objects
bar = {zork: 99};
Trait('lively.CopyTrait').applyTo(bar)
barCopy = bar.copy()
barCopy.zork; // 99
// When used interactively/itertatively from within a SCB they will
// automaticelly update classes and and objects. You can even apply Traits to
// Traits to compose behavior.
X
Traits can be used as containers of behavior that should be used in multiple places. They do not impose a single hierarchy, they can be used with objects as well as classes. Traits can be used to - separate a certain behavior that doesn't really fit into a class - provide reusability - prototype a certain behavior so that this can be enabled (temporarily / on demand) without changing the original implementation
browse Traits implementation
Tests
// load the test module (defines TestCase class)
module('lively.TestFramework').load(true)
AsyncTestCase.subclass('lively.tests.MyNewTestCase', {
    setUp: function() { alert('run before every test method') },
    tearDown: function() { alert('run after every test method') },
    testTryItOut: function() {
        this.assertEqual(1, 2, 'this test will fail');
        this.done();
    },
})
// The first argument can be a function that is run after each test
// the second argument is a function to run after all tests finished
test = new MyNewTestCase()
test.runAllThenDo(null/*status update func*/, function() {
    alert(test.result.printResult());
});
X
Lively provides a test framework that allows developers to write synchronous and asynchronous tests. This is used for development and regression testing. The Lively test suite is automatically run via travis: https://travis-ci.org/LivelyKernel/LivelyKernel. The current build status is
browse TestFramework
Test example
open test runner
PartsBin
What is the PartsBin? The Lively PartsBin is a repository of active components. It is a collaboration space in which users can find, alter, create and share new content. Parts are morphs that are either directly useful as, for example, editing tools or basic building blocks as, for example, simple input elements. The PartsBin is organized into categories that we call Parts spaces. What is the PartsBin Browser? The PartsBin Browser is a tool to explore, search, and load parts from Lively's PartsBin. It allows searching for a part by the part's name, browsing categories of grouped parts, and exploring the latest changes. How to open the PartsBin Browser? To open the browser, either use the world's menu's "PartsBin" entry or the keyboard short cut "cmd/ctrl - p". How to use the PartsBin Browser? Once the browser is open, use the list on the left side or the search on the top to find a part. When you click on a category or search by name previews of the actual parts appear in the browser's main pane. You can drag the actual versions out – click on one, hold that click and pull it right into your world. All parts are under version control. If you want to access the history you can click on the "more" button in the top-right corner of the browser. It shows all versions, associated commit messages, and a few buttons to load, copy or remove the part. Click on a specific version and then on the "load" button to get a part in a preceding version. How to publish morphs as parts to the PartsBin? Once you have built a new part or finished altering an existing part you can upload your version to the PartsBin. Right-click on the morph you want to share with all users to get its halo buttons. The "M" button opens a menu that holds a "publish" entry. Click it to get a publish dialog up. There you can specify where to publish the part (category), under which name (name), and a comment that describes the part in general. You can also commit a part with a commit message to describe how you changed it. How to load a part programmatically? To load a part from the PartsBin use the lively.PartsBin.getPart(partName, partsSpaceName) function or call the $world.loadPartItem(partName, partsSpaceName) function. Both load the parts from the shared repository. After loading, you can open them in your world. Or do it in one step. Try: $world.openPartItem('Triangle', 'PartsBin/Triangle');
browse PartsBin interface
open PartsBin
How do you create a new Part Bin item (programatically/visually)? What is the process from scratch to having it available in the Parts Bin?
How do you create a new Part Bin item (programatically/visually)? What is the process from scratch to having it available in the Parts Bin?
// Loading:
// Visually: Click on the menu halo and choose "copy to PartsBin"
// Pogramatically:
part = $part('Ellipse', 'PartsBin/NewWorld');
part.openInWorld();
// Storing:
// Visually: Click on the menu halu and choose "Copy to PartsBin"
// Programatically: 
// optPartsSpaceName can be nothing or a String that defines
// the PartsBin category ("PartsSpace") that the morph should go
// into, e.g. "PartsBin/Tools".
part.copyToPartsBin(optPartsSpaceName)
// access meta data:
part.getPartsBinMetaInfo()
X
Class system
How do you create a subclass of a morph?
// Select the following code and hit Ctrl/Cmd + d
lively.morphic.Morph.subclass('lively.morphic.MyOwnMorph',
'method category', {
    initialize: function($super) {
        $super(new lively.morphic.Shapes.Rectangle(new Rectangle(0,0,100,100)));
        this.setFill(Color.red);
    },
    addMorph: function($supermorph) {
        show('MyOwnMorph got a submorph: %s', morph);
        return $super(morph);
    }
});
// create an instance
morph = new lively.morphic.MyOwnMorph()
morph.openInWorldCenter();
// To add static/class side methods use
Object.extend(lively.morphic.MyOwnMorph, {
    createTen: function() {
        return Array.range(1,10).map(function() { return new this(); }, this);
    }
});
X
browse class system implementation
ObjectEditor / Scripting
How to use the tool
livedoc/Tools/ObjectEditor.xhtml
Working directly on objects allows to directly access the state of an object and experiment with its methods. You are also able to directly modify the UI using morphic controls. This usually allows to develop applications faster than with the more abstract class concept. On the other hand classes are great for generalizing behavior. For example, imagine you have written a BugTracker application directly with objects and want to create a Todo application. Possibly both applications/their UI will have shared logic. Using class inheritance will allow to more efficiently share the behavior and changes to a generic base class will affect both applications. For the BugTracker example this means to move certain methods out of the BugTracker object into some class. Side note: We are working on a concept to allow prototypical inheritance, i.e. with that the generalization described above can also be reached using objects only.
When should I use subclass and when should work on an object?
Networking
// URL / WebResource inerface
url = new URL("https://api.bitfinex.com/v1/ticker/btcusd")
// make a simple synchronous request and print the content:
url.asWebResource().get().content
// make an async request and automatically extract content as json:
url.asWebResource().beAsync().get().withJSONWhenDone(function(json, status) {
    if (!status.isSuccess()) {
        show('Could not successfully make request to %s\n, status: %s', url, status);
        return;
    }
    $world.addCodeEditor({
        content: Objects.inspect(json),
        title: "Result from " + url,
        textMode: "json"
    });
})
X
HTTP
In Lively we have our own interface (WebResource) for doing HTTP Requests. We do this, so we can access the whole Internet through our proxy and use the "connect" functionality.
Lively2Lively messaging
Please see the Lively2Lively presentation for what it is and how to use it.
browse URL implementation
browse WebResource implementation
Data bindings
lively.morphic.connect
<
start
>
clear
save as:
0


Morphic: Connections
One way for Morphs to interact with each other are AttributeConnections. You can tell a Morph to execute a function once an attribute of another morph has changed. In this part of the tutorial you will learn - how to graphically connect Morphs - how to programmatically connect Morphs - how to use converter functions in AttributeConnections. Let's go. (Use the '<' and '>' buttons below to navigate back and forth in this tutorial.)
Data bindings are used to establish a dependency between a source and a target object. Such a dependency can for example be "When the attribute `_Position` of morph1 changes update the attribute `textString` of morph2". Note that data bindings are not restricted to attribute connections!
browse connection implementation