This is some detailed text documentation about fluxus and the general concepts it uses. It's quite dense, so I recommend trying the examples and using this as reference as you learn scheme and work your way through.
The text is taken from the pawfal wiki1 look there for the current version (which may not match this version of fluxus).
1. http://www.pawfal.org/index.php?page=FluxusDocumentation
A graphical livecoding environment for Scheme. Builds for Linux or OSX, and released under the GPL licence.
Fluxus reads live audio or OSC network messages which can be used as a source of animation data for realtime performances or installations. Keyboard or mouse input can also be read for simple games development, and a physics engine is included for realtime simulations of rigid body dynamics.
The built in scheme code editor runs on top of the renderer, which means you can edit the scripts while they are running. As well as making livecoding possible, it's also gives you a very fast feedback way of experimenting or learning about graphics and animation.
Fluxus lends itself to procedural modelling and animation. There is an experimental procedural modelling tool, and full support for texturing, basic material properties and hardware shading.
Fluxus consists of an application, which embeds a Scheme interpreter, called the fluxus scratchpad, and a set of Scheme modules which extend an interpreter with graphics commands.
When you start fluxus, you will see the welcome text and a prompt - this is called the repl, or console. Generally fluxus scripts are written in text buffers, which can be switched to with ctrl and the numbers keys. Switch to the first one of these by pressing ctrl-1 (ctrl-0 switched you back to the fluxus console).
Now try entering the following command.
(build-cube)
Now press F5 (or ctrl-e) - the script will be executed, and a white cube should appear in the centre of the screen. Use the mouse and to move around the cube, pressing the buttons to get different movement controls.
To animate this cube, it will have to be called a little differently:
; buffersize and samplerate need to match jack's
(start-audio "jack-port-to-read-sound-from" 256 44100)
(define (render)
(colour (vector (gh 1) (gh 2) (gh 3)))
(draw-cube))
(every-frame (render))
Briefly, the (every-frame) function takes a function which is called once per frame by fluxus's internal engine. In this case it calls a function that sets the current colour using harmonics from the incoming sound with the (gh) - get harmonic - function; and draws a cube. Note that this time we use (draw-cube) not (build-cube). The difference will be explained below.
If everything goes as planned, and the audio is connected with some input - the cube will flash in a colourful manner along with the sound.
Now go and have a play with the examples. Load them by pressing ctrl-l or on the commandline, by entering the examples directory and typing fluxus followed by the script filename.
When using the fluxus scratchpad, the idea is that you only need the one window to build scripts, or play live. f5 (or ctrl-e) is the key that runs the script when you are ready. Selecting some text (using shift) and pressing f5 will execute the selected text only. This is handy for reevaluating functions without running the whole script each time.
Camera control
The camera is controlled by moving the mouse and pressing mouse buttons.
The script editor allows you to edit 9 scripts simultaneously by using workspaces. To switch workspaces, use ctrl+number key. Only one can be run at once though, hitting f5 will execute the currently active workspace script. Scripts in different workspaces can be saved to different files, press ctrl-s to save or ctrl-d to save-as and enter a new filename (the default filename is temp.scm).
If you press ctrl and 0, instead of getting another script workspace, you will be presented with a Read Evaluate Print Loop interpreter, or repl for short. This is really just an interactive interpreter similar to the commandline, where you can enter scheme code for immediate evaluation. This code is evaluated in the same interpreter as the other scripts, so you can use the repl to debug or inspect global variables and functions they define. This window is also where error reporting is printed, along with the terminal window you started fluxus from.
- ctrl-f : Fullscreen mode. - ctrl-w : Windowed mode. - ctrl-h : Hide/show the editor. - ctrl-l : Load a new script (navigate with cursors and return). - ctrl-s : Save current script. - ctrl-d : Save as - current script (opens a filename dialog). - ctrl-1 to 9 : Switch to selected workspace. - ctrl-0 : Switch to the REPL. - F3 : Resets the camera. - F5/ctrl-e : Execute the selected text, or all if none is selected. ctrl-e might be easier for mac users, as volume is usually bound to the f5 key. - F9 : Randomise the text colour (aka the panic button) - Escape : Editor panic button, resets the cursor if it gets stuck (let me know if you need to use this)
Scheme is a programming language invented by Jerald J. Sussman and Guy L. Steel Jr. in 1975. Scheme is based on another language - Lisp, which dates back to the fifties. It is a high level language, which means it is biased towards human, rather than machine understanding. The fluxus scratchpad embeds a Scheme interpreter (it can run Scheme programs) and the fluxus modules extend the Scheme language with commands for 3D computer graphics.
This chapter gives a very basic introduction to Scheme programming, and a fast path to working with fluxus - enough to get you started without prior programming experience, but I don't explain the details very well. For general scheme learning, I heartily recommend the following books (two of which have the complete text online):
The Little Schemer Daniel P. Friedman and Matthias Felleisen
How to Design Programs An Introduction to Computing and Programming Matthias Felleisen Robert Bruce Findler Matthew Flatt Shriram Krishnamurthi Online: http://www.htdp.org/2003-09-26/Book/
Structure and Interpretation of Computer Programs Harold Abelson and Gerald Jay Sussman with Julie Sussman Online: http://mitpress.mit.edu/sicp/full-text/book/book.html
We'll start by going through some language basics, which are easiest done in the fluxus scratchpad using the console mode - launch fluxus and press ctrl 0 to switch to console mode.
Languages like Scheme are composed of two things - operators (things which do things) and values which operators operate upon. Operators are always specified first in Scheme, so to add 1 and 2, we do the following:
fluxus> (+ 1 2) 3
This looks pretty odd to begin with, and takes some getting used to, but it means the language has less rules and makes things easier later on. It also has some other benefits, in that to add 3 numbers we can simply do:
fluxus> (+ 1 2 3) 6
It is common to "nest" the brackets inside one another, for example:
fluxus> (+ 1 (* 2 3)) 7
If we want to specify values and give them names we can use the Scheme command "define":
fluxus> (define size 2) fluxus> size 2 fluxus> (* size 2) 4
Naming is arguably the most important part of programming, and is the simplest form of what is termed "abstraction" - which means to separate the details (e.g. the value 2) from the meaning - size. This is not important as far as the machine is concerned, but it makes all the difference to you and other people reading code you have written. In this example, we only have to specify the value of size once, after that all uses of it in the code can refer to it by name - making the code much easier to understand and maintain.
Naming values is very useful, but we can also name operations (or collections of them) to make the code simpler for us:
fluxus> (define (square x) (* x x)) fluxus> (square 10) 100 fluxus> (square 2) 4
Look at this definition carefully, there are several things to take into account. Firstly we can describe the procedure definition in English as: To (define (square of x) (multiply x by itself)) The "x" is called an argument to the procedure, and like the size define above - it's name doesn't matter to the machine, so:
fluxus> (define (square apple) (* apple apple))
Will perform exactly the same work. Again, it is important to name these arguments so they actually make some sort of sense, otherwise you end up very confused. Now we are abstracting operations (or behaviour), rather than values, and this can be seen as adding to the vocabulary of the Scheme language with our own words, so we now have a square procedure, we can use it to make other procedures:
fluxus> (define (sum-of-squares x y) (+ (square x) (square y))) fluxus> (sum-of-squares 10 2) 104
The newline and whitespace tab after the define above is just a text formatting convention, and means that you can visually separate the description and it's argument from the internals (or body) of the procedure. Scheme doesn't care about whitespace in it's code, again it's all about making it readable to us.
Now we know enough to make some shapes with fluxus. To start with, leave the console by pressing ctrl-1 - you can go back at any time by pressing ctrl-0. Fluxus is now in script editing mode. You can write a script, execute it by pressing F5, edit it further, press F5 again... this is the normal way fluxus is used.
Enter this script:
(define (render) (draw-cube)) (every-frame (render))
Then press F5, you should see a cube on the screen, drag the mouse around the fluxus window, and you should be able to move the camera - left mouse for rotate, middle for zoom, right for translate.
This script defines a procedure that draws a cube, and calls it every frame - resulting in a static cube.
You can change the colour of the cube like so:
(define (render) (colour (vector 0 0.5 1)) (draw-cube)) (every-frame (render))
The colour command sets the current colour, and takes a single input - a vector. Vectors are used a lot in fluxus to represent positions and directions in 3D space, and colours - which are treated as triplets of red green and blue. So in this case, the cube should turn a light blue colour.
Add a scale command to your script:
(define (render) (scale (vector 0.5 0.5 0.5)) (colour (vector 0 0.5 1)) (draw-cube)) (every-frame (render))
Now your cube should get smaller. This might be difficult to tell, as you don't have anything to compare it with, so we can add another cube like so:
(define (render) (colour (vector 1 0 0)) (draw-cube) (translate (vector 2 0 0)) (scale (vector 0.5 0.5 0.5)) (colour (vector 0 0.5 1)) (draw-cube)) (every-frame (render))
Now you should see two cubes, a red one, then the blue one, moved to one side (by the translate procedure) and scaled to half the size of the red one.
(define (render) (colour (vector 1 0 0)) (draw-cube) (translate (vector 2 0 0)) (scale (vector 0.5 0.5 0.5)) (rotate (vector 0 45 0)) (colour (vector 0 0.5 1)) (draw-cube)) (every-frame (render))
For completeness, I added a rotate procedure, to twist the blue cube 45 degrees.
To do more interesting things, we will write a procedure to draw a row of cubes. This is done by recursion, where a procedure can call itself, and keep a record of how many times it's called itself, and end after so many iterations.
In order to stop calling our self as a procedure, we need to take a decision - we use cond for decisions.
(define (draw-row count) (cond ((not (zero? count)) (draw-cube) (translate (vector 1.1 0 0)) (draw-row (- count 1))))) (every-frame (draw-row 10))
Be careful with the brackets - the fluxus editor should help you by highlighting the region each bracket corresponds to. Run this script and you should see a row of 10 cubes. You can build a lot out of the concepts in this script, so take some time over this bit.
cond is used to ask questions, and it can ask as many as you like - it checks them in order and does the first one which is true. In the script above, we are only asking one question, (not (zero? count)) - if this is true, if count is anything other than zero, we will draw a cube, move a bit and then call our self again. Importantly, the next time we call draw-row, we do so with one taken off count. If count is 0, we don't do anything at all - the procedure exits without doing anything.
So to put it together, draw-row is called with count as 10 by every-frame. We enter the draw-row function, and ask a question - is count 0? No - so carry on, draw a cube, move a bit, call draw-row again with count as 9. Enter draw-row again, is count 0? No, and so on. After a while we call draw-row with count as 0, nothing happens - and all the other functions exit. We have drawn 10 cubes.
Recursion is a very powerful idea, and it's very well suited to visuals and concepts like self similarity. It is also nice for quickly making very complex graphics with scripts not very much bigger than this one.
Well, now you've got through that part, we can quite quickly take this script and make it move.
(define (draw-row count) (cond ((not (zero? count)) (draw-cube) (rotate (vector 0 0 (* 45 (sin (time))))) (translate (vector 1.1 0 0)) (draw-row (- count 1))))) (every-frame (draw-row 10))
time is a procedure which returns the time in seconds since fluxus started running. sin converts this into a sinewave, and the multiplication is used to scale it up to rotate in the range of -45 to +45 degrees (as sin only returns values between -1 and +1). Your row of cubes should be bending up and down. Try changing the number of cubes from 10, and the range of movement by changing the 45.
To give you something more visually interesting, this script calls itself twice - which results in an animating tree shape.
(define (draw-row count) (cond ((not (zero? count)) (translate (vector 2 0 0)) (draw-cube) (rotate (vector (* 10 (sin (time))) 0 0)) (with-state (rotate (vector 0 25 0)) (draw-row (- count 1))) (with-state (rotate (vector 0 -25 0)) (draw-row (- count 1)))))) (every-frame (draw-row 10))For an explanation of with-state, see the next section.
The state machine is the key to understanding how fluxus works, all it really means is that you can call functions which change the current context which has an effect on subsequent functions. This is a very efficient way of describing things, and is built on top of the OpenGl api, which works in a similar way. For example, in a function called every frame:
(colour (vector 1 0 0)) (draw-cube) (colour (vector 0 1 0)) (draw-cube)
Will draw a red cube, then a green cube (in this case, you can think of the (colour) call as changing a pen colour before drawing something). States can also be stacked, for example:
(colour (vector 1 0 0)) (with-state (colour (vector 0 1 0)) (draw-cube)) (draw-cube)
Will draw a green, then a red cube. The (with-state) isolates a state and gives it a lifetime, indicated by the brackets (so changes to the state inside are applied to the build-cube inside, but do not affect the build-cube afterwards). Its useful to use the indentation to help you see what is happening.
Both examples so far have used what is known as immediate mode, you have one state stack, the top of which is the current context, and everything is drawn once per frame. fluxus contains a structure known as a scenegraph for storing objects and their render states.
Time for another example:
(colour (vector 1 0 0)) (build-cube) (colour (vector 0 1 0)) (build-cube)
The only difference between this and the first example is the use of (build-cube) instead of (draw-cube). the build functions create a primitive object, copy the current renderstate and add the information into the scenegraph in a container called a scenenode.
The build- functions return object ID's (just numbers really) which enable you to do things to the scene node after it's been created. you can now specify objects like this:
(define myob (build-cube))
The cube will now be persistent in the scene until destroyed with
(destroy myob)
with-state returns the result of it's last expression, so to make new primitives with state you set up, you can do this:
(define my-object (with-state (colour (vector 1 0 0)) (scale (vector 0.5 0.5 0.5)) (build-cube)))
If you want to modify a objects renderstate after it's been loaded into the scenegraph, you can use with-primitive to set the current context to that of the object. This allows you to animate objects you have built, for instance:
<!-- build some cubes --> (colour (vector 1 1 1)) (define obj1 (build-cube)) (define obj2 (with-state (translate (vector 2 0 0)) (build-cube)) ... <!-- in a function called per frame --> (with-primitive obj1 (rotate (vector 0 1 0))) (with-primitive obj2 (rotate (vector 0 0 1)))
The scenegraph also enables you to parent objects to one another, using the renderstate's parent setting. this is only effective before an object is loaded into the scenegraph, setting it afterwards via with-primitive will be ignored:
(colour (vector 1 1 1)) (define a (build-cube)) (define b (with-state (parent a) (translate (vector 0 2 0)) (build-cube))) (define c (with-state (parent b) (translate (vector 0 2 0)) (build-cube)))
Creates three cubes, all attached to each other in a chain. Transforms for object a will be passed down to b and c, transforms on b will effect c.
Destroying a object in such a hierarchy will in turn destroy all child objects parented to it.
![]() |
![]() ![]() |
![]() ![]() ![]() | Copyleft (C) 2000 - 2008 dyne.org foundation and respective authors. Verbatim copying and non-commercial distribution is permitted in any medium, provided this notice is preserved. Send inquiries & questions to dyne.org's hackers. |
![]() |