Demo.prototype.sceneIntro = function () {
  this.setScene('intro');


  this.loader.addAnimation([
    {
      image: {
        name: 'img/bg_orangeTealGradient.png'
      },
      perspective: '2d',
      color: [
        {
          r: () => Sync.get('BG:R'),
          g: () => Sync.get('BG:G'),
          b: () => Sync.get('BG:B')
        }
      ],
      scale: [{ uniform2d: 1.0 }],
      position: [{
        x: 0,
        y: 0,
        z: -201
      }]
    }
  ]);

  this.loader.addAnimation([
    {
      id: 'liberty',
      image: {
        name: 'img/liberty.png'
      },
      perspective: '3d',
      color: [
        {
          a: () => Sync.get('BG:LibertyAlpha')
        }
      ],
      scale: [{ uniform2d: 40.7 }],
      enabled: () => Sync.get('BG:LibertyAlpha') > 0.01,
      position: [{
        x: () => Sync.get('BG:LibertyX'),
        y: () => Sync.get('BG:LibertyY'),
        z: -100
      }],
      angle: [{
        degreesZ: -30
      }],
      material: {
        transparent: true,
        depthTest: true,
        depthWrite: false,
        blending: 'NormalBlending'
      },
    }
  ]);

  this.loader.addAnimation([
    {
      id: 'grungefarjan',
      image: {
        name: 'img/grungefarjan.png'
      },
      perspective: '3d',
      color: [
        {
          a: () => Sync.get('BG:LibertyAlpha')
        }
      ],
      scale: [{ uniform2d: 30.7 }],
      enabled: () => Sync.get('BG:LibertyAlpha') > 0.01,
      position: [{
        x: () => -Sync.get('BG:LibertyX'),
        y: () => Sync.get('BG:LibertyY') * .75 - 5,
        z: -100
      }],
      angle: [{
        degreesZ: -65
      }],
      material: {
        transparent: true,
        depthTest: true,
        depthWrite: false,
        blending: 'NormalBlending'
      },
    }
  ]);

  this.loader.addAnimation({
    parent: 'liberty',
    start: 140,
    image: {
      name: "img/smoke.png"
    },
    perspective: '3d',
    color: [
      {
        a: 0,
      },
      {
        duration: 2,
      },
      {
        a: () => Sync.get('BG:LibertyAlpha')
      }
    ],
    scale: [{ uniform2d: 2.0 }],
    enabled: () => Sync.get('BG:LibertyAlpha') > 0.01,
    material: {
      transparent: true,
      depthTest: true,
      depthWrite: false,
      blending: 'NormalBlending'
    },
    "position": [{
      "x": -0.5,
      "y": 1.2,
      "z": 0
    }],
    angle: [{ degreesZ: 30 }]
    , "scale": [{ "x": 1.0, "y": 0.6 }]
    , "shader": {
      "name": "scenes/intro/smoke.fs"
      , "variable": [
        { "name": "strength", "value": [1.0] },
        { "name": "iteration", "value": [Utils.random() * 30.0] }
      ]
    },
  });

  this.loader.addAnimation({
    image: ['_embedded/defaultWhite.png'],
    perspective: '3d',
    position: [{ "x": () => window.camPos, "y": () => window.camPos, "z": 0.0 }],
    scale: [{ uniform2d: 1.0 }],
    "material": {
      depthTest: true,
      depthWrite: true,
      blending: 'NormalBlending'
    },
    "shader": {
      "name": ["multiSceneEffects/rayMarcher.vs", "multiSceneEffects/rayMarcher.fs"],
      "variable":
        [
          { "name": "MAX_STEPS", "type": "float", "value": [100.0] },
          { "name": "inCamPos", "type": "vec3", "value": [() => window.camPos] },
          { "name": "camDirection", "type": "vec3", "value": [() => window.camDirection] },
          { "name": "camNear", "type": "mat4", "value": [() => window.camNear] },
          { "name": "camFar", "type": "mat4", "value": [() => window.camFar] },
          { "name": "camFov", "type": "mat4", "value": [() => window.camFov] },
          { "name": "showTunnel", "type": "float", "value": [() => Sync.get('RayMarcher:ShowTunnel') > 0.1] },
          { "name": "tunnelDeformAmount", "type": "float", "value": [() => Sync.get('RayMarcher:TunnelDeformAmount')] },
          { "name": "showGround", "type": "float", "value": [0.0] },
          { "name": "tunnelMinZ", "type": "float", "value": [() => Sync.get('RayMarcher:TunnelMinZ')] },
          { "name": "tunnelMaxZ", "type": "float", "value": [() => Sync.get('RayMarcher:TunnelMaxZ')] },
          { "name": "tunnel2ndColorMix", "type": "float", "value": [() => Sync.get('RayMarcher:Tunnel2ndColorMix')] },
          { "name": "showHeartTunnel", "type": "float", "value": [0.0] },
          { "name": "heartTunnelMinZ", "type": "float", "value": [() => Sync.get('RayMarcher:HeartTunnelMinZ')] },
          { "name": "heartTunnelMaxZ", "type": "float", "value": [() => Sync.get('RayMarcher:HeartTunnelMaxZ')] },
          { "name": "showRainbowRoad", "type": "float", "value": [1.0] },
          { "name": "rainbowRoadMinZ", "type": "float", "value": [() => Sync.get('RayMarcher:RainbowRoadMinZ')] },
          { "name": "rainbowRoadMaxZ", "type": "float", "value": [() => Sync.get('RayMarcher:RainbowRoadMaxZ')] },
          { "name": "showFakeShadow", "type": "float", "value": [1.0] },
          { "name": "fakeShadowPos", "type": "vec2", "value": [() => Sync.get('RayMarcher:FakeShadowPosX'), () => Sync.get('RayMarcher:FakeShadowPosZ')] },
          { "name": "fakeShadowSize", "type": "vec2", "value": [() => Sync.get('RayMarcher:FakeShadowSizeX'), () => Sync.get('RayMarcher:FakeShadowSizeZ')] },
          { "name": "fakeShadowOpacity", "type": "float", "value": [() => Sync.get('RayMarcher:FakeShadowOpacity')] },
          { "name": "fakeShadowWarpFreq", "type": "vec2", "value": [() => Sync.get('RayMarcher:FakeShadowWarpFreqX'), () => Sync.get('RayMarcher:FakeShadowWarpFreqZ')] },
          { "name": "fakeShadowWarpAmp", "type": "vec2", "value": [() => Sync.get('RayMarcher:FakeShadowWarpAmpX'), () => Sync.get('RayMarcher:FakeShadowWarpAmpZ')] },
          { "name": "kick", "type": "float", "value": [() => Sync.get('Music:Kick')] },
          
        ]
    }
  });
  this.addEffectStarfield(0, 240,
    { count: 400, texture: 'img/basicParticleW2B.png' },
    {
      areaSizeX: 100,
      areaSizeY: 100,
      areaSizeZ: 200,
      particleSize: 5.5,
      speed: 1.0,
      enabledOnStart: true,
      enabled: 'BG:AdditiveStarfield',
      blending: 'AdditiveBlending'
    }
  );

  this.addEffectStarfield(0, 240,
    { count: 250, texture: 'img/basicParticleW2B.png' },
    {
      areaSizeX: 100,
      areaSizeY: 100,
      areaSizeZ: 200,
      colorR: 0.8, colorG: 0.4, colorB: 0.0,
      particleSize: 4.5,
      speed: 2.5,
      enabledOnStart: true,
      enabled: 'BG:SubtractiveStarfield',
      blending: 'AdditiveBlending',
      seed: 600
    }
  );

  this.addEffectStarfield(0, 240,
    { count: 250, texture: 'img/basicParticleW2B.png' },
    {
      areaSizeX: 100,
      areaSizeY: 100,
      areaSizeZ: 300,
      colorR: 0.0, colorG: 0.4, colorB: 0.8,
      particleSize: 4.5,
      speed: 2.4,
      enabledOnStart: true,
      enabled: 'BG:SubtractiveStarfield',
      blending: 'SubtractiveBlending',
      seed: 700,
    }
  );

  this.loader.addAnimation([{
    object: {
      name: "obj/jumalautapresents.obj",
    }
    , position: [{
      x: () => Sync.get('Logo:X'),
      y: () => Sync.get('Logo:Y'),
      z: () => Sync.get('Logo:Z'),
    }],
    angle: [{
      degreesX: 90,
      degreesZ: -45
    }]
    , scale: [{ uniform3d: () => Sync.get('Logo:jmlScale') * .025 }],
    visible: () => Sync.get('Logo:jmlScale') > 0.01,
    color: [{
      r: () => 1,
      g: () => 1,
      b: () => 0,
    }]
  }]);

  this.loader.addAnimation([{
    object: {
      name: "obj/automata.obj",
    }
    , position: [{
      x: () => Sync.get('Logo:AutoX'),
      y: () => Sync.get('Logo:AutoY'),
      z: () => Sync.get('Logo:AutoZ'),
    }],
    angle: [{
      degreesX: 90,
      degreesZ: 45
    }]
    , scale: [{ uniform3d: () => Sync.get('Logo:AutoScale') * .025 }],
    visible: () => Sync.get('Logo:AutoScale') > 0.01,
    color: [{
      r: () => 1,
      g: () => 1,
      b: () => 0,
    }]
  }]);
  /*
    this.loader.addAnimation({
      image: 'img/tex_spiral.png',
      angle: [
        { degreesZ: () => Sync.get('Time') * 360 }
      ],
      color: [{
        r: 0.5, g: 0.1, b: 0.75, a: 1.0
      }],
      perspective: '3d',
      scale: [{ uniform3d: 60.25 }],
      material: {
        blending: 'CustomBlending',
        transparent: false,
        depthWrite: false,
        depthTest: true
      },
      position: [{
        x: 0,
        y: 0,
        z: -60
      }]
    });
  
    this.loader.addAnimation({
      image: 'img/tex_spiral.png',
      angle: [
        { degreesZ: () => Sync.get('Time') * -360 }
      ],
      color: [{
        r: 0.2, g: 0.2, b: 1.15, a: 1.0
      }],
      perspective: '3d',
      scale: [{ uniform3d: 60.25 }],
      material: {
        blending: 'CustomBlending',
        transparent: false,
        depthWrite: false,
        depthTest: true
      },
      position: [{
        x: 0,
        y: 0,
        z: -60
      }]
    });
  */
  this.loader.addAnimation({
    light: {
      type: "Ambient",
      properties: { intensity: 2.0 },
      castShadow: false
    }
    , "color": [{
      "r": 0.8, "g": 0.8, "b": 0.8
    }]
  });

  this.loader.addAnimation({
    light: {
      type: "Directional",
      properties: { intensity: 3.0 },
      castShadow: true
    }
    , "color": [{
      "r": 0.8, "g": 0.8, "b": 0.8
    }]
    , position: [{
      x: 0,
      y: 1,
      z: .8
    }]

  });

  this.loader.addAnimation([{

    object: {
      name: "obj/gridtunnel.obj",
    }
    , position: [{
      x: 0.0,
      y: () => Sync.get('Objects:GridTunnelY'),
      z: 0
    }]
    , receiveShadow: false
    , angle: [{

      degreesY: 180,

    }],
    visible: () => Sync.get('Objects:GridTunnelScale') > 0.001,
    scale: [{ x: 4.0, y: 4.0, z: () => Sync.get('Objects:GridTunnelScale') }],
    color: [{
      r: 1.0, g: 1.0, b: 1.0
    }],
    shader: {
      vertexShaderPrefix: `
                uniform float kickSeq;
                uniform float scale;
                uniform float time;
                uniform float uvscale;
                `,
      vertexShaderSuffix: `
                
                vMapUv.y *= scale;
                vMapUv.y -= kickSeq*8.0 + time*2.;
                vMapUv.x -= sin(kickSeq*PI*2.+time*.25);
                vMapUv  = vMapUv* (1.0+0.05*uvscale);
                `,
      fragmentShaderPrefix: window.hueFSPrefix2,
      fragmentShaderSuffix: window.hueFSSuffix2,
      variable: [
        { name: 'hueRotate', value: [() => Sync.get('Music:KickSeq8') * .125] },
        { name: 'enabled', value: [1.0] },
        { name: 'scale', value: [() => Sync.get('Objects:GridTunnelScale')] },
        { name: 'time', value: [() => getSceneTimeFromStart()] },
        { name: 'uvscale', value: [() => Sync.get('Music:Kick')] }
      ]
    }
  }]);

  const heartSpiralCount = 30;
  this.addEffectMeshRepeater(0, 240,
    { count: 16, object: "obj/heart.obj" },
    {
      x: 0, y: 0, z: 0,
      spacing: 6,
      speed: -3 * (4 / window.beat),
      particleSize: 0.26,
      colorR: 1.0, colorG: 0.2, colorB: 0.2,
      enabled: "Objects:Hearts",
      enabledOnStart: false,
      particleX: (props) => 2.5 * Math.cos(props.index * (4 * 3.14) / heartSpiralCount),
      particleY: (props) => .85 + .55 * Math.abs(Math.sin(props.index * (4 * 3.14) / heartSpiralCount) * 3)

    }
  );
  const hellovilleSpacing = 20;

  this.addEffectMeshRepeater(0, 240,
    { count: 12, object: "obj/denbou.obj" },
    {
      x: () => 0, y: () => Math.sin(getSceneTimeFromStart() * 10) * .05, z: -6,
      spacing: hellovilleSpacing,
      speed: -hellovilleSpacing * (.5 / window.beat),
      particleSize: () => 2 + Sync.get('Music:Snare') * 1,
      enabled: "Objects:Rainbow",
      enabledOnStart: false,

      // particleAngleZ: (props) => 1.57079632679 * (Sync.get('Music:SnareSeq4') + props.index ),
      colorR: 1.0, colorG: 1.0, colorB: 1.0,
      hueRotateEnabled: 1,
      hueRotate: () => Sync.get('Flower:HueRotate')
    }
  );

  const deg2rad = Math.PI / 180;
  let dolphinDirection = 1;
  let dolphinRotateZ = 0;
  let dolphinSpeed = 1;
  const dolphinXMotion = (timeAddition) => {
    const beat = getSceneTimeFromStart() / window.beat;
    const x = -Math.sin((timeAddition + 1 / window.beat + getSceneTimeFromStart()) * (1 / window.beat));
    const prevX = -Math.sin((timeAddition + 1 / window.beat + (getSceneTimeFromStart() - (1. / 60.))) * (1 / window.beat));
    if (x > prevX) dolphinDirection = 1;
    else dolphinDirection = -1;
    dolphinRotateZ = 0;
    const rotoBeat = (beat / 6) % 4;
    if (rotoBeat < 1.0) {
      dolphinRotateZ = rotoBeat * (360 * 3) * dolphinDirection;
    }
    return x * 6.5;
  };
  const timeAdd = (Math.PI / 2) * window.beat * 1.5;
  const dolphinYMotion = (timeAddition) => -4 + 8 * Math.pow(Math.cos((timeAddition + getSceneTimeFromStart() + 1 / window.beat) * (1 / window.beat)), 2);

  this.addEffectMeshRepeater(0, 240,
    { count: 12, object: "obj/dolphin.obj" },
    {
      x: () => dolphinXMotion(timeAdd * 2),
      y: () => dolphinYMotion(timeAdd * 2),
      z: -5,
      spacing: hellovilleSpacing * .5,
      speed: -hellovilleSpacing * (.25 / window.beat),
      particleSize: .25,
      enabled: "Objects:DolphinsReal",
      enabledOnStart: false,
      particleAngleY: () => dolphinDirection < 0 ? 180 * deg2rad : 0,
      particleAngleZ: () => dolphinXMotion(timeAdd * 2) * deg2rad * 10 * -dolphinDirection,
      particleAngleX: () => dolphinRotateZ * deg2rad,
      // particleAngleZ: (props) => 1.57079632679 * (Sync.get('Music:SnareSeq4') + props.index ),
      colorR: .0, colorG: .9, colorB: 1.0,
      hueRotateEnabled: 1,
      hueRotate: () => Sync.get('Flower:HueRotate'),
      env: "img/dolphinenv.png"
    }
  );

  this.addEffectMeshRepeater(0, 240,
    { count: 12, object: "obj/dolphin.obj" },
    {
      x: () => dolphinXMotion(timeAdd),
      y: () => dolphinYMotion(timeAdd),
      z: -7,
      spacing: hellovilleSpacing * .5,
      speed: -hellovilleSpacing * (.25 / window.beat),
      particleSize: .25,
      enabled: "Objects:DolphinsReal",
      enabledOnStart: false,
      particleAngleY: () => dolphinDirection < 0 ? 180 * deg2rad : 0,
      particleAngleZ: () => dolphinXMotion(timeAdd) * deg2rad * 10 * -dolphinDirection,
      particleAngleX: () => dolphinRotateZ * deg2rad,
      // particleAngleZ: (props) => 1.57079632679 * (Sync.get('Music:SnareSeq4') + props.index ),
      colorR: .0, colorG: .9, colorB: 1.0,
      hueRotateEnabled: 1,
      hueRotate: () => Sync.get('Flower:HueRotate'),
      env: "img/dolphinenv.png"
    }
  );

  this.addEffectMeshRepeater(0, 240,
    { count: 12, object: "obj/dolphin.obj" },
    {
      x: () => dolphinXMotion(0),
      y: () => dolphinYMotion(0),
      z: -3,
      spacing: hellovilleSpacing * .5,
      speed: -hellovilleSpacing * (.25 / window.beat),
      particleSize: .25,
      enabled: "Objects:DolphinsReal",
      enabledOnStart: false,
      particleAngleY: () => dolphinDirection < 0 ? 180 * deg2rad : 0,
      particleAngleZ: () => dolphinXMotion(0) * deg2rad * 10 * +-dolphinDirection,
      particleAngleX: () => dolphinRotateZ * deg2rad,
      // particleAngleZ: (props) => 1.57079632679 * (Sync.get('Music:SnareSeq4') + props.index ),
      colorR: .0, colorG: .9, colorB: 1.0,
      hueRotateEnabled: 1,
      hueRotate: () => Sync.get('Flower:HueRotate'),
      env: "img/dolphinenv.png"
    }
  );
  this.addEffectMeshRepeater(0, 240,
    { count: 10, object: "obj/kukka1.obj" },
    {
      x: () => -5.5, y: 0.1, z: 7,
      spacing: hellovilleSpacing,
      speed: -hellovilleSpacing * (.5 / window.beat),
      particleSize: () => .75 + Sync.get('Music:Kick') * .75,
      enabled: "Objects:helloVille",
      enabledOnStart: false,
      angleZ: () => .5 * 1.57079632679 * Sync.get('Music:SnareSeq4'),
      colorR: 0.8, colorG: 0.8, colorB: 0.8,
      hueRotateEnabled: 1,
      hueRotate: () => .58 + Sync.get('Flower:HueRotate')
    }
  );

  this.addEffectMeshRepeater(0, 240,
    { count: 10, object: "obj/kukka1.obj" },
    {
      x: () => 5.5, y: 0.1, z: -2,
      spacing: hellovilleSpacing,
      speed: -hellovilleSpacing * (.5 / window.beat),
      particleSize: () => .75 + Sync.get('Music:Snare') * .75,
      enabled: "Objects:helloVille",
      enabledOnStart: false,
      angleZ: () => .5 * 1.57079632679 * Sync.get('Music:SnareSeq4'),
      colorR: 0.8, colorG: 0.8, colorB: 0.8,
      hueRotateEnabled: 1,
      hueRotate: () => .58 + .75 + Sync.get('Flower:HueRotate')
    }
  );

  // dolffiini

  this.addEffectMeshRepeater(0, 240,
    { count: 10, object: "obj/maro.obj" },
    {
      x: () => -2, y: .2, z: -15.5,
      maroHack: true,
      spacing: 3,
      speed: 4 * (.75 / window.beat),
      particleSize: () => .1,
      enabled: "Objects:Dolphin1",
      enabledOnStart: false,
      //angleY: Math.PI,
      colorR: 1.0, colorG: 1.0, colorB: 1.0,
      particleAngleY: () => 180 * deg2rad,
      particleY: (props) => props.index % 2 === 0 ? Math.sin(getSceneTimeFromStart() * 5) * .5 : Math.cos(getSceneTimeFromStart() * 5) * .5
    }
  );

  this.addEffectMeshRepeater(0, 240,
    { count: 10, object: "obj/farjan.obj" },
    {
      x: () => -2, y: -.5, z: -15,
      spacing: 3,
      speed: 4 * (.75 / window.beat),
      particleSize: () => .35,
      enabled: "Objects:Dolphin1",
      enabledOnStart: false,
      //angleY: Math.PI,
      colorR: 1.0, colorG: 1.0, colorB: 1.0,
      particleY: (props) => props.index % 2 === 0 ? Math.sin(getSceneTimeFromStart() * 5) * .5 : Math.cos(getSceneTimeFromStart() * 5) * .5
    }
  );

  this.addEffectMeshRepeater(0, 240,
    { count: 10, object: "obj/farjan.obj" },
    {
      x: () => 2, y: -.5, z: -13.5,
      spacing: 3,
      speed: 4 * (.75 / window.beat),
      particleSize: () => .35,
      enabled: "Objects:Dolphin1",
      enabledOnStart: false,
      //angleY: Math.PI,
      colorR: 1.0, colorG: 1.0, colorB: 1.0,
      particleY: (props) => props.index % 2 === 0 ? Math.cos(getSceneTimeFromStart() * 5) * .5 : Math.sin(getSceneTimeFromStart() * 5) * .5
    }
  );
  const blockWidth = 31;
  for (let i = 0; i < blockWidth; i++) {
    this.addEffectMeshRepeater(0, 240,
      { count: 25, object: "obj/sandblock.obj" },
      {
        x: i * 4 - (blockWidth - 1) * 2, y: -2.5, z: 0,
        spacing: 4,
        speed: -25.0,
        particleSize: 2.0,
        enabled: "Ground:SandBlock",
        enabledOnStart: false,
        superDisabled: () => Sync.get('Objects:hackySuperDisable'),
        colorR: 1.1, colorG: 1.1, colorB: 1.1,
        hackScale: ()=> Sync.get('Ground:SandBlockHackScale')
      }
    );
  }

  const muzzleFire = (parentId, i) => {
    const muzzleAlpha = () => {
      if (Sync.get('Objects:uhkaTankVisible') <= 0.01) return 0.0;
      return Sync.get('Objects:uhkaTankFire', 1.0);
    };
    const muzzleAdditive = true;
    const deg2rad = Math.PI / 180;

    const magazineSize = 90;
    let ak47BurstRateDelay = 0.25;

    this.loader.addAnimation({
      "parent": parentId
      , "image": {
        "name": "scenes/intro/muzzle_flame.png"
      }
      , "additive": muzzleAdditive
      , "perspective": "3d"
      , "position": [{
        "x": 0.00,
        "y": 6.0,
        "z": 30
      }]
      , "color": [{ "a": muzzleAlpha }]
      , "angle": [{
        "degreesY": 180,
      }]
      , "scale": [{ "uniform3d": () => 20.0 + Math.sin(i * getSceneTimeFromStart() * 20.0) * 0.1 }]
      , "shader": {
        "name": "scenes/intro/muzzle.fs"
        , "variable": [
          { "name": "strength", "value": [1.0] },
          { "name": "iteration", "value": [Utils.random() * 30.0] }
        ]
      }
    });
    const muzzlePosition = {
      "x": 0.0,
      "y": 6.0,
      "z": 30
    };
    this.loader.addAnimation({
      "parent": parentId
      , "image": {
        "name": "scenes/intro/tex_muzzle.png"
      }
      , material: { side: 'DoubleSide' }
      , "additive": muzzleAdditive
      , "perspective": "3d"
      , "position": [muzzlePosition]
      , "color": [{ "a": muzzleAlpha }]
      , "angle": [{
        "degreesY": 90,
      }]
      , "scale": [{ "uniform3d": () => 7.0 + Math.sin(i * getSceneTimeFromStart() * 20.0) * 0.1 }]
      , "shader": {
        "name": "scenes/intro/muzzle.fs"
        , "variable": [
          { "name": "strength", "value": [1.0] },
          { "name": "iteration", "value": [Utils.random() * 30.0] }
        ]
      }
    });
    this.loader.addAnimation({
      "parent": parentId
      , "image": {
        "name": "scenes/intro/tex_muzzle.png"
      }
      , material: { side: 'DoubleSide' }
      , "additive": muzzleAdditive
      , "perspective": "3d"
      , "position": [muzzlePosition]
      , "color": [{ "a": muzzleAlpha }]
      , "angle": [{
        "degreesX": -90,
        "degreesZ": 90,
      }]
      , "scale": [{ "uniform3d": () => 7.0 + Math.sin(i * getSceneTimeFromStart() * 20.0) * 0.1 }]
      , "shader": {
        "name": "scenes/intro/muzzle.fs"
        , "variable": [
          { "name": "strength", "value": [1.0] },
          { "name": "iteration", "value": [Utils.random() * 30.0] }
        ]
      }
    });
  };


  this.loader.addAnimation([{
    id: 'dancerTank',
    object: {
      "name": "obj/dancerTank.obj"
    }
    , position: [{
      x: () => Math.sin(getSceneTimeFromStart() * 2) * .05,
      y: () => -2.29 + Math.abs(Math.sin(getSceneTimeFromStart() * 10)) * .02 + Sync.get('Objects:UhkaTankY'),
      z: -1
    }]
    , scale: [{ "uniform3d": .2 }]
    , angle: [{
      degreesY: 180,
    }]
    , visible: () => Sync.get('Objects:uhkaTankVisible') > 0.1
  }]);
  //Dancertank cannon
  this.loader.addAnimation({
    parent: 'dancerTank',
    id: 'dancerTankCannon',
    object: {
      "name": "obj/dancerTank_cannon.obj"
    },
    visible: () => Sync.get('Objects:uhkaTankVisible') > 0.1,
    position: [{
      x: 0, y: 0.0, z: -4
    }],
    angle: [{
      degreesY: () => Sync.get('Objects:UhkaTankCannonAngle')
    }]
  });
  muzzleFire('dancerTankCannon', 1);

  const spiralXMotion = (particleIndex, spiralIndex) => {
    return Math.sin(getSceneTimeFromStart() + spiralIndex * Math.PI * .5 + particleIndex * (Math.PI * 2) / 9) * (2 + Sync.get('Music:Kick') * .5);
  }

  const spiralYMotion = (particleIndex, spiralIndex) => {
    return Math.cos(getSceneTimeFromStart() + spiralIndex * Math.PI * .5 + particleIndex * (Math.PI * 2) / 9) * (2 + Sync.get('Music:Kick') * .5);
  }
  const spiralAngleYMotion = (particleIndex, spiralIndex) => {
    const x = spiralXMotion(particleIndex, spiralIndex);
    const y = spiralYMotion(particleIndex, spiralIndex);
    const angle = Math.PI - Math.atan2(x, y) * 0.3;
    return angle;
  }

  const spiralAngleXMotion = (particleIndex, spiralIndex) => {
    return Math.cos(getSceneTimeFromStart() * 3 - particleIndex) * Math.PI * .25;
  }


  this.addEffectMeshRepeater(0, 240,
    { count: 36, object: "obj/cctv.obj" },
    {
      x: () => 0, y: () => 0, z: 0,
      //  repeaterAngle: () => getSceneTimeFromStart() * 90,
      spacing: 1.5,
      speed: -6.5 * (.5 / window.beat),
      particleSize: () => Sync.get("Objects:Starfield1Scale") * (.3 + Sync.get('Music:Kick') * 0.2),
      enabledOnStart: false,
      enabled: 'Objects:Object1StarEye',
      particleX: (props) => spiralXMotion(props.index, 0),
      particleY: (props) => spiralYMotion(props.index, 0),
      particleAngleY: (props) => spiralAngleYMotion(props.index, 0),
      particleAngleX: (props) => spiralAngleXMotion(props.index, 0),
      particleAngleZ: (props) => 0

    }
  );

  const eyeMaterial = {
        bumpMap: 'obj/eyetex2.png',
      };

  const eyeShader = {
      fragmentShaderPrefix:`
uniform float pupil;

void drawPupil() {
    gl_FragColor.rgb = mix(gl_FragColor.rgb, texture2D(bumpMap, vMapUv).rgb, pupil);
}
`,
      fragmentShaderSuffix:`
drawPupil();
`,
      variable: [
        { name: 'pupil', value: [() => Sync.get('Objects:Pupil', Math.sin(getSceneTimeFromStart()*2.5)*0.5+0.5)] },
      ]

    };


  this.addEffectMeshRepeater(0, 240,
    { count: 36, object: "obj/eye.obj" },
    {
      x: () => 0, y: () => 0, z: 0,
      // repeaterAngle: () => getSceneTimeFromStart() * 90,
      spacing: 1.5,
      speed: -6.5 * (.5 / window.beat),
      particleSize: () => Sync.get("Objects:Starfield1Scale") * (.3 + Sync.get('Music:Kick') * 0.2),
      enabledOnStart: false,
      enabled: 'Objects:Object1StarEye',
      particleX: (props) => spiralXMotion(props.index, 1),
      particleY: (props) => spiralYMotion(props.index, 1),
      particleAngleY: (props) => Math.sin(getSceneTimeFromStart() * 7 + props.index) * Math.PI * .25,
      particleAngleX: (props) => Math.sin(getSceneTimeFromStart() * 5 + props.index) * Math.PI * .125,
      shader: {...eyeShader},
      material: {...eyeMaterial}
    }
  );
  this.addEffectMeshRepeater(0, 240,
    { count: 36, object: "obj/cctv.obj" },
    {
      x: () => 0, y: () => 0, z: 0,
      //  repeaterAngle: () => getSceneTimeFromStart() * 90,
      spacing: 1.5,
      speed: -6.5 * (.5 / window.beat),
      particleSize: () => Sync.get("Objects:Starfield1Scale") * (.3 + Sync.get('Music:Kick') * 0.2),
      enabledOnStart: false,
      enabled: 'Objects:Object1StarEye',
      particleX: (props) => spiralXMotion(props.index, 2),
      particleY: (props) => spiralYMotion(props.index, 2),
      particleAngleY: (props) => spiralAngleYMotion(props.index, 2),
      particleAngleX: (props) => spiralAngleXMotion(props.index, 2),
      particleAngleX: (props) => 0
    }
  );
  this.addEffectMeshRepeater(0, 240,
    { count: 36, object: "obj/eye.obj" },
    {
      x: () => 0, y: () => 0, z: 0,
      //  repeaterAngle: () => getSceneTimeFromStart() * 90,
      spacing: 1.5,
      speed: -6.5 * (.5 / window.beat),
      particleSize: () => Sync.get("Objects:Starfield1Scale") * (.3 + Sync.get('Music:Kick') * 0.2),
      enabledOnStart: false,
      enabled: 'Objects:Object1StarEye',
      particleX: (props) => spiralXMotion(props.index, 3),
      particleY: (props) => spiralYMotion(props.index, 3),
      particleAngleY: (props) => Math.sin(getSceneTimeFromStart() * 5 + props.index) * Math.PI * .125,
      particleAngleX: (props) => Math.sin(getSceneTimeFromStart() * 7 + props.index) * Math.PI * .125,
      shader: {...eyeShader},
      material: {...eyeMaterial}
    }
  );

  /*
    this.addEffectMeshRepeater(0, 240,
      { count: 36, object: "obj/eye.obj" },
      {
        x: () => 0, y: () => 0, z: 0,
        repeaterAngle: () => getSceneTimeFromStart() * 90,
        spacing: 1.5,
        speed: -6.5 * (.5 / window.beat),
        particleSize: () => Sync.get("Objects:Starfield1Scale")*(.3 + Sync.get('Music:Kick') * 0.2),
        enabledOnStart: false,
        enabled: 'Objects:Object1StarEye',
        particleX: (props) => Math.sin(props.index * (Math.PI * 2) / 9) * (2 + Sync.get('Music:Kick') * .5),
        particleY: (props) => Math.cos(props.index * (Math.PI * 2) / 9) * (2 + Sync.get('Music:Kick') * .5),
       // particleAngleX: (props) => Math.PI * .5 + Math.sin(props.index + getSceneTimeFromStart() * 4) * Math.PI * .25,
       // particleAngleZ: (props) => Math.sin(props.index + getSceneTimeFromStart() * 5) * Math.PI * .25,
      }
    );
  
    this.addEffectMeshRepeater(0, 240,
      { count: 36, object: "obj/eye.obj" },
      {
        x: () => 0, y: () => 0, z: 0,
        repeaterAngle: () => getSceneTimeFromStart() * 90,
        spacing: 1,
        speed: -6.5 * (.5 / window.beat),
        particleSize: () => Sync.get("Objects:Starfield1Scale")*(.35 + Sync.get('Music:Kick') * 0.2),
        enabledOnStart: false,
        enabled: 'Objects:Object1StarEye',
        particleX: (props) => -(Math.sin(props.index * (Math.PI * 2) / 9) * (2 + Sync.get('Music:Kick') * .5)),
        particleY: (props) => -(Math.cos(props.index * (Math.PI * 2) / 9) * (2 + Sync.get('Music:Kick') * .5)),
        particleAngleX: (props) => Math.PI * .5 + Math.sin(props.index + getSceneTimeFromStart() * 4) * Math.PI * .25,
        particleAngleZ: (props) => Math.sin(props.index + getSceneTimeFromStart() * 5) * Math.PI * .25,
  
      }
    );
  */
  this.addEffectMeshStarfield(
    0, 240,
    { count: 30, object: "obj/tv.obj" },
    {
      areaSizeX: 7.5,
      areaSizeY: 7.5,
      areaSizeZ: 20,
      particleSize: () => 1.1 + Sync.get('Music:Kick') * 0.5,
      enabledOnStart: false,
      enabled: 'Objects:TVStarfield',
      seed: 662,
      speed: 3.65,
      safeZoneX: 3.,
      safeZoneY: 4.,
      targetCenter: true,
      uvyOffset: () => Sync.get('Music:PercSeq8Instant') * .125
    }
  );

  this.addEffectMeshStarfield(
    0, 240,
    { count: 25, object: "obj/drug.obj" },
    {
      areaSizeX: 7,
      areaSizeY: 7,
      areaSizeZ: 20,
      randomAngle: true,
      particleSize: () => .4 + Sync.get('Music:Kick') * 0.25,
      enabledOnStart: false,
      enabled: 'Objects:DrugStarfield',
      seed: 419,
      speed: 2,
      safeZoneX: .25,
      safeZoneY: .25
    }
  );

  this.addEffectMeshStarfield(
    0, 240,
    { count: 25, object: "obj/tab.obj" },
    {
      areaSizeX: 7,
      areaSizeY: 7,
      areaSizeZ: 20,
      randomAngle: true,
      particleSize: () => 0.5 + Sync.get('Music:Kick') * 0.25,
      enabledOnStart: false,
      enabled: 'Objects:DrugStarfield',
      seed: 61,
      speed: 2,
      safeZoneX: 0.1,
      safeZoneY: 0.1
    }
  );

  this.addEffectMeshStarfield(
    0, 240,
    { count: 25, object: "obj/syringeoutlined.obj" },
    {
      areaSizeX: 7,
      areaSizeY: 7,
      areaSizeZ: 20,
      randomAngle: true,
      particleSize: () => 1.0 + Sync.get('Music:Kick') * 0.5,
      enabledOnStart: false,
      enabled: 'Objects:DrugStarfield',
      seed: 999,
      speed: 2,
      safeZoneX: 0.1,
      safeZoneY: 0.1
    }
  );

  let symbolSpacing = 35;
  let gap = (1 / 6) * symbolSpacing;
  this.addEffectMeshRepeater(0, 240,
    { count: 3, object: "obj/penta.obj" },
    {
      x: () => 0, y: () => Math.sin(getSceneTimeFromStart() * 10) * .05, z: symbolSpacing * .5,
      spacing: symbolSpacing,
      speed: -7.5 * (.5 / window.beat),
      particleSize: () => (2 + Sync.get('Music:Snare') * 1) * Sync.get('Objects:SymbolScale'),
      enabled: "Objects:Penta",
      enabledOnStart: false,
      hueRotateEnabled: 1.0,
      particleAngleZ: (props) => (Sync.get('Cam:Roll') * Math.PI / 180) + getSceneTimeFromStart() + 18 * props.index,
      colorR: 1.0, colorG: 0.0, colorB: 0
    }
  );
  this.addEffectMeshRepeater(0, 240,
    { count: 3, object: "obj/gear.obj" },
    {
      x: () => 5.9, y: () => Math.sin(getSceneTimeFromStart() * 10) * .05, z: symbolSpacing * .5 - gap * 1,
      angle: 90,
      spacing: symbolSpacing,
      speed: -7.5 * (.5 / window.beat),
      particleSize: () => (2 + Sync.get('Music:Snare') * 1) * Sync.get('Objects:SymbolScale'),
      enabled: "Objects:Penta",
      enabledOnStart: false,
      hueRotateEnabled: 1.0,
      particleAngleZ: (props) => (Sync.get('Cam:Roll') * Math.PI / 180) + getSceneTimeFromStart() + 18 * props.index,
      colorR: 0, colorG: 0, colorB: 0.0
    }
  );
  this.addEffectMeshRepeater(0, 240,
    { count: 3, object: "obj/gear.obj" },
    {
      x: () => -5.9, y: () => Math.sin(getSceneTimeFromStart() * 10) * .05, z: symbolSpacing * .5 - gap * 1,
      angle: 90,
      spacing: symbolSpacing,
      speed: -7.5 * (.5 / window.beat),
      particleSize: () => (2 + Sync.get('Music:Snare') * 1) * Sync.get('Objects:SymbolScale'),
      enabled: "Objects:Penta",
      enabledOnStart: false,
      hueRotateEnabled: 1.0,
      particleAngleZ: (props) => (Sync.get('Cam:Roll') * Math.PI / 180) + getSceneTimeFromStart() + 18 * props.index,
      colorR: 0, colorG: 0, colorB: 0.0
    }
  );

  this.addEffectMeshRepeater(0, 240,
    { count: 3, object: "obj/gear.obj" },
    {
      x: () => 0, y: () => Math.sin(getSceneTimeFromStart() * 10) * .05, z: symbolSpacing * .5 - gap * 1,
      spacing: symbolSpacing,
      speed: -7.5 * (.5 / window.beat),
      particleSize: () => (2 + Sync.get('Music:Snare') * 1) * Sync.get('Objects:SymbolScale'),
      enabled: "Objects:Penta",
      enabledOnStart: false,
      hueRotateEnabled: 1.0,
      particleAngleZ: (props) => (Sync.get('Cam:Roll') * Math.PI / 180) - getSceneTimeFromStart() + 18 * props.index,
      colorR: 0, colorG: 0, colorB: 0.0
    }
  );

  this.addEffectMeshRepeater(0, 240,
    { count: 3, object: "obj/eu.obj" },
    {
      x: () => 0, y: () => Math.sin(getSceneTimeFromStart() * 10) * .05, z: symbolSpacing * .5 - gap * 2,
      spacing: symbolSpacing,
      speed: -7.5 * (.5 / window.beat),
      particleSize: () => (2 + Sync.get('Music:Snare') * 1) * Sync.get('Objects:SymbolScale'),
      enabled: "Objects:Penta",
      enabledOnStart: false,
      hueRotateEnabled: 1.0,
      particleAngleZ: (props) => (Sync.get('Cam:Roll') * Math.PI / 180) + getSceneTimeFromStart() + 18 * props.index,
      colorR: 0, colorG: 0, colorB: 1
    }
  );

  this.addEffectMeshRepeater(0, 240,
    { count: 3, object: "obj/hexagram.obj" },
    {
      x: () => 0, y: () => Math.sin(getSceneTimeFromStart() * 10) * .05, z: symbolSpacing * .5 - gap * 3,
      spacing: symbolSpacing,
      speed: -7.5 * (.5 / window.beat),
      particleSize: () => (2 + Sync.get('Music:Snare') * 1) * Sync.get('Objects:SymbolScale'),
      enabled: "Objects:Penta",
      enabledOnStart: false,
      hueRotateEnabled: 1.0,
      particleAngleZ: (props) => (Sync.get('Cam:Roll') * Math.PI / 180) - getSceneTimeFromStart() + 18 * props.index,
      colorR: 0.0, colorG: 0.1, colorB: 1.0
    }
  );

    this.addEffectMeshRepeater(0, 240,
    { count: 3, object: "obj/CROSS.obj" },
    {
      x: () => 0, y: () => Math.sin(getSceneTimeFromStart() * 10) * .05, z: symbolSpacing * .5 - gap * 4,
      spacing: symbolSpacing,
      speed: -7.5 * (.5 / window.beat),
      particleSize: () => (Sync.get("Objects:CrossScale") + Sync.get('Music:Snare') * Sync.get("Objects:CrossScale") * .5) * Sync.get('Objects:SymbolScale'),
      enabled: "Objects:Penta",
      enabledOnStart: false,
      hueRotateEnabled: 1.0,
      //particleAngleZ: (props) => (Sync.get('Cam:Roll') * Math.PI / 180) - getSceneTimeFromStart() + 18 * props.index,
      colorR: 0.0, colorG: 0.0, colorB: 0.0
    }
  );

  this.addEffectMeshRepeater(0, 240,
    { count: 3, object: "obj/trisomething.obj" },
    {
      x: () => 0, y: () => Math.sin(getSceneTimeFromStart() * 10) * .05, z: symbolSpacing * .5 - gap * 5,
      spacing: symbolSpacing,
      speed: -7.5 * (.5 / window.beat),
      particleSize: () => (1.5 + Sync.get('Music:Snare') * .75) * Sync.get('Objects:SymbolScale'),
      enabled: "Objects:Penta",
      enabledOnStart: false,
      hueRotateEnabled: 1.0,
      particleAngleZ: (props) => (Sync.get('Cam:Roll') * Math.PI / 180) - getSceneTimeFromStart() + 18 * props.index,
      colorR: 0.0, colorG: 0.0, colorB: 1.0
    }
  );



  // das bombs
  let bombStartY = 60;
  let bombEndY = -3;
  const bombFallSpeed = 1; // seconds to complete the fall
  const bombCount = 50;
  const bombSpacing = 3;
  const bombSpeed = -25;
  const bombAbsSpeed = Math.abs(bombSpeed);
  const bombTotalLength = bombCount * bombSpacing;
  const bombCycleTime = bombTotalLength / bombAbsSpeed;

  this.addEffectMeshRepeater(0, 240,
    { count: bombCount, object: "obj/missile.obj" },
    {
      x: () => 0, y: 0.0, z: 0,
      spacing: bombSpacing,
      speed: bombSpeed,
      particleSize: () => .75,
      enabled: "Objects:bombs",
      enabledOnStart: false,
      colorR: 0.0, colorG: 0.0, colorB: 0.0,
      bomb: true,
      seed: 999,
      bombExplosion: {
        enabled: "Objects:bombExplosions",
        bombEndY: bombEndY,
        duration: 2,
        amount: 15,
        particleScale: 6,
        maxDist: 20,
        xStartDim: 0, yStartDim: 0, zStartDim: 0,
        xDim: 1, yDim: 1, zDim: 1,
        xOffset: 0, yOffset: 1, zOffset: 0,
        particleTexture: 'img/exploparticle.png',
        particleTexture2: 'img/dustparticle.png',
      },
      particleX: (props) => {
        const seed = Math.sin(props.index * 9301 + 49297) * 49831;
        return (seed - Math.floor(seed)) * 80 - 40;
      },
      particleZ: (props) => {
        const seed = Math.sin(props.index * 7919 + 12347) * 31337;
        return (seed - Math.floor(seed)) * 35;
      },
      particleY: (props) => {
        const particlePhase = (props.index * bombSpacing) / bombAbsSpeed;
        const localTime = ((getSceneTimeFromStart() + particlePhase) % bombCycleTime + bombCycleTime) % bombCycleTime;
        const t = Math.min(localTime / bombFallSpeed, 1);
        return bombStartY + (bombEndY - bombStartY) * t;
      },
      particleAngleX: (props) => {
        const seed = Math.sin(props.index * 12345 + 67890) * 54321;
        return (seed - Math.floor(seed)) * Math.PI * .5 - Math.PI * .25;
      },
      particleAngleY: (props) => {
        const seed = Math.sin(props.index * 6789 + 13579) * 98765;
        return (seed - Math.floor(seed)) * Math.PI * .5 - Math.PI * .25;
      },
      particleAngleZ: (props) => {
        const seed = Math.sin(props.index * 2468 + 8642) * 19283;
        return (seed - Math.floor(seed)) * Math.PI * .5 - Math.PI * .25;
      }
    }
  );

  const tankYSin = 0.05;
  const tankYSinSpeed = 15;


  this.addEffectMeshRepeater(0, 240,
    { count: 10, object: "obj/uhkatank.obj" },
    {
      x: () => -14.1, y: -1.9, z: -35,
      spacing: 18,
      speed: 7 * (.75 / window.beat),
      particleSize: () => .15,
      enabled: "Objects:Tanks",
      enabledOnStart: false,
      angleY: Math.PI,
      colorR: 1.0, colorG: 1.0, colorB: 1.0,
      particleY: (props) => Math.sin(((props.index * 30) + getSceneTimeFromStart()) * tankYSinSpeed) * tankYSin,
      hackScale: ()=> Sync.get('Objects:TankHackScale')
    }
  );

  this.addEffectMeshRepeater(0, 240,
    { count: 10, object: "obj/uhkatank.obj" },
    {
      x: () => 13, y: -1.9, z: -5,
      spacing: 16,
      speed: 8 * (.75 / window.beat),
      particleSize: () => .15,
      enabled: "Objects:Tanks",
      enabledOnStart: false,
      angleY: Math.PI,
      colorR: 1.0, colorG: 1.0, colorB: 1.0,
      particleY: (props) => Math.sin(((props.index * 30) + getSceneTimeFromStart()) * tankYSinSpeed) * tankYSin,
        hackScale: ()=> Sync.get('Objects:TankHackScale'),
    }
  );

  this.addEffectMeshRepeater(0, 240,
    { count: 10, object: "obj/uhkatank.obj" },
    {
      x: () => 5.5, y: -1.9, z: -35,
      spacing: 17,
      speed: 5 * (.75 / window.beat),
      particleSize: () => .15,
      enabled: "Objects:Tanks",
      enabledOnStart: false,
      angleY: Math.PI,
      colorR: 1.0, colorG: 1.0, colorB: 1.0,
      particleY: (props) => Math.sin(((props.index * 30) + getSceneTimeFromStart()) * tankYSinSpeed) * tankYSin,
            hackScale: ()=> Sync.get('Objects:TankHackScale'),
    }
  );

  this.addEffectMeshRepeater(0, 240,
    { count: 10, object: "obj/uhkatank.obj" },
    {
      x: () => -5.5, y: -1.9, z: -5,
      spacing: 15,
      speed: 6 * (.75 / window.beat),
      particleSize: () => .15,
      enabled: "Objects:Tanks",
      enabledOnStart: false,
      angleY: Math.PI,
      colorR: 1.0, colorG: 1.0, colorB: 1.0,
      particleY: (props) => Math.sin(((props.index * 30) + getSceneTimeFromStart()) * tankYSinSpeed) * tankYSin,
      hackScale: ()=> Sync.get('Objects:TankHackScale'),
    }
  );

  const f15Xoffset = 10;
  const f15Ypos = 7;
  for (let k = 0; k < 2; k++) {
    for (let i = 0; i < 5; i++) {
      const zAdd = Utils.random() * 10 + k * 15;
      this.loader.addAnimation([{
        object: {
          name: "obj/f15.obj",
        }
        , position: [{
          x: f15Xoffset * i - (f15Xoffset * 2),
          y: f15Ypos,
          z: () => zAdd + Sync.get('Objects:F15Z'),
        }],
        angle: [{
          degreesY: 180,
        }]
        , scale: [{ uniform3d: 1.0 }],
        color: [{ r: 0.0, g: 0.0, b: 0.0 }],
        visible: () => Sync.get('Objects:F15Z') > -149,

      }]);
    }
}
this.addHumanoid();

};
