latest newsbuy art
Thoughts rearrange, familiar now strange.Holly Golightly & The Greenhornes break flowersmore quotes
very clickable
music + math
Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
WELCOME TO THE 5TH DIMENSION | This isn't meant to be understood — it's meant to be enjoyed.
Love music and science? Explore my collaboration with Max Cooper where we tell the story of infinities and animate the digits of π. Both tracks appear on Max's Yearning for the Infinite album.
Another collaboration with Max!

Max Cooper's Ascent — Making of the Music video

Enter the 5th dimension

Ascent answers the question: if you were living in a 5-dimensional room and projected digits of `\pi` onto its walls, what would you see?

1 · building the animation from the ground up

The Ascent video was created using a custom animation system that I wrote for the video. It's about 5,400 lines of Perl.

Having my own solution to animating the 5-dimensional scene gave me complete control (that could be automated) over every frame. If I wanted to add something (e.g. at some point Max wanted to see gradients mapped onto cube surfaces), I could “just” add it.

Having my own solution also meant a lot more fiddling and debugging, as I was caught up in my own high-dimensional loop of fixing and breaking the code.

I'm also not an animator — I have no familiarity with animation tools. I'm only vaguely aware of After Effects.

2 · straightforward math — complex output

It was possible for me to code the animation system because the underlying math is relatively straightforward. The cubes are just a list of `n`-vectors that form their vertices and rotations are just matrix products applied to the vector.

The projection of the high-dimensional objects onto the 2-dimensional canvas was done in the simplest way possible — an orthographic projection, in which we keep the `x` and `y` components of a vector and throw out all others (no matter how many).

Adding more dimensions to the scene only requires that you add one more component to the vector and grow the rotation matrix by a row and column. It's as easy to animate a 3-dimensional scene as a 5-dimensional (or higher) scene.

A lot of the funky effects that you see in the video are achieved by the difference blend (logical NAND). The individual compoents (e.g. edges, faces) of the cubes are drawn one at a time and, because of the NAND blending, we never saturate the canvas.

3 · how the animation system works

The system works in a very simple way, even though its output can appear quite complicated (thanks difference blend!).

The entire animation is based on a set of `n`-dimensional cubes. For the final version of the video `n = 5`.

The scene is composed of one or more cubes. The cube is composed of (a) vertices (e.g. 32 vertices in 5-dimensional space) and (b) list of area maps to be projected onto one (or more) of its faces.

Cubes are also associated with parameters that determine how the cube is drawn. First, we define whether to draw the cube edges and/or faces. For example, at the start of the video the first cube has its edges drawn but not faces. Later, new cubes are added whose faces are drawn but not edges.

Second, each cube has a size parameter associated for each dimension. This allows me to shrink (or suppress) the cube along some dimensions. So, a 5-dimensional cube can be drawn as a square by setting the size of `z`, `w` and `v` dimensions to zero.

Third, a cubes edges (and faces) have themselves a parameter that determines how much of the edge (or face) to draw. This is independent of the cube's size along a given dimension. For example, I can choose to draw only 50% of the edge, which can be done by starting at the vertices (gap in the middle of the edge) or at the middle of the edge (gap at the vertices). For faces, this works the same way — a face can be drawn partially as a (growing or shrinking) square in the middle of a cube face or as four squares tucked up against the vertices.

This basic functionality is relatively easy to program. For each cube in the scene, you (a) iterate across its edges and faces, (b) determine their coordinates in 5-dimensional space by applying the scene's angles (both the camera and cube can rotate independently) as well as the size of the dimension, (c) determine how much of the element to draw based on the edge length (or the analogous parameter for faces) and then (b) draw it as a line (for edges) or filled polygon (faces) using the `(x,y)` coordinates of the element (orthographic projection).

4 · defining the scene

Whereas the geometry is relatively straightfoward, by far the trickiest part of the system is how to define the scene and manage changes over time.

Some of the things that the system should know how to do (over time) is (a) zoom and rotate the camera (there are 10 independent axes of rotation in a 5-dimensional space), (b) add and remove cubes from the scene, (c) shrink and grow a cube, (d) shrink and grow edges and face fills, (e) add and remove area map projections to any set of faces of a cube and (f) shrink and grow area maps.

Finally, the system should be able to apply randomness to any of these parameters. This helps add variation to the animation. For example, I really don't want to have to define the angles of each keyframe manually — it's easier to initialize the angle and then apply a random drift to it over time.

4.1 · system parameters

To make the keyframe definitions more modular, I define various parameters that can be reused.

4.1.1 · absolute vs relative

Parameters define either relative or absolute values. The difference between these is that relative values are used as scaling factors and absolute values are additive.

For example, if we define

param = var1 r0.965

and later use the command (see below for command syntax)

cube c0 size [x] var1

then the size of cube c0 along the `x` dimension will be multiplied by 0.965.

However, if we define

param = var1 d0.1

then the size of the cube will be increased by 0.1. Here d stands for “delta”.

4.1.2 · randomly sampled

A great deal of what you see in the animation is randomly generated — in particular, the rotation angles. Nobody wants to manually manage the values of each of the 10 possible independent angles of rotation.

For example, the following parameter definition and command rotates the scene by angle `0.1 \times 2 \pi`.

param = var1 d0.1 # values of angles are in units of 2π
angle xy var1 

But if we define

param = var1 d0.1,0.2

then the value of the parameter will be sampled randomly (and uniformly) from the interval `[0.1,0.2]` each time it's used.

4.1.3 · normalized

Rotations can be defined about one or more planes of rotation. For example, we can rotate by a given angle about the `xy` plane or about the `xy` and `yz` planes. The latter corresponds to composition of rotations achieved by mutiplying the rotation matrices.

However, given an angle of rotation, the scene will appear to rotate faster (there will be more motion) the more rotations we compose together. For this reason, parameter definitions (used only for angles) can include an n to indicate that the value will be divided by the number of axes we're rotating around.

param = var1 dn0.020,0.040
frame = 1.a ; ... ; cube c1 angle [x][yz] var1
frame = 1.a ; ... ; cube c1 angle [xy][yzw] var1

will rotate cube c1 by a random value sampled from the interval [0.02,0.04], divided by the number of planes of rotation.

For frame 4.d, the planes of rotation are defined as [x][yz], which corresponds rotations about `xy` and `xz` (we make all pairs of dimensions from the two sets of brackets). Thus, in this case we have two axes of rotation so we would divide var1 by 2.

In the next keyframe we rotate about `xy`, `xz`, `xw`, `yz` and `yw`. We have 5 axes of rotation so we would divide var1 by 5.

4.1.4 · macros

A parameter value can be used to store a set of commands. For example,

param = rotxyz a [x][wv] var1 _ a [y][wv] var2

rotates about `xw` and `wv` by an amount var1 and about `yw` and `yv` by an amount var2. This is convenient when you want to bundle up multiple rotations in a single definition.

frame = 1.a ; ... ; rotxyz

Here, var1 and var1 may be randomly sampled and normalized, as described above.

4.1.5 · function macros

Parameters can also define a function, which helps shorten the syntax of keyframe definitions.

For example, the above could have been a function

param = rotxyz(v1,v2) a [x][wv] v1 _ a [y][wv] v2

which would be called

frame = 1.a ; ... ; rotxyz(var1,var2)

As another example, to add a cube with size 1 and edge length 0.5 to the scene, the syntax is

cube c1 + 
cube c1 size . 1
cube c1 fade . 0.5

This is pretty tedious. So we can define a function

param = cube_add(cn,sv,fv) cube cn + _ cube cn size . sv _ cube cn fade . fv

which will achieve the same thing if we call it as

frame = 1.a ; ... ; cube_add(c1,1,0.5)

These macros can be combined. The following will add the cube and rotate the scene. Notice how var2 defines an angle that is, on average, twice the size of var1. This lets us rotate about one set of axes slowly and around another set more quickly.

param = var1 dn0.020,0.040
param = var2 dn0.040,0.080
frame = 1.a ; ... ; cube_add(c1,1,0.5) ; rotxyz(var1,var2)

4.2 · system commands

Keyframes are defined by one or more commands.

################################################################
# global zoom dimensions 
size .    1.2 # apply to all dimensions
size [xy] 1.2 # apply only to x,y
################################################################
# scene angle (all angles in units of 2π)
angle xy 0.1      # rotate about xy by 0.1
angle [x][yz] 0.1 # rotate about xy and xz planes by 0.1
angle . 0.1       # rotate about all planes by 0.1
################################################################
# add a cube 
cube c1 +  # add cube named c1
################################################################
# cube angle
angle c1 xy 0.1      # rotate cube c1 about xy by 0.1
angle c1 [x][yz] 0.1 # rotate cube c1 about xy and xz by 0.1
angle c1 . 0.1       # rotate cube c1 about all planes by 0.1
################################################################
# cube size
cube c1 size x 0.1    # set size of x dimension of cube c1 to 0.1
cube c1 size [xy] 0.1 # set size of x and y dimensions of cube c1 to 0.1
cube c1 size . 0.1    # set size of all dimensions of cube c1 to 0.1
################################################################
# cube edge fade
# analogous to cube size, but now we define how much of the edge to hide
cube c1 fade x 0.1   
cube c1 fade [xy] 0.1
cube c1 fade . 0.1   
################################################################
# add an area map to a cube face
# map 22a is added to xy plane for z = 0
face c1 xy0 map 22a +
# map 22a is added to all faces 
face c1 . map 22a +
################################################################
# fade and zoom an area map
face c1 xy0 map 22a fade 0.5
face c1 xy0 map 22a zoom 0.5

