const editorMode = false;

const canvas = document.querySelector('canvas');
const instructions = document.getElementById('instructions');
const music = document.getElementById('music');

if (editorMode) {
    instructions.style.display = 'none';
    canvas.style.display = 'block';
    document.body.style.cursor = 'default';

    Theatre.studio.initialize();
}

const project = Theatre.core.getProject('HTML Animation Tutorial', {
    state: projectState,
});

const sheet = project.sheet('Sheet 1');
const obj = sheet.object('Heading 1', {
    boxX: 20,
    boxY: 20,
    boxZ: 20,
    moveY: 0,
    moveZ: 0,
    moveX: 20,
    cameraX: Theatre.core.types.number(100, { range: [-1000, 1000] }),
    cameraY: Theatre.core.types.number(200, { range: [-1000, 1000] }),
    cameraZ: Theatre.core.types.number(500, { range: [-1000, 1000] }),
    rotateX: Theatre.core.types.number(1, { range: [-1, 1] }),
    rotateY: Theatre.core.types.number(1, { range: [-1, 1] }),
    rotateZ: Theatre.core.types.number(1, { range: [-1, 1] }),
    rotateA: Theatre.core.types.number(1, { range: [0, Math.PI * 2] }),
    shadeR: Theatre.core.types.number(0, { range: [-1, 1] }),
    shadeB: Theatre.core.types.number(0, { range: [-1, 1] }),
    shadeG: Theatre.core.types.number(0, { range: [-1, 1] }),
    mixR: Theatre.core.types.number(0, { range: [-1, 1] }),
    mixB: Theatre.core.types.number(0, { range: [-1, 1] }),
    mixG: Theatre.core.types.number(0, { range: [-1, 1] }),
});

// not sure how to resize the bauble player so just forcing 1080p
canvas.width = 1920;
canvas.height = 1080;

/*
(def boxX (uniform 20 "boxX"))
(def boxY (uniform 20 "boxY"))
(def boxZ (uniform 20 "boxZ"))

(def rotateX (uniform 20 "rotateX"))
(def rotateY (uniform 20 "rotateY"))
(def rotateZ (uniform 20 "rotateZ"))
(def rotateA (uniform 20 "rotateA"))

(def moveX (uniform 20 "moveX"))
(def moveY (uniform 0 "moveY"))
(def moveZ (uniform 0 "moveZ"))

(def mixR (uniform -1.5 "mixR"))
(def mixG (uniform 0.5 "mixG"))
(def mixB (uniform 0 "mixB"))

((reduce
  (fn [shape _]
    (shape
      | rotate [rotateX rotateY rotateZ | normalize] rotateA
      | move [moveX moveY moveZ]
      | mirror x
    )
  )
  (box [boxX boxY boxZ])
  (range 15)
)
| shade [(uniform 0.5 "shadeR") (uniform 1.0 "shadeG") (uniform 1.0 "shadeB")] :f (fn [light color]
  (dot normal light.direction * light.color * (mix [mixR mixG mixB] color (step 0.5 light.brightness))
  )))
*/

const bauble = new Bauble(canvas, {
    source: "#version 300 es\nprecision highp float;\n\nstruct Ray {\n  vec3 origin;\n  vec3 direction;\n};\nstruct PerspectiveCamera {\n  vec3 position;\n  vec3 direction;\n  vec3 up;\n  float fov;\n};\nstruct Light {\n  vec3 color;\n  vec3 direction;\n  float brightness;\n};\n\nout vec4 frag_color;\n\nuniform float rotateX;\nuniform float boxX;\nuniform float boxY;\nuniform float rotateY;\nuniform float cameraX;\nuniform float cameraY;\nuniform float mixB;\nuniform float cameraZ;\nuniform float shadeR;\nuniform float moveY;\nuniform float rotateZ;\nuniform float mixG;\nuniform float boxZ;\nuniform float moveX;\nuniform float rotateA;\nuniform float moveZ;\nuniform float mixR;\nuniform float shadeG;\nuniform float shadeB;\nuniform float t;\nuniform vec4 viewport;\n\nmat2 rotation_2d(float angle) {\n  float s = sin(angle);\n  float c = cos(angle);\n  return mat2(c, s, -s, c);\n}\n\nfloat max_(vec2 v) {\n  return max(v.x, v.y);\n}\n\nvec3 perspective_vector(float fov, vec2 frag_coord) {\n  float cot_half_fov = tan(radians(90.0 - (fov * 0.5)));\n  return normalize(vec3(frag_coord, cot_half_fov));\n}\n\nRay let_outer(float cameraX, float cameraY, float cameraZ, vec2 frag_coord) {\n  {\n    PerspectiveCamera camera = PerspectiveCamera(vec3(cameraX, cameraY, cameraZ), normalize(vec3(0.0, 0.0, 0.0) - vec3(cameraX, cameraY, cameraZ)), vec3(0.0, 1.0, 0.0), 45.0);\n    vec3 z_axis = camera.direction;\n    vec3 x_axis = normalize(cross(z_axis, camera.up));\n    vec3 y_axis = cross(x_axis, z_axis);\n    return Ray(camera.position, mat3(x_axis, y_axis, z_axis) * perspective_vector(camera.fov, frag_coord));\n  }\n}\n\nmat3 cross_matrix(vec3 vec) {\n  return mat3(0.0, vec.z, -vec.y, -vec.z, 0.0, vec.x, vec.y, -vec.x, 0.0);\n}\n\nmat3 rotation_around(vec3 axis, float angle) {\n  return (cos(angle) * mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)) + (sin(angle) * cross_matrix(axis)) + ((1.0 - cos(angle)) * outerProduct(axis, axis));\n}\n\nfloat max_1(vec3 v) {\n  return max(v.x, max(v.y, v.z));\n}\n\nfloat sdf_box(vec3 size, vec3 p) {\n  vec3 d = abs(p) - size;\n  return length(max(d, 0.0)) + min(max_1(d), 0.0);\n}\n\nfloat rotate_outer(float boxX, float boxY, float boxZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return sdf_box(vec3(boxX, boxY, boxZ), p1);\n  }\n}\n\nfloat move_outer(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer(boxX, boxY, boxZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer1(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer1(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer1(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer1(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer1(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer2(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer1(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer2(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer2(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer2(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer2(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer3(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer2(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer3(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer3(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer3(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer3(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer4(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer3(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer4(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer4(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer4(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer4(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer5(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer4(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer5(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer5(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer5(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer5(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer6(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer5(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer6(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer6(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer6(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer6(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer7(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer6(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer7(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer7(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer7(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer7(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer8(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer7(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer8(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer8(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer8(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer8(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer9(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer8(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer9(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer9(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer9(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer9(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer10(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer9(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer10(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer10(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer10(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer10(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer11(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer10(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer11(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer11(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer11(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer11(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer12(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer11(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer12(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer12(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer12(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer12(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer13(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer12(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer13(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer13(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer13(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer13(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat rotate_outer14(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p * rotation_around(normalize(vec3(rotateX, rotateY, rotateZ)), rotateA);\n    return map_axes_outer13(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat move_outer14(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = p - (vec3(moveX, moveY, moveZ) * 1.0);\n    return rotate_outer14(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat map_axes_outer14(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = vec3(abs(p.x), p.y, p.z);\n    return move_outer14(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat nearest_distance(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  return map_axes_outer14(boxX, boxY, boxZ, moveX, moveY, moveZ, p, rotateA, rotateX, rotateY, rotateZ);\n}\n\nfloat march(out uint steps, float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, Ray ray, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  float ray_depth = 0.0;\n  for (steps = 0u; steps < 256u; ++steps) {\n    {\n      float depth = ray_depth;\n      vec3 P = ray.origin + (ray_depth * ray.direction);\n      vec3 p = P;\n      float dist = nearest_distance(boxX, boxY, boxZ, moveX, moveY, moveZ, p, rotateA, rotateX, rotateY, rotateZ);\n      if (((dist >= 0.0) && (dist < 0.1)) || (ray_depth > 65536.0)) return ray_depth;\n      float rate = (dist > 0.0) ? 0.95 : 1.05;\n      ray_depth += dist * rate;\n      if (ray_depth < 0.0) return 0.0;\n    }\n  }\n  return ray_depth;\n}\n\nfloat with_outer(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = (vec2(1.0, -1.0).xyy * 0.005) + p;\n    return nearest_distance(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat with_outer1(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = (vec2(1.0, -1.0).yyx * 0.005) + p;\n    return nearest_distance(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat with_outer2(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = (vec2(1.0, -1.0).yxy * 0.005) + p;\n    return nearest_distance(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nfloat with_outer3(float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 p1 = (vec2(1.0, -1.0).xxx * 0.005) + p;\n    return nearest_distance(boxX, boxY, boxZ, moveX, moveY, moveZ, p1, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nvec3 do_(vec2 Frag_Coord, vec2 resolution) {\n  const vec3 light = pow(vec3(69.0, 72.0, 79.0) / 255.0, vec3(2.2));\n  const vec3 dark = pow(vec3(40.0, 42.0, 46.0) / 255.0, vec3(2.2));\n  return vec3(mix(dark, light, (Frag_Coord.x + Frag_Coord.y) / (resolution.x + resolution.y)));\n}\n\nfloat with_outer4(float boxX, float boxY, float boxZ, float depth, vec3 light_position, float moveX, float moveY, float moveZ, vec3 ray_dir, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 P = light_position + (ray_dir * depth);\n    vec3 p = P;\n    return nearest_distance(boxX, boxY, boxZ, moveX, moveY, moveZ, p, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nLight cast_light_hard_shadow(vec3 light_color, vec3 light_position, vec3 P, float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 normal, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  if (light_position == P) return Light(light_color, vec3(0.0), 1.0);\n  vec3 to_light = normalize(light_position - P);\n  if (light_color == vec3(0.0)) return Light(light_color, to_light, 0.0);\n  if (dot(to_light, normal) < 0.0) return Light(light_color, to_light, 0.0);\n  vec3 target = (0.01 * normal) + P;\n  float light_distance = length(target - light_position);\n  vec3 ray_dir = (target - light_position) / light_distance;\n  float depth = 0.0;\n  for (uint i = 0u; i < 256u; ++i) {\n    float nearest = with_outer4(boxX, boxY, boxZ, depth, light_position, moveX, moveY, moveZ, ray_dir, rotateA, rotateX, rotateY, rotateZ);\n    if (nearest < 0.01) break;\n    depth += nearest;\n  }\n  if (depth >= light_distance) return Light(light_color, to_light, 1.0);\n  else return Light(light_color, to_light, 0.0);\n}\n\nfloat with_outer5(float boxX, float boxY, float boxZ, float depth, vec3 light_position, float moveX, float moveY, float moveZ, vec3 ray_dir, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  {\n    vec3 P = light_position + (ray_dir * depth);\n    vec3 p = P;\n    return nearest_distance(boxX, boxY, boxZ, moveX, moveY, moveZ, p, rotateA, rotateX, rotateY, rotateZ);\n  }\n}\n\nLight cast_light_soft_shadow(vec3 light_color, vec3 light_position, float softness, vec3 P, float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 normal, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  if (softness == 0.0) return cast_light_hard_shadow(light_color, light_position, P, boxX, boxY, boxZ, moveX, moveY, moveZ, normal, rotateA, rotateX, rotateY, rotateZ);\n  if (light_position == P) return Light(light_color, vec3(0.0), 1.0);\n  vec3 to_light = normalize(light_position - P);\n  if (light_color == vec3(0.0)) return Light(light_color, to_light, 0.0);\n  if (dot(to_light, normal) < 0.0) return Light(light_color, to_light, 0.0);\n  vec3 target = (0.01 * normal) + P;\n  float light_distance = length(target - light_position);\n  vec3 ray_dir = (target - light_position) / light_distance;\n  float brightness = 1.0;\n  float sharpness = 1.0 / (softness * softness);\n  float last_nearest = 1000000.0;\n  float depth = 0.0;\n  for (uint i = 0u; i < 256u; ++i) {\n    float nearest = with_outer5(boxX, boxY, boxZ, depth, light_position, moveX, moveY, moveZ, ray_dir, rotateA, rotateX, rotateY, rotateZ);\n    if (nearest < 0.01) break;\n    float intersect_offset = (nearest * nearest) / (2.0 * last_nearest);\n    float intersect_distance = sqrt((nearest * nearest) - (intersect_offset * intersect_offset));\n    brightness = min(brightness, (sharpness * intersect_distance) / max(0.0, (light_distance - depth) - intersect_offset));\n    depth += nearest;\n    last_nearest = nearest;\n  }\n  if (depth >= light_distance) return Light(light_color, to_light, brightness);\n  else return Light(light_color, to_light, 0.0);\n}\n\nfloat with_outer6(vec3 P, float boxX, float boxY, float boxZ, uint i, float moveX, float moveY, float moveZ, float rotateA, float rotateX, float rotateY, float rotateZ, vec3 step) {\n  {\n    vec3 P1 = (float(i) * step) + P;\n    vec3 p = P1;\n    return max(nearest_distance(boxX, boxY, boxZ, moveX, moveY, moveZ, p, rotateA, rotateX, rotateY, rotateZ), 0.0);\n  }\n}\n\nfloat calculate_occlusion(uint step_count, float max_distance, vec3 dir, vec3 P, float boxX, float boxY, float boxZ, float moveX, float moveY, float moveZ, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ) {\n  float step_size = max_distance / float(step_count);\n  float baseline = nearest_distance(boxX, boxY, boxZ, moveX, moveY, moveZ, p, rotateA, rotateX, rotateY, rotateZ);\n  float occlusion = 0.0;\n  vec3 step = dir * step_size;\n  for (uint i = 1u; i <= step_count; ++i) {\n    float expected_distance = (float(i) * step_size) + baseline;\n    float actual_distance = with_outer6(P, boxX, boxY, boxZ, i, moveX, moveY, moveZ, rotateA, rotateX, rotateY, rotateZ, step);\n    occlusion += actual_distance / expected_distance;\n  }\n  return clamp(occlusion / float(step_count), 0.0, 1.0);\n}\n\nvec3 normalize_safe(vec3 v) {\n  return (v == vec3(0.0)) ? v : normalize(v);\n}\n\nLight cast_light_no_shadow(vec3 light_color, vec3 light_position, vec3 P) {\n  return Light(light_color, normalize_safe(light_position - P), 1.0);\n}\n\nLight do_1(vec3 P, vec3 normal, float occlusion) {\n  Light light = cast_light_no_shadow(vec3(0.15), P + (normal * 0.1), P);\n  light.brightness = light.brightness * mix(0.1, 1.0, occlusion);\n  return light;\n}\n\nvec3 shade(Light light, Light light1, float mixB, float mixG, float mixR, vec3 normal, float shadeB, float shadeG, float shadeR) {\n  vec3 result = vec3(0.0);\n  result += (dot(normal, light.direction) * light.color) * mix(vec3(mixR, mixG, mixB), vec3(shadeR, shadeG, shadeB), step(0.5, light.brightness));\n  result += (dot(normal, light1.direction) * light1.color) * mix(vec3(mixR, mixG, mixB), vec3(shadeR, shadeG, shadeB), step(0.5, light1.brightness));\n  return result;\n}\n\nvec3 shade_outer(Light light, Light light1, float mixB, float mixG, float mixR, vec3 normal, float shadeB, float shadeG, float shadeR) {\n  {\n    return shade(light, light1, mixB, mixG, mixR, normal, shadeB, shadeG, shadeR);\n  }\n}\n\nvec3 hoist_outer(vec3 P, float boxX, float boxY, float boxZ, float mixB, float mixG, float mixR, float moveX, float moveY, float moveZ, vec3 normal, vec3 p, float rotateA, float rotateX, float rotateY, float rotateZ, float shadeB, float shadeG, float shadeR) {\n  {\n    Light light = cast_light_soft_shadow(vec3(1.15), P - (normalize(vec3(-2.0, -2.0, -1.0)) * 2048.0), 0.25, P, boxX, boxY, boxZ, moveX, moveY, moveZ, normal, rotateA, rotateX, rotateY, rotateZ);\n    float occlusion = calculate_occlusion(8u, 20.0, normal, P, boxX, boxY, boxZ, moveX, moveY, moveZ, p, rotateA, rotateX, rotateY, rotateZ);\n    Light light1 = do_1(P, normal, occlusion);\n    return shade_outer(light, light1, mixB, mixG, mixR, normal, shadeB, shadeG, shadeR);\n  }\n}\n\nvec4 sample_(vec2 Frag_Coord, float boxX, float boxY, float boxZ, float cameraX, float cameraY, float cameraZ, vec2 frag_coord, float mixB, float mixG, float mixR, float moveX, float moveY, float moveZ, vec2 resolution, float rotateA, float rotateX, float rotateY, float rotateZ, float shadeB, float shadeG, float shadeR) {\n  Ray ray_star = Ray(vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0));\n  vec3 ortho_quad = vec3(0.0, 0.0, 0.0);\n  float ortho_scale = 0.0;\n  float fov = 0.0;\n  ray_star = let_outer(cameraX, cameraY, cameraZ, frag_coord);\n  uint steps = 0u;\n  {\n    Ray ray = ray_star;\n    float depth = march(steps, boxX, boxY, boxZ, moveX, moveY, moveZ, ray, rotateA, rotateX, rotateY, rotateZ);\n    vec3 P = ray.origin + (ray.direction * depth);\n    vec3 p = P;\n    float dist = nearest_distance(boxX, boxY, boxZ, moveX, moveY, moveZ, p, rotateA, rotateX, rotateY, rotateZ);\n    vec3 normal = normalize((vec2(1.0, -1.0).xyy * with_outer(boxX, boxY, boxZ, moveX, moveY, moveZ, p, rotateA, rotateX, rotateY, rotateZ)) + (vec2(1.0, -1.0).yyx * with_outer1(boxX, boxY, boxZ, moveX, moveY, moveZ, p, rotateA, rotateX, rotateY, rotateZ)) + (vec2(1.0, -1.0).yxy * with_outer2(boxX, boxY, boxZ, moveX, moveY, moveZ, p, rotateA, rotateX, rotateY, rotateZ)) + (vec2(1.0, -1.0).xxx * with_outer3(boxX, boxY, boxZ, moveX, moveY, moveZ, p, rotateA, rotateX, rotateY, rotateZ)));\n    vec4 color = vec4(0.0);\n    color = (dist >= 10.0) ? vec4(do_(Frag_Coord, resolution), 1.0) : vec4(hoist_outer(P, boxX, boxY, boxZ, mixB, mixG, mixR, moveX, moveY, moveZ, normal, p, rotateA, rotateX, rotateY, rotateZ, shadeB, shadeG, shadeR), 1.0);\n    return color;\n  }\n}\n\nvec3 pow_(vec3 v, float e) {\n  return pow(v, vec3(e));\n}\n\nvoid main() {\n  const float gamma = 2.2;\n  vec3 color = vec3(0.0, 0.0, 0.0);\n  float alpha = 0.0;\n  const uint aa_grid_size = 1u;\n  const float aa_sample_width = 1.0 / float(1u + aa_grid_size);\n  const vec2 pixel_origin = vec2(0.5, 0.5);\n  vec2 local_frag_coord = gl_FragCoord.xy - viewport.xy;\n  mat2 rotation = rotation_2d(0.2);\n  for (uint y = 1u; y <= aa_grid_size; ++y) {\n    for (uint x = 1u; x <= aa_grid_size; ++x) {\n      vec2 sample_offset = (aa_sample_width * vec2(float(x), float(y))) - pixel_origin;\n      sample_offset = rotation * sample_offset;\n      sample_offset = fract(sample_offset + pixel_origin) - pixel_origin;\n      {\n        vec2 Frag_Coord = local_frag_coord + sample_offset;\n        vec2 resolution = viewport.zw;\n        vec2 frag_coord = ((Frag_Coord - (0.5 * resolution)) / max_(resolution)) * 2.0;\n        vec4 this_sample = clamp(sample_(Frag_Coord, boxX, boxY, boxZ, cameraX, cameraY, cameraZ, frag_coord, mixB, mixG, mixR, moveX, moveY, moveZ, resolution, rotateA, rotateX, rotateY, rotateZ, shadeB, shadeG, shadeR), 0.0, 1.0);\n        color += this_sample.rgb * this_sample.a;\n        alpha += this_sample.a;\n      }\n    }\n  }\n  if (alpha > 0.0) {\n    color = color / alpha;\n    alpha /= float(aa_grid_size * aa_grid_size);\n  }\n  frag_color = vec4(pow_(color, 1.0 / gamma), alpha);\n}\n",

    animation: false, // wait for keypress to start
    interaction: false,
    uniforms: {
        boxX: "float",
        boxY: "float",
        boxZ: "float",
        rotateX: "float",
        rotateY: "float",
        rotateZ: "float",
        rotateA: "float",
        moveX: "float",
        moveY: "float",
        moveZ: "float",
        cameraX: "float",
        cameraY: "float",
        cameraZ: "float",
        shadeR: "float",
        shadeG: "float",
        shadeB: "float",
        mixR: "float",
        mixG: "float",
        mixB: "float",
    }
});

// Theatre to Bauble
obj.onValuesChange((obj) => {
    bauble.set(obj);
});


// Demo controls
document.addEventListener('keydown', (e) => {
    if (e.key === 'f') {
        if (!document.fullscreenElement) {
            document.body.requestFullscreen();
        } else {
            document.exitFullscreen();
        }
    }

    if (e.key === ' ') {
        if (!editorMode) {
            sheet.sequence.play();
            instructions.style.display = 'none';
            canvas.style.display = 'block';
        }
    }
});

Theatre.core.onChange(sheet.sequence.pointer, (pointer) => {
    const { playing, position } = pointer;

    if (playing && music.paused) {
        music.currentTime = position;
        music.play();
    } else if (!playing && !music.paused) {
        music.pause();
    }
});