Most commands use a kind of regular expresion to narrow down their targets. For example,

# apply to cube c1 plane xy
angle c1 xy 0.1
# apply to cube c1,c2,c3 plane xy
angle c[1-3] xy 0.1
# apply to cube c1,c2,c3 and any plane
angle c[1-3] . 0.1
# apply to any cube and any plane
angle . . 0.1

Thus the last command would rotate all cubes on the scene about each plane by 0.1.

4.3 · building keyframes

Keyframes are composed of one or more commands and the number of frames over which the parameters changed by the commands are interpolated (see below).

For example, the keyframe

frame = 1.a1 ; angle . 0

will set all angles of the scene to 0.

4.4 · interpolating frames

Frames are interpolated between keyframes to smoothly vary parameter changes that the keyframes define. The argument to n defines how many frames to interpolate between these two keyframes.

For example, in this pair of keyframes we first set all angles of the scene to zero. In the second keyframe we add 0.1 to the angle about the `xy` plane and interpolate this change over 2fs frames.

frame = 1.a1 ; angle . 0
frame = 1.a2 ; n 2fs ; angle xy d0.1

By default, fs = 24, which is the number of frames per second. Thus, we have a 2 second rotation of 0.1 about the plane `xy`.

Here is a slightly more complex example

frame = 1.a1 ; angle . 0
# 2 second rotation about xy by 0.1
frame = 1.a2 ; n 2fs ; angle xy d0.1
# 2 second rotation about xy by 0.2 (faster rotation)
frame = 1.a3 ; n 2fs ; angle xy d0.2
# 2 second rotation about xy by 0.2 (faster rotation) and by yz by 0.1
frame = 1.a4 ; n 2fs ; angle xy d0.2 ; angle yz d0.1

Keyframes can be repeated.

frame = 1.a4 ; n 2fs ; angle xy d0.2 ; angle yz d0.1
frame = 1.a5 ; n 2fs ; angle xy d0.2 ; angle yz d0.1

can be shortened to

frame = 1.a4 ; n 2fs ; angle xy d0.2 ; angle yz d0.1; rep 2

The purpose of the rep command is to make the keyframe definitions more modular. For example, the above could have been written as

frame = 1.a4 ; n 4fs ; angle xy d0.4 ; angle yz d0.2;

where we interpolate over twice as many frames 4fs and rotate about angles that are twice as large. However, over time course of defining scenes I discovered that it was very helpful to keep changes defined in keyframes incremental.

5 · walkthrough the first few keyframes of ascent

If you've gotten this far, then you're in a good place to understand how each of the keyframes in the Ascent video is defined. Here, I walk you through some of the early keyframes.

Here, I've added the parameter definitions before the keyframe that uses them. Normally, they're stored in a separate file.

# define a scene marker to which we can jump or stop at
frame = 1:
# add cube c0
param = fs 24
param = cube_add(cn,sv,fv) cube cn + _ cube cn size . sv _ cube cn fade . fv
frame = 1.a; cube_add(c0,0,1)
# arrange yw rotation for the split at 1.c*
param = astepa2 d-0.048978
frame = 1.a0; a yw astepa2
# grow horizontal line
frame = 1.a1; n 2fs; c c0 f [xy] 0
frame = 1.a2; n 2fs; c c0 s [x]  0.05  
frame = 1.a3; n 2fs; c c0 s [x]  0.10  
frame = 1.a4; n 2fs; c c0 s [x]  0.15  
# grow y and rotate
param = astepb3 d-0.041667
param = rxy3    a xy astepb3 
frame = 1.a5; n 3fs; c c0 s [y]  0.05 ; rxy3
frame = 1.a6; n 3fs; c c0 s [y]  0.10 ; rxy3 
frame = 1.a7; n 2fs; c c0 s [y]  0.15 ; rxy3 
# grow z
param = astepa6 d-0.016326
param = ryz6    a yz astepa6
frame = 1.b1; n 2fs; c c0 s [xy] 0.15 ; c c0 s [z] 0.100 ; c c0 f [z] 0.80 ; ryz6
frame = 1.b2; n 2fs; c c0 s [xy] 0.15 ; c c0 s [z] 0.110 ; c c0 f [z] 0.60 ; ryz6
frame = 1.b3; n 2fs; c c0 s [xy] 0.15 ; c c0 s [z] 0.120 ; c c0 f [z] 0.40 ; ryz6
frame = 1.b4; n 2fs; c c0 s [xy] 0.15 ; c c0 s [z] 0.130 ; c c0 f [z] 0.20 ; ryz6
frame = 1.b5; n 2fs; c c0 s [xy] 0.15 ; c c0 s [z] 0.140 ; c c0 f [z] 0.10 ; ryz6
frame = 1.b6; n 2fs; c c0 s [xy] 0.15 ; c c0 s [z] 0.150 ; c c0 f [z] 0.00 ; ryz6
# split cubes along w (needs yw angle set, see above)
frame = 1.c1; n 1fs; c c0 s [xyz] 0.15 ; c c0 s [w] 0.815
# a pause
frame = 1.c2; n 2fs;

6 · ascent configuration files

Here are all the configuration files for the animation system. Each file has a hierarchy of blocks that define groups of parameters.

Typically, parameters in sub-blocks overwrite those in their parent blocks.

6.1 · global system configuration

This is the top-level configuration for the animation.

Configuration files are imported via the include directive.

# Debug groups, one or more
# cube, eval, basis, angle, timer, step, schedule, size, map, key, param, progress, out, child, param, color, tween, render
debug = cube,edge,basis,eval,timer,schedule,t,size,param,progress,out,param,tween

scene_name   = ascent-acropolis-1
#hdhalf       = yes 
seed         = 1
nproc        = 100
haldnproc    = 100
fps          = 24
#wide         = 3
lookup_tol   = 0.001
lookup_make  = yes
cache_dir    = /tmp/cube
frame_dir    = /tmp/cube
hald_dir     = ../hald
map_dir      = cache/maps
clear_cache  = no
clear_frames = no
aa           = no

# All angles in units of 2pi
<angle>
b  = 0.125    # 0.78539816339     # pi/4
b2 = 0.0625   # 0.392699          # b/2
b4 = 0.03125  # 0.392699          # b/4
a  = 0.097956 # 0.615479708670387 # Math::Trig::asin( Math::Trig::tan(pi/6) )
a2 = 0.048978 # 0.3077395         # a/2
a4 = 0.024489 # 0.3077395         # a/4
</angle>

# Other useful angles 
param beta   0.125
param beta2  beta/2
param beta4  beta/4
param beta6  beta/6
param beta8  beta/8
param alpha  0.097956
param alpha2 alpha/2
param alpha4 alpha/4
param alpha6 alpha/6
param alpha8 alpha/8
param gamma  0.152043362
param gamma2 0.076021681

# angle bookmarks
param refxy 135/360 # 147/360 #pi/180 ?135
param refxz 135/360 # 129/360 #pi/180
param refxw 270/360 # 259/360 #pi/180
param refxv 270/360 # 269/360 #pi/180
param refyz 180/360 # 192/360 #
param refyw 180/360 # 210/360 #pi/180
param refyv 180/360 # 267/360 #pi/180
# elements to draw
cube_edge   = yes
face_map    = yes
face_label  = yes
map_line    = yes
map_fill    = yes
z_tone      = no
z_tone_edge = no
dim_color   = yes

xmult = 1
ymult = 1

################################################################
# Break points
#
# 0  after scene init
# 1  after keyframe
# 2  after frame
# 3  after memory size report
# 4  after tween
#
################################################################
# GLOBALS 
# Define dimensions  ndim N
# Inactive           -COMMAND ...
#                    -size 1
#                    -a 02 10
# Size dimensions    size 1,1,1,1
#                    size . 1
#                    size 1 1
#                    size x 1
#                    size [12] 1
#                    size [xy] 1
#                    size [1-3] 1
# Global angle       a 02 0.5
#                    a xz 0.5
#                    a [xy]z 0.5
# CUBES
#
# add a cube         cube NAME +
#
# Cube angle         a CUBE xz VALUE    CUBE = RX (eg:  . = all)
#                                              _ current
# 
# Face               f xy    COMMAND   all xy   
#                    f xy0   COMMAND   xy z=0   
#                    f xy1   COMMAND   xy z=1   
#                    f xy.1  COMMAND   xy z=ANY w=1
#                    f xyz   COMMAND   all pairs from xyz
#                    f xy1.  COMMAND   all xy z=1 w=ANY
#                    f x     COMMAND   any with x
#                    f x.1.  COMMAND   any with x z=1
#                    f x.10  COMMAND   any with x z=1 w=0 (same as xy10)
#                    f .     COMMAND   any face
# Blends
#                 diff creates dark intersections
#                  add creates light intersections 
#              lighten like add, but more subtle
#             multiply high contrast; needs white background, nice with opacity 0.5
#               darken more subtle multiply
#                  hue fun
#                 
# Some m/n Pi approximations
#   19     6 3.166666666667 0.007981306249 improved
#   22     7 3.142857142857 0.000402499435 improved
#  179    57 3.140350877193 0.000395269704 improved
#  201    64 3.140625000000 0.000308013704 improved
#  223    71 3.140845070423 0.000237963113 improved
#  245    78 3.141025641026 0.000180485705 improved
#  267    85 3.141176470588 0.000132475164 improved
#  289    92 3.141304347826 0.000091770575 improved
#  311    99 3.141414141414 0.000056822190 improved
#  333   106 3.141509433962 0.000026489630 improved
#  355   113 3.141592920354 0.000000084914 improved
# Layer
#
# cube:targetlayer:combine:opacity:color:ztone:thickness

level = 3

# Variations of final video
<<include acropolis/scene.ascent.conf>>

# Scenes for testing 
<<include liverpool/scene.ascent.conf>>
<<include scene.310.conf>> # 310
<<include scene.306.conf>> # 306
<<include scene.305.conf>> # 305
<<include scene.304.conf>> # 304
<<include scene.302.conf>> # 302 303
<<include scene.301.conf>> # 301
<<include scene.300.conf>> # 300
<<include scene.205.conf>> # 205
<<include scene.204.conf>> # 204
<<include scene.203.conf>> # 203
<<include scene.202.conf>> # 202
<<include scene.201.conf>> # 201
<<include scene.200.conf>> # 200
<<include scene.105.conf>> # 105 106 107
<<include scene.101.conf>> # 101 102 103 104
<<include scene.100.conf>> # 100
<<include scene.004.conf>> # 004
<<include scene.003.conf>> # 003
<<include scene.002.conf>> # 002
<<include scene.001.conf>> # 001
<<include scene.000.conf>> # 000
# Description of audio effects at specific frames
# For debugging - they do not influence the animation.
<schedule>
0    strt
1296 chng
1992 upmd
2184 bass
2592 dist
3840 chrd
5328 dyad
6672 peak
7392 outr
7800 dc
7944 fd
8568 end
</scedule>

# Times of musical accents in the video. 
# For debugging - they do not influence the animation.
<accents>
0:16 *
0:28 *
0:34 *
0:43 *
1:07 *
1:13 *
1:22 *
1:30 *
1:36 *
1:57 *
1:59 *
2:06 *
2:16 *
2:22 *
2:27 *
2:47 *
2:56 *
3:14 *
3:23 *
3:34 *
3:52 *
4:03 *
4:10 *
4:16 *
4:22 *
4:32 *
5:26 *
5:28 *
</accents>

# Size of the rendered frame 
<canvas>
width  = 1920
height = 1080
scale  = 0.5
</canvas>

# Some colors
<color>
0      = fg
1      = fg
2      = fg
3      = 255,0,0
4      = 0,255,0
5      = 0,0,255
6      = 255,0,255
7      = 0,255,255
8      = 255,255,0
bg     = 0,0,0
lbg    = 128,128,128
vlbg   = 200,200,200
vvlbg  = 225,225,225
fg     = 255,255,255
orange = 251,176,59
blue   = 41,171,226
dblue  = 0,113,188
green  = 140,198,63
dgreen = 0,146,69
red    = 193,39,45
purple = 102,45,145
magenta= 237,30,121

eblue   = 30,58,245
egreen  = 127,249,107
epurple = 76,39,245
emagenta= magenta

# If using 10 dims
#d0 = 237,32,121
#d1 = 237,62,54
#d2 = 247,99,33
#d3 = 255,183,59
#d4 = 245,236,43
#d5 = 141,197,58
#d6 = 55,179,71
#d7 = 0,171,238
#d8 = 40,56,145
#d9 = 146,39,139
# If using 5 dims
d0 = 237,32,121
#d1 = 237,62,54
d1 = 247,99,33
#d3 = 255,183,59
d2 = 245,236,43
#d5 = 141,197,58
d3 = 55,179,71
#d7 = 0,171,238
d4 = 40,56,145
#d9 = 146,39,139
#d2     = orange
#d3     = red
#d5     = blue
#d9     = green
</color>

# For larger number of dimensions, PDL is faster
# e.g. ndim=8, 1 frames per dim : PDL (8 sec), Math::Matrix (23 sec)
use_pdl      = no
# Use precompiled rotation functions from rotate.pm (see bin/make_rotate_package)
# For ndim > 8, PDL is faster
use_fast_rot = no

number       = pi
number_file  = num/conf(number).5000.txt
divide_ratio = 1

6.2 · global parameters

Parameters and functions used in the keyframe definitions.

# Not all these parameters are used - many are left over 
# from past versions.

param = zremap -1 1 0 1 1
param = xmult 1; ymult 1 

# Ways in which we shrink edges and faces. For example, edge fade
# is set to 'shrinkcorners' meaning that when edges are drawn only
# partially, there will a gap in the middle of the edge
# shrinkmid | shrinkstart | shrinkend | shrinkcorners | hide | ignore
param = mapedgefade shrinkmidrand 
param = mapfillfade shrinkmidrand
param = edgefade shrinkcorners   
param = fillfade shrinkcorners   
param = facefillsort dimdesc # area | dim | faceidx
# Randomly sampled angle rotation rates. 
# d - the value is an absolute amount to be added
# n - the value is normalized by the number of axes we're rotating on
# x,y - the value is sampled uniformly from [x,y] 
param = astep-vvslow   dn0.001,0.002
param = astep-vslow    dn0.002,0.005
param = astep-slow     dn0.005,0.010
param = astep-med      dn0.010,0.020
param = astep-fast     dn0.020,0.040
param = astep-vfast    dn0.040,0.060
param = astep-vvfast   dn0.060,0.080
param = astep-vvvfast  dn0.080,0.100
param = astep2-vvslow  dn0.00125,0.0025
param = astep2-vslow   dn0.00250,0.0060
param = astep2-slow    dn0.00600,0.0125
param = astep2-med     dn0.01250,0.0240
param = astep2-fast    dn0.024,0.050
param = astep2-vfast   dn0.050,0.070
param = astep2-vvfast  dn0.070,0.090
param = astep2-vvvfast dn0.090,0.110

# Fixed values for rotation
param = astepa  d-alpha
param = astepb  d-beta
param = astepa2 d-0.048978
param = astepb2 d-0.0625  
param = astepa3 d-0.032652
param = astepb3 d-0.041667
param = astepa4 d-0.024489
param = astepb4 d-0.03125
param = astepa6 d-0.016326

# Various absolute (d) and relative (r) values used in sizing
param = s3s  d0.025
param = s3f  d0.10
param = s4f  d0.30
param = s4u  d0.10
param = p1   r0.965
param = p2   d0.05
param = s5f  d0.009
param = s5cf r0.96
param = s5cs r0.98
param = ps20 d0.05
param = ps21 d-0.025

# Specific plane rotations
# e.g. rxy1 rotates in xy plane by amount astepb
param = rxy1    a xy astepb
param = ryz1    a yz astepa
param = rxz1    a xz astepb
param = rxy2    a xy astepb2 
param = ryz2    a yz astepa2
param = rxz2    a xz astepa2
param = rxy3    a xy astepb3 
param = ryz3    a yz astepa3
param = rxz3    a xz astepa3
param = rxy4    a xy astepb4 
param = ryz4    a yz astepa4
param = rxz4    a xz astepa4
param = ryz6    a yz astepa6

# Function macros, _ acts as a delimiter between steps
#
# Adding, sizing, fading, rotating cubes
param = cube_add(cn,sv,fv) cube cn + _ cube cn size . sv _ cube cn fade . fv
param = map_add(cn,rx,mn)  face cn rx map mn + _ face cn . map . fade 1 _ face cn . map . zoom 1
param = map_fade(cn,mn,fv) face cn . map mn fade fv
param = cube_rot(cn,rx,av) cube cn a rx av
param = cube_size(cn,sv)   cube cn size . sv

# Scene rotations
# e.g. a [xy][wu] rotates about xw xu yw wu by astep-vvslow 
param = rotvvs  a [xy][wu] astep-vvslow  _ a [xy][vt] astep2-vvslow  _ a xz astep-vvslow
param = rotvs   a [xy][wu] astep-vslow   _ a [xy][vt] astep2-vslow   _ a xz astep-vslow
param = rots    a [xy][wu] astep-slow    _ a [xy][vt] astep2-slow    _ a xz astep-slow
param = rotm    a [xy][wu] astep-med     _ a [xy][vt] astep2-med     _ a xz astep-med
param = rotf    a [xy][wu] astep-fast    _ a [xy][vt] astep2-fast    _ a xz astep-fast
param = rotvf   a [xy][wu] astep-vfast   _ a [xy][vt] astep2-vfast   _ a xz astep-vfast
param = rotvvf  a [xy][wu] astep-vvfast  _ a [xy][vt] astep2-vvfast  _ a xz astep-vvfast
param = rotvvvf a [xy][wu] astep-vvvfast _ a [xy][vt] astep2-vvvfast _ a xz astep-vvvfast
param = rotthis2 a [x][wu] astep-vslow _ a [y][zv] astep2-vslow _ ryz2 _ !rxz2 _ rxy2 
param = rotthis3 a [x][wu] astep-fast _ a [y][zv] astep2-fast _ ryz2 _ rxy2 
param = rot6vvvf a [x][wu] astep-vvfast _ a [y][zv] astep2-vvvfast
param = rot6vvf  a [x][wu] astep-vvfast _ a [y][zv] astep2-vvfast 
param = rot6vf   a [x][wu] astep-vfast  _ a [y][zv] astep2-vfast  
param = rot6f    a [x][wu] astep-fast   _ a [y][zv] astep2-fast   
param = rot6m    a [x][wu] astep-med    _ a [y][zv] astep2-med    
param = rot6s    a [x][wu] astep-slow   _ a [y][zv] astep2-slow   
param = rot6vs   a [x][wu] astep-vslow  _ a [y][zv] astep2-vslow  
param = rot6vvs  a [x][wu] astep-vvslow _ a [y][zv] astep2-vvslow 

# rotate along each axis
# here the . matches any plane of rotation
param = rotallvvvf a . dn0.75-1.00
param = rotallvvf  a . dn0.50-0.75
param = rotallvf   a . dn0.25-0.50
param = rotallf    a . dn0.125-0.25
param = rotallm    a . astep-med
param = rotalls    a . astep-slow
param = rotallvs   a . astep-vslow
param = rotallvvs  a . astep-vvslow

# some relative multipliers
param = s2f  r0.80
param = p3   r0.95
param = ps4  r1.01
param = ps5  0.95
param = ps6  0.950-0.990
param = ps7  0.925-0.950
param = ps8  0.900-0.925
param = ps9  0.875-0.900
param = ps10 0.850-0.875
param = ps11 0.825-0.850
param = ps12 0.800-0.825
param = ps13 0.850-0.900
param = ps14 0.900-0.950
param = ps15 0.950-0.975

param = p5  r0.95
param = q31 r0.85
param = q30 r0.75
param = q29 r0.65
param = q32 d0.125
param = q33 d0.025 
param = q34 d0.05
param = q40 r0.70 
param = q50 d0.0315

6.3 · scene variations

Variety of scene definitions. Most of these vary based on the color of elements. Here, colors are defined with e.g. color1 and then these values are used in the layer definitions. All of these have the text “acropolis” because the initial version of the video was prepared for Max's Live at the Acropolis show.

The final version of the video is ascent-acropolis-11.

################################################################
# B/W and color final render
<scene ascent-acropolis-11> # viridis
param = name acropolis
param = version 11
param = color0 fg # initial cube
param = color1 fg # 
param = color2 fg #
param = color3 fg #
param = color4 fg #
<<include scene.ascent.layers.v11.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-11v> # viridis
param = name acropolis
param = version 11v
param = color0 map_plasma_rev  # initial cube
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
<<include scene.ascent.layers.v11.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-11p> # plasma
param = name acropolis
param = version 11p
param = color0 map_viridis_rev # initial cube
param = color1 map_plasma_rev # 
param = color2 map_plasma_rev #
param = color3 map_plasma_rev #
param = color4 map_plasma_rev #
<<include scene.ascent.layers.v11.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-11pdebug> # plasma debug with annotation
param = name acropolis
param = version 11pdebug
param = color0 map_viridis_rev # initial cube
param = color1 map_plasma_rev # 
param = color2 map_plasma_rev #
param = color3 map_plasma_rev #
param = color4 map_plasma_rev #
<<include scene.ascent.layers.v11.conf>>
<<include acropolis/scene.ascent.main.v11.debug.conf>>
</scene>
#
################################################################
# Other prototype scenes 

<scene ascent-acropolis-1>
param = name acropolis
param = version 1
param = color1 fg
param = color2 fg
param = color3 fg
param = color4 fg
<<include acropolis/scene.ascent.main.conf>>
</scene>

<scene ascent-acropolis-2>
param = name acropolis
param = version 2
param = color1 eblue    # eblue
param = color2 egreen   # egreen
param = color3 epurple  # epurple
param = color4 emagenta # emagenta
<<include acropolis/scene.ascent.main.conf>>
</scene>

<scene ascent-acropolis-3>
param = name acropolis
param = version 3
param = color1 blue   # eblue
param = color2 green  # egreen
param = color3 dblue  # epurple
param = color4 dgreen # emagenta
<<include acropolis/scene.ascent.main.conf>>
</scene>

<scene ascent-acropolis-4>
param = name acropolis
param = version 4
param = color1 eblue  # eblue
param = color2 egreen # egreen
param = color3 eblue  # epurple
param = color4 egreen # emagenta
<<include acropolis/scene.ascent.main.conf>>
</scene>

# scene 6 is faster below
# 4th maps level c in scene 6 and 7

<scene ascent-acropolis-5>
param = name acropolis
param = version 5
param = color1 eblue    # eblue
param = color2 egreen   # egreen
param = color3 epurple  # epurple
param = color4 emagenta # emagenta
<<include acropolis/scene.ascent.main.conf>>
</scene>

<scene ascent-acropolis-6>
param = name acropolis
param = version 6
param = color1 egreen   # eblue
param = color2 fg       # egreen
param = color3 eblue    # epurple
param = color4 emagenta # emagenta
<<include acropolis/scene.ascent.main.conf>>
</scene>

<scene ascent-acropolis-7>
param = name acropolis
param = version 7
param = color1 eblue   # eblue
param = color2 fg      # egreen
param = color3 fg      # epurple
param = color4 egreen  # emagenta
<<include acropolis/scene.ascent.main.conf>>
</scene>

<scene ascent-acropolis-8>
param = name acropolis
param = version 8
param = color1 egreen   # eblue
param = color2 fg       # egreen
param = color3 fg       # epurple
param = color4 emagenta # emagenta
<<include acropolis/scene.ascent.main.conf>>
</scene>

<scene ascent-acropolis-9>
param = name acropolis
param = version 9
param = color1 fg # eblue
param = color2 fg # egreen
param = color3 fg # epurple
param = color4 fg # emagenta
<<include acropolis/scene.ascent.main.conf>>
</scene>

# This version used at the concert.
<scene ascent-acropolis-10>
param = name acropolis
param = version 10
param = color1 fg # eblue
param = color2 fg # egreen
param = color3 fg # epurple
param = color4 fg # emagenta
<<include scene.ascent.layers.v10.conf>>
<<include acropolis/scene.ascent.main.v10.conf>>
</scene>

<scene ascent-acropolis-11va>
param = name acropolis
param = version 11va
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
<<include scene.ascent.layers.v11.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-11vb>
param = name acropolis
param = version 11vb
param = area_fraction_max 0.02
param = area_transition   0.5
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
<<include scene.ascent.layers.v11.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

# old v26
<scene ascent-acropolis-11vc>
param = name acropolis
param = version 11vc
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.01
param = area_transition   0.75
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v11.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

# old v28
<scene ascent-acropolis-11vd>
param = name acropolis
param = version 11vd
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.02
param = area_transition   0.5
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v28.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-11ma>
param = name acropolis
param = version 11ma
param = color1 map_magma_rev # 
param = color2 map_magma_rev #
param = color3 map_magma_rev #
param = color4 map_magma_rev #
<<include scene.ascent.layers.v11.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-11mb>
param = name acropolis
param = version 11mb
param = area_fraction_max 0.02
param = area_transition   0.5
param = color1 map_magma_rev # 
param = color2 map_magma_rev #
param = color3 map_magma_rev #
param = color4 map_magma_rev #
<<include scene.ascent.layers.v11.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

# old v26
<scene ascent-acropolis-11mc>
param = name acropolis
param = version 11mc
param = color1 map_magma_rev # 
param = color2 map_magma_rev #
param = color3 map_magma_rev #
param = color4 map_magma_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.01
param = area_transition   0.75
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v11.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

# old v28
<scene ascent-acropolis-11md>
param = name acropolis
param = version 11md
param = color1 map_magma_rev # 
param = color2 map_magma_rev #
param = color3 map_magma_rev #
param = color4 map_magma_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.02
param = area_transition   0.5
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v28.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-11vma>
param = name acropolis
param = version 11vma
param = colorm map_magma_rev # 
param = colorv map_viridis_rev #
<<include scene.ascent.layers.v11vm.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-11vmb>
param = name acropolis
param = version 11vmb
param = area_fraction_max 0.02
param = area_transition   0.5
param = colorm map_magma_rev # 
param = colorv map_viridis_rev #
<<include scene.ascent.layers.v11vm.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

# old v26
<scene ascent-acropolis-11vmc>
param = name acropolis
param = version 11vmc
param = colorm map_magma_rev # 
param = colorv map_viridis_rev #
param = area_fraction_max 0.01
param = area_transition   0.75
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v11.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

# old v28
<scene ascent-acropolis-11vmd>
param = name acropolis
param = version 11vmd
param = colorm map_magma_rev # 
param = colorv map_viridis_rev #
param = area_fraction_max 0.02
param = area_transition   0.5
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v28vm.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

################################################################
################################################################
################################################################

<scene ascent-acropolis-12>
param = name acropolis
param = version 12
param = color1 map_magma # 
param = color2 map_magma #
param = color3 map_magma #
param = color4 map_magma #
<<include scene.ascent.layers.v11.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-13>
param = name acropolis
param = version 13
param = color1 map_inferno # 
param = color2 map_inferno #
param = color3 map_inferno #
param = color4 map_inferno #
<<include scene.ascent.layers.v11.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-14>
param = name acropolis
param = version 14
param = color1 map_viridis # 
param = color2 map_viridis #
param = color3 map_viridis #
param = color4 map_viridis #
<<include scene.ascent.layers.v14.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-14b>
param = name acropolis
param = version 14b
param = hald hald1
param = color1 map_viridis # 
param = color2 map_viridis #
param = color3 map_viridis #
param = color4 map_viridis #
<<include scene.ascent.layers.v14.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-15>
param = name acropolis
param = version 15
param = color1 map_viridis     # 
param = color2 map_viridis_rev #
param = color3 map_viridis     #
param = color4 map_viridis_rev #
<<include scene.ascent.layers.v14.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-16>
param = name acropolis
param = version 16
param = color1 map_viridis_rev # 
param = color2 map_viridis     #
param = color3 map_viridis_rev #
param = color4 map_viridis     #
<<include scene.ascent.layers.v14.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-16b>
param = name acropolis
param = version 16b
param = hald hald1
param = color1 map_viridis_rev # 
param = color2 map_viridis     #
param = color3 map_viridis_rev #
param = color4 map_viridis     #
<<include scene.ascent.layers.v14.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-17>
param = name acropolis
param = version 17
param = color1 map_viridis     # 
param = color2 map_viridis     #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
<<include scene.ascent.layers.v14.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-17b>
param = name acropolis
param = version 17b
param = hald hald1
param = color1 map_viridis     # 
param = color2 map_viridis     #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
<<include scene.ascent.layers.v14.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-17c>
param = name acropolis
param = version 17c
param = hald hald1
param = color1 map_viridis     # 
param = color2 map_viridis     #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = area_fraction_max 0.05
param = area_transition   0.5
<<include scene.ascent.layers.v14.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-17d>
param = name acropolis
param = version 17d
param = hald hald1
param = color1 map_viridis     # 
param = color2 map_viridis     #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = area_fraction_max 0.04
param = area_transition   0.5
<<include scene.ascent.layers.v14.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-17e>
param = name acropolis
param = version 17e
param = hald hald1
param = color1 map_viridis     # 
param = color2 map_viridis     #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = area_fraction_max 0.03
param = area_transition   0.5
<<include scene.ascent.layers.v14.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-17f>
param = name acropolis
param = version 17f
param = hald hald1
param = color1 map_viridis     # 
param = color2 map_viridis     #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = area_fraction_max 0.02
param = area_transition   0.5
<<include scene.ascent.layers.v14.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-17g>
param = name acropolis
param = version 17g
param = hald hald1
param = color1 map_viridis     # 
param = color2 map_viridis     #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = area_fraction_max 0.01
param = area_transition   0.5
<<include scene.ascent.layers.v14.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-18>
param = name acropolis
param = version 18
param = color1 map_viridis     # 
param = color2 map_viridis     #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
<<include scene.ascent.layers.v18.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-19>
param = name acropolis
param = version 19
param = color1 map_viridis     # 
param = color2 map_viridis     #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
<<include scene.ascent.layers.v19.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-20>
param = name acropolis
param = version 20
param = color1 map_viridis     # 
param = color2 map_viridis     #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
<<include scene.ascent.layers.v20.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-21>
param = name acropolis
param = version 21
param = color1 map_viridis     # 
param = color2 map_viridis     #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
<<include scene.ascent.layers.v21.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-22>
param = name acropolis
param = version 22
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.005
param = area_transition   0.5
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v22.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-22b>
param = name acropolis
param = version 22b
param = hald hald1
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.005
param = area_transition   0.5
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v22.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-23>
param = name acropolis
param = version 23
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.004
param = area_transition   0.5
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v22.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-24>
param = name acropolis
param = version 24
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.003
param = area_transition   0.35
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v22.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-24b>
param = name acropolis
param = version 24b
param = hald hald1
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.003
param = area_transition   0.35
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v22.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-25>
param = name acropolis
param = version 25
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.0025
param = area_transition   0.2
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v22.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>


<scene ascent-acropolis-26b>
param = name acropolis
param = version 26b
param = hald hald1
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.002
param = area_transition   0.5
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v22.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-27>
param = name acropolis
param = version 27
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.002
param = area_transition   0.5
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v27.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>


<scene ascent-acropolis-28b>
param = name acropolis
param = version 28b
param = hald hald1
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.002
param = area_transition   0.5
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v28.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

<scene ascent-acropolis-29>
param = name acropolis
param = version 29
param = color1 map_viridis_rev # 
param = color2 map_viridis_rev #
param = color3 map_viridis_rev #
param = color4 map_viridis_rev #
param = polycolor1 fg # 
param = polycolor2 fg #
param = polycolor3 fg #
param = polycolor4 fg #
param = area_fraction_max 0.002
param = area_transition   0.5
param = zremap_local -1 1 0 1 1
<<include scene.ascent.layers.v29.conf>>
<<include acropolis/scene.ascent.main.v11.conf>>
</scene>

6.4 · scene parameters

Parameters specific to the final version.

# Include annotations about scene on frame and/or file
param = annot      0
param = annotcube  0
param = annotmap   0
param = annotframe 0
param = annotfile  0
# Number of child frame renderers to spawn
param = nproc3 144
param = nproc4 144
param = nproc5 50   # careful here, this may need to be as low as 20
param = nproc6 10
param = ndim   5    # 
param = fs     24   # set to FPS to make fs = 1 second
param = seed   1
param = tween  0.85 # final 0.85

<<include scene.ascent.mapcube.conf>>
<<include scene.ascent.param.conf>>
<<include scene.ascent.keyframes.conf>>

# This is a funky feature in which we do not rotate about
# the canonical axes but a random orthonormal basis. Because
# we're not rotating about features of the cube, the projection
# appears more uniformly complex (but actually less interesting!).
# dimensions at this or larger index are random 
#param = randombasis 0 

6.5 · object layers

The layers define the order in which elements are drawn, which parts of the cube to draw (e.g. edges), what blend to use (mostly difference), which color to use and line thickness.

# Blend modes are one of
# normal | multiply | add | subtract | diff | lighten | darken | hue | sat | value | color

layer = c0:cubeline:normal:1:color0:no:2

layer = c1:cubeline:diff:1:color1:no:5
layer = c2:cubeline:diff:1:color2:no:5
layer = c3:cubeline:diff:1:color3:no:5
layer = c4:cubeline:diff:1:color4:no:5

layer = c1:mapline:diff:1:color1:no:2
layer = c2:mapline:diff:1:color2:no:2
layer = c3:mapline:diff:1:color3:no:2
layer = c4:mapline:diff:1:color4:no:2

layer = c5:cubeface:diff:1:color1:no:1
layer = c6:cubeface:diff:1:color2:no:1
layer = c7:cubeface:diff:1:color3:no:1
layer = c8:cubeface:diff:1:color4:no:1

layer = cg:mapfill:diff:1:color1:no:1
layer = ce:mapfill:diff:1:color2:no:1
layer = cf:mapfill:diff:1:color3:no:1
layer = ch:mapfill:diff:1:color4:no:1

layer = ca:mapfill:diff:1:color1:no:1
layer = cb:mapfill:diff:1:color2:no:1
layer = cc:mapfill:diff:1:color3:no:1
layer = cd:mapfill:diff:1:color4:no:1

6.6 · cubes and area maps

Cubes and area maps to initialize. Cubes are called by name (e.g. c0, ca) in the keyframe definitions.

# Various approximations of pi
map   = 10a 10/3 50000 2 
map   = 10b 10/3 50000 3 
map   = 10c 10/3 50000 4 
map   = 10d 10/3 50000 5 
map   = 10e 10/3 50000 6
map   = 22a 22/7 50000 2 
map   = 22b 22/7 50000 3 
map   = 22c 22/7 50000 4 
map   = 22d 22/7 50000 5
map   = 22e 22/7 50000 6 
map   = 179a 179/57 50000 2 
map   = 179b 179/57 50000 3 
map   = 179c 179/57 50000 4 
map   = 179d 179/57 50000 5
map   = 179e 179/57 50000 6
map   = 179f 179/57 150000 7
map   = 245a 245/78 50000 2 
map   = 245b 245/78 50000 3 
map   = 245c 245/78 50000 4 
map   = 245d 245/78 50000 5
map   = 245e 245/78 50000 6
map   = 245f 245/78 150000 7
map   = 355a 355/113 50000 2 
map   = 355b 355/113 50000 3 
map   = 355c 355/113 50000 4 
map   = 355d 355/113 50000 5
map   = 355e 355/113 50000 6
map   = pia pi 50000 2 
map   = pib pi 50000 3 
map   = pic pi 50000 4 
map   = pid pi 50000 5
map   = pie pi 50000 6
# Cube names
cube  = c0
cube  = c1
cube  = c2
cube  = c3
cube  = c4
cube  = c5 
cube  = c6
cube  = c7
cube  = c8
cube  = ca
cube  = cb
cube  = cc
cube  = cd
cube  = ce
cube  = cf
cube  = cg
cube  = ch

6.7 · keyframes

Keyframes for the final version of the video.


frame = init ; a . 0 ; size . 1; fade . 1 

################################################################
# SCENE 1 - cube c0 grows to max dimensions and c0 twinkles from corners

frame = 1:

frame = 1.a; cube_add(c0,0,1)
# arrange yw rotation for the split at 1.c*
frame = 1.a0; a yw astepa2
# grow horizontal line
frame = 1.a1; n 2fs; c c0 f [xy] 0
frame = 1.a2; n 2fs; c c0 s [x]  0.05 ; 
frame = 1.a3; n 2fs; c c0 s [x]  0.10 ; 
frame = 1.a4; n 2fs; c c0 s [x]  0.15 ; 
# grow y and rotate
frame = 1.a5; n 3fs; c c0 s [y]  0.05 ; rxy3
frame = 1.a6; n 3fs; c c0 s [y]  0.10 ; rxy3 
frame = 1.a7; n 2fs; c c0 s [y]  0.15 ; rxy3 
# grow z
frame = 1.b1; n 2fs; c c0 s [xy] 0.15 ; c c0 s [z] 0.100 ; c c0 f [z] 0.80 ; ryz6
frame = 1.b2; n 2fs; c c0 s [xy] 0.15 ; c c0 s [z] 0.110 ; c c0 f [z] 0.60 ; ryz6
frame = 1.b3; n 2fs; c c0 s [xy] 0.15 ; c c0 s [z] 0.120 ; c c0 f [z] 0.40 ; ryz6
frame = 1.b4; n 2fs; c c0 s [xy] 0.15 ; c c0 s [z] 0.130 ; c c0 f [z] 0.20 ; ryz6
frame = 1.b5; n 2fs; c c0 s [xy] 0.15 ; c c0 s [z] 0.140 ; c c0 f [z] 0.10 ; ryz6
frame = 1.b6; n 2fs; c c0 s [xy] 0.15 ; c c0 s [z] 0.150 ; c c0 f [z] 0.00 ; ryz6
# split cubes along w (needs yw angle set, see above)
frame = 1.c1; n 1fs; c c0 s [xyz] 0.15 ; c c0 s [w] 0.815
frame = 1.c2; n 2fs;
# grow w and start to rotate xy/yz/rot* 
frame = 1.d1; n 2fs; c c0 s [xyz] 0.15 ; c c0 s [w] 0.715 ; c c0 f [w] 0.9 ; rots; !ryz2; rxy2; a xw astepb4 
frame = 1.d2; n 2fs; c c0 s [xyz] 0.15 ; c c0 s [w] 0.615 ; c c0 f [w] 0.8 ; rots; !ryz2; rxy2; a xw astepb4
frame = 1.d3; n 2fs; c c0 s [xyz] 0.15 ; c c0 s [w] 0.515 ; c c0 f [w] 0.7 ; rots; !ryz2; rxy2; a xw astepb4
frame = 1.d4; n 2fs;                   ; c c0 s [w] 0.415 ; c c0 f [w] 0.6 ; rots; !ryz2; rxy2; a xw astepb4
frame = 1.d5; n 2fs;                   ; c c0 s [w] 0.315 ; c c0 f [w] 0.4 ; rots; !ryz2; rxy2; a xw astepb4
frame = 1.d6; n 2fs;                   ; c c0 s [w] 0.215 ; c c0 f [w] 0.2 ; rots; !ryz2; rxy2; a xw astepb4 
frame = 1.d7; n 2fs;                   ; c c0 s [w] 0.150 ; c c0 f [w] 0.0 ; rots; !ryz2; rxy2; a xw astepb4 
 # grow v
frame = 1.e1; n 2fs;                   ; c c0 s [v] 0.150 ;                   rots; ryz2; rxy2               
frame = 1.e2; n 2fs; c c0 s [xyzwv] 0.150 ;               ; c c0 f [v] 1.00 ; rots; ryz2; rxy2               
frame = 1.e3; n 2fs; c c0 s [xyzwv] 0.175 ;               ; c c0 f [v] 1.00 ; rots; ryz2; rxy2
frame = 1.e3; n 1fs; c c0 s [xyzwv] 0.175 ;               ; c c0 f [v] 1.05 ; rots; ryz2; rxy2
frame = 1.e4; n 2fs; c c0 s [xyzwv] 0.200 ;               ; c c0 f [v] 1.00 ; rots; ryz2; rxy2               
frame = 1.e5; n 2fs; c c0 s [xyzwv] 0.225 ;               ; c c0 f [v] 1.00 ; rots; ryz2; rxy2               ; size . 1.30
frame = 1.e6; n 2fs; c c0 s [xyzwv] 0.250 ;               ; c c0 f [v] 0.80 ; rots; ryz2; rxy2
frame = 1.e7; n 2fs; c c0 s [xyzwv] 0.275 ;               ; c c0 f [v] 0.70 ; rots; ryz2; rxy2
frame = 1.e8; n 2fs; c c0 s [xyzwv] 0.300 ;               ; c c0 f [v] 0.50 ; rots; ryz2; rxy2
frame = 1.e9; n 2fs; c c0 s [xyzwv] 0.325 ;               ; c c0 f [v] 0.40 ; rots; ryz2; rxy2
frame = 1.f1; n 2fs;                                      ; c c0 f [v] 0.30 ; rots; ryz2; rxy2
frame = 1.f2; n 2fs;                                        c c0 f [v] 0.20 ; rots; ryz2; rxy2
frame = 1.f3; n 2fs;                                        c c0 f [v] 0.10 ; rots; ryz2; rxy2
frame = 1.f4; n 2fs;                                        c c0 f [v] 0.00 ; rots; ryz2; rxy2

################################################################
# xy, xz, xw, *** dimensions grow along edges of new cubes

frame = 2:

frame = 2.a; cube c1 copyfrom c0 . 1
frame = 2.a; cube c2 copyfrom c0 . 1
frame = 2.a; cube c3 copyfrom c0 . 1
frame = 2.a; cube c4 copyfrom c0 . 1


 
frame = 2.a; n 2fs; c c1 f [xy] s2f ;                                                      rotthis2; 
frame = 2.b; n 2fs; c c1 f [xy] s2f ;                                                      rotthis2; 
frame = 2.c; n 2fs; c c1 f [xy] s2f ;                                                      rotthis2; 
frame = 2.d; n 2fs; c c1 f [xy] s2f ;                                                      rotthis2; 
frame = 2.e; n 2fs; c c1 f [xy] s2f ;                                                      rotthis2;
frame = 2.f; n 2fs; c c1 f [xy] s2f ; c c2 f [xz] s2f ;                                    rotthis2;
frame = 2.g; n 2fs; c c1 f [xy] s2f ; c c2 f [xz] s2f ;                                    rotthis2; 
frame = 2.h; n 2fs; c c1 f [xy] s2f ; c c2 f [xz] s2f ;                                    rotthis2;
frame = 2.i; n 2fs; c c1 f [xy] s2f ; c c2 f [xz] s2f ; c c3 f [xw] s2f ;                  rotthis2;
frame = 2.j; n 2fs; c c1 f [xy] s2f ; c c2 f [xz] s2f ; c c3 f [xw] s2f ;                  rotthis2; 
frame = 2.k; n 2fs; c c1 f [xy] s2f ; c c2 f [xz] s2f ; c c3 f [xw] s2f ;                  rotthis2;
frame = 2.l; n 2fs; c c1 f [xy] s2f ; c c2 f [xz] s2f ; c c3 f [xw] s2f ;                  rotthis2; 
frame = 2.m; n 2fs; c c1 f [xy] s2f ; c c2 f [xz] s2f ; c c3 f [xw] s2f ; c c4 f [xv] s2f; rotthis2; 
frame = 2.n; n 2fs; c c1 f [xy] s2f ; c c2 f [xz] s2f ; c c3 f [xw] s2f ; c c4 f [xv] s2f; rotthis2; 
frame = 2.o; n 2fs; c c1 f [xy] s2f ; c c2 f [xz] s2f ; c c3 f [xw] s2f ; c c4 f [xv] s2f; rotthis2;
frame = 2.p; n 2fs; c c1 f [xy] s2f ; c c2 f [xz] s2f ; c c3 f [xw] s2f ; c c4 f [xv] s2f; rotthis2; 
frame = 2.q; n 2fs; c c1 f [xy] s2f ; c c2 f [xz] s2f ; c c3 f [xw] s2f ; c c4 f [xv] s2f; rotthis2;
frame = 2.r; n 2fs; c c1 f [xy] 0   ; c c2 f [xz] 0   ; c c3 f [xw] 0   ; c c4 f [xv] 0  ; rotthis2;

################################################################
# each cube from (2) expands, splitting up the dimension pairs

frame = 3:

frame = 3.a; n 2fs; c c1 s . s3s;                                            rotthis2 
frame = 3.b; n 2fs; c c1 s . s3s;                                            rotthis2
frame = 3.c; n 2fs; c c1 s . s3s; c c2 s . s3s;                              rotthis2
frame = 3.d; n 2fs; c c1 s . s3s; c c2 s . s3s;                              rotthis2
frame = 3.e; n 2fs; c c1 s . s3s; c c2 s . s3s; c c3 s . s3s; c c0 f . s3f ; rotthis2
frame = 3.f; n 2fs; c c1 s . s3s; c c2 s . s3s; c c3 s . s3s; c c0 f . s3f ; rotthis2 
frame = 3.g; n 2fs; c c[1-4] s . s3s;                         c c0 f . s3f ; rotthis2
frame = 3.h; n 2fs; c c[1-4] s . s3s;                         c c0 f . s3f ; rotthis2  
frame = 3.i; n 2fs; c c[1-4] s . s3s;                         c c0 f . s3f ; rotthis2 ; rep 2                   
frame = 3.j; n 2fs;                                           c c0 f . s3f ; rotthis2 ; rep 2
frame = 3.k; n 2fs;                                                        ; rotthis2 ; rep 2

################################################################
# 
# maps fade in one at a time as original cube c0 shrinks to corners

frame = 4:

frame = 4.a; map_add(c1,xyzwv,22a) 
frame = 4.a; map_add(c2,xyzwv,22b) 
frame = 4.a; map_add(c3,xyzwv,22b) 
frame = 4.a; map_add(c4,xyzwv,22b) 

frame = 4.a; n 2fs; map_fade(c1,.,p1) ; c c1 f [xy] s4f ; c c[0-1] s . p2 ; size . s4u ; rotthis3; c c0 f . 0.90; 
frame = 4.b; n 2fs; map_fade(c1,.,p1) ; c c1 f [xy] s4f ; c c[0-1] s . p2 ; size . s4u ; rotthis3;
frame = 4.c; n 2fs; map_fade(c1,.,p1) ; c c1 f [xy] s4f ; c c[0-1] s . p2 ; size . s4u ; rotthis3;

frame = 4.d; n 2fs; map_fade(c2,.,p1) ; c c2 f [xz] s4f ; c c[0-2] s . p2 ; size . s4u ; rotthis3; cube c[1]   a [xy][yzwvu] astep-fast
frame = 4.e; n 2fs; map_fade(c2,.,p1) ; c c2 f [xz] s4f ; c c[0-2] s . p2 ; size . s4u ; rotthis3; cube c[1-2] a [xy][yzwvu] astep-fast
frame = 4.f; n 2fs; map_fade(c2,.,p1) ; c c2 f [xz] s4f ; c c[0-2] s . p2 ; size . s4u ; rotthis3; cube c[1-2] a [xy][yzwvu] astep-fast 

frame = 4.g; n 2fs; map_fade(c3,.,p1) ; c c3 f [xw] s4f ; c c[0-3] s . p2 ; size . s4u ; rotthis3; cube c[1-2] a [xy][yzwvu] astep-fast 
frame = 4.h; n 2fs; map_fade(c3,.,p1) ; c c3 f [xw] s4f ; c c[0-3] s . p2 ; size . s4u ; rotthis3; cube c[1-3] a [xy][yzwvu] astep-fast
frame = 4.i; n 2fs; map_fade(c4,.,p1) ; c c3 f [xw] s4f ; c c[0-3] s . p2 ; size . s4u ; rotthis3; cube c[1-3] a [xy][yzwvu] astep-fast

frame = 4.j; n 2fs; map_fade(c[1-4],.,p1); c c4     f [xv] s4f ;            size . s4u ; rotthis3; cube c[1-3] a [xy][yzwvu] astep-fast 
frame = 4.k; n 2fs; map_fade(c[1-4],.,p1); c c4     f [xv] s4f ;            size . s4u ; rotthis3; cube c[1-4] a [xy][yzwvu] astep-fast 
frame = 4.l; n 2fs; map_fade(c[1-4],.,p1); c c4     f [xv] s4f ;            size . s4u ; rotthis3; cube c[1-4] a [xy][yzwvu] astep-fast
frame = 4.m; n 2fs; map_fade(c[1-4],.,p1);                                  size . s4u ; rotthis3; cube c[1-4] a [xy][yzwvu] astep-fast

# cube fills from corners and cubes start to independently rotate
# fade out map edges c1-4

frame = 5:

frame = 5.a; cube c5 copyfrom c1 . 1
frame = 5.a; cube c6 copyfrom c2 . 1
frame = 5.a; cube c7 copyfrom c3 . 1
frame = 5.a; cube c8 copyfrom c4 . 1
frame = 5.a; cube c[5-8] f . 1
frame = 5.a; face c[5-8] . map . -

frame = 5.a; n 2fs; c c[5-5] f . s5cf; map_fade(c[1-4],.,s5f) ; rotthis3 ; c c[1-4] a [xy][yzwvu] astep-vfast
frame = 5.b; n 2fs; c c[5-5] f . s5cf; map_fade(c[1-4],.,s5f) ; rotthis3 ; c c[1-4] a [xy][yzwvu] astep-vfast
frame = 5.c; n 2fs; c c[5-6] f . s5cf; map_fade(c[1-4],.,s5f) ; rotthis3 ; c c[1-5] a [xy][yzwvu] astep-vfast ; rep 5
frame = 5.d; n 2fs; c c[5-7] f . s5cf; map_fade(c[1-4],.,s5f) ; rotthis3 ; c c[1-6] a [xy][yzwvu] astep-vfast ; rep 9
frame = 5.e; n 2fs; c c[5-8] f . s5cf; map_fade(c[1-4],.,s5f) ; rotthis3 ; c c[1-7] a [xy][yzwvu] astep-vfast ; rep 4
frame = 5.f; n 2fs; c c[5-8] f . s5cs;                          rotthis3 ; c c[1-8] a [xy][yzwvu] astep-vfast ; rep 5
frame = 5.g; n 2fs; c c[5-8] f . s5cs;                          rotthis3 ; c c[1-8] a [xy][yzwvu] astep-vfast ; rep 6

################################################################
# dyads (28)
#
# Map fills grow

frame = 6:

frame = 6.a; cube ca copyfrom c1 . 1
frame = 6.a; cube cb copyfrom c2 . 1
frame = 6.a; cube cc copyfrom c3 . 1
frame = 6.a; cube cd copyfrom c4 . 1
frame = 5.a; cube c[a-d] f . 1

frame = 6.a; map_add(ca,xyzwv,179a) 
frame = 6.a; map_add(cb,xyzwv,179b) 
frame = 6.a; map_add(cc,xyzwv,179b) 
frame = 6.a; map_add(cd,xyzwv,179c) 

frame = 6.b; n 14fs; a xy refxy; a xz refxz; a xw refxw; a xv refxv ; a yz refyz; a yw refyw; a yv refyv; c c[0-9a-d] a . 0 ; map_fade(c[a-d],.,ps6)
frame = 6.c; n 2fs; rot6vvs;  a xw d0.01 ; f . . map . fade ps15 ; cube c[0-8] fade . ps15 ; cube_rot(.,[xy][yzwvu],astep-vvslow) ;                size . ps20
frame = 6.d; n 2fs; rot6vs;   a xw d0.01 ; f . . map . fade ps14 ; cube c[0-8] fade . ps14 ; cube_rot(.,[xy][yzwvu],astep-vvslow) ; a xy d-0.001 ; size . ps20
frame = 6.e; n 2fs; rot6s;    a xw d0.01 ; f . . map . fade ps13 ; cube c[0-8] fade . ps13 ; cube_rot(.,[xy][yzwvu],astep-vslow)  ; a xy d-0.002 ; size . ps20
frame = 6.f; n 2fs; rot6s;    a xw d0.01 ; f . . map . fade ps12 ; cube c[0-8] fade . ps12 ; cube_rot(.,[xy][yzwvu],astep-slow)   ; a xy d-0.002 ; size . ps20
frame = 6.g; n 2fs; rot6f;    a xw d0.02 ; f . . map . fade ps11 ; cube c[0-8] fade . ps11 ; cube_rot(.,[xy][yzwvu],astep-slow)   ; a xy d-0.002 ; size . ps20
frame = 6.h; n 2fs; rot6f;    a xw d0.02 ; f . . map . fade ps10 ; cube c[0-8] fade . ps10 ; cube_rot(.,[xy][yzwvu],astep-med)    ; a xy d-0.002 ; size . ps20
frame = 6.i; n 2fs; rot6vf;   a xw d0.03 ; f . . map . fade ps9  ; cube c[0-8] fade . ps9  ; cube_rot(.,[xy][yzwvu],astep-med)    ; a xy d-0.003 ; size . ps20
frame = 6.j; n 2fs; rot6vf;   a xw d0.03 ; f . . map . fade ps8  ; cube c[0-8] fade . ps8  ; cube_rot(.,[xy][yzwvu],astep-fast)   ; a xy d-0.003 ; size . ps20
frame = 6.k; n 2fs; rot6vf;   a xw d0.04 ; f . . map . fade ps7  ; cube c[0-8] fade . ps7  ; cube_rot(.,[xy][yzwvu],astep-fast)   ; a xy d-0.004 ; size . ps21
frame = 6.l; n 2fs; rot6vf;   a xw d0.05 ; f . . map . fade ps6  ; cube c[0-8] fade . ps6  ; cube_rot(.,[xy][yzwvu],astep-vfast)  ; a xy d-0.005 ; size . ps21
frame = 6.m; n 2fs; rot6vvf;  a xw d0.06 ; f . . map . fade ps6  ; cube c[0-8] fade . ps6  ; cube_rot(.,[xy][yzwvu],astep-vfast)  ; a xy d-0.010 ; size . ps21
frame = 6.n; n 2fs; rot6vvf;  a xw d0.07 ; f . . map . fade ps6  ; cube c[0-8] fade . ps6  ; cube_rot(.,[xy][yzwvu],astep-vfast)  ; a xy d-0.010 ; size . ps21
frame = 6.o; n 2fs; rot6vvvf; a xw d0.08 ; f . . map . fade ps8  ; cube c[0-8] fade . ps8  ; cube_rot(.,[xy][yzwvu],astep-vvfast) ; a xy d-0.007 ; size . ps21
frame = 6.p; n 2fs; rot6vvvf; a xw d0.05 ; f . . map . fade ps10 ; cube c[0-8] fade . ps10 ; cube_rot(.,[xy][yzwvu],astep-vvfast) ; a xy d-0.004 ; size . ps21
frame = 6.q; n 2fs; rot6vvvf; a xw d0.03 ; f . . map . fade ps12 ; cube c[0-8] fade . ps12 ; cube_rot(.,[xy][yzwvu],astep-vvfast) ; a xy d-0.002 ; size . ps21
frame = 6.r; n 2fs; rot6vvvf; a xw d0.01 ; f . . map . fade ps14 ; cube c[0-8] fade . ps14 ; cube_rot(.,[xy][yzwvu],astep-vvfast) ; a xy d-0.001 ; size . ps21

################################################################
# peak (14)
#
# Grow four maps, drawing their edges.

frame = 7:

frame = 7.a; cube_add(ce,1,1)
frame = 7.a; cube_add(cf,1,1)
frame = 7.a; cube_add(cg,1,1)
frame = 7.a; cube_add(ch,1,1)
frame = 7.a; cube ce size . 1.1
frame = 7.a; cube cf size . 1.2
frame = 7.a; cube cg size . 1.35
frame = 7.a; cube ch size . 1.5
frame = 7.a; cube c[e-h] angle . 0-0.25
frame = 7.a; map_add(ce,xyzwv,pia) 
frame = 7.a; map_add(cf,xyzwv,pib) 
frame = 7.a; map_add(cg,xyzwv,pib) 
frame = 7.a; map_add(ch,xyzwv,pic) 

frame = 7.a; n 2fs; rot6f;   rep 2 ; face c[0-9a-e] . map . fade p5 ; cube c[0-2] fade . p5 ; cube_rot(.,[xy][yzwvu],astep-med)
frame = 7.b; n 2fs; rot6f;   rep 2 ;                                                          cube_rot(.,[xy][yzwvu],astep-med) 
frame = 7.c; n 2fs; rot6vf;  rep 2 ; face c[0-9a-f] . map . fade p5 ; cube c[0-4] fade . p5 ; cube_rot(.,[xy][yzwvu],astep-med)  
frame = 7.d; n 2fs; rot6vf;  rep 2 ;                                                          cube_rot(.,[xy][yzwvu],astep-med)  
frame = 7.e; n 2fs; rot6vvf; rep 2 ; face c[0-9a-g] . map . fade p5 ; cube c[0-6] fade . p5 ; cube_rot(.,[xy][yzwvu],astep-med)  
frame = 7.f; n 2fs; rot6vvf; rep 2 ;                                                          cube_rot(.,[xy][yzwvu],astep-med)  
frame = 7.g; n 2fs; rot6vf;  rep 2 ; face c[0-9a-h] . map . fade p5 ; cube c[0-8] fade . p5 ; cube_rot(.,[xy][yzwvu],astep-med)  
frame = 7.h; n 2fs; rot6vf;  rep 2 ;                                                          cube_rot(.,[xy][yzwvu],astep-med)  
frame = 7.i; n 2fs; rot6vf;  rep 2 ; face . . map . fade p5         ; cube c[0-8] fade . p5 ; cube_rot(.,[xy][yzwvu],astep-med)  
frame = 7.j; n 2fs; rot6vf;  rep 2 ;                                                          cube_rot(.,[xy][yzwvu],astep-med)  

################################################################
# outro (18) 
#
# Slow down rotation and start shrinking and fading everything

frame = 8:

frame = 8.a; n 2fs ; rep 4 ; rot6f ; size . r0.95 ; cube_rot(.,[xy][yzwvu],astep-med) ; cube . f . q33 ; map_fade(.,.,q33) ; cube c[e-h] s . r0.95
frame = 8.a; n 2fs ; rep 2 ; rot6m ; size . r0.90 ; cube_rot(.,[xy][yzwvu],astep-med) ; cube . f . q33 ; map_fade(.,.,q33) ; cube c[e-h] s . r0.95

frame = 8.c; n 2fs ; rot6s ; rep 4 ; size . q31 ; cube_rot(.,[xy][yzwvu],astep-med) ; cube . f . q50 ; map_fade(.,.,q50) ; cube c[e-h] s . r0.95

################################################################
# decay and fade (18)
#
# Further slow rotations and keep shrinking

frame = 9:

frame = 9.a; n 2fs ; rot6s ; rep 6 ; size . q30 ; cube_rot(.,[xy][ywvu],astep-med) ; cube . f . q50 ; map_fade(.,.,q50)
frame = 9.b; n 2fs ; rot6s ; rep 6 ; size . q29 ; cube_rot(.,[xy][ywvu],astep-med) ; cube . f . q50 ; map_fade(.,.,q50)
frame = 9.c; n 1fs ; rot6s ;  size . 0 ; cube_rot(.,[xy][yzwvu],astep-med) ; cube . f . 1 ; map_fade(.,.,1)

frame = stop

news + thoughts

Regression modeling of time-to-event data with censoring

Mon 21-11-2022

If you sit on the sofa for your entire life, you’re running a higher risk of getting heart disease and cancer. —Alex Honnold, American rock climber

In a follow-up to our Survival analysis — time-to-event data and censoring article, we look at how regression can be used to account for additional risk factors in survival analysis.

We explore accelerated failure time regression (AFTR) and the Cox Proportional Hazards model (Cox PH).

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
Nature Methods Points of Significance column: Regression modeling of time-to-event data with censoring. (read)

Dey, T., Lipsitz, S.R., Cooper, Z., Trinh, Q., Krzywinski, M & Altman, N. (2022) Points of significance: Regression modeling of time-to-event data with censoring. Nature Methods 19.

Music video for Max Cooper's Ascent

Tue 25-10-2022

My 5-dimensional animation sets the visual stage for Max Cooper's Ascent from the album Unspoken Words. I have previously collaborated with Max on telling a story about infinity for his Yearning for the Infinite album.

I provide a walkthrough the video, describe the animation system I created to generate the frames, and show you all the keyframes

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
Frame 4897 from the music video of Max Cooper's Asent.

The video recently premiered on YouTube.

Renders of the full scene are available as NFTs.

Gene Cultures exhibit — art at the MIT Museum

Tue 25-10-2022

I am more than my genome and my genome is more than me.

The MIT Museum reopened at its new location on 2nd October 2022. The new Gene Cultures exhibit featured my visualization of the human genome, which walks through the size and organization of the genome and some of the important structures.

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
My art at the MIT Museum Gene Cultures exhibit tells shows the scale and structure of the human genome. Pay no attention to the pink chicken.

Annals of Oncology cover

Wed 14-09-2022

My cover design on the 1 September 2022 Annals of Oncology issue shows 570 individual cases of difficult-to-treat cancers. Each case shows the number and type of actionable genomic alterations that were detected and the length of therapies that resulted from the analysis.

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
An organic arrangement of 570 individual cases of difficult-to-treat cancers showing genomic changes and therapies. Apperas on Annals of Oncology cover (volume 33, issue 9, 1 September 2022).

Pleasance E et al. Whole-genome and transcriptome analysis enhances precision cancer treatment options (2022) Annals of Oncology 33:939–949.

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
My Annals of Oncology 570 cancer cohort cover (volume 33, issue 9, 1 September 2022). (more)

Browse my gallery of cover designs.

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
A catalogue of my journal and magazine cover designs. (more)

Survival analysis—time-to-event data and censoring

Fri 05-08-2022

Love's the only engine of survival. —L. Cohen

We begin a series on survival analysis in the context of its two key complications: skew (which calls for the use of probability distributions, such as the Weibull, that can accomodate skew) and censoring (required because we almost always fail to observe the event in question for all subjects).

We discuss right, left and interval censoring and how mishandling censoring can lead to bias and loss of sensitivity in tests that probe for differences in survival times.

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
Nature Methods Points of Significance column: Survival analysis—time-to-event data and censoring. (read)

Dey, T., Lipsitz, S.R., Cooper, Z., Trinh, Q., Krzywinski, M & Altman, N. (2022) Points of significance: Survival analysis—time-to-event data and censoring. Nature Methods 19:906–908.

3,117,275,501 Bases, 0 Gaps

Sun 21-08-2022

See How Scientists Put Together the Complete Human Genome.

My graphic in Scientific American's Graphic Science section in the August 2022 issue shows the full history of the human genome assembly — from its humble shotgun beginnings to the gapless telomere-to-telomere assembly.

Read about the process and methods behind the creation of the graphic.

Martin Krzywinski @MKrzywinski mkweb.bcgsc.ca
3,117,275,501 Bases, 0 Gaps. Text by Clara Moskowitz (Senior Editor), art direction by Jen Christiansen (Senior Graphics Editor), source: UCSC Genome Browser.

See all my Scientific American Graphic Science visualizations.


© 1999–2022 Martin Krzywinski | contact | Canada's Michael Smith Genome Sciences CentreBC Cancer Research CenterBC CancerPHSA