/*
 * This file was automatically generated, do not edit.
 */

#include <geogram/basic/file_system.h>

void register_embedded_glsl_files(
   GEO::FileSystem::MemoryNode* n
);

void register_embedded_glsl_files(
   GEO::FileSystem::MemoryNode* n
) {
     n->create_file("course/raytrace_step1.glsl",
        "// Raytracing tutorial step 1:\n"
        "// Let us draw a red sphere\n"
        "//\n"
        "// Try this: move the \"head\" up and down, left and right,\n"
        "// by changing the point you are looking at in mainImage()\n"
        "\n"
        "// The viewing parameters\n"
        "//\n"
        "struct Camera {\n"
        "    vec3 Obs;    // Position of the \"observer\"\n"
        "    vec3 View;   // Viewing vector\n"
        "    vec3 Up;     // Up direction\n"
        "    vec3 Horiz;  // Horizontal direction\n"
        "    float H;     // Image height (in pixels)\n"
        "    float W;     // Image width (in pixel)\n"
        "    float z;     // Location of the viewing plane along the View vector\n"
        "};\n"
        "\n"
        "// Initializes a camera\n"
        "// Obs:    location of the observer\n"
        "// LookAt: a 3D point the observer is looking at\n"
        "// aperture: camera aperture in degrees\n"
        "//\n"
        "Camera camera(in vec3 Obs, in vec3 LookAt, in float aperture) {\n"
        "   Camera C;\n"
        "   C.Obs = Obs;\n"
        "   C.View = normalize(LookAt - Obs);\n"
        "   C.Horiz = normalize(cross(vec3(0.0, 0.0, 1.0), C.View));\n"
        "   C.Up = cross(C.View, C.Horiz);\n"
        "   C.W = float(iResolution.x);\n"
        "   C.H = float(iResolution.y);\n"
        "   C.z = (C.H/2.0) / tan((aperture * 3.1415 / 180.0) / 2.0);\n"
        "   return C;\n"
        "}\n"
        "\n"
        "\n"
        "struct Ray {\n"
        "    vec3 Origin; // Origin of the ray (for now,\n"
        "                 //  it will be the observer, more to come...)\n"
        "    vec3 Dir;    // Direction of the ray (not necessarily normalized)\n"
        "};\n"
        "\n"
        "\n"
        "// Launches a ray from the camera\n"
        "// C the camera\n"
        "// XY the coordinates of the pixel, in [0..width]x[0..height]\n"
        "//\n"
        "Ray launch(in Camera C, in vec2 XY) {\n"
        "   return Ray(\n"
        "      C.Obs,\n"
        "      C.z*C.View+(XY.x-C.W/2.0)*C.Horiz+(XY.y-C.H/2.0)*C.Up\n"
        "   );\n"
        "}\n"
        "\n"
        "\n"
        "struct Sphere {\n"
        "   vec3 Center; // Center of the sphere\n"
        "   float R;     // Radius of the sphere\n"
        "};\n"
        "\n"
        "// Tests whether there is an intersection between a ray and\n"
        "// a sphere\n"
        "//   in  R: the ray\n"
        "//   in  S: the sphere\n"
        "//   out t: when there is an intersection, it is given by R.Origin + t*R.Dir\n"
        "//   returns true if there is an intersection, false otherwise\n"
        "//\n"
        "bool intersect_sphere(in Ray R, in Sphere S, out float t) {\n"
        "   // How to find the intersection between a ray and a sphere:\n"
        "   // (1) Equation of the sphere: ||M - S.Center||^2 = S.R^2\n"
        "   //      (or dot(M - S.Center, M - S.Center) = S.R*S.R)\n"
        "   // (2) Equation of the ray:    M = R.Origin + t * R.Dir\n"
        "   //      (imagine that a photon starts at R.Origin at time t=0,\n"
        "   //       at time t its location is R.Origin + t * R.Dir)\n"
        "   // Now inject (2) into (1), expand, collect, you end up with\n"
        "   // a quadratic equation in t: a t^2 + b t + c = 0, solve for\n"
        "   // t. There can be 0,1 or 2 solutions (0, 1 or 2 intersections\n"
        "   // between a straight line and a sphere). Take the nearest one.\n"
        "   vec3 CO = R.Origin - S.Center;\n"
        "   float a = dot(R.Dir, R.Dir);\n"
        "   float b = 2.0*dot(R.Dir, CO);\n"
        "   float c = dot(CO, CO) - S.R*S.R;\n"
        "   float delta = b*b - 4.0*a*c;\n"
        "   if(delta < 0.0) {\n"
        "      return false;\n"
        "   }\n"
        "   t = (-b-sqrt(delta)) / (2.0*a);\n"
        "   return true;\n"
        "}\n"
        "\n"
        "// This function is called for each pixel of the image\n"
        "// in fragCoord : the coordinates of the pixel, in [0..width]x[0..height]\n"
        "// out fragColor: the computed color for the pixel\n"
        "//\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord ) {\n"
        "\n"
        "   Camera C = camera(\n"
        "       vec3(2.0, 2.0, 1.5), // You are here\n"
        "       vec3(0.0, 0.0, 0.0), // You are looking at this point\n"
        "       50.0                 // Camera aperture = 50 degrees\n"
        "   );\n"
        "   Ray R = launch(C, fragCoord);\n"
        "   Sphere S = Sphere(vec3(1.3, 0.0, 0.0), 0.2);\n"
        "\n"
        "   // We initialize the color with the background.\n"
        "   vec3 color = vec3(0.2, 0.2, 0.5);\n"
        "\n"
        "   // If there was an intersection with the sphere,\n"
        "   // we paint the pixel in green.\n"
        "   float t;\n"
        "   if(intersect_sphere(R,S,t)) {\n"
        "      color = vec3(0.0, 1.0, 0.5);               \n"
        "   }\n"
        "\n"
        "   // This writes the color to the pixel (the 1.0\n"
        "   // arg. is for transparency, not used here).\n"
        "   fragColor = vec4(color, 1.0);\n"
        "}\n"
        "\n"
     );

     n->create_file("course/raytrace_step2.glsl",
        "// Raytracing tutorial step 2:\n"
        "// The red sphere orbits a circle\n"
        "//\n"
        "// Try this:\n"
        "// - program other motions for the red sphere\n"
        "// - fix the red sphere, program a motion for the camera\n"
        "\n"
        "// The viewing parameters\n"
        "//\n"
        "struct Camera {\n"
        "    vec3 Obs;    // Position of the \"observer\"\n"
        "    vec3 View;   // Viewing vector\n"
        "    vec3 Up;     // Up direction\n"
        "    vec3 Horiz;  // Horizontal direction\n"
        "    float H;     // Image height (in pixels)\n"
        "    float W;     // Image width (in pixel)\n"
        "    float z;     // Location of the viewing plane along the View vector\n"
        "};\n"
        "\n"
        "// Initializes a camera\n"
        "// Obs:    location of the observer\n"
        "// LookAt: a 3D point the observer is looking at\n"
        "// aperture: camera aperture in degrees\n"
        "//\n"
        "Camera camera(in vec3 Obs, in vec3 LookAt, in float aperture) {\n"
        "   Camera C;\n"
        "   C.Obs = Obs;\n"
        "   C.View = normalize(LookAt - Obs);\n"
        "   C.Horiz = normalize(cross(vec3(0.0, 0.0, 1.0), C.View));\n"
        "   C.Up = cross(C.View, C.Horiz);\n"
        "   C.W = float(iResolution.x);\n"
        "   C.H = float(iResolution.y);\n"
        "   C.z = (C.H/2.0) / tan((aperture * 3.1415 / 180.0) / 2.0);\n"
        "   return C;\n"
        "}\n"
        "\n"
        "\n"
        "struct Ray {\n"
        "    vec3 Origin; // Origin of the ray (for now,\n"
        "                 //  it will be the observer, more to come...)\n"
        "    vec3 Dir;    // Direction of the ray (not necessarily normalized)\n"
        "};\n"
        "\n"
        "\n"
        "// Launches a ray from the camera\n"
        "// C the camera\n"
        "// XY the coordinates of the pixel, in [0..width]x[0..height]\n"
        "//\n"
        "Ray launch(in Camera C, in vec2 XY) {\n"
        "   return Ray(\n"
        "      C.Obs,\n"
        "      C.z*C.View+(XY.x-C.W/2.0)*C.Horiz+(XY.y-C.H/2.0)*C.Up\n"
        "   );\n"
        "}\n"
        "\n"
        "\n"
        "struct Sphere {\n"
        "   vec3 Center; // Center of the sphere\n"
        "   float R;     // Radius of the sphere\n"
        "};\n"
        "\n"
        "// Tests whether there is an intersection between a ray and\n"
        "// a sphere\n"
        "//   in  R: the ray\n"
        "//   in  S: the sphere\n"
        "//   out t: when there is an intersection, it is given by R.Origin + t*R.Dir\n"
        "//   returns true if there is an intersection, false otherwise\n"
        "//\n"
        "bool intersect_sphere(in Ray R, in Sphere S, out float t) {\n"
        "   // How to find the intersection between a ray and a sphere:\n"
        "   // (1) Equation of the sphere: ||M - S.Center||^2 = S.R^2\n"
        "   //      (or dot(M - S.Center, M - S.Center) = S.R*S.R)\n"
        "   // (2) Equation of the ray:    M = R.Origin + t * R.Dir\n"
        "   //      (imagine that a photon starts at R.Origin at time t=0,\n"
        "   //       at time t its location is R.Origin + t * R.Dir)\n"
        "   // Now inject (2) into (1), expand, collect, you end up with\n"
        "   // a quadratic equation in t: a t^2 + b t + c = 0, solve for\n"
        "   // t. There can be 0,1 or 2 solutions (0, 1 or 2 intersections\n"
        "   // between a straight line and a sphere). Take the nearest one.\n"
        "   vec3 CO = R.Origin - S.Center;\n"
        "   float a = dot(R.Dir, R.Dir);\n"
        "   float b = 2.0*dot(R.Dir, CO);\n"
        "   float c = dot(CO, CO) - S.R*S.R;\n"
        "   float delta = b*b - 4.0*a*c;\n"
        "   if(delta < 0.0) {\n"
        "      return false;\n"
        "   }\n"
        "   t = (-b-sqrt(delta)) / (2.0*a);\n"
        "   return true;\n"
        "}\n"
        "\n"
        "// This function is called for each pixel of the image\n"
        "// in fragCoord : the coordinates of the pixel, in [0..width]x[0..height]\n"
        "// out fragColor: the computed color for the pixel\n"
        "//\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord ) {\n"
        "\n"
        "   Camera C = camera(\n"
        "       vec3(2.0, 2.0, 1.5), // You are here\n"
        "       vec3(0.0, 0.0, 0.0), // You are looking at this point\n"
        "       50.0                 // Camera aperture = 50 degrees\n"
        "   );\n"
        "   Ray R = launch(C, fragCoord);\n"
        "\n"
        "   // Now let us move the center of the sphere on\n"
        "   // a circular orbit centered on the origin and\n"
        "   // of radius 1.3\n"
        "   // iTime is a builtin variable (in seconds)\n"
        "   // angle goes from 0 to 2 pi in 4 seconds\n"
        "   float angle = iTime * 6.28 / 4.0;\n"
        "   float s = sin(angle);\n"
        "   float c = cos(angle);\n"
        "   Sphere S = Sphere(\n"
        "       vec3(1.3*c, 1.3*s, 0.0), // The center of the sphere\n"
        "       0.2                      // The radius\n"
        "   );\n"
        "\n"
        "   // We initialize the color with the background.\n"
        "   vec3 color = vec3(0.2, 0.2, 0.5);\n"
        "\n"
        "   // If there was an intersection with the sphere,\n"
        "   // we paint the pixel in green.\n"
        "   float t;\n"
        "   if(intersect_sphere(R,S,t)) {\n"
        "      color = vec3(0.0, 1.0, 0.5);               \n"
        "   }\n"
        "\n"
        "   // This writes the color to the pixel (the 1.0\n"
        "   // arg. is for transparency, not used here).\n"
        "   fragColor = vec4(color, 1.0);\n"
        "}\n"
        "\n"
     );

     n->create_file("course/raytrace_step3.glsl",
        "// Raytracing tutorial step 3:\n"
        "// Now the red sphere orbits around a white one\n"
        "//\n"
        "// Try this:\n"
        "// - what happens if you enlarge the radii of the two spheres ?\n"
        "//   how can you explain that ?\n"
        "// - add a blue sphere that orbits around the red one\n"
        "//   (like a \"moon\" of the \"red planet\")\n"
        "// - add other spheres with other motions\n"
        "\n"
        "\n"
        "// The viewing parameters\n"
        "//\n"
        "struct Camera {\n"
        "    vec3 Obs;    // Position of the \"observer\"\n"
        "    vec3 View;   // Viewing vector\n"
        "    vec3 Up;     // Up direction\n"
        "    vec3 Horiz;  // Horizontal direction\n"
        "    float H;     // Image height (in pixels)\n"
        "    float W;     // Image width (in pixel)\n"
        "    float z;     // Location of the viewing plane along the View vector\n"
        "};\n"
        "\n"
        "// Initializes a camera\n"
        "// Obs:    location of the observer\n"
        "// LookAt: a 3D point the observer is looking at\n"
        "// aperture: camera aperture in degrees\n"
        "//\n"
        "Camera camera(in vec3 Obs, in vec3 LookAt, in float aperture) {\n"
        "   Camera C;\n"
        "   C.Obs = Obs;\n"
        "   C.View = normalize(LookAt - Obs);\n"
        "   C.Horiz = normalize(cross(vec3(0.0, 0.0, 1.0), C.View));\n"
        "   C.Up = cross(C.View, C.Horiz);\n"
        "   C.W = float(iResolution.x);\n"
        "   C.H = float(iResolution.y);\n"
        "   C.z = (C.H/2.0) / tan((aperture * 3.1415 / 180.0) / 2.0);\n"
        "   return C;\n"
        "}\n"
        "\n"
        "\n"
        "struct Ray {\n"
        "    vec3 Origin; // Origin of the ray (for now,\n"
        "                 //  it will be the observer, more to come...)\n"
        "    vec3 Dir;    // Direction of the ray (not necessarily normalized)\n"
        "};\n"
        "\n"
        "\n"
        "// Launches a ray from the camera\n"
        "// C the camera\n"
        "// XY the coordinates of the pixel, in [0..width]x[0..height]\n"
        "//\n"
        "Ray launch(in Camera C, in vec2 XY) {\n"
        "   return Ray(\n"
        "      C.Obs,\n"
        "      C.z*C.View+(XY.x-C.W/2.0)*C.Horiz+(XY.y-C.H/2.0)*C.Up\n"
        "   );\n"
        "}\n"
        "\n"
        "\n"
        "struct Sphere {\n"
        "   vec3 Center; // Center of the sphere\n"
        "   float R;     // Radius of the sphere\n"
        "};\n"
        "\n"
        "// Tests whether there is an intersection between a ray and\n"
        "// a sphere\n"
        "//   in  R: the ray\n"
        "//   in  S: the sphere\n"
        "//   out t: when there is an intersection, it is given by R.Origin + t*R.Dir\n"
        "//   returns true if there is an intersection, false otherwise\n"
        "//\n"
        "bool intersect_sphere(in Ray R, in Sphere S, out float t) {\n"
        "   // How to find the intersection between a ray and a sphere:\n"
        "   // (1) Equation of the sphere: ||M - S.Center||^2 = S.R^2\n"
        "   //      (or dot(M - S.Center, M - S.Center) = S.R*S.R)\n"
        "   // (2) Equation of the ray:    M = R.Origin + t * R.Dir\n"
        "   //      (imagine that a photon starts at R.Origin at time t=0,\n"
        "   //       at time t its location is R.Origin + t * R.Dir)\n"
        "   // Now inject (2) into (1), expand, collect, you end up with\n"
        "   // a quadratic equation in t: a t^2 + b t + c = 0, solve for\n"
        "   // t. There can be 0,1 or 2 solutions (0, 1 or 2 intersections\n"
        "   // between a straight line and a sphere). Take the nearest one.\n"
        "   vec3 CO = R.Origin - S.Center;\n"
        "   float a = dot(R.Dir, R.Dir);\n"
        "   float b = 2.0*dot(R.Dir, CO);\n"
        "   float c = dot(CO, CO) - S.R*S.R;\n"
        "   float delta = b*b - 4.0*a*c;\n"
        "   if(delta < 0.0) {\n"
        "      return false;\n"
        "   }\n"
        "   t = (-b-sqrt(delta)) / (2.0*a);\n"
        "   return true;\n"
        "}\n"
        "\n"
        "// This function is called for each pixel of the image\n"
        "// in fragCoord : the coordinates of the pixel, in [0..width]x[0..height]\n"
        "// out fragColor: the computed color for the pixel\n"
        "//\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord ) {\n"
        "\n"
        "   Camera C = camera(\n"
        "       vec3(2.0, 2.0, 1.5), // You are here\n"
        "       vec3(0.0, 0.0, 0.0), // You are looking at this point\n"
        "       50.0                 // Camera aperture = 50 degrees\n"
        "   );\n"
        "   Ray R = launch(C, fragCoord);\n"
        "\n"
        "\n"
        "   // A sphere centered on the origin\n"
        "   // (this one does not move)\n"
        "   Sphere sun = Sphere(\n"
        "       vec3(0.0, 0.0, 0.0),\n"
        "       0.3\n"
        "   );\n"
        "\n"
        "   // Another sphere that moves on a\n"
        "   // a circular orbit centered on the origin and\n"
        "   // of radius 1.3\n"
        "   // iTime is a builtin variable (in seconds)\n"
        "   // angle goes from 0 to 2 pi in 4 seconds\n"
        "   float angle = iTime * 6.28 / 4.0;\n"
        "   float s = sin(angle);\n"
        "   float c = cos(angle);\n"
        "   Sphere planet = Sphere(\n"
        "       vec3(1.3*c, 1.3*s, 0.0), // The center of the sphere\n"
        "       0.2                      // The radius\n"
        "   );\n"
        "\n"
        "   // We initialize the color with the background.\n"
        "   vec3 color = vec3(0.2, 0.2, 0.5);\n"
        "\n"
        "   // t corresponds to the distance to the nearest intersection\n"
        "   // along the ray. We initialize it to a large value, meaning\n"
        "   // that what we see is the sky, at infinity.\n"
        "   float t = 1e30;\n"
        "\n"
        "   // If there is an intersection with the first sphere,\n"
        "   // and if this intersection is nearer than the current one\n"
        "   // (this second condition will be always true since the previous\n"
        "   // t parameter corresponds to the sky at infinity, anything is\n"
        "   // nearer...), then update t, and paint the current pixel in red.\n"
        "   float cur_t;\n"
        "   if(intersect_sphere(R,sun,cur_t) && cur_t < t) {\n"
        "      t = cur_t;\n"
        "      color = vec3(1.0, 1.0, 1.0);\n"
        "   }\n"
        "\n"
        "   // If there is an intersection with the second sphere,\n"
        "   // and if this intersection is nearer than the current one,\n"
        "   // then update t, and paint the current pixel in white.\n"
        "   if(intersect_sphere(R,planet,cur_t) && cur_t < t) {\n"
        "      t = cur_t;\n"
        "      color = vec3(0.0, 1.0, 0.5);\n"
        "   }\n"
        "\n"
        "   // This writes the color to the pixel (the 1.0\n"
        "   // arg. is for transparency, not used here).\n"
        "   fragColor = vec4(color, 1.0);\n"
        "}\n"
        "\n"
     );

     n->create_file("course/raytrace_step4.glsl",
        "// Raytracing tutorial step 4:\n"
        "// Let there be light !\n"
        "\n"
        "// The viewing parameters\n"
        "//\n"
        "struct Camera {\n"
        "    vec3 Obs;    // Position of the \"observer\"\n"
        "    vec3 View;   // Viewing vector\n"
        "    vec3 Up;     // Up direction\n"
        "    vec3 Horiz;  // Horizontal direction\n"
        "    float H;     // Image height (in pixels)\n"
        "    float W;     // Image width (in pixel)\n"
        "    float z;     // Location of the viewing plane along the View vector\n"
        "};\n"
        "\n"
        "// Initializes a camera\n"
        "// Obs:    location of the observer\n"
        "// LookAt: a 3D point the observer is looking at\n"
        "// aperture: camera aperture in degrees\n"
        "//\n"
        "Camera camera(in vec3 Obs, in vec3 LookAt, in float aperture) {\n"
        "   Camera C;\n"
        "   C.Obs = Obs;\n"
        "   C.View = normalize(LookAt - Obs);\n"
        "   C.Horiz = normalize(cross(vec3(0.0, 0.0, 1.0), C.View));\n"
        "   C.Up = cross(C.View, C.Horiz);\n"
        "   C.W = float(iResolution.x);\n"
        "   C.H = float(iResolution.y);\n"
        "   C.z = (C.H/2.0) / tan((aperture * 3.1415 / 180.0) / 2.0);\n"
        "   return C;\n"
        "}\n"
        "\n"
        "\n"
        "struct Ray {\n"
        "    vec3 Origin; // Origin of the ray (for now,\n"
        "                 //  it will be the observer, more to come...)\n"
        "    vec3 Dir;    // Direction of the ray (not necessarily normalized)\n"
        "};\n"
        "\n"
        "\n"
        "// Launches a ray from the camera\n"
        "// C the camera\n"
        "// XY the coordinates of the pixel, in [0..width]x[0..height]\n"
        "//\n"
        "Ray launch(in Camera C, in vec2 XY) {\n"
        "   return Ray(\n"
        "      C.Obs,\n"
        "      C.z*C.View+(XY.x-C.W/2.0)*C.Horiz+(XY.y-C.H/2.0)*C.Up\n"
        "   );\n"
        "}\n"
        "\n"
        "\n"
        "struct Sphere {\n"
        "   vec3 Center; // Center of the sphere\n"
        "   float R;     // Radius of the sphere\n"
        "};\n"
        "\n"
        "// Tests whether there is an intersection between a ray and\n"
        "// a sphere\n"
        "//   in  R: the ray\n"
        "//   in  S: the sphere\n"
        "//   out t: when there is an intersection, it is given by R.Origin + t*R.Dir\n"
        "//   returns true if there is an intersection, false otherwise\n"
        "//\n"
        "bool intersect_sphere(in Ray R, in Sphere S, out float t) {\n"
        "   // How to find the intersection between a ray and a sphere:\n"
        "   // (1) Equation of the sphere: ||M - S.Center||^2 = S.R^2\n"
        "   //      (or dot(M - S.Center, M - S.Center) = S.R*S.R)\n"
        "   // (2) Equation of the ray:    M = R.Origin + t * R.Dir\n"
        "   //      (imagine that a photon starts at R.Origin at time t=0,\n"
        "   //       at time t its location is R.Origin + t * R.Dir)\n"
        "   // Now inject (2) into (1), expand, collect, you end up with\n"
        "   // a quadratic equation in t: a t^2 + b t + c = 0, solve for\n"
        "   // t. There can be 0,1 or 2 solutions (0, 1 or 2 intersections\n"
        "   // between a straight line and a sphere). Take the nearest one.\n"
        "   vec3 CO = R.Origin - S.Center;\n"
        "   float a = dot(R.Dir, R.Dir);\n"
        "   float b = 2.0*dot(R.Dir, CO);\n"
        "   float c = dot(CO, CO) - S.R*S.R;\n"
        "   float delta = b*b - 4.0*a*c;\n"
        "   if(delta < 0.0) {\n"
        "      return false;\n"
        "   }\n"
        "   t = (-b-sqrt(delta)) / (2.0*a);\n"
        "   return true;\n"
        "}\n"
        "\n"
        "// This function is called for each pixel of the image\n"
        "// in fragCoord : the coordinates of the pixel, in [0..width]x[0..height]\n"
        "// out fragColor: the computed color for the pixel\n"
        "//\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord ) {\n"
        "\n"
        "   Camera C = camera(\n"
        "       vec3(2.0, 2.0, 1.5), // You are here\n"
        "       vec3(0.0, 0.0, 0.0), // You are looking at this point\n"
        "       50.0                 // Camera aperture = 50 degrees\n"
        "   );\n"
        "   Ray R = launch(C, fragCoord);\n"
        "\n"
        "   Sphere sun = Sphere(\n"
        "      vec3(0.0, 0.0, 0.0),\n"
        "      0.3\n"
        "   );\n"
        "\n"
        "   float angle = iTime * 6.28 / 4.0;\n"
        "   float s = sin(angle);\n"
        "   float c = cos(angle);\n"
        "   Sphere planet = Sphere(\n"
        "       vec3(1.3*c, 1.3*s, 0.0),\n"
        "       0.2\n"
        "   );\n"
        "\n"
        "   // Background color\n"
        "   vec3 color = vec3(0.2, 0.2, 0.5);\n"
        "\n"
        "   // t corresponds to the distance to the nearest intersection\n"
        "   // along the ray. We initialize it to a large value, meaning\n"
        "   // that what we see is the sky, at infinity.\n"
        "   float t = 1e30;\n"
        "   float cur_t;\n"
        "\n"
        "   // The sun\n"
        "   if(intersect_sphere(R,sun,cur_t) && cur_t < t) {\n"
        "      t = cur_t;\n"
        "      color = vec3(1.0, 1.0, 1.0);\n"
        "   }\n"
        "\n"
        "   // The planet\n"
        "   if(intersect_sphere(R,planet,cur_t) && cur_t < t) {\n"
        "      t = cur_t;\n"
        "      // Compute the intersection point\n"
        "      vec3 I = R.Origin + t * R.Dir;\n"
        "      // Compute the normal vector to the sphere at\n"
        "      // the intersection point\n"
        "      vec3 N = I - planet.Center;\n"
        "      // Lambert law: lighting = cosine of the angle between\n"
        "      // the normal vector N and the light vector L-I\n"
        "      float lamb = dot(N,sun.Center-I)/(length(N)*length(sun.Center-I));\n"
        "      lamb = max(lamb,0.0);\n"
        "      color = lamb * vec3(0.0, 1.0, 0.5);\n"
        "   }\n"
        "\n"
        "   fragColor = vec4(color, 1.0);\n"
        "}\n"
        "\n"
     );

     n->create_file("course/raytrace_step5.glsl",
        "// Raytracing tutorial step 5:\n"
        "// Fly me to the moon !\n"
        "\n"
        "// The viewing parameters\n"
        "//\n"
        "struct Camera {\n"
        "    vec3 Obs;    // Position of the \"observer\"\n"
        "    vec3 View;   // Viewing vector\n"
        "    vec3 Up;     // Up direction\n"
        "    vec3 Horiz;  // Horizontal direction\n"
        "    float H;     // Image height (in pixels)\n"
        "    float W;     // Image width (in pixel)\n"
        "    float z;     // Location of the viewing plane along the View vector\n"
        "};\n"
        "\n"
        "// Initializes a camera\n"
        "// Obs:    location of the observer\n"
        "// LookAt: a 3D point the observer is looking at\n"
        "// aperture: camera aperture in degrees\n"
        "//\n"
        "Camera camera(in vec3 Obs, in vec3 LookAt, in float aperture) {\n"
        "   Camera C;\n"
        "   C.Obs = Obs;\n"
        "   C.View = normalize(LookAt - Obs);\n"
        "   C.Horiz = normalize(cross(vec3(0.0, 0.0, 1.0), C.View));\n"
        "   C.Up = cross(C.View, C.Horiz);\n"
        "   C.W = float(iResolution.x);\n"
        "   C.H = float(iResolution.y);\n"
        "   C.z = (C.H/2.0) / tan((aperture * 3.1415 / 180.0) / 2.0);\n"
        "   return C;\n"
        "}\n"
        "\n"
        "\n"
        "struct Ray {\n"
        "    vec3 Origin; // Origin of the ray (for now,\n"
        "                 //  it will be the observer, more to come...)\n"
        "    vec3 Dir;    // Direction of the ray (not necessarily normalized)\n"
        "};\n"
        "\n"
        "\n"
        "// Launches a ray from the camera\n"
        "// C the camera\n"
        "// XY the coordinates of the pixel, in [0..width]x[0..height]\n"
        "//\n"
        "Ray launch(in Camera C, in vec2 XY) {\n"
        "   return Ray(\n"
        "      C.Obs,\n"
        "      C.z*C.View+(XY.x-C.W/2.0)*C.Horiz+(XY.y-C.H/2.0)*C.Up\n"
        "   );\n"
        "}\n"
        "\n"
        "\n"
        "struct Sphere {\n"
        "   vec3 Center; // Center of the sphere\n"
        "   float R;     // Radius of the sphere\n"
        "};\n"
        "\n"
        "// Tests whether there is an intersection between a ray and\n"
        "// a sphere\n"
        "//   in  R: the ray\n"
        "//   in  S: the sphere\n"
        "//   out t: when there is an intersection, it is given by R.Origin + t*R.Dir\n"
        "//   returns true if there is an intersection, false otherwise\n"
        "//\n"
        "bool intersect_sphere(in Ray R, in Sphere S, out float t) {\n"
        "   // How to find the intersection between a ray and a sphere:\n"
        "   // (1) Equation of the sphere: ||M - S.Center||^2 = S.R^2\n"
        "   //      (or dot(M - S.Center, M - S.Center) = S.R*S.R)\n"
        "   // (2) Equation of the ray:    M = R.Origin + t * R.Dir\n"
        "   //      (imagine that a photon starts at R.Origin at time t=0,\n"
        "   //       at time t its location is R.Origin + t * R.Dir)\n"
        "   // Now inject (2) into (1), expand, collect, you end up with\n"
        "   // a quadratic equation in t: a t^2 + b t + c = 0, solve for\n"
        "   // t. There can be 0,1 or 2 solutions (0, 1 or 2 intersections\n"
        "   // between a straight line and a sphere). Take the nearest one.\n"
        "   vec3 CO = R.Origin - S.Center;\n"
        "   float a = dot(R.Dir, R.Dir);\n"
        "   float b = 2.0*dot(R.Dir, CO);\n"
        "   float c = dot(CO, CO) - S.R*S.R;\n"
        "   float delta = b*b - 4.0*a*c;\n"
        "   if(delta < 0.0) {\n"
        "      return false;\n"
        "   }\n"
        "   t = (-b-sqrt(delta)) / (2.0*a);\n"
        "   return true;\n"
        "}\n"
        "\n"
        "// This function is called for each pixel of the image\n"
        "// in fragCoord : the coordinates of the pixel, in [0..width]x[0..height]\n"
        "// out fragColor: the computed color for the pixel\n"
        "//\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord ) {\n"
        "\n"
        "   Camera C = camera(\n"
        "       vec3(2.0, 2.0, 1.5), // You are here\n"
        "       vec3(0.0, 0.0, 0.0), // You are looking at this point\n"
        "       50.0                 // Camera aperture = 50 degrees\n"
        "   );\n"
        "   Ray R = launch(C, fragCoord);\n"
        "\n"
        "\n"
        "\n"
        "   // The sun\n"
        "   Sphere sun = Sphere(\n"
        "       vec3(0.0, 0.0, 0.0),\n"
        "       0.3\n"
        "   );\n"
        "\n"
        "   // A planet that turns around the sun\n"
        "   float angle1 = iTime * 6.28 / 4.0;\n"
        "   float s1 = sin(angle1);\n"
        "   float c1 = cos(angle1);\n"
        "   float x1 = 1.3*c1;\n"
        "   float y1 = 1.3*s1;\n"
        "   Sphere planet = Sphere(\n"
        "       vec3(x1, y1, 0.0),\n"
        "       0.2\n"
        "   );\n"
        "\n"
        "\n"
        "   // A moon that turns around the planet\n"
        "   float angle2 = iTime * 6.28 * 2.0;\n"
        "   float s2 = sin(angle2);\n"
        "   float c2 = cos(angle2);\n"
        "   float x2 = 0.5*c2;\n"
        "   float y2 = 0.5*s2;\n"
        "   Sphere moon = Sphere(\n"
        "       vec3(x1+x2, y1+y2, 0.0),\n"
        "       0.05\n"
        "   );\n"
        "\n"
        "   // Background color\n"
        "   vec3 color = vec3(0.2, 0.2, 0.5);\n"
        "\n"
        "   float t = 1e30;\n"
        "   float cur_t;\n"
        "\n"
        "   if(intersect_sphere(R,sun,cur_t) && cur_t < t) {\n"
        "      t = cur_t;\n"
        "      color = vec3(1.0, 1.0, 1.0);\n"
        "   }\n"
        "\n"
        "   if(intersect_sphere(R,planet,cur_t) && cur_t < t) {\n"
        "      t = cur_t;\n"
        "      // Compute the intersection point\n"
        "      vec3 I = R.Origin + t * R.Dir;\n"
        "\n"
        "\n"
        "      Ray lighting_ray = Ray(I, sun.Center-I);\n"
        "      float lighting_t;\n"
        "      // Compute the normal vector to the sphere at\n"
        "      // the intersection point\n"
        "      vec3 N = I - planet.Center;\n"
        "      // Lambert law: lighting = cosine of the angle between\n"
        "      // the normal vector N and the light vector L-I\n"
        "      float lamb = dot(N,sun.Center-I)/(length(N)*length(sun.Center-I));\n"
        "      lamb = max(lamb,0.0);\n"
        "      color = lamb * vec3(0.0, 1.0, 0.5);\n"
        "   }\n"
        "\n"
        "   if(intersect_sphere(R,moon,cur_t) && cur_t < t) {\n"
        "      t = cur_t;\n"
        "      color = vec3(1.0, 1.0, 0.0);\n"
        "   }\n"
        "\n"
        "   fragColor = vec4(color, 1.0);\n"
        "\n"
        "}\n"
        "\n"
     );

     n->create_file("course/raytrace_step6.glsl",
        "// Raytracing tutorial step 6:\n"
        "// Eclipses\n"
        "//\n"
        "// Try this:\n"
        "// - implement lighting for the moon\n"
        "//   (including the shadow cast by the planet)\n"
        "\n"
        "// The viewing parameters\n"
        "//\n"
        "struct Camera {\n"
        "    vec3 Obs;    // Position of the \"observer\"\n"
        "    vec3 View;   // Viewing vector\n"
        "    vec3 Up;     // Up direction\n"
        "    vec3 Horiz;  // Horizontal direction\n"
        "    float H;     // Image height (in pixels)\n"
        "    float W;     // Image width (in pixel)\n"
        "    float z;     // Location of the viewing plane along the View vector\n"
        "};\n"
        "\n"
        "// Initializes a camera\n"
        "// Obs:    location of the observer\n"
        "// LookAt: a 3D point the observer is looking at\n"
        "// aperture: camera aperture in degrees\n"
        "//\n"
        "Camera camera(in vec3 Obs, in vec3 LookAt, in float aperture) {\n"
        "   Camera C;\n"
        "   C.Obs = Obs;\n"
        "   C.View = normalize(LookAt - Obs);\n"
        "   C.Horiz = normalize(cross(vec3(0.0, 0.0, 1.0), C.View));\n"
        "   C.Up = cross(C.View, C.Horiz);\n"
        "   C.W = float(iResolution.x);\n"
        "   C.H = float(iResolution.y);\n"
        "   C.z = (C.H/2.0) / tan((aperture * 3.1415 / 180.0) / 2.0);\n"
        "   return C;\n"
        "}\n"
        "\n"
        "\n"
        "struct Ray {\n"
        "    vec3 Origin; // Origin of the ray (for now,\n"
        "                 //  it will be the observer, more to come...)\n"
        "    vec3 Dir;    // Direction of the ray (not necessarily normalized)\n"
        "};\n"
        "\n"
        "\n"
        "// Launches a ray from the camera\n"
        "// C the camera\n"
        "// XY the coordinates of the pixel, in [0..width]x[0..height]\n"
        "//\n"
        "Ray launch(in Camera C, in vec2 XY) {\n"
        "   return Ray(\n"
        "      C.Obs,\n"
        "      C.z*C.View+(XY.x-C.W/2.0)*C.Horiz+(XY.y-C.H/2.0)*C.Up\n"
        "   );\n"
        "}\n"
        "\n"
        "\n"
        "struct Sphere {\n"
        "   vec3 Center; // Center of the sphere\n"
        "   float R;     // Radius of the sphere\n"
        "};\n"
        "\n"
        "// Tests whether there is an intersection between a ray and\n"
        "// a sphere\n"
        "//   in  R: the ray\n"
        "//   in  S: the sphere\n"
        "//   out t: when there is an intersection, it is given by R.Origin + t*R.Dir\n"
        "//   returns true if there is an intersection, false otherwise\n"
        "//\n"
        "bool intersect_sphere(in Ray R, in Sphere S, out float t) {\n"
        "   // How to find the intersection between a ray and a sphere:\n"
        "   // (1) Equation of the sphere: ||M - S.Center||^2 = S.R^2\n"
        "   //      (or dot(M - S.Center, M - S.Center) = S.R*S.R)\n"
        "   // (2) Equation of the ray:    M = R.Origin + t * R.Dir\n"
        "   //      (imagine that a photon starts at R.Origin at time t=0,\n"
        "   //       at time t its location is R.Origin + t * R.Dir)\n"
        "   // Now inject (2) into (1), expand, collect, you end up with\n"
        "   // a quadratic equation in t: a t^2 + b t + c = 0, solve for\n"
        "   // t. There can be 0,1 or 2 solutions (0, 1 or 2 intersections\n"
        "   // between a straight line and a sphere). Take the nearest one.\n"
        "   vec3 CO = R.Origin - S.Center;\n"
        "   float a = dot(R.Dir, R.Dir);\n"
        "   float b = 2.0*dot(R.Dir, CO);\n"
        "   float c = dot(CO, CO) - S.R*S.R;\n"
        "   float delta = b*b - 4.0*a*c;\n"
        "   if(delta < 0.0) {\n"
        "      return false;\n"
        "   }\n"
        "   t = (-b-sqrt(delta)) / (2.0*a);\n"
        "   return true;\n"
        "}\n"
        "\n"
        "// This function is called for each pixel of the image\n"
        "// in fragCoord : the coordinates of the pixel, in [0..width]x[0..height]\n"
        "// out fragColor: the computed color for the pixel\n"
        "//\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord ) {\n"
        "\n"
        "   Camera C = camera(\n"
        "       vec3(2.0, 2.0, 1.5), // You are here\n"
        "       vec3(0.0, 0.0, 0.0), // You are looking at this point\n"
        "       50.0                 // Camera aperture = 50 degrees\n"
        "   );\n"
        "   Ray R = launch(C, fragCoord);\n"
        "\n"
        "\n"
        "\n"
        "   // The sun\n"
        "   Sphere sun = Sphere(\n"
        "       vec3(0.0, 0.0, 0.0),\n"
        "       0.3\n"
        "   );\n"
        "\n"
        "   // A planet that turns around the sun\n"
        "   float angle1 = iTime * 6.28 / 4.0;\n"
        "   float s1 = sin(angle1);\n"
        "   float c1 = cos(angle1);\n"
        "   float x1 = 1.3*c1;\n"
        "   float y1 = 1.3*s1;\n"
        "   Sphere planet = Sphere(\n"
        "       vec3(x1, y1, 0.0),\n"
        "       0.2\n"
        "   );\n"
        "\n"
        "\n"
        "   // A moon that turns around the planet\n"
        "   float angle2 = iTime * 6.28 / 2.0;\n"
        "   float s2 = sin(angle2);\n"
        "   float c2 = cos(angle2);\n"
        "   float x2 = 0.5*c2;\n"
        "   float y2 = 0.5*s2;\n"
        "   Sphere moon = Sphere(\n"
        "       vec3(x1+x2, y1+y2, 0.0),\n"
        "       0.05\n"
        "   );\n"
        "\n"
        "   // Background color\n"
        "   vec3 color = vec3(0.2, 0.2, 0.5);\n"
        "\n"
        "   float t = 1e30;\n"
        "   float cur_t;\n"
        "\n"
        "   if(intersect_sphere(R,sun,cur_t) && cur_t < t) {\n"
        "      t = cur_t;\n"
        "      color = vec3(1.0, 1.0, 1.0);\n"
        "   }\n"
        "\n"
        "   if(intersect_sphere(R,planet,cur_t) && cur_t < t) {\n"
        "      t = cur_t;\n"
        "      // Compute the intersection point\n"
        "      vec3 I = R.Origin + t * R.Dir;\n"
        "\n"
        "\n"
        "      Ray lighting_ray = Ray(I, sun.Center-I);\n"
        "      float lighting_t;\n"
        "      if(intersect_sphere(lighting_ray,moon,lighting_t) &&\n"
        "         lighting_t > 0.0 && lighting_t < 1.0\n"
        "      ) {\n"
        "         color = vec3(0.0, 0.0, 0.0);\n"
        "      } else {\n"
        "         // Compute the normal vector to the sphere at\n"
        "         // the intersection point\n"
        "         vec3 N = I - planet.Center;\n"
        "         // Lambert law: lighting = cosine of the angle between\n"
        "         // the normal vector N and the light vector L-I\n"
        "         float lamb = dot(N,sun.Center-I)/(length(N)*length(sun.Center-I));\n"
        "         lamb = max(lamb,0.0);\n"
        "         color = lamb * vec3(0.0, 1.0, 0.5);\n"
        "      }\n"
        "   }\n"
        "\n"
        "   if(intersect_sphere(R,moon,cur_t) && cur_t < t) {\n"
        "      t = cur_t;\n"
        "      color = vec3(1.0, 1.0, 0.0);\n"
        "   }\n"
        "\n"
        "   fragColor = vec4(color, 1.0);\n"
        "\n"
        "}\n"
        "\n"
     );

     n->create_file("ShaderToy/AlloyPlatedVoronoi.glsl",
        "// https://www.shadertoy.com/view/XdfyWM\n"
        "\n"
        "/*\n"
        "\n"
        "    Alloy Plated Voronoi\n"
        "    --------------------\n"
        "\n"
        "    This was originally a rigid scrolling example, but I thought the movement looked more\n"
        "    interesting. Obviously, hard, fluid alloy doesn't make a lot of physical sense, so if the\n"
        "    situation really messes with your sense of correctness, uncomment the \"RIGID_SCOLL\"\n"
        "    define... or just pretend it's futuristic alien alloy from another dimension. :D\n"
        "\n"
        "    From a technical perspective, it's a couple of smooth Voronoi layers (based on IQ's\n"
        "    article below), split into fractional contours then bump mapped. Hardly cutting edge,\n"
        "    and    not all that exciting. One of the things that did require some effort was producing\n"
        "    the succinct smooth borders with enough quality to allow for pronounced bump mapping\n"
        "    with minimal artifacts. The results are sufficient, but there are probably more efficent\n"
        "    ways to achieve the same.\n"
        "\n"
        "    I was going for a tarnished silver kind of look. Not sure whether it worked, but it looks\n"
        "    shiny, so that's good enough for me. :) When I first started taking an interest in graphics,\n"
        "    my idea of producing a metallic looking object was to render it flat grey, then add some\n"
        "    ambient lighting... Yes, I was \"that\" naive. :D\n"
        "\n"
        "    These days, I apply a little more science, but a lot of it is still made up. Specular\n"
        "    lighting and fake reflections help add to the illusion, but I find that    ramping the diffuse\n"
        "    light to a few powers tends to work best. Also, to give the light more angularity, I\n"
        "    accentuated the bump mapping more than I usually would.\n"
        "\n"
        "    \n"
        "    \n"
        "\n"
        "    Similar Examples:\n"
        "\n"
        "    Voronoi - smooth - iq\n"
        "    https://www.shadertoy.com/view/ldB3zc\n"
        "\n"
        "    // Great accompanying article.\n"
        "    http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm\n"
        "\n"
        "\n"
        "    // A cleaner, more simplistic rendering.\n"
        "    Smooth Voronoi Contours - Shane\n"
        "    https://www.shadertoy.com/view/4sdXDX\n"
        "\n"
        "\n"
        "*/\n"
        "\n"
        "//#define RIGID_SCROLL\n"
        "\n"
        "// Gradient factor. See the \"func\" function. It's a fudge factor used to make the contour lines appear\n"
        "// unison in width. It's a mildly expensive calulation, and I'm reusing it, so it's global. I'll try to\n"
        "// localize it later.\n"
        "float gF;\n"
        "\n"
        "//float sFract(float x, float sm){ float fx = fract(x); return fx - smoothstep(fwidth(x)*sm, 0., 1. - fx); }\n"
        "//float sFract(float x, float sm){ float fx = fract(x); return min(fx, fx*(1. - fx)/gF/sm); }//fwidth(x)\n"
        "\n"
        "// Based on Ollj's smooth \"fract\" formula.\n"
        "float sFract(float x, float sm){\n"
        "\n"
        "    // Extra smoothing factor. \"1\" is the norm.\n"
        "    const float sf = .5;\n"
        "\n"
        "    // The hardware \"fwidth\" is cheap, but you could take the expensive route and\n"
        "    // calculate it by hand if more quality was required.\n"
        "    vec2 u = vec2(x, fwidth(x)*sf*sm);\n"
        "\n"
        "    // Ollj's original formula with a transcendental term omitted.\n"
        "    u.x = fract(u.x);\n"
        "    u += (1. - 2.*u)*step(u.y, u.x);\n"
        "    return clamp(1. - u.x/u.y, 0., 1.); // Cos term ommitted.\n"
        "}\n"
        "\n"
        "\n"
        "\n"
        "float sFloor(float x){ return x - sFract(x, 1.); } // Only works for nonnegative \"x,\" which is fine here.\n"
        "\n"
        "\n"
        "// Standard hue rotation formula with a bit of streamlining.\n"
        "vec3 rotHue(vec3 p, float a){\n"
        "\n"
        "    vec2 cs = sin(vec2(1.570796, 0) + a);\n"
        "\n"
        "    mat3 hr = mat3(0.299,  0.587,  0.114,  0.299,  0.587,  0.114,  0.299,  0.587,  0.114) +\n"
        "              mat3(0.701, -0.587, -0.114, -0.299,  0.413, -0.114, -0.300, -0.588,  0.886) * cs.x +\n"
        "              mat3(0.168,  0.330, -0.497, -0.328,  0.035,  0.292,  1.250, -1.050, -0.203) * cs.y;\n"
        "                            \n"
        "    return clamp(p*hr, 0., 1.);\n"
        "}\n"
        "\n"
        "\n"
        "// Standard 2x2 hash algorithm.\n"
        "vec2 hash22(vec2 p) {\n"
        "\n"
        "    // Faster, but probaly doesn't disperse things as nicely as other methods.\n"
        "    float n = sin(dot(p, vec2(41, 289)));\n"
        "    p = fract(vec2(2097152, 262144)*n);\n"
        "    #ifdef RIGID_SCROLL\n"
        "    return p - .5;\n"
        "    #else\n"
        "    return cos(p*6.283 + iTime)*.5;\n"
        "    //return abs(fract(p+ iTime*.25)-.5)*2. - .5; // Snooker.\n"
        "    //return abs(cos(p*6.283 + iTime))*.5; // Bounce.\n"
        "    #endif\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "// vec3 to vec3 hash algorithm.\n"
        "vec3 hash33(vec3 p) {\n"
        "\n"
        "    // Faster, but doesn't disperse things quite as nicely as the block below it. However, when framerate\n"
        "    // is an issue, and it often is, this is the one to use. Basically, it's a tweaked amalgamation I put\n"
        "    // together, based on a couple of other random algorithms I've seen around... so use it with caution,\n"
        "    // because I make a tonne of mistakes. :)\n"
        "    float n = sin(dot(p, vec3(7, 157, 113)));\n"
        "    return fract(vec3(2097152, 262144, 32768)*n)*2. - 1.; // return fract(vec3(64, 8, 1)*32768.0*n)*2.-1.;\n"
        "\n"
        "    // I'll assume the following came from IQ.\n"
        "    //p = vec3( dot(p, vec3(127.1, 311.7, 74.7)), dot(p, vec3(269.5, 183.3, 246.1)), dot(p, vec3(113.5, 271.9, 124.6)));\n"
        "    //return (fract(sin(p)*43758.5453)*2. - 1.);\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "\n"
        "// Cheap, streamlined 3D Simplex noise... of sorts. I cut a few corners, so it's not perfect, but it's\n"
        "// artifact free and does the job. I gave it a different name, so that it wouldn't be mistaken for\n"
        "// the real thing.\n"
        "//\n"
        "// Credits: Ken Perlin, the inventor of Simplex noise, of course. Stefan Gustavson's paper -\n"
        "// \"Simplex Noise Demystified,\" IQ, other \"ShaderToy.com\" people, etc.\n"
        "float tetraNoise(in vec3 p){\n"
        "\n"
        "    // Skewing the cubic grid, then determining the first vertice and fractional position.\n"
        "    vec3 i = floor(p + dot(p, vec3(0.333333)) );  p -= i - dot(i, vec3(0.166666)) ;\n"
        "\n"
        "    // Breaking the skewed cube into tetrahedra with partitioning planes, then determining which side of the\n"
        "    // intersecting planes the skewed point is on. Ie: Determining which tetrahedron the point is in.\n"
        "    vec3 i1 = step(p.yzx, p), i2 = max(i1, 1.0-i1.zxy); i1 = min(i1, 1.0-i1.zxy);\n"
        "\n"
        "    // Using the above to calculate the other three vertices. Now we have all four tetrahedral vertices.\n"
        "    vec3 p1 = p - i1 + 0.166666, p2 = p - i2 + 0.333333, p3 = p - 0.5;\n"
        "\n"
        "\n"
        "    // 3D simplex falloff.\n"
        "    vec4 v = max(0.5 - vec4(dot(p,p), dot(p1,p1), dot(p2,p2), dot(p3,p3)), 0.0);\n"
        "\n"
        "    // Dotting the fractional position with a random vector generated for each corner -in order to determine\n"
        "    // the weighted contribution distribution... Kind of. Just for the record, you can do a non-gradient, value\n"
        "    // version that works almost as well.\n"
        "    vec4 d = vec4(dot(p, hash33(i)), dot(p1, hash33(i + i1)), dot(p2, hash33(i + i2)), dot(p3, hash33(i + 1.)));\n"
        "\n"
        "\n"
        "    // Simplex noise... Not really, but close enough. :)\n"
        "    return clamp(dot(d, v*v*v*8.)*1.732 + .5, 0., 1.); // Not sure if clamping is necessary. Might be overkill.\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "\n"
        "// Smooth Voronoi. I'm not sure who came up with the original, but I think IQ\n"
        "// was behind this particular algorithm. It's just like the regular Voronoi\n"
        "// algorithm, but instead of determining the minimum distance, you accumulate\n"
        "// values - analogous to adding metaball field values. The result is a nice\n"
        "// smooth pattern. The \"falloff\" variable is a smoothing factor of sorts.\n"
        "//\n"
        "float smoothVoronoi(vec2 p, float falloff) {\n"
        "\n"
        "    vec2 ip = floor(p); p -= ip;\n"
        "    \n"
        "    float d = 1., res = 0.;\n"
        "    \n"
        "    for(int i=-1; i<=2; i++) {\n"
        "        for(int j=-1; j<=2; j++) {\n"
        "\n"
        "            vec2 b = vec2(i, j);\n"
        "\n"
        "            vec2 v = b - p + hash22(ip + b);\n"
        "\n"
        "            d = max(dot(v,v), 1e-8);\n"
        "            \n"
        "            res += 1./pow(d, falloff );\n"
        "            //res += exp( -16.*d ); // Alternate version.\n"
        "        }\n"
        "    }\n"
        "\n"
        "    return pow(1./res, .5/falloff);\n"
        "    //return clamp((-(1./16.)*log(res) + .1)/1.1, 0., 1.); // Alternate version.\n"
        "}\n"
        "\n"
        "\n"
        "\n"
        "// 2D function we'll be creating the fractional contours for.\n"
        "float func2D(vec2 p){\n"
        "\n"
        "    #ifdef RIGID_SCROLL\n"
        "    p += vec2(-.2, 0)*iTime; // Scrolling.\n"
        "    #endif\n"
        "\n"
        "    return smoothVoronoi(p*2., 4.)*.66 + smoothVoronoi(p*6., 4.)*.34;\n"
        "\n"
        "}\n"
        "\n"
        "// For fractional countours, something like \"fract(func(p)*layers\" will work, but the results\n"
        "// are aliased, so a smooth \"fract\" function needs to be applied. For nice, even contour lines,\n"
        "// the functional curvature needs to be taken into account. Hence the \"fxr\" and \"fyb\" samples.\n"
        "float func(vec2 p){\n"
        "\n"
        "    float f = func2D(p); // Function value.\n"
        "\n"
        "    // Samples in the X and Y directions to even up the contour lines according to curvature.\n"
        "    vec2 e = vec2(8./iResolution.y, 0);\n"
        "    float fxr = func2D(p - e.xy);\n"
        "    float fyb = func2D(p - e.yx);\n"
        "\n"
        "    // Gradient factor. Four samples would be better, but I'm trying to save some calculations.\n"
        "    // I made \"gF\" global, for reuse purposes, but I'll try to rectify that later. See the \"sFract\"\n"
        "    // function. Press pause, then set \"gF\" to a constant, like \".04,\" to see what it does.\n"
        "    // This example would be a lot faster if \"gF\" was set to a constant (since the two samples\n"
        "    // above wouldn't be necessary), so if you like that aesthetic more, then that's the way to go.\n"
        "    gF = length(f - vec2(fxr, fyb));\n"
        "\n"
        "    const float palNum = 12.; // 12 contour lines.\n"
        "    return sFract(f*palNum, 4.); // 4 is a smoothing factor. Getting the balance right can be frustrating.\n"
        "\n"
        "}\n"
        "\n"
        "// Simple environment mapping. Pass the reflected vector in and create some\n"
        "// colored noise with it.\n"
        "vec3 envMap(vec3 rd){\n"
        "\n"
        "\n"
        "    float c = tetraNoise(rd*3.)*.57 + tetraNoise(rd*6.)*.28 + tetraNoise(rd*12.)*.15; // Noise value.\n"
        "    c = smoothstep(.4, 1., c); // Darken and add contast for more of a spotlight look.\n"
        "\n"
        "    vec3 col = vec3(c*c*c, c*c, c); // Simple, cool coloring.\n"
        "    //vec3 col = vec3(min(c*1.5, 1.), pow(c, 2.5), pow(c, 12.)); // Warm color.\n"
        "\n"
        "    // Mix in the reverse color to tone it down and return.\n"
        "    return mix(col, col.zxy, rd*.25 + .25);\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "\n"
        "void mainImage(out vec4 fragColor, in vec2 fragCoord){\n"
        "\n"
        "    // Screen coordinates.\n"
        "    vec2 u = (fragCoord.xy - iResolution.xy*.5)/iResolution.y;\n"
        "\n"
        "    // Function value.\n"
        "    float f = func(u);\n"
        "    float ssd = func2D(u); // Saving the unpalettized noise value to add a little gradient to the color, etc.\n"
        "\n"
        "    // Four sample values around the original. Used for edging and highlighting. Note the \"1.5\" factor in a\n"
        "    // couple of samples. I was playing around and liked it more that way, but you can take it out if you want.\n"
        "    vec2 e = vec2(2./450., 0);\n"
        "    float fxl = func(u + e.xy*1.5);\n"
        "    float fxr = func(u - e.xy);\n"
        "    float fyt = func(u + e.yx*1.5);\n"
        "    float fyb = func(u - e.yx);\n"
        "\n"
        "    // Colorizing the the function value.\n"
        "    vec3 col = vec3(.5);\n"
        "\n"
        "    // Applying some color and hue rotation based on fractional layer and position. Designed to coincide\n"
        "    // with the \"func\" function.\n"
        "    const float palNum2 = 12.;\n"
        "    float fi = (1. - clamp(sFloor(ssd*(palNum2))/(palNum2 - 1.), 0., 1.));\n"
        "    fi = mod(fi, 4./12.);\n"
        "\n"
        "    if(fi>3./12.) {\n"
        "        // Extra color layers. I found it a bit much.\n"
        "        //col *= vec3(1, .18, .28);\n"
        "        //col = rotHue(col, mod(iTime/3. + 3.14159, 6.2831853) + (length(u*vec2(3., 5.))));\n"
        "        col *= .25;\n"
        "    }\n"
        "    else if(fi>2./12.) {\n"
        "\n"
        "        col *= vec3(1, .18, .28);\n"
        "        col = rotHue(col, mod(iTime/4., 6.2831853) + (length(u*vec2(2.5, 4.5))));// + iTime*.5\n"
        "    }\n"
        "\n"
        "    // Adding a bit of noise for a bit more authenticity.\n"
        "    vec3 u3 = vec3(u, f); // Fake height, \"ssd,\" according to function value.\n"
        "    #ifdef RIGID_SCROLL\n"
        "    u3.xy += vec2(-.2, 0)*iTime; // Scrolling.\n"
        "    #endif\n"
        "    col = min(col*.8 + tetraNoise(u3*128.)*.4, 1.);\n"
        "\n"
        "\n"
        "\n"
        "    // Extra highlighting to shine up the edges. Purely for aesthetics. Not based on science. :)\n"
        "    col += vec3(.5, .7, 1)*(max(f - fyt, 0.) + max(f - fxl, 0.))*1.*ssd*2.;\n"
        "\n"
        "\n"
        "    vec3 rd = normalize(vec3(u, 1)); // Unit direction vector.\n"
        "    vec3 n = normalize(vec3(0, 0, -1) + vec3(fxr - fxl, fyb - fyt, 0)/e.x/1.4*.01); // Bumped normal.\n"
        "    vec3 ld = (vec3(.25, .25, -1.) - vec3(u, 0)); // Light direction - Position minus surface point.\n"
        "\n"
        "    float dist = length(ld); // Light distance.\n"
        "    float atten = 1./(1. + dist*dist*.25); // Light attenuation.\n"
        "\n"
        "    ld /= dist; // Normalizing the light dirction vector.\n"
        "\n"
        "\n"
        "    float diff = max(dot(ld, n), 0.); // Diffuse.\n"
        "    diff = pow(diff, 4.)*.66 + pow(diff, 8.)*.34; // Ramped diffuse - for shininess.\n"
        "    float spec = pow(max(dot(reflect(ld, n), rd), 0.), 8.); // Specular.\n"
        "    float fres = pow(clamp(dot(rd, n) + 1., 0., 1.), 3.); // Fresnel.\n"
        "\n"
        "    // Combining the above terms to produce the lit color.\n"
        "    col = col*(diff*2. + .125) + vec3(1, .7, .3)*spec*2. + vec3(.25, .5, 1)*fres*2.;\n"
        "    //col += vec3(.5, .7, 1)*diff*diff*.5; // Too much shine. :)\n"
        "\n"
        "\n"
        "    // Fake environment mapping for that reflective look.\n"
        "    col += (col*.65 + .35)*envMap(reflect(rd, vec3(0, 0, -1)*.25 + n*.75))*2.;\n"
        "\n"
        "    // Attenuating, then adding some brown shadowing for a subtle tarnished look.\n"
        "    col *= atten*(vec3(f, pow(f, 1.1), pow(f, 1.2))*.85 + .15);\n"
        "\n"
        "\n"
        "    // col *= vec3(1.2, .95, .8); // Bronze, copper... kind of.\n"
        "\n"
        "\n"
        "    // Subtle, bluish vignette.\n"
        "    //u = fragCoord/iResolution.xy;\n"
        "    //col = mix(vec3(0, .1, 1), col, pow( 16.0*u.x*u.y*(1.0-u.x)*(1.0-u.y) , .125)*.15 + .85);\n"
        "\n"
        "     \n"
        "    // Rough gamma correction.\n"
        "    fragColor = vec4(sqrt(clamp(col, 0., 1.)), 1);\n"
        "\n"
        "}\n"
     );

     n->create_file("ShaderToy/AndromedaJewel.glsl",
        "// https://www.shadertoy.com/view/4sVfWR\n"
        "\n"
        "#define pi 3.14159265359\n"
        "//this noise stuff is from iq thanks\n"
        "float hash (vec2 v) {\n"
        "    v = floor(v);\n"
        "    return fract(67.3249*sin(17.1234*length(v-vec2(34.14,123.))));\n"
        "}\n"
        "float noise (vec2 v) {\n"
        "    vec4 n = vec4(floor(v),ceil(v));\n"
        "    vec4 h = vec4(hash(n.xy),hash(n.zy),hash(n.xw),hash(n.zw));\n"
        "    return mix(mix(h.x,h.y,v.x-n.x),mix(h.z,h.w,v.x-n.x),v.y-n.y);\n"
        "}\n"
        "mat2 r (float a) {\n"
        "    float s = sin(a), c = cos(a);\n"
        "    return mat2(s,-c,c,s);\n"
        "}\n"
        "float no (vec2 v) {\n"
        "    float c = 0.;\n"
        "    for (int i = 1; i < 10; i++) {\n"
        "        v = 2.*r(0.2944*pi)*v;\n"
        "        c += 0.2*noise(v)/(1.+length(sin(0.5*v)));\n"
        "    }\n"
        "    return c;\n"
        "}\n"
        "// flow stuff is from trirop https://www.shadertoy.com/view/MsScWD very cool\n"
        "vec2 ff (vec2 v) {\n"
        "        float n = 1.+0.5*noise(v);\n"
        "        return\n"
        "            sign(v.y-0.5)*50.*vec2(n*sin(1.4*v.y),0.)/(v.y+3.5)+\n"
        "            .1*vec2(sin(-12.*v.y*n),cos(13.*v.x))+\n"
        "            1.8*vec2(cos(-6.*v.y),sin(4.*v.x))+\n"
        "            1.2*vec2(sin(-1.4*v.y),cos(1.5*v.x))+\n"
        "            2.0*vec2(sin(-.5*v.y),cos(.6*v.x))+\n"
        "            0.8*vec2(sin(-.2*v.y),cos(.2*v.x*n))\n"
        "         ;}\n"
        "bool star = false;\n"
        "vec2 mouse;\n"
        "void sphere (inout vec3 p, inout vec3 d) {\n"
        "    float r = .7, dp = dot(d,p), pp = dot(p,p), det = dp*dp+r*r-pp;\n"
        "    if (det < 0.) star = true;\n"
        "    float x = -dp+sqrt(det);\n"
        "    p = (p+d*x);\n"
        "    d = reflect(normalize(p),d);\n"
        "}\n"
        "\n"
        "vec3 surface (vec2 uv) {\n"
        "    vec3 col = 0.*vec3(7.-abs(uv.y))*no (uv);\n"
        "    for (int i = 0; i < 45; i++) {\n"
        "        uv += 0.01*(2.+1.5*sin(.1*iTime))*ff(uv);\n"
        "    }\n"
        "    float j = no(0.1*uv*pi);\n"
        "    vec3 c = sin(j*vec3(1,2,3));\n"
        "    col += abs(mix(c*c*c,vec3(j),abs(1.-uv.y/7.5)));\n"
        "    return col;\n"
        "}\n"
        "vec3 stars (vec2 v) {\n"
        "    return vec3(pow(1.35*no(0.1*iTime+5.*mouse+3.*v/dot(v,v)),7.));\n"
        "}\n"
        "void mainImage( out vec4 fragColor, in vec2 U )\n"
        "{\n"
        "    vec2 uv = (2.*U-iResolution.xy)/iResolution.y;\n"
        "       float q = 1.2+0.1*min(17.,iTime);\n"
        "    vec3 p = vec3(0,0,-q);\n"
        "    vec3 d = normalize(vec3(uv,4.));\n"
        "    mouse = iMouse.xy/iResolution.xy;\n"
        "    p.yz = r(-mouse.y+0.7*pi)*p.yz;\n"
        "    d.yz = r(-mouse.y+0.7*pi)*d.yz;\n"
        "    p.zx = r(mouse.x+0.25*pi)*p.zx;\n"
        "    d.zx = r(mouse.x+0.25*pi)*d.zx;\n"
        "    vec3 col;\n"
        "    sphere(p,d);\n"
        "    if (star) {\n"
        "        col = stars(uv);\n"
        "    } else {\n"
        "        col = 0.8*surface(8.*vec2(atan(d.z,d.x)+0.01*iTime*min(iTime,17.),acos(d.y)));\n"
        "        float sh = dot(d,normalize(vec3(1,0,-1)));\n"
        "        col *= sh+0.4;\n"
        "    }\n"
        "    float l = length(uv-vec2(0.2,0))*q;\n"
        "    col = col+.09*vec3(0.5,0.7,1.)*(uv.x+0.5)*exp(-0.01*l*l*l*l)*q;\n"
        "    fragColor = vec4(col,1);\n"
        "}\n"     );

     n->create_file("ShaderToy/Circuits.glsl",
        "// https://www.shadertoy.com/view/XlX3Rj\n"
        "\n"
        "#define time iTime*.02\n"
        "\n"
        "\n"
        "#define width .005\n"
        "float zoom = .18;\n"
        "\n"
        "float shape=0.;\n"
        "vec3 color=vec3(0.),randcol;\n"
        "\n"
        "void formula(vec2 z, float c) {\n"
        "    float minit=0.;\n"
        "    float o,ot2,ot=ot2=1000.;\n"
        "    for (int i=0; i<9; i++) {\n"
        "        z=abs(z)/clamp(dot(z,z),.1,.5)-c;\n"
        "        float l=length(z);\n"
        "        o=min(max(abs(min(z.x,z.y)),-l+.25),abs(l-.25));\n"
        "        ot=min(ot,o);\n"
        "        ot2=min(l*.1,ot2);\n"
        "        minit=max(minit,float(i)*(1.-abs(sign(ot-o))));\n"
        "    }\n"
        "    minit+=1.;\n"
        "    float w=width*minit*2.;\n"
        "    float circ=pow(max(0.,w-ot2)/w,6.);\n"
        "    shape+=max(pow(max(0.,w-ot)/w,.25),circ);\n"
        "    vec3 col=normalize(vec3(0.3,0.3,0.3));\n"
        "    color+=col*(.4+mod(minit/9.-time*10.+ot2*2.,1.)*1.6);\n"
        "    color+=vec3(1.,.7,.3)*circ*(10.-minit)*3.*smoothstep(0.,.5,.15-.5);\n"
        "}\n"
        "\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{\n"
        "    vec2 pos = fragCoord.xy / iResolution.xy - .5;\n"
        "    pos.x*=iResolution.x/iResolution.y;\n"
        "    vec2 uv=pos;\n"
        "    float sph = length(uv); sph = sqrt(1. - sph*sph)*1.5; // curve for spheric distortion\n"
        "    uv=normalize(vec3(uv,sph)).xy;\n"
        "    float a=time+mod(time,1.)*.5;\n"
        "    vec2 luv=uv;\n"
        "    float b=a*5.48535;\n"
        "//    zoom*=1.+sin(time*3.758123)*.8;\n"
        "    uv*=mat2(cos(b),sin(b),-sin(b),cos(b));\n"
        "    uv+=vec2(sin(a),cos(a*.5))*8.;\n"
        "    uv*=zoom;\n"
        "    float pix=.5/iResolution.x*zoom/sph;\n"
        "    float dof=max(1.,(10.-mod(time,1.)/.01));\n"
        "    float c=1.5+mod(floor(time),6.)*.125;\n"
        "    for (int aa=0; aa<36; aa++) {\n"
        "        vec2 aauv=floor(vec2(float(aa)/6.,mod(float(aa),6.)));\n"
        "        formula(uv+aauv*pix*dof,c);\n"
        "    }\n"
        "    shape/=36.; color/=36.;\n"
        "    vec3 colo=mix(vec3(.15),color,shape)*(1.-length(pos))*min(1.,abs(.5-mod(time+.5,1.))*10.);    \n"
        "    colo*=vec3(1.2,1.1,1.0);\n"
        "    fragColor = vec4(colo,1.0);\n"
        "}\n"
        "\n"
     );

     n->create_file("ShaderToy/ContouredLayers.glsl",
        "// https://www.shadertoy.com/view/3lj3zt\n"
        "\n"
        "/*\n"
        "\n"
        "    Contoured Layers\n"
        "    ----------------\n"
        "\n"
        "    Constructing some concise contoured layers, then applying various edge and shading\n"
        "    effects to produce some faux depth. Technically, that's what is happening here, but\n"
        "    this example was mainly put together as a means to demonstrate various layering\n"
        "    effects, like strokes, highlights, shadows, etc. No 3D was harmed during the making\n"
        "    of this example. :)\n"
        "\n"
        "    I love those contoured noise-based paper layer images that various graphic artists\n"
        "    from places like Adobe distribute with their applications. Most consist of some\n"
        "    antialised noise layers rendered in a flat tone with drop shadows for each. The\n"
        "    fancier ones sometimes include highlighted edges, etc, which is what I've put\n"
        "    together here. None of it is difficult to produce, provided you're happy with\n"
        "    concept of smoothing layers at a particular threshold with respect to the field\n"
        "    derivative.\n"
        "\n"
        "    I put in a few diferent aesthetic options to try, just to show how much something\n"
        "    like a simple palette change, drop shadow, etc, can effect the overall feel.\n"
        "    Anyway, feel free to play around with the defines below. At some stage, I might\n"
        "    render some icons and allow the various options to be manipulated via the mouse,\n"
        "    but for now, this will suffice.\n"
        "\n"
        "    I also have a few raymarched 3D versions that I'll put up at a later date.    \n"
        "\n"
        "\n"
        "*/\n"
        "\n"
        "// Dropping down a blurry dark layer to give a fake ambient occlusion effect.\n"
        "// It's subtle, but gives things a bit more depth. However, turning it off gives\n"
        "// a crisper look. I guess it depends what you're after.\n"
        "#define FAKE_AO\n"
        "\n"
        "// Controur strokes are great for that hand drawn look, or just to give some definition\n"
        "// to geometry. This one is dark, but it can be any color.\n"
        "#define STROKE\n"
        "\n"
        "// Highlights, to give the impression that light is hitting the surface.\n"
        "#define HILIGHT\n"
        "\n"
        "// Shadows: There aren't too many times when I wouldn't want shadows, but I can think\n"
        "// of a few. If expense if a problem, you can fake it with a thicker AO layer, but it's\n"
        "// not quite the same.\n"
        "#define SHADOW\n"
        "\n"
        "// Include the metallic texture. I overuse this particular texture, but it's the only\n"
        "// one on Shadertoy with a fine enough grade on it. I'm hoping more subtle textures\n"
        "// will get added at some stage. :)\n"
        "// #define TEXTURED\n"
        "\n"
        "// Running a cheap hatch-like algorithm over the layers for a bit of extra texture.\n"
        "#define HATCH\n"
        "\n"
        "// Very subtle paper grain. It's pretty simple, and I think it came from one of\n"
        "// Flockaroo's examples.\n"
        "#define PAPER_GRAIN\n"
        "\n"
        "// Palette: It's amazing how something as simple as color choice can effect the feel\n"
        "// of an image.\n"
        "// Settings: Greyscale: 0, Red: 1, Blue: 2, Earth: 3, Pink and grey: 4.\n"
        "#define PALETTE 3\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "// Standard 2D rotation formula.\n"
        "mat2 rot2(in float a){ float c = cos(a), s = sin(a); return mat2(c, -s, s, c); }\n"
        "\n"
        "// vec3 to float hash.\n"
        "float hash21( vec2 p ){\n"
        "\n"
        "    return fract(sin(dot(p, vec2(41, 289)))*45758.5453);\n"
        "\n"
        "    //p.x = fract(sin(dot(p, vec2(1, 113)))*45758.5453);\n"
        "    //return sin(p.x*6.2831853 + iTime);\n"
        "}\n"
        "\n"
        "// vec2 to vec2 hash.\n"
        "vec2 hash22(vec2 p) {\n"
        "\n"
        "    // Faster, but doesn't disperse things quite as nicely. However, when framerate\n"
        "    // is an issue, and it often is, this is a good one to use. Basically, it's a tweaked\n"
        "    // amalgamation I put together, based on a couple of other random algorithms I've\n"
        "    // seen around... so use it with caution, because I make a tonne of mistakes. :)\n"
        "    float n = sin(dot(p, vec2(1, 113)));\n"
        "    //return fract(vec2(262144, 32768)*n)*2. - 1.;\n"
        "\n"
        "    // Animated.\n"
        "    p = fract(vec2(262144, 32768)*n);\n"
        "    // Note the \".45,\" insted of \".5\" that you'd expect to see. When edging, it can open\n"
        "    // up the cells ever so slightly for a more even spread. In fact, lower numbers work\n"
        "    // even better, but then the random movement would become too restricted. Zero would\n"
        "    // give you square cells.\n"
        "    return sin( p*6.2831853 + iTime);\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "\n"
        "// Cheap and nasty 2D smooth noise function with inbuilt hash function -- based on IQ's\n"
        "// original. Very trimmed down. In fact, I probably went a little overboard. I think it\n"
        "// might also degrade with large time values, but that's not an issue here.\n"
        "float n2D(vec2 p) {\n"
        "\n"
        "    vec2 i = floor(p); p -= i; p *= p*(3. - p*2.);\n"
        "\n"
        "    return dot(mat2(fract(sin(vec4(0, 1, 113, 114) + dot(i, vec2(1, 113)))*43758.5453))*\n"
        "                vec2(1. - p.y, p.y), vec2(1. - p.x, p.x) );\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "// Based on IQ's gradient noise formula.\n"
        "float n2D3G( in vec2 p ){\n"
        "\n"
        "    vec2 i = floor(p); p -= i;\n"
        "\n"
        "    vec4 v;\n"
        "    v.x = dot(hash22(i), p);\n"
        "    v.y = dot(hash22(i + vec2(1, 0)), p - vec2(1, 0));\n"
        "    v.z = dot(hash22(i + vec2(0, 1)), p - vec2(0, 1));\n"
        "    v.w = dot(hash22(i + 1.), p - 1.);\n"
        "\n"
        "#if 1\n"
        "    // Quintic interpolation.\n"
        "    p = p*p*p*(p*(p*6. - 15.) + 10.);\n"
        "#else\n"
        "    // Cubic interpolation.\n"
        "    p = p*p*(3. - 2.*p);\n"
        "#endif\n"
        "\n"
        "    return mix(mix(v.x, v.y, p.x), mix(v.z, v.w, p.x), p.y);\n"
        "    //return v.x + p.x*(v.y - v.x) + p.y*(v.z - v.x) + p.x*p.y*(v.x - v.y - v.z + v.w);\n"
        "}\n"
        "\n"
        "\n"
        "\n"
        "// The map function. Just two layers of gradient noise. Way more interesting\n"
        "// functions are possible, but we're keeping things simple.\n"
        "float map(vec3 p, float i){\n"
        "\n"
        "    return n2D3G(p.xy*3.)*.66 + n2D3G(p.xy*6.)*.34 + i/10.*1. - .15;\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "// 2D derivative function.\n"
        "vec3 getNormal(in vec3 p, float m, float i) {\n"
        "    \n"
        "    vec2 e = vec2(.001, 0);\n"
        "\n"
        "    // Four extra samples. Slightly better, but not really needed here.\n"
        "    //return (vec3(map(p + e.xyy, i) - map(p - e.xyy, i), map(p + e.yxy, i) - map(p - e.yxy, i),    0.))/e.x*.7071;\n"
        "\n"
        "    // Three samples, but only two extra sample calculations.\n"
        "    return (vec3(m - map(p - e.xyy, i), m - map(p - e.yxy, i),    0.))/e.x*1.4142;\n"
        "}\n"
        "\n"
        "// The map layer and its derivative. To produce constant width layer edges, the derivative\n"
        "// is necessary, so the distance field value and the derivative at the point is returned.\n"
        "vec4 mapLayer(in vec3 p, float i){\n"
        "\n"
        "    vec4 d;\n"
        "\n"
        "    d.x = map(p, i); // Distance field value.\n"
        "\n"
        "    d.yzw = getNormal(p, d.x, i); // Derivative.\n"
        "\n"
        "    return d;\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "\n"
        "// Layer color. Based on the shade, layer number and smoothing factor.\n"
        "vec3 getCol(vec2 p, float sh, float fi, float sf){\n"
        "\n"
        "    // Color.\n"
        "    vec3 col;\n"
        "\n"
        "\n"
        "    #if PALETTE == 0\n"
        "        // Light attenuation palette.\n"
        "        col = vec3(1)*(1. - .75/(1. + sh*sh*2.));\n"
        "        //col = vec3(sh*sh*.65 + .22);\n"
        "        //col = vec3(sh*.5 + .2);\n"
        "        // Etc.\n"
        "    #elif PALETTE == 1\n"
        "        col = pow(min(vec3(1.5, 1, 1)*(sh*.35 + .6), 1.), vec3(1, 3, 16));\n"
        "        if(fi==0.) col = vec3(.35, .05, .3);\n"
        "        col = mix(col.xzy, col, sh*.5 + .5);\n"
        "    #elif PALETTE == 2\n"
        "        col = pow(min(vec3(1.5, 1, 1)*(sh*.35 + .6), 1.), vec3(1, 3, 16));\n"
        "        if(fi==0.) col = vec3(.6, .2, .07);\n"
        "        col = mix(col.xzy, col, sh*.5 + .5).zyx;\n"
        "    #elif PALETTE == 3\n"
        "        if(fi==0.) col = vec3(.25, .52, .75);\n"
        "        if(fi==1.) col = vec3(.8, .8, .6);\n"
        "        if(fi==2.) col = vec3(.75, .6, .5);\n"
        "        if(fi==3.) col = vec3(.6, .58, .5);\n"
        "        if(fi==4.) col = vec3(.5, .72, .4);\n"
        "        if(fi==5.) col = vec3(.65, .85, .5);\n"
        "    #else\n"
        "        if(mod(fi, 2.)<.5) col = vec3(.25, .15, .2);\n"
        "        else col = vec3(1, .15, .4)*.8;\n"
        "    #endif\n"
        "\n"
        "\n"
        "    #ifdef TEXTURED\n"
        "    vec3 tx = texture(iChannel0, p + hash21(vec2(sh, fi))).xyz; tx *= tx;\n"
        "    col = min(col*tx*3., 1.);\n"
        "    #endif\n"
        "\n"
        "\n"
        "    return col;\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "void mainImage(out vec4 fragColor, in vec2 fragCoord){\n"
        "\n"
        "\n"
        "    // Aspect correct screen coordinates. Setting a minumum resolution on the\n"
        "    // fullscreen setting in an attempt to keep things relatively crisp.\n"
        "    float res = min(iResolution.y, 700.);\n"
        "    vec2 uv = (fragCoord - iResolution.xy*.5)/res;\n"
        "\n"
        "    // Scaling and translation.\n"
        "    vec2 p = uv + vec2(0.1, 0.1)*iTime;\n"
        "\n"
        "    // Resolution based smoothing factor. Later, the contour derivative will\n"
        "    // be factored in.\n"
        "    float sf = 1./iResolution.y;\n"
        "\n"
        "    // Initialize to the first layer color.\n"
        "    vec3 col = getCol(p, 0., 0., sf);\n"
        "\n"
        "    // Previous layer variable.\n"
        "    float pL = 0.;\n"
        "\n"
        "\n"
        "    // Random looking diagonal hatch lines.\n"
        "    vec2 u2 = p*res/16.;\n"
        "    float hatch = clamp(sin((u2.x - u2.y)*3.14159*200.)*2. + .5, 0., 1.); // Diagonal lines.\n"
        "    float hRnd = hash21(floor(u2*6.) + .73);\n"
        "    if(hRnd>.66) hatch = hRnd; // Slight randomization of the diagonal lines.\n"
        "    #ifdef TEXTURED\n"
        "    hatch = hatch*.75 + .5; // Stronger hatching for the textured version.\n"
        "    #else\n"
        "    hatch = hatch*.5 + .75;\n"
        "    #endif\n"
        "\n"
        "    #ifndef HATCH\n"
        "    hatch = 1.;\n"
        "    #endif\n"
        "\n"
        "    // Applying the cross hatch.\n"
        "    col *= hatch;\n"
        "\n"
        "    // Number of layers.\n"
        "    int lNum = 5;\n"
        "    float flNum = 5.;\n"
        "\n"
        "\n"
        "    for(int i = 0; i<5; i++){\n"
        "\n"
        "\n"
        "        float fi = float(i);\n"
        "\n"
        "        // The map layer value (just some gradient noise), and its derivative.\n"
        "        vec4 c = mapLayer(vec3(p, 1.), fi);\n"
        "        // Offset noise layer value with derivative. It's offset so as to coincide with\n"
        "        // to the directional lighting.\n"
        "        vec4 cSh = mapLayer(vec3(p - vec2(.03, -.03)*((flNum - fi)/flNum*.5 + .5), 1.), fi);\n"
        "\n"
        "        // Shade.\n"
        "        float sh = (fi + 1.)/(flNum);\n"
        "\n"
        "        // Layer color.\n"
        "        vec3 lCol = getCol(p, sh, fi + 1., sf);\n"
        "\n"
        "        // Some standard direct lighting to apply to the edge layer. It's set in a\n"
        "        // direction to compliment the shadow layer.\n"
        "        vec3 ld = normalize(vec3(-1, 1, -.25));\n"
        "        vec3 n = normalize(vec3(0, 0, -1) + c.yzw);\n"
        "        float diff = max(dot(ld, n), 0.);\n"
        "        #ifdef TEXTURED\n"
        "        diff *= 2.5; // Add a bit more light to the edges for the textured version.\n"
        "        #else\n"
        "        diff *= 2.;\n"
        "        #endif\n"
        "\n"
        "\n"
        "        // Applying the diffuse lighting to the edge layer.\n"
        "        vec3 eCol = lCol*(diff + 1.);\n"
        "\n"
        "        // Apply the layers.\n"
        "\n"
        "        // Smoothing factor, based on the distance field derivative.\n"
        "        float sfL = sf*length(c.yzx)*2.;\n"
        "        float sfLSh = sf*length(cSh.yzx)*6.;\n"
        "\n"
        "        // Drop shadow.\n"
        "        #ifdef SHADOW\n"
        "        #ifdef TEXTURED\n"
        "        const float shF = .5;\n"
        "        #else\n"
        "        const float shF = .35;\n"
        "        #endif\n"
        "        col = mix(col, vec3(0), (1. - smoothstep(0., sfLSh, max(cSh.x, pL)))*shF);\n"
        "        #endif\n"
        "\n"
        "        // Dark blurred layer.\n"
        "        #ifdef FAKE_AO\n"
        "        col = mix(col, vec3(0), (1. - smoothstep(0., sfL*3., c.x))*.25);\n"
        "        #endif\n"
        "\n"
        "        // Dark edge stroke.\n"
        "        #ifdef STROKE\n"
        "        col = mix(col, vec3(0), (1. - smoothstep(0., sfL, c.x))*.85);\n"
        "        #endif\n"
        "\n"
        "        // Hilight and color layer.\n"
        "        #ifdef HILIGHT\n"
        "        col = mix(col, eCol*hatch, (1. - smoothstep(0., sfL, c.x + length(c.yzx)*.003)));\n"
        "        col = mix(col, lCol*hatch, (1. - smoothstep(0., sfL, c.x + length(c.yzx)*.006)));\n"
        "        #else\n"
        "        col = mix(col, lCol*hatch, (1. - smoothstep(0., sfL, c.x + length(c.yzx)*.0025)));\n"
        "        #endif\n"
        "\n"
        "        // Previous layer, to take away from the shadow.\n"
        "        pL = c.x;\n"
        "\n"
        "    }\n"
        "\n"
        "\n"
        "\n"
        "    // Mixing in a little extra noisy color for the default greyscale textured setting.\n"
        "    #ifdef TEXTURED\n"
        "    #if PALETTE == 0\n"
        "    col *= mix(vec3(1.8, 1, .7).zyx, vec3(1.8, 1, .7).xzy, n2D(p*2.));\n"
        "    #endif\n"
        "    #endif\n"
        "\n"
        "\n"
        "\n"
        "    // Paper.\n"
        "    #ifdef PAPER_GRAIN\n"
        "    vec3 rn3 = vec3(n2D((uv*iResolution.y/1. + 1.7)) - n2D(vec2(uv*iResolution.y/1. + 3.4)));\n"
        "    col *= .93 + .07*rn3.xyz  + .07*dot(rn3, vec3(.299, .587, .114));\n"
        "    #endif\n"
        "\n"
        "\n"
        "    // Subtle vignette.\n"
        "    uv = fragCoord/iResolution.xy;\n"
        "    col *= pow(16.*uv.x*uv.y*(1. - uv.x)*(1. - uv.y) , .0625);\n"
        "    // Colored variation.\n"
        "    //col = mix(col*vec3(.3, 0, 1), col, pow(16.*uv.x*uv.y*(1. - uv.x)*(1. - uv.y) , .125));\n"
        "\n"
        "\n"
        "    // Rough gamma correction, then output to the screen.\n"
        "    fragColor = vec4(sqrt(max(col, 0.)), 1);\n"
        "}\n"
     );

     n->create_file("ShaderToy/FractalLand.glsl",
        "// https://www.shadertoy.com/view/XsBXWt\n"
        "\n"
        "// \"Fractal Cartoon\" - former \"DE edge detection\" by Kali\n"
        "\n"
        "// There are no lights and no AO, only color by normals and dark edges.\n"
        "\n"
        "// update: Nyan Cat cameo, thanks to code from mu6k: https://www.shadertoy.com/view/4dXGWH\n"
        "\n"
        "\n"
        "//#define SHOWONLYEDGES\n"
        "//#define NYAN\n"
        "#define WAVES\n"
        "#define BORDER\n"
        "\n"
        "#define RAY_STEPS 150\n"
        "\n"
        "#define BRIGHTNESS 1.2\n"
        "#define GAMMA 1.4\n"
        "#define SATURATION .65\n"
        "\n"
        "\n"
        "#define detail .001\n"
        "#define t iTime*.5\n"
        "\n"
        "\n"
        "const vec3 origin=vec3(-1.,.7,0.);\n"
        "float det=0.0;\n"
        "\n"
        "\n"
        "// 2D rotation function\n"
        "mat2 rot(float a) {\n"
        "    return mat2(cos(a),sin(a),-sin(a),cos(a));    \n"
        "}\n"
        "\n"
        "// \"Amazing Surface\" fractal\n"
        "vec4 formula(vec4 p) {\n"
        "        p.xz = abs(p.xz+1.)-abs(p.xz-1.)-p.xz;\n"
        "        p.y-=.25;\n"
        "        p.xy*=rot(radians(35.));\n"
        "        p=p*2./clamp(dot(p.xyz,p.xyz),.2,1.);\n"
        "    return p;\n"
        "}\n"
        "\n"
        "// Distance function\n"
        "float de(vec3 pos) {\n"
        "#ifdef WAVES\n"
        "    pos.y+=sin(pos.z-t*6.)*.15; //waves!\n"
        "#endif\n"
        "    float hid=0.;\n"
        "    vec3 tpos=pos;\n"
        "    tpos.z=abs(3.-mod(tpos.z,6.));\n"
        "    vec4 p=vec4(tpos,1.);\n"
        "    for (int i=0; i<4; i++) {p=formula(p);}\n"
        "    float fr=(length(max(vec2(0.),p.yz-1.5))-1.)/p.w;\n"
        "    float ro=max(abs(pos.x+1.)-.3,pos.y-.35);\n"
        "          ro=max(ro,-max(abs(pos.x+1.)-.1,pos.y-.5));\n"
        "    pos.z=abs(.25-mod(pos.z,.5));\n"
        "          ro=max(ro,-max(abs(pos.z)-.2,pos.y-.3));\n"
        "          ro=max(ro,-max(abs(pos.z)-.01,-pos.y+.32));\n"
        "    float d=min(fr,ro);\n"
        "    return d;\n"
        "}\n"
        "\n"
        "\n"
        "// Camera path\n"
        "vec3 path(float ti) {\n"
        "    ti*=1.5;\n"
        "    vec3  p=vec3(sin(ti),(1.-sin(ti*2.))*.5,-ti*5.)*.5;\n"
        "    return p;\n"
        "}\n"
        "\n"
        "// Calc normals, and here is edge detection, set to variable \"edge\"\n"
        "\n"
        "float edge=0.;\n"
        "vec3 normal(vec3 p) {\n"
        "    vec3 e = vec3(0.0,det*5.,0.0);\n"
        "\n"
        "    float d1=de(p-e.yxx),d2=de(p+e.yxx);\n"
        "    float d3=de(p-e.xyx),d4=de(p+e.xyx);\n"
        "    float d5=de(p-e.xxy),d6=de(p+e.xxy);\n"
        "    float d=de(p);\n"
        "    edge=abs(d-0.5*(d2+d1))+abs(d-0.5*(d4+d3))+abs(d-0.5*(d6+d5));//edge finder\n"
        "    edge=min(1.,pow(edge,.55)*15.);\n"
        "    return normalize(vec3(d1-d2,d3-d4,d5-d6));\n"
        "}\n"
        "\n"
        "\n"
        "// Used Nyan Cat code by mu6k, with some mods\n"
        "\n"
        "vec4 rainbow(vec2 p)\n"
        "{\n"
        "    float q = max(p.x,-0.1);\n"
        "    float s = sin(p.x*7.0+t*70.0)*0.08;\n"
        "    p.y+=s;\n"
        "    p.y*=1.1;\n"
        "    \n"
        "    vec4 c;\n"
        "    if (p.x>0.0) c=vec4(0,0,0,0); else\n"
        "    if (0.0/6.0<p.y&&p.y<1.0/6.0) c= vec4(255,43,14,255)/255.0; else\n"
        "    if (1.0/6.0<p.y&&p.y<2.0/6.0) c= vec4(255,168,6,255)/255.0; else\n"
        "    if (2.0/6.0<p.y&&p.y<3.0/6.0) c= vec4(255,244,0,255)/255.0; else\n"
        "    if (3.0/6.0<p.y&&p.y<4.0/6.0) c= vec4(51,234,5,255)/255.0; else\n"
        "    if (4.0/6.0<p.y&&p.y<5.0/6.0) c= vec4(8,163,255,255)/255.0; else\n"
        "    if (5.0/6.0<p.y&&p.y<6.0/6.0) c= vec4(122,85,255,255)/255.0; else\n"
        "    if (abs(p.y)-.05<0.0001) c=vec4(0.,0.,0.,1.); else\n"
        "    if (abs(p.y-1.)-.05<0.0001) c=vec4(0.,0.,0.,1.); else\n"
        "        c=vec4(0,0,0,0);\n"
        "    c.a*=.8-min(.8,abs(p.x*.08));\n"
        "    c.xyz=mix(c.xyz,vec3(length(c.xyz)),.15);\n"
        "    return c;\n"
        "}\n"
        "\n"
        "vec4 nyan(vec2 p)\n"
        "{\n"
        "    vec2 uv = p*vec2(0.4,1.0);\n"
        "    float ns=3.0;\n"
        "    float nt = iTime*ns; nt-=mod(nt,240.0/256.0/6.0); nt = mod(nt,240.0/256.0);\n"
        "    float ny = mod(iTime*ns,1.0); ny-=mod(ny,0.75); ny*=-0.05;\n"
        "//    vec4 color = texture(iChannel1,vec2(uv.x/3.0+210.0/256.0-nt+0.05,.5-uv.y-ny));\n"
        "        vec4 color = vec4(0.0, 0.0, 0.0, 1.0);\n"
        "    if (uv.x<-0.3) color.a = 0.0;\n"
        "    if (uv.x>0.2) color.a=0.0;\n"
        "    return color;\n"
        "}\n"
        "\n"
        "\n"
        "// Raymarching and 2D graphics\n"
        "\n"
        "vec3 raymarch(in vec3 from, in vec3 dir)\n"
        "\n"
        "{\n"
        "    edge=0.;\n"
        "    vec3 p, norm;\n"
        "    float d=100.;\n"
        "    float totdist=0.;\n"
        "    for (int i=0; i<RAY_STEPS; i++) {\n"
        "        if (d>det && totdist<25.0) {\n"
        "            p=from+totdist*dir;\n"
        "            d=de(p);\n"
        "            det=detail*exp(.13*totdist);\n"
        "            totdist+=d;\n"
        "        }\n"
        "    }\n"
        "    vec3 col=vec3(0.);\n"
        "    p-=(det-d)*dir;\n"
        "    norm=normal(p);\n"
        "#ifdef SHOWONLYEDGES\n"
        "    col=1.-vec3(edge); // show wireframe version\n"
        "#else\n"
        "    col=(1.-abs(norm))*max(0.,1.-edge*.8); // set normal as color with dark edges\n"
        "#endif        \n"
        "    totdist=clamp(totdist,0.,26.);\n"
        "    dir.y-=.02;\n"
        "//    float sunsize=7.-max(0.,texture(iChannel0,vec2(.6,.2)).x)*5.; // responsive sun size\n"
        "        float sunsize=7.;\n"
        "    float an=atan(dir.x,dir.y)+iTime*1.5; // angle for drawing and rotating sun\n"
        "    float s=pow(clamp(1.0-length(dir.xy)*sunsize-abs(.2-mod(an,.4)),0.,1.),.1); // sun\n"
        "    float sb=pow(clamp(1.0-length(dir.xy)*(sunsize-.2)-abs(.2-mod(an,.4)),0.,1.),.1); // sun border\n"
        "    float sg=pow(clamp(1.0-length(dir.xy)*(sunsize-4.5)-.5*abs(.2-mod(an,.4)),0.,1.),3.); // sun rays\n"
        "    float y=mix(.45,1.2,pow(smoothstep(0.,1.,.75-dir.y),2.))*(1.-sb*.5); // gradient sky\n"
        "    \n"
        "    // set up background with sky and sun\n"
        "    vec3 backg=vec3(0.5,0.,1.)*((1.-s)*(1.-sg)*y+(1.-sb)*sg*vec3(1.,.8,0.15)*3.);\n"
        "         backg+=vec3(1.,.9,.1)*s;\n"
        "         backg=max(backg,sg*vec3(1.,.9,.5));\n"
        "    \n"
        "    col=mix(vec3(1.,.9,.3),col,exp(-.004*totdist*totdist));// distant fading to sun color\n"
        "    if (totdist>25.) col=backg; // hit background\n"
        "    col=pow(col,vec3(GAMMA))*BRIGHTNESS;\n"
        "    col=mix(vec3(length(col)),col,SATURATION);\n"
        "#ifdef SHOWONLYEDGES\n"
        "    col=1.-vec3(length(col));\n"
        "#else\n"
        "    col*=vec3(1.,.9,.85);\n"
        "#ifdef NYAN\n"
        "    dir.yx*=rot(dir.x);\n"
        "    vec2 ncatpos=(dir.xy+vec2(-3.+mod(-t,6.),-.27));\n"
        "    vec4 ncat=nyan(ncatpos*5.);\n"
        "    vec4 rain=rainbow(ncatpos*10.+vec2(.8,.5));\n"
        "    if (totdist>8.) col=mix(col,max(vec3(.2),rain.xyz),rain.a*.9);\n"
        "    if (totdist>8.) col=mix(col,max(vec3(.2),ncat.xyz),ncat.a*.9);\n"
        "#endif\n"
        "#endif\n"
        "    return col;\n"
        "}\n"
        "\n"
        "// get camera position\n"
        "vec3 move(inout vec3 dir) {\n"
        "    vec3 go=path(t);\n"
        "    vec3 adv=path(t+.7);\n"
        "    float hd=de(adv);\n"
        "    vec3 advec=normalize(adv-go);\n"
        "    float an=adv.x-go.x; an*=min(1.,abs(adv.z-go.z))*sign(adv.z-go.z)*.7;\n"
        "    dir.xy*=mat2(cos(an),sin(an),-sin(an),cos(an));\n"
        "    an=advec.y*1.7;\n"
        "    dir.yz*=mat2(cos(an),sin(an),-sin(an),cos(an));\n"
        "    an=atan(advec.x,advec.z);\n"
        "    dir.xz*=mat2(cos(an),sin(an),-sin(an),cos(an));\n"
        "    return go;\n"
        "}\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{\n"
        "    vec2 uv = fragCoord.xy / iResolution.xy*2.-1.;\n"
        "    vec2 oriuv=uv;\n"
        "    uv.y*=iResolution.y/iResolution.x;\n"
        "    vec2 mouse=(iMouse.xy/iResolution.xy-.5)*3.;\n"
        "    if (iMouse.z<1.) mouse=vec2(0.,-0.05);\n"
        "    float fov=.9-max(0.,.7-iTime*.3);\n"
        "    vec3 dir=normalize(vec3(uv*fov,1.));\n"
        "    dir.yz*=rot(mouse.y);\n"
        "    dir.xz*=rot(mouse.x);\n"
        "    vec3 from=origin+move(dir);\n"
        "    vec3 color=raymarch(from,dir);\n"
        "    #ifdef BORDER\n"
        "    color=mix(vec3(0.),color,pow(max(0.,.95-length(oriuv*oriuv*oriuv*vec2(1.05,1.1))),.3));\n"
        "    #endif\n"
        "    fragColor = vec4(color,1.);\n"
        "}\n"
        "\n"
     );

     n->create_file("ShaderToy/GeodesicTiling.glsl",
        "// https://www.shadertoy.com/view/llVXRd\n"
        "\n"
        "#define MODEL_ROTATION vec2(.3, .25)\n"
        "#define CAMERA_ROTATION vec2(.5, .5)\n"
        "\n"
        "// 0: Defaults\n"
        "// 1: Model\n"
        "// 2: Camera\n"
        "#define MOUSE_CONTROL 1\n"
        "\n"
        "//#define DEBUG\n"
        "\n"
        "// 1, 2, or 3\n"
        "//#define LOOP 1\n"
        "\n"
        "\n"
        "// --------------------------------------------------------\n"
        "// HG_SDF\n"
        "// https://www.shadertoy.com/view/Xs3GRB\n"
        "// --------------------------------------------------------\n"
        "\n"
        "void pR(inout vec2 p, float a) {\n"
        "    p = cos(a)*p + sin(a)*vec2(p.y, -p.x);\n"
        "}\n"
        "\n"
        "float pReflect(inout vec3 p, vec3 planeNormal, float offset) {\n"
        "    float t = dot(p, planeNormal)+offset;\n"
        "    if (t < 0.) {\n"
        "        p = p - (2.*t)*planeNormal;\n"
        "    }\n"
        "    return sign(t);\n"
        "}\n"
        "\n"
        "float smax(float a, float b, float r) {\n"
        "    float m = max(a, b);\n"
        "    if ((-a < r) && (-b < r)) {\n"
        "        return max(m, -(r - sqrt((r+a)*(r+a) + (r+b)*(r+b))));\n"
        "    } else {\n"
        "        return m;\n"
        "    }\n"
        "}\n"
        "\n"
        "\n"
        "// --------------------------------------------------------\n"
        "// Icosahedron domain mirroring\n"
        "// Adapted from knighty https://www.shadertoy.com/view/MsKGzw\n"
        "// --------------------------------------------------------\n"
        "\n"
        "#define PI 3.14159265359\n"
        "\n"
        "vec3 facePlane;\n"
        "vec3 uPlane;\n"
        "vec3 vPlane;\n"
        "\n"
        "int Type=5;\n"
        "vec3 nc;\n"
        "vec3 pab;\n"
        "vec3 pbc;\n"
        "vec3 pca;\n"
        "\n"
        "void initIcosahedron() {//setup folding planes and vertex\n"
        "    float cospin=cos(PI/float(Type)), scospin=sqrt(0.75-cospin*cospin);\n"
        "    nc=vec3(-0.5,-cospin,scospin);//3rd folding plane. The two others are xz and yz planes\n"
        "    pbc=vec3(scospin,0.,0.5);//No normalization in order to have 'barycentric' coordinates work evenly\n"
        "    pca=vec3(0.,scospin,cospin);\n"
        "    pbc=normalize(pbc); pca=normalize(pca);//for slightly better DE. In reality it's not necesary to apply normalization :)\n"
        "    pab=vec3(0,0,1);\n"
        "\n"
        "    facePlane = pca;\n"
        "    uPlane = cross(vec3(1,0,0), facePlane);\n"
        "    vPlane = vec3(1,0,0);\n"
        "}\n"
        "\n"
        "void pModIcosahedron(inout vec3 p) {\n"
        "    p = abs(p);\n"
        "    pReflect(p, nc, 0.);\n"
        "    p.xy = abs(p.xy);\n"
        "    pReflect(p, nc, 0.);\n"
        "    p.xy = abs(p.xy);\n"
        "    pReflect(p, nc, 0.);\n"
        "}\n"
        "\n"
        "\n"
        "// --------------------------------------------------------\n"
        "// Triangle tiling\n"
        "// Adapted from mattz https://www.shadertoy.com/view/4d2GzV\n"
        "// --------------------------------------------------------\n"
        "\n"
        "const float sqrt3 = 1.7320508075688772;\n"
        "const float i3 = 0.5773502691896258;\n"
        "\n"
        "const mat2 cart2hex = mat2(1, 0, i3, 2. * i3);\n"
        "const mat2 hex2cart = mat2(1, 0, -.5, .5 * sqrt3);\n"
        "\n"
        "#define PHI (1.618033988749895)\n"
        "#define TAU 6.283185307179586\n"
        "\n"
        "struct TriPoints {\n"
        "    vec2 a;\n"
        "    vec2 b;\n"
        "    vec2 c;\n"
        "    vec2 center;\n"
        "    vec2 ab;\n"
        "    vec2 bc;\n"
        "    vec2 ca;\n"
        "};\n"
        "\n"
        "TriPoints closestTriPoints(vec2 p) {\n"
        "    vec2 pTri = cart2hex * p;\n"
        "    vec2 pi = floor(pTri);\n"
        "    vec2 pf = fract(pTri);\n"
        "\n"
        "    float split1 = step(pf.y, pf.x);\n"
        "    float split2 = step(pf.x, pf.y);\n"
        "\n"
        "    vec2 a = vec2(split1, 1);\n"
        "    vec2 b = vec2(1, split2);\n"
        "    vec2 c = vec2(0, 0);\n"
        "\n"
        "    a += pi;\n"
        "    b += pi;\n"
        "    c += pi;\n"
        "\n"
        "    a = hex2cart * a;\n"
        "    b = hex2cart * b;\n"
        "    c = hex2cart * c;\n"
        "\n"
        "    vec2 center = (a + b + c) / 3.;\n"
        "\n"
        "    vec2 ab = (a + b) / 2.;\n"
        "    vec2 bc = (b + c) / 2.;\n"
        "    vec2 ca = (c + a) / 2.;\n"
        "\n"
        "    return TriPoints(a, b, c, center, ab, bc, ca);\n"
        "}\n"
        "\n"
        "\n"
        "// --------------------------------------------------------\n"
        "// Geodesic tiling\n"
        "// --------------------------------------------------------\n"
        "\n"
        "struct TriPoints3D {\n"
        "    vec3 a;\n"
        "    vec3 b;\n"
        "    vec3 c;\n"
        "    vec3 center;\n"
        "    vec3 ab;\n"
        "    vec3 bc;\n"
        "    vec3 ca;\n"
        "};\n"
        "\n"
        "vec3 intersection(vec3 n, vec3 planeNormal, float planeOffset) {\n"
        "    float denominator = dot(planeNormal, n);\n"
        "    float t = (dot(vec3(0), planeNormal ) + planeOffset) / -denominator;\n"
        "    return n * t;\n"
        "}\n"
        "\n"
        "//// Edge length of an icosahedron with an inscribed sphere of radius of 1\n"
        "//float edgeLength = 1. / ((sqrt(3.) / 12.) * (3. + sqrt(5.)));\n"
        "//// Inner radius of the icosahedron's face\n"
        "//float faceRadius = (1./6.) * sqrt(3.) * edgeLength;\n"
        "float faceRadius = 0.3819660112501051;\n"
        "\n"
        "// 2D coordinates on the icosahedron face\n"
        "vec2 icosahedronFaceCoordinates(vec3 p) {\n"
        "    vec3 pn = normalize(p);\n"
        "    vec3 i = intersection(pn, facePlane, -1.);\n"
        "    return vec2(dot(i, uPlane), dot(i, vPlane));\n"
        "}\n"
        "\n"
        "// Project 2D icosahedron face coordinates onto a sphere\n"
        "vec3 faceToSphere(vec2 facePoint) {\n"
        "    return normalize(facePlane + (uPlane * facePoint.x) + (vPlane * facePoint.y));\n"
        "}\n"
        "\n"
        "TriPoints3D geodesicTriPoints(vec3 p, float subdivisions) {\n"
        "    // Get 2D cartesian coordiantes on that face\n"
        "    vec2 uv = icosahedronFaceCoordinates(p);\n"
        "\n"
        "    // Get points on the nearest triangle tile\n"
        "    float uvScale = subdivisions / faceRadius / 2.;\n"
        "    TriPoints points = closestTriPoints(uv * uvScale);\n"
        "\n"
        "    // Project 2D triangle coordinates onto a sphere\n"
        "    vec3 a = faceToSphere(points.a / uvScale);\n"
        "    vec3 b = faceToSphere(points.b / uvScale);\n"
        "    vec3 c = faceToSphere(points.c / uvScale);\n"
        "    vec3 center = faceToSphere(points.center / uvScale);\n"
        "    vec3 ab = faceToSphere(points.ab / uvScale);\n"
        "    vec3 bc = faceToSphere(points.bc / uvScale);\n"
        "    vec3 ca = faceToSphere(points.ca / uvScale);\n"
        "\n"
        "    return TriPoints3D(a, b, c, center, ab, bc, ca);\n"
        "}\n"
        "\n"
        "\n"
        "// --------------------------------------------------------\n"
        "// Spectrum colour palette\n"
        "// IQ https://www.shadertoy.com/view/ll2GD3\n"
        "// --------------------------------------------------------\n"
        "\n"
        "vec3 pal( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d ) {\n"
        "    return a + b*cos( 6.28318*(c*t+d) );\n"
        "}\n"
        "\n"
        "vec3 spectrum(float n) {\n"
        "    return pal( n, vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,1.0,1.0),vec3(0.0,0.33,0.67) );\n"
        "}\n"
        "\n"
        "\n"
        "// --------------------------------------------------------\n"
        "// Model/Camera Rotation\n"
        "// --------------------------------------------------------\n"
        "\n"
        "mat3 sphericalMatrix(float theta, float phi) {\n"
        "    float cx = cos(theta);\n"
        "    float cy = cos(phi);\n"
        "    float sx = sin(theta);\n"
        "    float sy = sin(phi);\n"
        "    return mat3(\n"
        "        cy, -sy * -sx, -sy * cx,\n"
        "        0, cx, sx,\n"
        "        sy, cy * -sx, cy * cx\n"
        "    );\n"
        "}\n"
        "\n"
        "mat3 mouseRotation(bool enable, vec2 xy) {\n"
        "    if (enable) {\n"
        "        vec2 mouse = iMouse.xy / iResolution.xy;\n"
        "\n"
        "        if (mouse.x != 0. && mouse.y != 0.) {\n"
        "            xy.x = mouse.x;\n"
        "            xy.y = mouse.y;\n"
        "        }\n"
        "    }\n"
        "    float rx, ry;\n"
        "\n"
        "    rx = (xy.y + .5) * PI;\n"
        "    ry = (-xy.x) * 2. * PI;\n"
        "\n"
        "    return sphericalMatrix(rx, ry);\n"
        "}\n"
        "\n"
        "mat3 modelRotation() {\n"
        "    mat3 m = mouseRotation(MOUSE_CONTROL==1, MODEL_ROTATION);\n"
        "    return m;\n"
        "}\n"
        "\n"
        "mat3 cameraRotation() {\n"
        "    mat3 m = mouseRotation(MOUSE_CONTROL==2, CAMERA_ROTATION);\n"
        "    return m;\n"
        "}\n"
        "\n"
        "\n"
        "// --------------------------------------------------------\n"
        "// Animation\n"
        "// --------------------------------------------------------\n"
        "\n"
        "const float SCENE_DURATION = 6.;\n"
        "const float CROSSFADE_DURATION = 2.;\n"
        "\n"
        "float time;\n"
        "\n"
        "struct HexSpec {\n"
        "    float roundTop;\n"
        "    float roundCorner;\n"
        "    float height;\n"
        "    float thickness;\n"
        "    float gap;\n"
        "};\n"
        "\n"
        "HexSpec newHexSpec(float subdivisions) {\n"
        "    return HexSpec(\n"
        "        .05 / subdivisions,\n"
        "        .1 / subdivisions,\n"
        "        2.,\n"
        "        2.,\n"
        "        .005\n"
        "    );\n"
        "}\n"
        "\n"
        "// Animation 1\n"
        "\n"
        "float animSubdivisions1() {\n"
        "    return mix(2.4, 3.4, cos(time * PI) * .5 + .5);\n"
        "}\n"
        "\n"
        "HexSpec animHex1(vec3 hexCenter, float subdivisions) {\n"
        "    HexSpec spec = newHexSpec(subdivisions);\n"
        "\n"
        "    float offset = time * 3. * PI;\n"
        "    offset -= subdivisions;\n"
        "    float blend = dot(hexCenter, pca);\n"
        "    blend = cos(blend * 30. + offset) * .5 + .5;\n"
        "    spec.height = mix(1.75, 2., blend);\n"
        "\n"
        "    spec.thickness = spec.height;\n"
        "\n"
        "    return spec;\n"
        "}\n"
        "\n"
        "// Animation 2\n"
        "\n"
        "float animSubdivisions2() {\n"
        "    return mix(1., 2.3, sin(time * PI/2.) * .5 + .5);\n"
        "}\n"
        "\n"
        "HexSpec animHex2(vec3 hexCenter, float subdivisions) {\n"
        "    HexSpec spec = newHexSpec(subdivisions);\n"
        "\n"
        "    float blend = hexCenter.y;\n"
        "    spec.height = mix(1.6, 2., sin(blend * 10. + time * PI) * .5 + .5);\n"
        "\n"
        "    spec.roundTop = .02 / subdivisions;\n"
        "    spec.roundCorner = .09 / subdivisions;\n"
        "    spec.thickness = spec.roundTop * 4.;\n"
        "    spec.gap = .01;\n"
        "\n"
        "    return spec;\n"
        "}\n"
        "\n"
        "// Animation 3\n"
        "\n"
        "float animSubdivisions3() {\n"
        "    return 5.;\n"
        "}\n"
        "\n"
        "HexSpec animHex3(vec3 hexCenter, float subdivisions) {\n"
        "    HexSpec spec = newHexSpec(subdivisions);\n"
        "\n"
        "    float blend = acos(dot(hexCenter, pab)) * 10.;\n"
        "    blend = cos(blend + time * PI) * .5 + .5;\n"
        "    spec.gap = mix(.01, .4, blend) / subdivisions;\n"
        "\n"
        "    spec.thickness = spec.roundTop * 2.;\n"
        "\n"
        "    return spec;\n"
        "}\n"
        "\n"
        "// Transition between animations\n"
        "\n"
        "float sineInOut(float t) {\n"
        "  return -0.5 * (cos(PI * t) - 1.0);\n"
        "}\n"
        "\n"
        "float transitionValues(float a, float b, float c) {\n"
        "    #ifdef LOOP\n"
        "        #if LOOP == 1\n"
        "            return a;\n"
        "        #endif\n"
        "        #if LOOP == 2\n"
        "            return b;\n"
        "        #endif\n"
        "        #if LOOP == 3\n"
        "            return c;\n"
        "        #endif\n"
        "    #endif\n"
        "    float t = time / SCENE_DURATION;\n"
        "    float scene = floor(mod(t, 3.));\n"
        "    float blend = fract(t);\n"
        "    float delay = (SCENE_DURATION - CROSSFADE_DURATION) / SCENE_DURATION;\n"
        "    blend = max(blend - delay, 0.) / (1. - delay);\n"
        "    blend = sineInOut(blend);\n"
        "    float ab = mix(a, b, blend);\n"
        "    float bc = mix(b, c, blend);\n"
        "    float cd = mix(c, a, blend);\n"
        "    float result = mix(ab, bc, min(scene, 1.));\n"
        "    result = mix(result, cd, max(scene - 1., 0.));\n"
        "    return result;\n"
        "}\n"
        "\n"
        "HexSpec transitionHexSpecs(HexSpec a, HexSpec b, HexSpec c) {\n"
        "    float roundTop = transitionValues(a.roundTop, b.roundTop, c.roundTop);\n"
        "    float roundCorner = transitionValues(a.roundCorner, b.roundCorner, c.roundCorner);\n"
        "    float height = transitionValues(a.height, b.height, c.height);\n"
        "    float thickness = transitionValues(a.thickness, b.thickness, c.thickness);\n"
        "    float gap = transitionValues(a.gap, b.gap, c.gap);\n"
        "    return HexSpec(roundTop, roundCorner, height, thickness, gap);\n"
        "}\n"
        "\n"
        "\n"
        "// --------------------------------------------------------\n"
        "// Modelling\n"
        "// --------------------------------------------------------\n"
        "\n"
        "const vec3 FACE_COLOR = vec3(.9,.9,1.);\n"
        "const vec3 BACK_COLOR = vec3(.1,.1,.15);\n"
        "const vec3 BACKGROUND_COLOR = vec3(.0, .005, .03);\n"
        "\n"
        "struct Model {\n"
        "    float dist;\n"
        "    vec3 albedo;\n"
        "    float glow;\n"
        "};\n"
        "\n"
        "Model hexModel(\n"
        "    vec3 p,\n"
        "    vec3 hexCenter,\n"
        "    vec3 edgeA,\n"
        "    vec3 edgeB,\n"
        "    HexSpec spec\n"
        ") {\n"
        "    float d;\n"
        "\n"
        "    float edgeADist = dot(p, edgeA) + spec.gap;\n"
        "    float edgeBDist = dot(p, edgeB) - spec.gap;\n"
        "    float edgeDist = smax(edgeADist, -edgeBDist, spec.roundCorner);\n"
        "\n"
        "    float outerDist = length(p) - spec.height;\n"
        "    d = smax(edgeDist, outerDist, spec.roundTop);\n"
        "\n"
        "    float innerDist = length(p) - spec.height + spec.thickness;\n"
        "    d = smax(d, -innerDist, spec.roundTop);\n"
        "\n"
        "    vec3 color;\n"
        "\n"
        "    float faceBlend = (spec.height - length(p)) / spec.thickness;\n"
        "    faceBlend = clamp(faceBlend, 0., 1.);\n"
        "    color = mix(FACE_COLOR, BACK_COLOR, step(.5, faceBlend));\n"
        "\n"
        "    vec3 edgeColor = spectrum(dot(hexCenter, pca) * 5. + length(p) + .8);\n"
        "    float edgeBlend = smoothstep(-.04, -.005, edgeDist);\n"
        "    color = mix(color, edgeColor, edgeBlend);\n"
        "\n"
        "    return Model(d, color, edgeBlend);\n"
        "}\n"
        "\n"
        "// checks to see which intersection is closer\n"
        "Model opU( Model m1, Model m2 ){\n"
        "    if (m1.dist < m2.dist) {\n"
        "        return m1;\n"
        "    } else {\n"
        "        return m2;\n"
        "    }\n"
        "}\n"
        "\n"
        "Model geodesicModel(vec3 p) {\n"
        "\n"
        "    pModIcosahedron(p);\n"
        "\n"
        "    float subdivisions = transitionValues(\n"
        "        animSubdivisions1(),\n"
        "        animSubdivisions2(),\n"
        "        animSubdivisions3()\n"
        "       );\n"
        "    TriPoints3D points = geodesicTriPoints(p, subdivisions);\n"
        "\n"
        "    vec3 edgeAB = normalize(cross(points.center, points.ab));\n"
        "    vec3 edgeBC = normalize(cross(points.center, points.bc));\n"
        "    vec3 edgeCA = normalize(cross(points.center, points.ca));\n"
        "\n"
        "    Model model, part;\n"
        "    HexSpec spec;\n"
        "\n"
        "    spec = transitionHexSpecs(\n"
        "        animHex1(points.b, subdivisions),\n"
        "        animHex2(points.b, subdivisions),\n"
        "        animHex3(points.b, subdivisions)\n"
        "    );\n"
        "    part = hexModel(p, points.b, edgeAB, edgeBC, spec);\n"
        "    model = part;\n"
        "\n"
        "    spec = transitionHexSpecs(\n"
        "        animHex1(points.c, subdivisions),\n"
        "        animHex2(points.c, subdivisions),\n"
        "        animHex3(points.c, subdivisions)\n"
        "    );\n"
        "    part = hexModel(p, points.c, edgeBC, edgeCA, spec);\n"
        "    model = opU(model, part);\n"
        "\n"
        "    spec = transitionHexSpecs(\n"
        "        animHex1(points.a, subdivisions),\n"
        "        animHex2(points.a, subdivisions),\n"
        "        animHex3(points.a, subdivisions)\n"
        "    );\n"
        "    part = hexModel(p, points.a, edgeCA, edgeAB, spec);\n"
        "    model = opU(model, part);\n"
        "\n"
        "    return model;\n"
        "}\n"
        "\n"
        "Model map( vec3 p ){\n"
        "    mat3 m = modelRotation();\n"
        "    p *= m;\n"
        "    #ifndef LOOP\n"
        "        pR(p.xz, time * PI/16.);\n"
        "    #endif\n"
        "    Model model = geodesicModel(p);\n"
        "    return model;\n"
        "}\n"
        "\n"
        "// --------------------------------------------------------\n"
        "// LIGHTING\n"
        "// Adapted from IQ https://www.shadertoy.com/view/Xds3zN\n"
        "// --------------------------------------------------------\n"
        "\n"
        "vec3 doLighting(Model model, vec3 pos, vec3 nor, vec3 ref, vec3 rd) {\n"
        "    vec3 lightPos = normalize(vec3(.5,.5,-1.));\n"
        "    vec3 backLightPos = normalize(vec3(-.5,-.3,1));\n"
        "    vec3 ambientPos = vec3(0,1,0);\n"
        "\n"
        "    vec3  lig = lightPos;\n"
        "    float amb = clamp((dot(nor, ambientPos) + 1.) / 2., 0., 1.);\n"
        "    float dif = clamp( dot( nor, lig ), 0.0, 1.0 );\n"
        "    float bac = pow(clamp(dot(nor, backLightPos), 0., 1.), 1.5);\n"
        "    float fre = pow( clamp(1.0+dot(nor,rd),0.0,1.0), 2.0 );\n"
        "\n"
        "    vec3 lin = vec3(0.0);\n"
        "    lin += 1.20 * dif * vec3(.9);\n"
        "    lin += 0.80 * amb * vec3(.5, .7, .8);\n"
        "    lin += 0.30 * bac * vec3(.25);\n"
        "    lin += 0.20 * fre * vec3(1);\n"
        "\n"
        "    vec3 albedo = model.albedo;\n"
        "    vec3 col = mix(albedo * lin, albedo, model.glow);\n"
        "\n"
        "    return col;\n"
        "}\n"
        "\n"
        "\n"
        "// --------------------------------------------------------\n"
        "// Ray Marching\n"
        "// Adapted from cabbibo https://www.shadertoy.com/view/Xl2XWt\n"
        "// --------------------------------------------------------\n"
        "\n"
        "const float MAX_TRACE_DISTANCE = 8.; // max trace distance\n"
        "const float INTERSECTION_PRECISION = .001; // precision of the intersection\n"
        "const int NUM_OF_TRACE_STEPS = 100;\n"
        "const float FUDGE_FACTOR = .9; // Default is 1, reduce to fix overshoots\n"
        "\n"
        "struct CastRay {\n"
        "    vec3 origin;\n"
        "    vec3 direction;\n"
        "};\n"
        "\n"
        "struct Ray {\n"
        "    vec3 origin;\n"
        "    vec3 direction;\n"
        "    float len;\n"
        "};\n"
        "\n"
        "struct Hit {\n"
        "    Ray ray;\n"
        "    Model model;\n"
        "    vec3 pos;\n"
        "    bool isBackground;\n"
        "    vec3 normal;\n"
        "    vec3 color;\n"
        "};\n"
        "\n"
        "vec3 calcNormal( in vec3 pos ){\n"
        "    vec3 eps = vec3( 0.001, 0.0, 0.0 );\n"
        "    vec3 nor = vec3(\n"
        "        map(pos+eps.xyy).dist - map(pos-eps.xyy).dist,\n"
        "        map(pos+eps.yxy).dist - map(pos-eps.yxy).dist,\n"
        "        map(pos+eps.yyx).dist - map(pos-eps.yyx).dist );\n"
        "    return normalize(nor);\n"
        "}\n"
        "\n"
        "Hit raymarch(CastRay castRay){\n"
        "\n"
        "    float currentDist = INTERSECTION_PRECISION * 2.0;\n"
        "    Model model;\n"
        "\n"
        "    Ray ray = Ray(castRay.origin, castRay.direction, 0.);\n"
        "\n"
        "    for( int i=0; i< NUM_OF_TRACE_STEPS ; i++ ){\n"
        "        if (currentDist < INTERSECTION_PRECISION || ray.len > MAX_TRACE_DISTANCE) {\n"
        "            break;\n"
        "        }\n"
        "        model = map(ray.origin + ray.direction * ray.len);\n"
        "        currentDist = model.dist;\n"
        "        ray.len += currentDist * FUDGE_FACTOR;\n"
        "    }\n"
        "\n"
        "    bool isBackground = false;\n"
        "    vec3 pos = vec3(0);\n"
        "    vec3 normal = vec3(0);\n"
        "    vec3 color = vec3(0);\n"
        "\n"
        "    if (ray.len > MAX_TRACE_DISTANCE) {\n"
        "        isBackground = true;\n"
        "    } else {\n"
        "        pos = ray.origin + ray.direction * ray.len;\n"
        "        normal = calcNormal(pos);\n"
        "    }\n"
        "\n"
        "    return Hit(ray, model, pos, isBackground, normal, color);\n"
        "}\n"
        "\n"
        "\n"
        "// --------------------------------------------------------\n"
        "// Rendering\n"
        "// --------------------------------------------------------\n"
        "\n"
        "void shadeSurface(inout Hit hit){\n"
        "\n"
        "    vec3 color = BACKGROUND_COLOR;\n"
        "\n"
        "    if (hit.isBackground) {\n"
        "        hit.color = color;\n"
        "        return;\n"
        "    }\n"
        "\n"
        "    vec3 ref = reflect(hit.ray.direction, hit.normal);\n"
        "\n"
        "    #ifdef DEBUG\n"
        "        color = hit.normal * 0.5 + 0.5;\n"
        "    #else\n"
        "        color = doLighting(\n"
        "            hit.model,\n"
        "            hit.pos,\n"
        "            hit.normal,\n"
        "            ref,\n"
        "            hit.ray.direction\n"
        "        );\n"
        "    #endif\n"
        "\n"
        "    hit.color = color;\n"
        "}\n"
        "\n"
        "vec3 render(Hit hit){\n"
        "    shadeSurface(hit);\n"
        "    return hit.color;\n"
        "}\n"
        "\n"
        "\n"
        "// --------------------------------------------------------\n"
        "// Camera\n"
        "// https://www.shadertoy.com/view/Xl2XWt\n"
        "// --------------------------------------------------------\n"
        "\n"
        "mat3 calcLookAtMatrix( in vec3 ro, in vec3 ta, in float roll )\n"
        "{\n"
        "    vec3 ww = normalize( ta - ro );\n"
        "    vec3 uu = normalize( cross(ww,vec3(sin(roll),cos(roll),0.0) ) );\n"
        "    vec3 vv = normalize( cross(uu,ww));\n"
        "    return mat3( uu, vv, ww );\n"
        "}\n"
        "\n"
        "void doCamera(out vec3 camPos, out vec3 camTar, out float camRoll, in float time, in vec2 mouse) {\n"
        "    float dist = 5.5;\n"
        "    camRoll = 0.;\n"
        "    camTar = vec3(0,0,0);\n"
        "    camPos = vec3(0,0,-dist);\n"
        "    camPos *= cameraRotation();\n"
        "    camPos += camTar;\n"
        "}\n"
        "\n"
        "\n"
        "// --------------------------------------------------------\n"
        "// Gamma\n"
        "// https://www.shadertoy.com/view/Xds3zN\n"
        "// --------------------------------------------------------\n"
        "\n"
        "const float GAMMA = 2.2;\n"
        "\n"
        "vec3 gamma(vec3 color, float g) {\n"
        "    return pow(color, vec3(g));\n"
        "}\n"
        "\n"
        "vec3 linearToScreen(vec3 linearRGB) {\n"
        "    return gamma(linearRGB, 1.0 / GAMMA);\n"
        "}\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{\n"
        "    time = iTime;\n"
        "\n"
        "    #ifdef LOOP\n"
        "        #if LOOP == 1\n"
        "            time = mod(time, 2.);\n"
        "        #endif\n"
        "        #if LOOP == 2\n"
        "            time = mod(time, 4.);\n"
        "        #endif\n"
        "        #if LOOP == 3\n"
        "            time = mod(time, 2.);\n"
        "        #endif\n"
        "    #endif\n"
        "\n"
        "    initIcosahedron();\n"
        "\n"
        "    vec2 p = (-iResolution.xy + 2.0*fragCoord.xy)/iResolution.y;\n"
        "    vec2 m = iMouse.xy / iResolution.xy;\n"
        "\n"
        "    vec3 camPos = vec3( 0., 0., 2.);\n"
        "    vec3 camTar = vec3( 0. , 0. , 0. );\n"
        "    float camRoll = 0.;\n"
        "\n"
        "    // camera movement\n"
        "    doCamera(camPos, camTar, camRoll, iTime, m);\n"
        "\n"
        "    // camera matrix\n"
        "    mat3 camMat = calcLookAtMatrix( camPos, camTar, camRoll );  // 0.0 is the camera roll\n"
        "\n"
        "    // create view ray\n"
        "    vec3 rd = normalize( camMat * vec3(p.xy,2.0) ); // 2.0 is the lens length\n"
        "\n"
        "    Hit hit = raymarch(CastRay(camPos, rd));\n"
        "\n"
        "    vec3 color = render(hit);\n"
        "\n"
        "    #ifndef DEBUG\n"
        "        color = linearToScreen(color);\n"
        "    #endif\n"
        "\n"
        "    fragColor = vec4(color,1.0);\n"
        "}\n"
        "\n"
     );

     n->create_file("ShaderToy/Geomechanical.glsl",
        "// https://www.shadertoy.com/view/MdcXzn\n"
        "\n"
        "// Author : Sebastien Berube\n"
        "// Created : March 2015\n"
        "// Modified : Jan 2016\n"
        "//\n"
        "// Composition made from a repeated hexagon prism pattern.\n"
        "// Hexagon prism distance function had to be modified to smooth out vertical edges.\n"
        "//\n"
        "// Sources:\n"
        "// Inigo Quilez\n"
        "// http://iquilezles.org/www/articles/distfunctions/distfunctions.htm\n"
        "// http://iquilezles.org/www/articles/raymarchingdf/raymarchingdf.htm\n"
        "// For those interested in the origin of sphere tracing:\n"
        "// Sphere Tracing: A Geometric Method for the Antialiased Ray Tracing of Implicit Surfaces (1994)\n"
        "// http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.48.3825\n"
        "// Spline\n"
        "// http://www.lighthouse3d.com/tutorials/maths/catmull-rom-spline/\n"
        "//\n"
        "// License : Creative Commons Non-commercial (NC) license\n"
        "//\n"
        "\n"
        "//----------------------\n"
        "// Constants\n"
        "const float PI = 3.14159;\n"
        "const float SCALE = 1.0;\n"
        "const float MAX_DIST = 1000.0;\n"
        "const float FLOOR_HEIGHT  = 0.0;\n"
        "const float X_REPEAT_DIST = 0.90*SCALE;\n"
        "const float Z_REPEAT_DIST = 1.05*SCALE;\n"
        "const float PRIM_HEIGHT    = 1.0;\n"
        "const float HEX_HALF_WIDTH = 0.26*SCALE;\n"
        "const float GEOMETRY_DISPLACEMENT = 1.00;\n"
        "float g_time;\n"
        "\n"
        "struct AnimationChannels\n"
        "{\n"
        "    float material_roughness;   //[0-1 range]\n"
        "    float geometry_width;       //[0-1 range]\n"
        "    float geometry_scale;       //[0-1 range]\n"
        "    float geometry_displacement;//[0-1 range]\n"
        "    float geometry_smoothness;  //[0-1 range]\n"
        "    vec3 camPos;                //[IR range]\n"
        "    vec3 camLookAt;             //[IR range]\n"
        "};\n"
        "AnimationChannels g_animationChannels;\n"
        "\n"
        "//Material ID enum\n"
        "const int MATERIALID_NONE      = 0;\n"
        "const int MATERIALID_FLOOR     = 1;\n"
        "const int MATERIALID_SKY       = 2;\n"
        "const int MATERIALID_PLASTIC   = 3;\n"
        "const int MATERIALID_METAL     = 4;\n"
        "\n"
        "//Debug flag enum\n"
        "const int DEBUG_RAYLEN  = 0;\n"
        "const int DEBUG_GEODIST = 1;\n"
        "const int DEBUG_NORMAL  = 2;\n"
        "const int DEBUG_MATID   = 3;\n"
        "\n"
        "float fDEBUG = 0.1;\n"
        "\n"
        "//Defines\n"
        "#define saturate(x) clamp(x,0.0,1.0)\n"
        "//----------------------\n"
        "// Camera\n"
        "struct Cam { vec3 R; vec3 U; vec3 D; vec3 o; float lens; float zoom; }; //Right, Up, Direction, origin\n"
        "Cam    CAM_lookAt(vec3 target, float pitchAngleRad, float dist, float theta);\n"
        "Cam    CAM_mouseLookAt(vec3 at, float dst);\n"
        "Cam    CAM_animate(vec2 uv, float fTime);\n"
        "vec3   CAM_getRay(Cam cam, vec2 uv);\n"
        "\n"
        "//----------------------\n"
        "// Post Process\n"
        "vec3 POST_ProcessFX(vec3 c, vec2 uv);\n"
        "\n"
        "//----------------------\n"
        "// Analytic Intersections\n"
        "float RAYINTERSEC_plane(vec3 o, vec3 d, vec3 po, vec3 pn)\n"
        "{\n"
        "    return dot(po-o,pn)/dot(d,pn);\n"
        "}\n"
        "\n"
        "struct repeatInfo\n"
        "{\n"
        "    vec3 smpl; //object-space, cyclic\n"
        "    vec3 anchor; //world space\n"
        "};\n"
        "\n"
        "#define normalized_wave(a) (0.5*a+0.5)\n"
        "repeatInfo DF_repeatHex(vec3 p)\n"
        "{\n"
        "    //Repetition\n"
        "    float xRepeatDist = X_REPEAT_DIST;\n"
        "    float zRepeatDist = Z_REPEAT_DIST*0.5;\n"
        "    float latticeX = (fract(p.x/xRepeatDist+0.5)-0.5)*xRepeatDist;\n"
        "    float latticeY = (fract(p.z/zRepeatDist+0.5)-0.5)*zRepeatDist;\n"
        "    vec2 anchorPosXZ = p.xz-vec2(latticeX,latticeY);\n"
        "    p.x = latticeX; //Cyclic coords.\n"
        "    p.z = latticeY;\n"
        "\n"
        "    //Variation\n"
        "    float period = fract(g_time/30.)*3.0;\n"
        "    float theta = period*2.0*PI;\n"
        "    float overallAmplitude = normalized_wave(-cos(theta)); //Overall amplitude modulation\n"
        "    float waveAmplitude = g_animationChannels.geometry_displacement\n"
        "                         *normalized_wave(sin(anchorPosXZ.x+anchorPosXZ.y+theta*4.0));\n"
        "    float primHeight = FLOOR_HEIGHT+overallAmplitude*waveAmplitude;\n"
        "\n"
        "    repeatInfo outData;\n"
        "    outData.anchor = vec3(anchorPosXZ[0], primHeight, anchorPosXZ[1]);\n"
        "    outData.smpl = p;\n"
        "\n"
        "    return outData;\n"
        "}\n"
        "\n"
        "#define zclamp(a) max(a,0.0) //Clamp negative values at zero\n"
        "float DF_RoundedHex( vec3 p, float width, float height)\n"
        "{\n"
        "    //Modified version (smooth edges) of the exagon prism found here:\n"
        "    //http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm\n"
        "    float smoothRadius = g_animationChannels.geometry_smoothness*0.2;\n"
        "    width -= smoothRadius*2.0;\n"
        "\n"
        "    //Hexagon prism constructed using X,Y,Z symmetry.\n"
        "    //Only quadrant 1 needs to be solved, but the joining diagonal to quadrant IV is also\n"
        "    //required for distance blending (see db).\n"
        "    p = abs(p);\n"
        "\n"
        "    //Hexagonal edge distances :\n"
        "    //Note : [.8666,0.5] = [sin(PI/3,cos(PI/3)] -> Hexagon edges rotation coeff (60 degrees).\n"
        "    float da = (p.x*0.866025+p.z*0.5)-width; //quadrant I diagonal edge distance\n"
        "    float db = (p.x*0.866025-p.z*0.5)-width; //quadrant IV diagonal edge distance (needed for blending)\n"
        "    float dc = p.z-width; //upper distance\n"
        "\n"
        "    vec3 d = zclamp(vec3(da,db,dc));\n"
        "    //Note: this is not an euclidian length, therefore this operation slightly distorts our distance field.\n"
        "    //Yet, it is harmless to convergence, and does the smoothing job quite well.\n"
        "    float dw = length(d)-smoothRadius; //hexagonal part smoothness (blending at 60 deg)\n"
        "    float dh = p.y-height;\n"
        "\n"
        "    //Now that we have xz distance(dw) and y distance (dh), we can compute the distance\n"
        "    //for the given isovalue (the smoothing radius).\n"
        "    //Note : internal distance (maxX,maxY,maxZ) is also used to genereate internal signed dist,\n"
        "    //       helping convergence when overstepping (very frequent with domain repetition).\n"
        "    float externalDistance = length(zclamp(vec2(dh,dw)))-smoothRadius; //Smoothed, unsigned\n"
        "    float internalDistance = max(max(da,dc),dh); //Sharp, signed.\n"
        "    return min(externalDistance,internalDistance);\n"
        "}\n"
        "\n"
        "struct DF_out\n"
        "{\n"
        "    float d;\n"
        "    int matID;\n"
        "    vec3 objectPos;\n"
        "};\n"
        "\n"
        "//The distance field composition.\n"
        "//::DF_composition\n"
        "DF_out DF_composition( in vec3 pos )\n"
        "{\n"
        "    //Explanation:\n"
        "    //http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm\n"
        "    DF_out oFloor;\n"
        "    DF_out oHexA;\n"
        "    DF_out oHexB;\n"
        "\n"
        "    oHexA.matID = MATERIALID_PLASTIC;\n"
        "    repeatInfo infoA = DF_repeatHex(pos-vec3(0));\n"
        "    oHexA.objectPos = infoA.anchor;\n"
        "    oHexA.d = DF_RoundedHex( infoA.smpl-vec3(0,infoA.anchor.y,0),\n"
        "                             g_animationChannels.geometry_width*HEX_HALF_WIDTH, PRIM_HEIGHT );\n"
        "\n"
        "    oHexB.matID = MATERIALID_PLASTIC;\n"
        "    repeatInfo infoB = DF_repeatHex(pos-vec3(X_REPEAT_DIST*0.5,0, Z_REPEAT_DIST*0.25));\n"
        "    oHexB.objectPos = infoB.anchor;\n"
        "    oHexB.d = DF_RoundedHex( infoB.smpl-vec3(0,infoB.anchor.y,0),\n"
        "                             g_animationChannels.geometry_width*HEX_HALF_WIDTH, PRIM_HEIGHT );\n"
        "\n"
        "    if(oHexA.d<oHexB.d)\n"
        "        return oHexA;\n"
        "    else\n"
        "        return oHexB;\n"
        "}\n"
        "\n"
        "//The distance field gradient\n"
        "vec3 DF_gradient( in vec3 p )\n"
        "{\n"
        "    //The field gradient is the distance derivative along each axis.\n"
        "    //The surface normal follows the direction where this variation is strongest.\n"
        "    const float d = 0.001;\n"
        "    vec3 grad = vec3(DF_composition(p+vec3(d,0,0)).d-DF_composition(p-vec3(d,0,0)).d,\n"
        "                     DF_composition(p+vec3(0,d,0)).d-DF_composition(p-vec3(0,d,0)).d,\n"
        "                     DF_composition(p+vec3(0,0,d)).d-DF_composition(p-vec3(0,0,d)).d);\n"
        "    return grad/(2.0*d);\n"
        "}\n"
        "\n"
        "#define OVERSTEP_COMPENSATION 1\n"
        "\n"
        "//o = ray origin, d = direction, t = distance travelled along ray, starting from origin\n"
        "float RAYMARCH_isosurface( vec3 o, vec3 d, float isoSurfaceValue)\n"
        "{\n"
        "    //Learned from Inigo Quilez DF ray marching :\n"
        "    //http://www.iquilezles.org/www/articles/raymarchingdf/raymarchingdf.htm\n"
        "    //Original articles (interesting read) :\n"
        "    //Sphere Tracing: A Geometric Method for the Antialiased Ray Tracing of Implicit Surfaces (1989)\n"
        "    //http://mathinfo.univ-reims.fr/IMG/pdf/hart94sphere.pdf\n"
        "    //John C. Hart Sphere Tracing: A Geometric Method for the Antialiased Ray Tracing of Implicit Surfaces (1994)\n"
        "    //http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.48.3825 p. 5.75-5.85\n"
        "\n"
        "    const float tolerance = 0.0001;\n"
        "    float t = 0.0;\n"
        "    float dist = MAX_DIST;\n"
        "    #if OVERSTEP_COMPENSATION\n"
        "    for( int i=0; i<30; i++ )\n"
        "    {\n"
        "        dist = DF_composition( o+d*t ).d;\n"
        "        dist -= isoSurfaceValue;\n"
        "\n"
        "        if( abs(dist)<tolerance*100.0 ) break;\n"
        "        t += dist;\n"
        "    }\n"
        "\n"
        "    t -= Z_REPEAT_DIST/2.0;\n"
        "\n"
        "    for( int i=0; i<30; i++ )\n"
        "    {\n"
        "        dist = DF_composition( o+d*t ).d;\n"
        "        dist -= isoSurfaceValue;\n"
        "\n"
        "        if( abs(dist)<tolerance ) break;\n"
        "\n"
        "        t += min(dist,Z_REPEAT_DIST/5.0);\n"
        "    }\n"
        "    #else\n"
        "    for( int i=0; i<70; i++ )\n"
        "    {\n"
        "        dist = DF_composition( o+d*t ).d;\n"
        "        dist -= isoSurfaceValue;\n"
        "\n"
        "        if( abs(dist)<tolerance ) break;\n"
        "        t += dist;\n"
        "    }\n"
        "    #endif\n"
        "\n"
        "    return t;\n"
        "}\n"
        "\n"
        "#define saturate(x) clamp(x,0.0,1.0)\n"
        "float RAYMARCH_DFSS( vec3 o, vec3 L, float coneWidth )\n"
        "{\n"
        "    //Variation of the Distance Field Soft Shadow from : https://www.shadertoy.com/view/Xds3zN\n"
        "    //Initialize the minimum aperture (angle tan) allowable with this distance-field technique\n"
        "    //(45deg: sin/cos = 1:1)\n"
        "    float minAperture = 1.0;\n"
        "    float t = 0.0; //initial travel distance, from geometry surface (usually, pretty close)\n"
        "    float dist = 10.0;\n"
        "    for( int i=0; i<7; i++ )\n"
        "    {\n"
        "        vec3 p = o+L*t; //Sample position = ray origin + ray direction * travel distance\n"
        "        float dist = DF_composition( p ).d;\n"
        "        dist = min(dist,t);\n"
        "        float curAperture = dist/t; //Aperture ~= cone angle tangent (sin=dist/cos=travelDist)\n"
        "        minAperture = min(minAperture,curAperture);\n"
        "        //Step size : limit range (0.02-0.42)\n"
        "        t += 0.02+min(dist,0.4);\n"
        "    }\n"
        "\n"
        "    //The cone width controls shadow transition. The narrower, the sharper the shadow.\n"
        "    return saturate(minAperture/coneWidth); //Should never exceed [0-1]. 0 = shadow, 1 = fully lit.\n"
        "}\n"
        "\n"
        "float RAYMARCH_DFAO( vec3 o, vec3 N, float isoSurfaceValue)\n"
        "{\n"
        "    //Variation of DFAO from : https://www.shadertoy.com/view/Xds3zN\n"
        "    //Interesting reads:\n"
        "    //https://docs.unrealengine.com/latest/INT/Engine/Rendering/LightingAndShadows/DistanceFieldAmbientOcclusion/index.html#howdoesitwork?\n"
        "    //Implementation notes:\n"
        "    //-Doubling step size at each iteration\n"
        "    //-Allowing negative distance field values to contribute, making cracks much darker\n"
        "    //-Not reducing effect with distance (specific to this application)\n"
        "    float MaxOcclusion = 0.0;\n"
        "    float TotalOcclusion = 0.0;\n"
        "    const int nSAMPLES = 4;\n"
        "    float stepSize = 0.11/float(nSAMPLES);\n"
        "    for( int i=0; i<nSAMPLES; i++ )\n"
        "    {\n"
        "        float t = 0.01 + stepSize;\n"
        "        //Double distance each iteration (only valid for small sample count, e.g. 4)\n"
        "        stepSize = stepSize*2.0;\n"
        "        float dist = DF_composition( o+N*t ).d-isoSurfaceValue;\n"
        "        //Occlusion factor inferred from the difference between the\n"
        "        //distance covered along the ray, and the distance from other surrounding geometry.\n"
        "        float occlusion = zclamp(t-dist);\n"
        "        TotalOcclusion += occlusion;//Not reducing contribution on each iteration\n"
        "        MaxOcclusion += t;\n"
        "    }\n"
        "\n"
        "    //Here, TotalOcclusion can actually exceed MaxOcclusion, where the rays\n"
        "    //get inside the shape and grab negative occlusion values. It does look good\n"
        "    //that way IMHO (much darker in the cracks), therefore the maximum occlusion is bumped\n"
        "    //25% to allow those cracks to get darker.\n"
        "    return saturate(1.0-TotalOcclusion/(MaxOcclusion*1.25));\n"
        "}\n"
        "\n"
        "struct TraceData\n"
        "{\n"
        "    float rayLen;  //Ray travel distance\n"
        "    vec3  rayDir;  //Ray direction\n"
        "    float geoDist; //Distance to geometry (error on final position)\n"
        "    vec3  normal;  //Geometry normal\n"
        "    vec3  objectPos; //Object position (center)\n"
        "    int   matID;     //Material ID\n"
        "};\n"
        "\n"
        "TraceData new_TraceData()\n"
        "{\n"
        "    TraceData td;\n"
        "    td.rayLen = 0.;\n"
        "    td.rayDir = vec3(0);\n"
        "    td.geoDist = 0.;\n"
        "    td.normal = vec3(0);\n"
        "    td.objectPos = vec3(0);\n"
        "    td.matID = MATERIALID_NONE;\n"
        "    return td;\n"
        "}\n"
        "\n"
        "vec3 PBR_HDRremap(vec3 c)\n"
        "{\n"
        "    float fHDR = smoothstep(2.900,3.0,c.x+c.y+c.z);\n"
        "    return mix(c,1.3*vec3(4.5,3.5,3.0),fHDR);\n"
        "}\n"
        "\n"
        "//http://refractiveindex.info/?shelf=3d&book=liquids&page=water\n"
        "const float F_DIELECTRIC_PLASTIC = 1.49; //@550nm\n"
        "const float F_DIELECTRIC_WATER   = 1.33; //@550nm\n"
        "const float F_DIELECTRIC_DIAMOND = 2.42; //@550nm\n"
        "\n"
        "//ior = index of refraction\n"
        "//n = refraction index\n"
        "vec3 PBR_Fresnel_Schlick_Dielectric(vec3 n, float VdotH)\n"
        "{\n"
        "    //<Source : https://en.wikipedia.org/wiki/Schlick%27s_approximation>\n"
        "    vec3 F0 = abs ((1.0 - n) / (1.0 + n));\n"
        "    return F0 + (1.-F0) * pow( 1. - VdotH, 5.);\n"
        "    //</Source : https://en.wikipedia.org/wiki/Schlick%27s_approximation>\n"
        "}\n"
        "\n"
        "vec3 PBR_ABL_Equation(vec3 V, vec3 L, vec3 N, float roughness, float metallic, vec3 ior_n, vec3 ior_k)\n"
        "{\n"
        "    roughness = max(roughness,0.01);\n"
        "\n"
        "    vec3 H = normalize(L+V);\n"
        "    float NdotH = dot(N,H);//Nn.H;\n"
        "    float NdotL = dot(N,L);//Nn.Ln;\n"
        "    float VdotH = dot(V,H);//Vn.H;\n"
        "    float NdotV = dot(N,V);//Nn.Vn;\n"
        "\n"
        "    //Distribution term\n"
        "    //This D value is an approximation of the probability for a given light to bounce into the viewing vector direction.\n"
        "    //It is not necessarily 100% mathematically/physically correct : this is still just a function which has a curve that decently\n"
        "    //matches the physical distribution.\n"
        "    //<Source: https://de45xmedrsdbp.cloudfront.net/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf p.3/59>\n"
        "    float PI = 3.14159;\n"
        "    float alpha2 = roughness * roughness;\n"
        "    float NoH2 = NdotH * NdotH;\n"
        "    float den = NoH2*(alpha2-1.0)+1.0;\n"
        "    float D = (NdotH>0.)?alpha2/(PI*den*den):0.0;\n"
        "    //</https://de45xmedrsdbp.cloudfront.net/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf p.3/59>\n"
        "\n"
        "    //Fresnel term\n"
        "    vec3 F = PBR_Fresnel_Schlick_Dielectric(ior_n, VdotH);\n"
        "\n"
        "    //Geometric term\n"
        "    //<Source: https://de45xmedrsdbp.cloudfront.net/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf p.3/59>\n"
        "    float Gk = (roughness+1.)*(roughness+1.)/8.; //<-Disney's modification for ABL\n"
        "    float Gl = max(NdotL,0.)/(NdotL*(1.0-Gk)+Gk);\n"
        "    float Gv = max(NdotV,0.)/(NdotV*(1.0-Gk)+Gk);\n"
        "    float G = Gl*Gv;\n"
        "    //</https://de45xmedrsdbp.cloudfront.net/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf p.3/59>\n"
        "\n"
        "    //The PBR equation seen pretty much everywhere:\n"
        "    //<Source : https://seblagarde.wordpress.com/2015/07/14/siggraph-2014-moving-frostbite-to-physically-based-rendering/ p.14>\n"
        "    //<Source : http://www.codinglabs.net/article_physically_based_rendering_cook_torrance.aspx>\n"
        "    float softTr = 0.2; // Valid range : [0.001-0.25]. Will reduce reflexivity on edges if too high.\n"
        "    //Personal addition : This parameter softens up the transition at grazing angles (otherwise too sharp IMHO).\n"
        "    vec3 Rs = D*F*G / (4.*NdotV*NdotL*(1.0-softTr)+softTr);\n"
        "    //<Source : http://www.codinglabs.net/article_physically_based_rendering_cook_torrance.aspx>\n"
        "\n"
        "    return Rs;\n"
        "}\n"
        "\n"
        "#define saturate(x) clamp(x,0.0,1.0)\n"
        "vec3 MAT_Plastic(TraceData traceData, vec3 cDiff, vec3 N, vec3 V, vec3 L0, vec3 L1, float dfao, float dfss0, float dfss1)\n"
        "{\n"
        "    vec3 col = vec3(0);\n"
        "\n"
        "    float fRoughness = g_animationChannels.material_roughness;\n"
        "\n"
        "    //Ambient directional contribution (3x):\n"
        "    //           color*directionalContribution(<normal,ambientDir>)\n"
        "    //This give a basic \"ambient\" shading, which varies with normal angle\n"
        "    vec3 cAmb  = vec3(0.26,0.24,0.23)*vec3(0.5+0.5*dot(traceData.normal,vec3(+0.08,1,+0.1)))\n"
        "               + vec3(0.25,0.25,0.30)*vec3(0.5+0.5*dot(traceData.normal,vec3(-0.28,1,-0.17)))\n"
        "               + vec3(0.19,0.25,0.30)*vec3(0.5+0.5*dot(traceData.normal,vec3(+0.28,1,-0.27)));\n"
        "    //2 x PBR lights\n"
        "    vec3 CL0  = PBR_HDRremap(vec3(1))*PBR_ABL_Equation(V,L0,traceData.normal, fRoughness, 0., vec3(F_DIELECTRIC_PLASTIC), vec3(0));\n"
        "    vec3 CL1  = PBR_HDRremap(vec3(1))*PBR_ABL_Equation(V,L1,traceData.normal, fRoughness, 0., vec3(F_DIELECTRIC_PLASTIC), vec3(0));\n"
        "\n"
        "    col = cAmb*dfao;\n"
        "    col *= saturate(0.30+fRoughness*0.5+0.2*(dfss0+dfss1));\n"
        "    col += (dfss0+fRoughness*0.25)*CL0;\n"
        "    col += (dfss1+fRoughness*0.25)*CL1;\n"
        "\n"
        "    return col*0.75;\n"
        "}\n"
        "\n"
        "float SAMPLER_trilinear(vec3 p)\n"
        "{\n"
        "    //Noise layering trick from Inigo Quilez.\n"
        "    //See this for more explanation: https://www.shadertoy.com/view/Ms3SRr\n"
        "    const float TEXTURE_RES = 256.0; //Noise texture resolution\n"
        "    p *= TEXTURE_RES;   //Computation in pixel space (1 unit = 1 pixel)\n"
        "    vec3 pixCoord = floor(p);//Pixel coord, integer [0,1,2,3...256...]\n"
        "    vec3 t = p-pixCoord;     //Pixel interpolation position, linear range [0-1] (fractional part)\n"
        "    t = (3.0 - 2.0 * t) * t * t; //interpolant easing function : linear->cubic\n"
        "    vec2 layer_translation = -pixCoord.y*vec2(37.0,17.0)/TEXTURE_RES; //noise volume stacking trick : g layer = r layer shifted by (37x17 pixels -> this is no keypad smashing, but the actual translation embedded in the noise texture).\n"
        "//    vec2 layer1_layer2 = texture(iChannel0,layer_translation+(pixCoord.xz+t.xz+0.5)/TEXTURE_RES,-100.0).xy; //Note : +0.5 to fall right on pixel center\n"
        "    vec2 layer1_layer2 = vec2(0.0, 0.0);\n"
        "    return mix( layer1_layer2.x, layer1_layer2.y, t.y ); //Layer interpolation (trilinear/volumetric)\n"
        "}\n"
        "\n"
        "float MAT_remap_angle_probability(float x_01)\n"
        "{\n"
        "    //cos(jitter) is used to alter probabilty distribution :\n"
        "    //it remaps an evenly distributed function into another\n"
        "    //one where closer angles are more probable, and wider\n"
        "    //angles are less probable.\n"
        "    return (1.0-cos(x_01*PI/2.0));\n"
        "}\n"
        "\n"
        "vec3 MAT_addFog(float travelDist, in vec3 color, in vec3 p, in vec3 c_atmosphere)\n"
        "{\n"
        "    float a = 0.08;\n"
        "    float NORMALIZATION_TERM = log((1.+a)/a);\n"
        "    float da = travelDist/50.0;\n"
        "    da = log((da+a)/a)/NORMALIZATION_TERM;\n"
        "    vec3 FinalColor = mix(color,c_atmosphere,saturate(da));\n"
        "    return FinalColor;\n"
        "}\n"
        "\n"
        "//::MAT_apply\n"
        "vec4 MAT_apply(vec3 pos, TraceData traceData)\n"
        "{\n"
        "    vec3 c_atmosphere = mix(vec3(0.87,0.94,1.0),vec3(0.6,0.80,1.0),clamp(3.0*pos.y/length(pos.xz),0.,1.));\n"
        "\n"
        "    if(traceData.matID==MATERIALID_SKY)\n"
        "    {\n"
        "        return vec4(c_atmosphere,1.0);\n"
        "    }\n"
        "\n"
        "    vec4 col = vec4(0);\n"
        "    vec3 N = traceData.normal;\n"
        "    vec3 V = normalize(-traceData.rayDir);\n"
        "    vec3 L0 = normalize(vec3(0.5,1.2,0.3));\n"
        "    vec3 L1 = normalize(vec3(-L0.x,L0.y,-L0.z+0.5));\n"
        "\n"
        "    //<Jittered AO Samples around Y axis, to reduce artifacts associated with closely repeated geometry>\n"
        "    float fNoiseAmplitude = 0.4;\n"
        "    float jitter_01 = SAMPLER_trilinear(pos*10.0+g_time*50.0);\n"
        "    float t = MAT_remap_angle_probability(jitter_01)*fNoiseAmplitude;\n"
        "    vec3 Na = vec3(N.xz*mat2(cos(t),sin(t),-sin(t),cos(t)),N.y).xzy; //Rotate(t)\n"
        "    jitter_01 = SAMPLER_trilinear(5.0+pos*9.11);\n"
        "    t = MAT_remap_angle_probability(jitter_01)*fNoiseAmplitude;\n"
        "    vec3 Nb = vec3(N.xz*mat2(cos(t),-sin(t),sin(t),cos(t)),N.y).xzy; //Rotate(-t)\n"
        "    float dfaoA = RAYMARCH_DFAO( pos, Na, 0.02);\n"
        "    float dfaoB = RAYMARCH_DFAO( pos, Nb, 0.02);\n"
        "    float dfaoAveraged = 0.5*(dfaoA+dfaoB);\n"
        "    //</Jittered AO Samples>\n"
        "\n"
        "    float dfss0 = RAYMARCH_DFSS( pos+L0*0.01, L0, 0.2);\n"
        "    float dfss1 = RAYMARCH_DFSS( pos+L1*0.01, L1, 0.2);\n"
        "\n"
        "    if(traceData.matID==MATERIALID_PLASTIC)\n"
        "    {\n"
        "        col.rgb = MAT_Plastic(traceData, vec3(1), N, V, L0, L1, dfaoAveraged, dfss0, dfss1);\n"
        "    }\n"
        "\n"
        "    col.rgb = MAT_addFog(traceData.rayLen*0.3, col.rgb, pos, c_atmosphere);\n"
        "\n"
        "    return col;\n"
        "}\n"
        "\n"
        "float TRACE_zprime(vec3 o, vec3 d)\n"
        "{\n"
        "    float geometryCeiling = FLOOR_HEIGHT+PRIM_HEIGHT\n"
        "                           +g_animationChannels.geometry_displacement*GEOMETRY_DISPLACEMENT;\n"
        "    float t = RAYINTERSEC_plane(o, d, vec3(0,geometryCeiling,0), vec3(0,1,0));\n"
        "    return (t<0.0)?MAX_DIST:t;\n"
        "    return t;\n"
        "}\n"
        "\n"
        "//o=ray origin, d=ray direction\n"
        "//::TRACE_geometry\n"
        "TraceData TRACE_geometry(vec3 o, vec3 d)\n"
        "{\n"
        "    //Raymarching (the expensive function)\n"
        "    TraceData dfTrace;\n"
        "    float rayLen = RAYMARCH_isosurface(o,d,0.0);\n"
        "    vec3 dfHitPosition = o+rayLen*d;\n"
        "\n"
        "    //Additional sample, to gather material ID and other info\n"
        "    //(we want that stuff coompiled out of the raymarching loop, it clutters the code and might slow things down)\n"
        "    DF_out compInfo = DF_composition( dfHitPosition );\n"
        "    rayLen += compInfo.d;\n"
        "    dfHitPosition = o+rayLen*d;\n"
        "\n"
        "    dfTrace.rayLen     = rayLen;\n"
        "    dfTrace.matID      = compInfo.matID;\n"
        "    dfTrace.objectPos  = compInfo.objectPos;\n"
        "    dfTrace.geoDist    = compInfo.d;\n"
        "    dfTrace.rayDir     = d;\n"
        "    dfTrace.normal     = normalize(DF_gradient(dfHitPosition));\n"
        "\n"
        "    return dfTrace;\n"
        "}\n"
        "\n"
        "vec3 TRACE_debug(TraceData traceData, int elemID)\n"
        "{\n"
        "    if(elemID==DEBUG_RAYLEN)  return vec3(log(traceData.rayLen)*0.2);\n"
        "    if(elemID==DEBUG_GEODIST) return vec3(traceData.geoDist);\n"
        "    if(elemID==DEBUG_NORMAL)  return traceData.normal;\n"
        "    if(elemID==DEBUG_MATID)   return traceData.matID==MATERIALID_PLASTIC?vec3(1):\n"
        "                                     vec3(traceData.matID==MATERIALID_FLOOR?1:0,\n"
        "                                          traceData.matID==MATERIALID_METAL?1:0,\n"
        "                                          traceData.matID==MATERIALID_SKY?1:0);\n"
        "    return vec3(0);\n"
        "}\n"
        "\n"
        "const int SPLINE_POINT_COUNT = 8;\n"
        "struct SPLINE_CtrlPts\n"
        "{\n"
        "    vec4 p[SPLINE_POINT_COUNT];\n"
        "};\n"
        "vec4 SPLINE_PointArray(int i, SPLINE_CtrlPts ctrlPts)\n"
        "{\n"
        "    //Just a way to get around the fact global arrays do not support random index access.\n"
        "    //(only texture/resources)\n"
        "    if(i==0 || i==SPLINE_POINT_COUNT  ) return ctrlPts.p[0];\n"
        "    if(i==1 || i==SPLINE_POINT_COUNT+1) return ctrlPts.p[1];\n"
        "    if(i==2 || i==SPLINE_POINT_COUNT+2) return ctrlPts.p[2];\n"
        "    if(i==3) return ctrlPts.p[3];\n"
        "    if(i==4) return ctrlPts.p[4];\n"
        "    if(i==5) return ctrlPts.p[5];\n"
        "    if(i==6) return ctrlPts.p[6];\n"
        "    if(i==7) return ctrlPts.p[7];\n"
        "    return vec4(0);\n"
        "}\n"
        "\n"
        "vec4 SPLINE_catmullRom(float fTime, SPLINE_CtrlPts ctrlPts)\n"
        "{\n"
        "    float t = fract(fTime);\n"
        "    const float n = float(SPLINE_POINT_COUNT);\n"
        "\n"
        "    int idxOffset = int(t*n);\n"
        "    vec4 p1 = SPLINE_PointArray(idxOffset,ctrlPts);\n"
        "    vec4 p2 = SPLINE_PointArray(idxOffset+1,ctrlPts);\n"
        "    vec4 p3 = SPLINE_PointArray(idxOffset+2,ctrlPts);\n"
        "    vec4 p4 = SPLINE_PointArray(idxOffset+3,ctrlPts);\n"
        "\n"
        "    //For some reason, fract(t) returns garbage on my machine with small values of t.\n"
        "    //return fract(n*t);\n"
        "    //Using this below yields the same results, minus the glitches.\n"
        "    t *= n;\n"
        "    t = (t-float(int(t)));\n"
        "\n"
        "    //A classic catmull-rom\n"
        "    //e.g.\n"
        "    //http://steve.hollasch.net/cgindex/curves/catmull-rom.html\n"
        "    //http://www.lighthouse3d.com/tutorials/maths/catmull-rom-spline/\n"
        "    vec4 val = 0.5 * ((-p1 + 3.*p2 -3.*p3 + p4)*t*t*t\n"
        "               + (2.*p1 -5.*p2 + 4.*p3 - p4)*t*t\n"
        "               + (-p1+p3)*t\n"
        "               + 2.*p2);\n"
        "    return val;\n"
        "}\n"
        "\n"
        "void ANIM_main(float fTime)\n"
        "{\n"
        "    float t1 = 0.010*fTime;\n"
        "    float t2 = 0.010*fTime+0.03;\n"
        "\n"
        "    SPLINE_CtrlPts cameraPosKeyFrames; //100 sec cycle.\n"
        "    //                    DATA: PosX,PosY,PosZ,Tilt\n"
        "    cameraPosKeyFrames.p[1] = vec4(10.0,2.70,05.0,1.90); //t=00.0s\n"
        "    cameraPosKeyFrames.p[2] = vec4(16.0,3.30,08.5,1.00); //t=12.5s\n"
        "    cameraPosKeyFrames.p[3] = vec4(20.0,6.80,05.0,2.97); //t=25.0s\n"
        "    cameraPosKeyFrames.p[4] = vec4(40.0,3.40,17.5,0.82); //t=37.5s\n"
        "    cameraPosKeyFrames.p[5] = vec4(30.0,3.10,27.5,1.97); //t=50.0s\n"
        "    cameraPosKeyFrames.p[6] = vec4(25.0,3.20,22.5,1.93); //t=62.5s\n"
        "    cameraPosKeyFrames.p[7] = vec4(15.0,3.00,24.5,1.95); //t=75.0s\n"
        "    cameraPosKeyFrames.p[0] = vec4(05.0,2.80,12.5,1.20); //t=87.5s\n"
        "    vec4 cameraPos = SPLINE_catmullRom(t1,cameraPosKeyFrames);\n"
        "    vec4 cameraDir = normalize(SPLINE_catmullRom(t2,cameraPosKeyFrames)-cameraPos);\n"
        "\n"
        "    SPLINE_CtrlPts geometryKeyFrames; //25 sec cycle.\n"
        "    //                      DATA: round,width,roughness,displacement\n"
        "    geometryKeyFrames.p[1] = vec4(0.070,1.000,0.30,1.000); //t=00.0s\n"
        "    geometryKeyFrames.p[2] = vec4(0.090,0.900,0.50,0.900); //t=01.25s\n"
        "    geometryKeyFrames.p[3] = vec4(0.080,1.000,0.20,1.000); //t=02.50s\n"
        "    geometryKeyFrames.p[4] = vec4(0.150,0.970,0.50,0.990); //t=03.75s\n"
        "    geometryKeyFrames.p[5] = vec4(0.090,0.820,0.50,0.820); //t=05.00s\n"
        "    geometryKeyFrames.p[6] = vec4(0.110,0.970,0.50,0.990); //t=06.25s\n"
        "    geometryKeyFrames.p[7] = vec4(0.050,0.930,0.50,0.930); //t=07.50s\n"
        "    geometryKeyFrames.p[0] = vec4(0.120,0.950,0.50,0.980); //t=08.75s\n"
        "    vec4 geoPose = SPLINE_catmullRom(t1*25.0,geometryKeyFrames);\n"
        "\n"
        "    g_animationChannels.camPos    = cameraPos.xyz;\n"
        "    g_animationChannels.camLookAt = cameraPos.xyz+cameraDir.xyz-vec3(0,cameraPos.w,0);\n"
        "    g_animationChannels.geometry_smoothness = geoPose[0];\n"
        "    g_animationChannels.material_roughness = 0.45;\n"
        "    g_animationChannels.geometry_width = geoPose[1];\n"
        "    g_animationChannels.geometry_displacement = GEOMETRY_DISPLACEMENT;\n"
        "}\n"
        "\n"
        "vec3 TRACE_main( vec3 o, vec3 dir, vec2 uv)\n"
        "{\n"
        "    float fRemainingAlpha = 1.0;\n"
        "    float zStart = TRACE_zprime(o, dir);\n"
        "    vec3 pt = o+dir*zStart;\n"
        "    vec3 ptGeo = vec3(0);\n"
        "\n"
        "    TraceData geometryTraceData;\n"
        "    if(zStart< MAX_DIST)\n"
        "    {\n"
        "        geometryTraceData = TRACE_geometry(pt, dir);\n"
        "        geometryTraceData.rayLen += zStart;\n"
        "        ptGeo = o+dir*geometryTraceData.rayLen;\n"
        "    }\n"
        "    else\n"
        "    {\n"
        "        geometryTraceData.rayLen     = MAX_DIST;\n"
        "        geometryTraceData.matID      = MATERIALID_SKY;\n"
        "        geometryTraceData.objectPos  = pt;\n"
        "        geometryTraceData.geoDist    = 0.0;\n"
        "        geometryTraceData.rayDir     = dir;\n"
        "        ptGeo = pt;\n"
        "    }\n"
        "\n"
        "    //return TRACE_debug(geometryTraceData, DEBUG_RAYLEN);  //OK\n"
        "    //return TRACE_debug(geometryTraceData, DEBUG_GEODIST); //OK\n"
        "    //return TRACE_debug(geometryTraceData, DEBUG_NORMAL);  //OK\n"
        "    //return TRACE_debug(geometryTraceData, DEBUG_MATID);   //OK\n"
        "\n"
        "    vec4 cFinal = MAT_apply(ptGeo,geometryTraceData);\n"
        "\n"
        "    return cFinal.rgb;\n"
        "}\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{\n"
        "    g_time = iTime+2.6; //Time offset for better preview\n"
        "    vec2 uv = (fragCoord.xy-0.5*iResolution.xy) / iResolution.xx;\n"
        "\n"
        "    float fTime = g_time+2.1;\n"
        "    ANIM_main(fTime);\n"
        "\n"
        "    Cam cam = CAM_animate(uv,fTime);\n"
        "    vec3 d = CAM_getRay(cam,uv);\n"
        "    vec3 c = TRACE_main(cam.o, d, uv);\n"
        "\n"
        "    //No supersampling required for most PostProcessFX.\n"
        "    c = POST_ProcessFX(c,uv);\n"
        "\n"
        "    fragColor = vec4(c,1.0);\n"
        "}\n"
        "\n"
        "vec3 POST_ProcessFX(vec3 c, vec2 uv)\n"
        "{\n"
        "    //Vignetting\n"
        "    float lensRadius = 0.65;\n"
        "    uv /= lensRadius;\n"
        "    float sin2 = uv.x*uv.x+uv.y*uv.y;\n"
        "    float cos2 = 1.0-min(sin2*sin2,1.0);\n"
        "    float cos4 = cos2*cos2;\n"
        "    c *= cos4;\n"
        "\n"
        "    //Gamma\n"
        "    c = pow(c,vec3(0.4545));\n"
        "    return c;\n"
        "}\n"
        "\n"
        "//----------------------\n"
        "// Camera\n"
        "//::CAM\n"
        "Cam CAM_animate(vec2 uv, float fTime)\n"
        "{\n"
        "    Cam cam;\n"
        "    cam.o = g_animationChannels.camPos;\n"
        "    cam.D = normalize(g_animationChannels.camLookAt-cam.o);\n"
        "    cam.R = normalize(cross(cam.D,vec3(0,1,0)));\n"
        "    cam.U = normalize(cross(cam.R,cam.D));\n"
        "    cam.lens = 1.2+0.3*sin(fTime*0.1);\n"
        "    cam.zoom = 3.0+sin(fTime*0.1)/cam.lens;\n"
        "    return cam;\n"
        "}\n"
        "\n"
        "vec3 CAM_getRay(Cam cam,vec2 uv)\n"
        "{\n"
        "    uv = cam.lens*uv/(cam.lens-length(uv)*length(uv));\n"
        "    uv *= cam.zoom;\n"
        "    return normalize(uv.x*cam.R+uv.y*cam.U+cam.D);\n"
        "}\n"
        "\n"
     );

     n->create_file("ShaderToy/HappyJumping.glsl",
        "// https://www.shadertoy.com/view/3lsSzf\n"
        "\n"
        "// Created by inigo quilez - iq/2019\n"
        "// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.\n"
        "//\n"
        "//\n"
        "// An animation test - a happy dull and blobby creature jumping and looking around.\n"
        "//\n"
        "// Set AA to 1 if your machine is too slow\n"
        "\n"
        "#define AA 1\n"
        "\n"
        "\n"
        "//------------------------------------------------------------------\n"
        "\n"
        "\n"
        "// http://iquilezles.org/www/articles/smin/smin.htm\n"
        "float smin( float a, float b, float k )\n"
        "{\n"
        "    float h = max(k-abs(a-b),0.0);\n"
        "    return min(a, b) - h*h*0.25/k;\n"
        "}\n"
        "\n"
        "vec2 smin( vec2 a, vec2 b, float k )\n"
        "{\n"
        "    #if 0\n"
        "    float h = max(k-abs(a.x-b.x),0.0);\n"
        "    return vec2(min(a.x,b.x) - h*h*0.25/k, mix(a.y,b.y, clamp((a.x-b.x)/k,0.0,1.0)) );\n"
        "    #else\n"
        "    float h = clamp( 0.5+0.5*(b.x-a.x)/k, 0.0, 1.0 );\n"
        "    return mix( b, a, h ) - k*h*(1.0-h);\n"
        "    #endif\n"
        "}\n"
        "\n"
        "// http://iquilezles.org/www/articles/smin/smin.htm\n"
        "float smax( float a, float b, float k )\n"
        "{\n"
        "    float h = clamp( 0.5 + 0.5*(b-a)/k, 0.0, 1.0 );\n"
        "    return mix( a, b, h ) + k*h*(1.0-h);\n"
        "}\n"
        "\n"
        "// http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm\n"
        "float sdSphere( vec3 p, float s )\n"
        "{\n"
        "    return length(p)-s;\n"
        "}\n"
        "\n"
        "// http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm\n"
        "float sdEllipsoid( in vec3 p, in vec3 r ) // approximated\n"
        "{\n"
        "    float k0 = length(p/r);\n"
        "    float k1 = length(p/(r*r));\n"
        "    return k0*(k0-1.0)/k1;\n"
        "}\n"
        "\n"
        "vec2 sdStick(vec3 p, vec3 a, vec3 b, float r1, float r2) // approximated\n"
        "{\n"
        "    vec3 pa = p-a, ba = b-a;\n"
        "    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n"
        "    return vec2( length( pa - ba*h ) - mix(r1,r2,h*h*(3.0-2.0*h)), h );\n"
        "}\n"
        "\n"
        "vec4 opU( vec4 d1, vec4 d2 )\n"
        "{\n"
        "    return (d1.x<d2.x) ? d1 : d2;\n"
        "}\n"
        "\n"
        "//------------------------------------------------------------------\n"
        "\n"
        "#define ZERO (min(iFrame,0.0))\n"
        "\n"
        "//------------------------------------------------------------------\n"
        "\n"
        "float href;\n"
        "\n"
        "vec4 map( in vec3 pos, float atime )\n"
        "{\n"
        "    float t1 = fract(atime);\n"
        "    float t4 = abs(fract(atime*0.5)-0.5)/0.5;\n"
        "\n"
        "    float p = 4.0*t1*(1.0-t1);\n"
        "    float pp = 4.0*(1.0-2.0*t1); // derivative of p\n"
        "\n"
        "    vec3 cen = vec3( 0.5*(-1.0 + 2.0*t4),\n"
        "                     pow( p, 2.0-smoothstep(0.0,0.25,p)) + 0.1,\n"
        "                     floor(atime) + pow(t1,0.7) -1.0 );\n"
        "\n"
        "    // body\n"
        "    vec2 uu = normalize(vec2( 1.0, -pp ));\n"
        "    vec2 vv = vec2(-uu.y, uu.x);\n"
        "\n"
        "    float sy = 0.5 + 0.5*p;\n"
        "    float compress = 1.0-smoothstep(0.0,0.4,p);\n"
        "    sy = sy*(1.0-compress) + compress;\n"
        "    float sz = 1.0/sy;\n"
        "\n"
        "    vec3 q = pos - cen;\n"
        "    float rot = -0.25*(-1.0 + 2.0*t4);\n"
        "    float rc = cos(rot);\n"
        "    float rs = sin(rot);\n"
        "    q.xy = mat2x2(rc,rs,-rs,rc)*q.xy;\n"
        "    vec3 r = q;\n"
        "    href = q.y;\n"
        "    q.yz = vec2( dot(uu,q.yz), dot(vv,q.yz) );\n"
        "\n"
        "    vec4 res = vec4( sdEllipsoid( q, vec3(0.25, 0.25*sy, 0.25*sz) ), 2.0, 0.0, 1.0 );\n"
        "\n"
        "    if( res.x<1.0 ) // bounding volume\n"
        "    {\n"
        "    float t2 = fract(atime+0.8);\n"
        "    float p2 = 0.5-0.5*cos(6.2831*t2);\n"
        "    r.z += 0.05-0.2*p2;\n"
        "    r.y += 0.2*sy-0.2;\n"
        "    vec3 sq = vec3( abs(r.x), r.yz );\n"
        "\n"
        "    // head\n"
        "    vec3 h = r;\n"
        "    float hr = sin(0.791*atime);\n"
        "    hr = 0.7*sign(hr)*smoothstep(0.5,0.7,abs(hr));\n"
        "    h.xz = mat2x2(cos(hr),sin(hr),-sin(hr),cos(hr))*h.xz;\n"
        "    vec3 hq = vec3( abs(h.x), h.yz );\n"
        "       float d  = sdEllipsoid( h-vec3(0.0,0.20,0.02), vec3(0.08,0.2,0.15) );\n"
        "    float d2 = sdEllipsoid( h-vec3(0.0,0.21,-0.1), vec3(0.20,0.2,0.20) );\n"
        "    d = smin( d, d2, 0.1 );\n"
        "    res.x = smin( res.x, d, 0.1 );\n"
        "\n"
        "    // belly wrinkles\n"
        "    {\n"
        "    float yy = r.y-0.02-2.5*r.x*r.x;\n"
        "    res.x += 0.001*sin(yy*120.0)*(1.0-smoothstep(0.0,0.1,abs(yy)));\n"
        "    }\n"
        "\n"
        "    // arms\n"
        "    {\n"
        "    vec2 arms = sdStick( sq, vec3(0.18-0.06*hr*sign(r.x),0.2,-0.05), vec3(0.3+0.1*p2,-0.2+0.3*p2,-0.15), 0.03, 0.06 );\n"
        "    res.xz = smin( res.xz, arms, 0.01+0.04*(1.0-arms.y)*(1.0-arms.y)*(1.0-arms.y) );\n"
        "    }\n"
        "\n"
        "    // ears\n"
        "    {\n"
        "    float t3 = fract(atime+0.9);\n"
        "    float p3 = 4.0*t3*(1.0-t3);\n"
        "    vec2 ear = sdStick( hq, vec3(0.15,0.32,-0.05), vec3(0.2+0.05*p3,0.2+0.2*p3,-0.07), 0.01, 0.04 );\n"
        "    res.xz = smin( res.xz, ear, 0.01 );\n"
        "    }\n"
        "\n"
        "    // mouth\n"
        "    {\n"
        "       d = sdEllipsoid( h-vec3(0.0,0.15+4.0*hq.x*hq.x,0.15), vec3(0.1,0.04,0.2) );\n"
        "    res.w = 0.3+0.7*clamp( d*150.0,0.0,1.0);\n"
        "    res.x = smax( res.x, -d, 0.03 );\n"
        "    }\n"
        "\n"
        "    // legs\n"
        "    {\n"
        "    float t6 = cos(6.2831*(atime*0.5+0.25));\n"
        "    float ccc = cos(1.57*t6*sign(r.x));\n"
        "    float sss = sin(1.57*t6*sign(r.x));\n"
        "    vec3 base = vec3(0.12,-0.07,-0.1); base.y -= 0.1/sy;\n"
        "    vec2 legs = sdStick( sq, base, base + vec3(0.2,-ccc,sss)*0.2, 0.04, 0.07 );\n"
        "    res.xz = smin( res.xz, legs, 0.07 );\n"
        "    }\n"
        "\n"
        "    // eye\n"
        "    {\n"
        "    float blink = pow(0.5+0.5*sin(2.1*iTime),20.0);\n"
        "    float eyeball = sdSphere(hq-vec3(0.08,0.27,0.06),0.065+0.02*blink);\n"
        "    res.x = smin( res.x, eyeball, 0.03 );\n"
        "\n"
        "    vec3 cq = hq-vec3(0.1,0.34,0.08);\n"
        "    cq.xy = mat2x2(0.8,0.6,-0.6,0.8)*cq.xy;\n"
        "    d = sdEllipsoid( cq, vec3(0.06,0.03,0.03) );\n"
        "    res.x = smin( res.x, d, 0.03 );\n"
        "\n"
        "    float eo = 1.0-0.5*smoothstep(0.01,0.04,length((hq.xy-vec2(0.095,0.285))*vec2(1.0,1.1)));\n"
        "    res = opU( res, vec4(sdSphere(hq-vec3(0.08,0.28,0.08),0.060),3.0,0.0,eo));\n"
        "    res = opU( res, vec4(sdSphere(hq-vec3(0.075,0.28,0.102),0.0395),4.0,0.0,1.0));\n"
        "    }\n"
        "    }\n"
        "\n"
        "    // ground\n"
        "    float fh = -0.1 - 0.05*(sin(pos.x*2.0)+sin(pos.z*2.0));\n"
        "    float t5 = fract(atime+0.05);\n"
        "    float k = length(pos.xz-cen.xz);\n"
        "    float tt = t5*15.0-6.2831 - k*3.0;\n"
        "    fh -= 0.1*exp(-k*k)*sin(tt)*exp(-max(tt,0.0)/2.0)*smoothstep(0.0,0.01,t5);\n"
        "    float d = pos.y - fh;\n"
        "\n"
        "    // bubbles\n"
        "    {\n"
        "    vec3 vp = vec3( mod(abs(pos.x),3.0),pos.y,mod(pos.z+1.5,3.0)-1.5);\n"
        "    vec2 id = vec2( floor(pos.x/3.0), floor((pos.z+1.5)/3.0) );\n"
        "    float fid = id.x*11.1 + id.y*31.7;\n"
        "    float fy = fract(fid*1.312+atime*0.1);\n"
        "    float y = -1.0+4.0*fy;\n"
        "    vec3  rad = vec3(0.7,1.0+0.5*sin(fid),0.7);\n"
        "    rad -= 0.1*(sin(pos.x*3.0)+sin(pos.y*4.0)+sin(pos.z*5.0));\n"
        "    float siz = 4.0*fy*(1.0-fy);\n"
        "    float d2 = sdEllipsoid( vp-vec3(2.0,y,0.0), siz*rad );\n"
        "    d2 -= 0.03*smoothstep(-1.0,1.0,sin(18.0*pos.x)+sin(18.0*pos.y)+sin(18.0*pos.z));\n"
        "    d2 *= 0.6;\n"
        "    d2 = min(d2,2.0);\n"
        "    d = smin( d, d2, 0.32 );\n"
        "    if( d<res.x ) res = vec4(d,1.0,0.0,1.0);\n"
        "    }\n"
        "\n"
        "    // candy\n"
        "    {\n"
        "    float fs = 5.0;\n"
        "    vec3 qos = fs*vec3(pos.x, pos.y-fh, pos.z );\n"
        "    vec2 id = vec2( floor(qos.x+0.5), floor(qos.z+0.5) );\n"
        "    vec3 vp = vec3( fract(qos.x+0.5)-0.5,qos.y,fract(qos.z+0.5)-0.5);\n"
        "    vp.xz += 0.1*cos( id.x*130.143 + id.y*120.372 + vec2(0.0,2.0) );\n"
        "    float den = sin(id.x*0.1+sin(id.y*0.091))+sin(id.y*0.1);\n"
        "    float fid = id.x*0.143 + id.y*0.372;\n"
        "    float ra = smoothstep(0.0,0.1,den*0.1+fract(fid)-0.95);\n"
        "    d = sdSphere( vp, 0.35*ra )/fs;\n"
        "    if( d<res.x ) res = vec4(d,5.0,qos.y,1.0);\n"
        "    }\n"
        "\n"
        "\n"
        "    return res;\n"
        "}\n"
        "\n"
        "\n"
        "vec4 castRay( in vec3 ro, in vec3 rd, float time )\n"
        "{\n"
        "    vec4 res = vec4(-1.0,-1.0,0.0,1.0);\n"
        "\n"
        "    float tmin = 0.5;\n"
        "    float tmax = 20.0;\n"
        "\n"
        "    #if 1\n"
        "    // raytrace bounding plane\n"
        "    float tp = (3.5-ro.y)/rd.y;\n"
        "    if( tp>0.0 ) tmax = min( tmax, tp );\n"
        "    #endif\n"
        "\n"
        "    float t = tmin;\n"
        "    for( int i=0; i<256 && t<tmax; i++ )\n"
        "    {\n"
        "        vec4 h = map( ro+rd*t, time );\n"
        "        if( abs(h.x)<(0.0005*t) )\n"
        "        {\n"
        "            res = vec4(t,h.yzw);\n"
        "            break;\n"
        "        }\n"
        "        t += h.x;//*(1.0+t*0.01);\n"
        "    }\n"
        "\n"
        "    return res;\n"
        "}\n"
        "\n"
        "\n"
        "// http://iquilezles.org/www/articles/rmshadows/rmshadows.htm\n"
        "float calcSoftshadow( in vec3 ro, in vec3 rd, float time )\n"
        "{\n"
        "    float res = 1.0;\n"
        "\n"
        "    float tmax = 12.0;\n"
        "    #if 1\n"
        "    float tp = (3.5-ro.y)/rd.y; // raytrace bounding plane\n"
        "    if( tp>0.0 ) tmax = min( tmax, tp );\n"
        "    #endif\n"
        "\n"
        "    float t = 0.02;\n"
        "    for( int i=0; i<50; i++ )\n"
        "    {\n"
        "        float h = map( ro + rd*t, time ).x;\n"
        "        res = min( res, 16.0*h/t );\n"
        "        t += clamp( h, 0.05, 0.40 );\n"
        "        if( res<0.005 || t>tmax ) break;\n"
        "    }\n"
        "    return clamp( res, 0.0, 1.0 );\n"
        "}\n"
        "\n"
        "// http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm\n"
        "vec3 calcNormal( in vec3 pos, float time )\n"
        "{\n"
        "#if 0\n"
        "    vec2 e = vec2(1.0,-1.0)*0.5773*0.0005;\n"
        "    return normalize( e.xyy*map( pos + e.xyy, time ).x +\n"
        "                      e.yyx*map( pos + e.yyx, time ).x +\n"
        "                      e.yxy*map( pos + e.yxy, time ).x +\n"
        "                      e.xxx*map( pos + e.xxx, time ).x );\n"
        "#else\n"
        "    // inspired by klems - a way to prevent the compiler from inlining map() 4 times\n"
        "    vec3 n = vec3(0.0);\n"
        "    for( int i=int(ZERO); i<4; i++ )\n"
        "    {\n"
        "        vec3 e = 0.5773*(2.0*vec3((((i+3)>>1)&1),((i>>1)&1),(i&1))-1.0);\n"
        "        n += e*map(pos+0.0005*e,time).x;\n"
        "    }\n"
        "    return normalize(n);\n"
        "#endif\n"
        "}\n"
        "\n"
        "float calcOcclusion( in vec3 pos, in vec3 nor, float time )\n"
        "{\n"
        "    float occ = 0.0;\n"
        "    float sca = 1.0;\n"
        "    for( int i=int(ZERO); i<5; i++ )\n"
        "    {\n"
        "        float h = 0.01 + 0.11*float(i)/4.0;\n"
        "        vec3 opos = pos + h*nor;\n"
        "        float d = map( opos, time ).x;\n"
        "        occ += (h-d)*sca;\n"
        "        sca *= 0.95;\n"
        "    }\n"
        "    return clamp( 1.0 - 2.0*occ, 0.0, 1.0 );\n"
        "}\n"
        "\n"
        "vec3 render( in vec3 ro, in vec3 rd, float time )\n"
        "{\n"
        "    // sky dome\n"
        "    vec3 col = vec3(0.5, 0.8, 0.9) - max(rd.y,0.0)*0.5;\n"
        "    // sky clouds\n"
        "    vec2 uv = 1.5*rd.xz/rd.y;\n"
        "    float cl  = 1.0*(sin(uv.x)+sin(uv.y)); uv *= mat2(0.8,0.6,-0.6,0.8)*2.1;\n"
        "          cl += 0.5*(sin(uv.x)+sin(uv.y));\n"
        "    col += 0.1*(-1.0+2.0*smoothstep(-0.1,0.1,cl-0.4));\n"
        "    // sky horizon\n"
        "    col = mix( col, vec3(0.5, 0.7, .9), exp(-10.0*max(rd.y,0.0)) );\n"
        "\n"
        "\n"
        "    // geometry\n"
        "    vec4 res = castRay(ro,rd, time);\n"
        "    \n"
        "    if( res.y>-0.5 )\n"
        "    {\n"
        "        float t = res.x;\n"
        "        vec3 pos = ro + t*rd;\n"
        "        vec3 nor = calcNormal( pos, time );\n"
        "        vec3 ref = reflect( rd, nor );\n"
        "        float focc = res.w;\n"
        "\n"
        "        // material\n"
        "        col = vec3(0.2);\n"
        "        float ks = 1.0;\n"
        "\n"
        "        if( res.y>4.5 )  // candy\n"
        "        {\n"
        "             col = vec3(0.07,0.024,0.0);\n"
        "             vec2 id = floor(5.0*pos.xz+0.5);\n"
        "             col += 0.018*cos((id.x*11.1+id.y*37.341) + vec3(0.0,1.0,2.0) );\n"
        "             col = max(col,0.0);\n"
        "             focc = clamp(4.0*res.z,0.0,1.0);\n"
        "        }\n"
        "        else if( res.y>3.5 ) // eyeball\n"
        "        {\n"
        "            col = vec3(0.0);\n"
        "        }\n"
        "        else if( res.y>2.5 ) // iris\n"
        "        {\n"
        "            col = vec3(0.2);\n"
        "        }\n"
        "        else if( res.y>1.5 ) // body\n"
        "        {\n"
        "            col = mix(vec3(0.08,0.05,0.002)*0.9,vec3(0.18,0.05,0.02),res.z*res.z);\n"
        "            col = mix(col,vec3(0.14,0.09,0.06), (1.0-res.z)*smoothstep(-0.15, 0.15, -href));\n"
        "        }\n"
        "        else // terrain\n"
        "        {\n"
        "            // base green\n"
        "            col = vec3(0.023,0.040,0.009)*1.08;\n"
        "            float f = 0.2*(-1.0+2.0*smoothstep(-0.2,0.2,sin(18.0*pos.x)+sin(18.0*pos.y)+sin(18.0*pos.z)));\n"
        "            col += f*vec3(0.03,0.03,0.01);\n"
        "            ks = 0.5 + pos.y*0.15;\n"
        "\n"
        "            // footprints\n"
        "            vec2 mp = vec2(pos.x-0.5*(mod(floor(pos.z+0.5),2.0)*2.0-1.0), fract(pos.z+0.5)-0.5 );\n"
        "            float mark = 1.0-smoothstep(0.1, 0.5, length(mp));\n"
        "            mark *= smoothstep(0.0, 0.1, floor(time) - floor(pos.z+0.5) );\n"
        "            col *= mix( vec3(1.0), vec3(0.5,0.5,0.4), mark );\n"
        "            ks *= 1.0-0.5*mark;\n"
        "        }\n"
        "\n"
        "        // lighting (sun, sky, bounce, back, sss)\n"
        "        float occ = calcOcclusion( pos, nor, time )*focc;\n"
        "        float fre = clamp(1.0+dot(nor,rd),0.0,1.0);\n"
        "\n"
        "        vec3  sun_lig = normalize( vec3(0.6, 0.35, 0.5) );\n"
        "        float sun_dif = clamp(dot( nor, sun_lig ), 0.0, 1.0 );\n"
        "        vec3  sun_hal = normalize( sun_lig-rd );\n"
        "        float sun_sha = calcSoftshadow( pos, sun_lig, time );\n"
        "        float sun_spe = ks*pow(clamp(dot(nor,sun_hal),0.0,1.0),8.0)*sun_dif*(0.04+0.96*pow(clamp(1.0+dot(sun_hal,rd),0.0,1.0),5.0));\n"
        "        float sky_dif = sqrt(clamp( 0.5+0.5*nor.y, 0.0, 1.0 ));\n"
        "        float sky_spe = ks*smoothstep( 0.0, 0.5, ref.y )*(0.04+0.96*pow(fre,4.0));\n"
        "        float bou_dif = sqrt(clamp( 0.1-0.9*nor.y, 0.0, 1.0 ))*clamp(1.0-0.1*pos.y,0.0,1.0);\n"
        "        float bac_dif = clamp(0.1+0.9*dot( nor, normalize(vec3(-sun_lig.x,0.0,-sun_lig.z))), 0.0, 1.0 );\n"
        "        float sss_dif = fre*sky_dif*(0.25+0.75*sun_dif*sun_sha);\n"
        "\n"
        "        vec3 lin = vec3(0.0);\n"
        "        lin += 12.00*sun_dif*vec3(1.35,1.00,0.70)*vec3(sun_sha,sun_sha*sun_sha*0.5+0.5*sun_sha,sun_sha*sun_sha);\n"
        "        lin +=  2.00*sky_dif*vec3(0.50,0.70,1.00)*occ;\n"
        "        lin +=  2.00*bou_dif*vec3(0.20,0.70,0.10)*occ;\n"
        "        lin +=  2.00*bac_dif*vec3(0.45,0.35,0.25)*occ;\n"
        "        lin +=  4.50*sss_dif*vec3(1.30,1.10,1.00)*occ;\n"
        "        col = col*lin;\n"
        "        col +=  9.00*sun_spe*vec3(1.10,0.90,0.70)*sun_sha;\n"
        "        col +=  0.50*sky_spe*vec3(0.40,0.60,1.30)*occ*occ;\n"
        "          \n"
        "        col = pow(col,vec3(0.8,0.9,1.0) );\n"
        "\n"
        "        // fog\n"
        "        col = mix( col, vec3(0.5,0.7,0.9), 1.0-exp( -0.0001*t*t*t ) );\n"
        "    }\n"
        "\n"
        "    return col;//vec3( clamp(col,0.0,1.0) );\n"
        "}\n"
        "\n"
        "mat3 setCamera( in vec3 ro, in vec3 ta, float cr )\n"
        "{\n"
        "    vec3 cw = normalize(ta-ro);\n"
        "    vec3 cp = vec3(sin(cr), cos(cr),0.0);\n"
        "    vec3 cu = normalize( cross(cw,cp) );\n"
        "    vec3 cv =          ( cross(cu,cw) );\n"
        "    return mat3( cu, cv, cw );\n"
        "}\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{\n"
        "    vec3 tot = vec3(0.0);\n"
        "#if AA>1\n"
        "    for( int m=ZERO; m<AA; m++ )\n"
        "    for( int n=ZERO; n<AA; n++ )\n"
        "    {\n"
        "        // pixel coordinates\n"
        "        vec2 o = vec2(float(m),float(n)) / float(AA) - 0.5;\n"
        "        vec2 p = (-iResolution.xy + 2.0*(fragCoord+o))/iResolution.y;\n"
        "        // time coordinate (motion blurred, shutter=0.5)\n"
        "        float d = 0.5*sin(fragCoord.x*147.0)*sin(fragCoord.y*131.0);\n"
        "        float time = iTime - 0.5*(1.0/24.0)*(float(m*AA+n)+d)/float(AA*AA-1);\n"
        "#else\n"
        "        vec2 p = (-iResolution.xy + 2.0*fragCoord)/iResolution.y;\n"
        "        float time = iTime;\n"
        " #endif\n"
        "        time += -2.6;\n"
        "        time *= 0.9;\n"
        "\n"
        "        // camera    \n"
        "        float cl = sin(0.5*time);\n"
        "        float an = 1.57 + 0.7*sin(0.15*time);\n"
        "        vec3  ta = vec3( 0.0, 0.65, -0.6+time*1.0 - 0.4*cl);\n"
        "        vec3  ro = ta + vec3( 1.3*cos(an), -0.250, 1.3*sin(an) );\n"
        "        float ti = fract(time-0.15);\n"
        "        ti = 4.0*ti*(1.0-ti);\n"
        "        ta.y += 0.15*ti*ti*(3.0-2.0*ti)*smoothstep(0.4,0.9,cl);\n"
        "\n"
        "        // camera bounce\n"
        "        float t4 = abs(fract(time*0.5)-0.5)/0.5;\n"
        "        float bou = -1.0 + 2.0*t4;\n"
        "        ro += 0.06*sin(time*12.0+vec3(0.0,2.0,4.0))*smoothstep( 0.85, 1.0, abs(bou) );\n"
        "\n"
        "        // camera-to-world rotation\n"
        "        mat3 ca = setCamera( ro, ta, 0.0 );\n"
        "\n"
        "        // ray direction\n"
        "        vec3 rd = ca * normalize( vec3(p,1.8) );\n"
        "\n"
        "        // render    \n"
        "        vec3 col = render( ro, rd, time );\n"
        "\n"
        "        // gamma\n"
        "        col = pow( col, vec3(0.4545) );\n"
        "\n"
        "        tot += col;\n"
        "#if AA>1\n"
        "    }\n"
        "    tot /= float(AA*AA);\n"
        "#endif\n"
        "\n"
        "    // color grading\n"
        "    tot = tot*vec3(1.05,0.95,0.9) + vec3(0.0,0.0,0.0);\n"
        "    tot = clamp(tot,0.0,1.0);\n"
        "    tot = tot*0.5 + 0.5*tot*tot*(3.0-2.0*tot);\n"
        "\n"
        "    // vignetting\n"
        "    vec2 q = fragCoord/iResolution.xy;\n"
        "    tot *= 0.5 + 0.5*pow(16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.25);\n"
        "\n"
        "    // output\n"
        "    fragColor = vec4( tot, 1.0 );\n"
        "}\n"     );

     n->create_file("ShaderToy/HexFlow.glsl",
        "// https://www.shadertoy.com/view/llSyDh\n"
        "\n"
        "/*\n"
        "\n"
        "    Hexagonal Maze Flow\n"
        "    -------------------\n"
        "\n"
        "    I've been playing around with hexagonal grids lately. It's possible to make all kinds of\n"
        "    interesting things with them. I'll eventually tire of hexagons and get back to what I'm\n"
        "    supposed to be doing, but for now, here's a maze with a flowing polkadot snake-like\n"
        "    pattern running through it... I'm not really sure what it is either. :)\n"
        "\n"
        "    It has an impossible geometry feel to it, and is rendered in an oldschool kind of game\n"
        "    style. It was pretty easy to produce: Obtain some hexagonal grid cell coordinates and\n"
        "    corresponding ID, render some lines, shapes, and a few arcs for the Truchet component,\n"
        "    apply some shading, etc.\n"
        "    \n"
        "    It was more of an exercise in applying layers in the right order than anything else. One\n"
        "    of the things that might be of interest is the flowing Truchet pattern. Producing a\n"
        "    flowing hexagonal Truchet isn't much different to producing a square one. In fact, it's\n"
        "    easier - in the sense that you don't have to reverse directions from cell to cell.\n"
        "\n"
        "    However, one of the downsides is that it's not immediately obvious how to apply UV\n"
        "    coordinates - I think BigWings mentioned this, and I concur. :) I got around the problem\n"
        "    by ensuring that the texture pattern had the appropriate symmetry and applying hybrid\n"
        "    polar coordinates. By that, I mean, I wrapped the polar angles across the arc boundaries\n"
        "    and used that for one coordinate, then used the Truchet distance field itself for the\n"
        "    other...\n"
        "\n"
        "    Roughly speaking, it's not much different to a circle: In that situation, you use the\n"
        "    familiar polar coordinates (r = length(u), a = atan(u.y, u.x)). The only difference in\n"
        "    this case is that you use a modified radial coordinate (r = min(min(r1, r2), r3)) - or\n"
        "    to put it another way, you use the distance field value... It's a bit difficult to\n"
        "    explain, but easy to perform. When I get time, I'm going to produce a more robust Truchet\n"
        "    texturing example.\n"
        "    \n"
        "\n"
        "    Related references:\n"
        "\n"
        "    // You can't do a hexagonal grid example without referencing this. :) Very stylish.\n"
        "    Hexagons - distance - iq\n"
        "    https://www.shadertoy.com/view/Xd2GR3\n"
        "    \n"
        "\n"
        "    // Simpler hexagonal grid example that attempts to explain the grid setup used to produce\n"
        "    // the pattern here.\n"
        "    //\n"
        "    Minimal Hexagonal Grid - Shane\n"
        "    https://www.shadertoy.com/view/Xljczw\n"
        "\n"
        "*/\n"
        "\n"
        "// Interlaced variation - Interesting, but patched together in a hurry.\n"
        "#define INTERLACING\n"
        "\n"
        "// A quick hack to get rid of the winding overlay - in order to show the maze only.\n"
        "//#define MAZE_ONLY\n"
        "\n"
        "\n"
        "\n"
        "// Helper vector. If you're doing anything that involves regular triangles or hexagons, the\n"
        "// 30-60-90 triangle will be involved in some way, which has sides of 1, sqrt(3) and 2.\n"
        "const vec2 s = vec2(1, 1.7320508);\n"
        "\n"
        "// Standard vec2 to float hash - Based on IQ's original.\n"
        "float hash21(vec2 p){ return fract(sin(dot(p, vec2(141.173, 289.927)))*43758.5453); }\n"
        "\n"
        "\n"
        "// Standard 2D rotation formula.\n"
        "mat2 r2(in float a){ float c = cos(a), s = sin(a); return mat2(c, -s, s, c); }\n"
        "\n"
        "\n"
        "// The 2D hexagonal isosuface function: If you were to render a horizontal line and one that\n"
        "// slopes at 60 degrees, mirror, then combine them, you'd arrive at the following.\n"
        "float hex(in vec2 p){\n"
        "\n"
        "    p = abs(p);\n"
        "\n"
        "    // Below is equivalent to:\n"
        "    //return max(p.x*.5 + p.y*.866025, p.x);\n"
        "\n"
        "    return max(dot(p, s*.5), p.x); // Hexagon.\n"
        "\n"
        "}\n"
        "\n"
        "// This function returns the hexagonal grid coordinate for the grid cell, and the corresponding\n"
        "// hexagon cell ID - in the form of the central hexagonal point. That's basically all you need to\n"
        "// produce a hexagonal grid.\n"
        "//\n"
        "// When working with 2D, I guess it's not that important to streamline this particular function.\n"
        "// However, if you need to raymarch a hexagonal grid, the number of operations tend to matter.\n"
        "// This one has minimal setup, one \"floor\" call, a couple of \"dot\" calls, a ternary operator, etc.\n"
        "// To use it to raymarch, you'd have to double up on everything - in order to deal with\n"
        "// overlapping fields from neighboring cells, so the fewer operations the better.\n"
        "vec4 getHex(vec2 p){\n"
        "\n"
        "    // The hexagon centers: Two sets of repeat hexagons are required to fill in the space, and\n"
        "    // the two sets are stored in a \"vec4\" in order to group some calculations together. The hexagon\n"
        "    // center we'll eventually use will depend upon which is closest to the current point. Since\n"
        "    // the central hexagon point is unique, it doubles as the unique hexagon ID.\n"
        "    vec4 hC = floor(vec4(p, p - vec2(.5, 1))/s.xyxy) + .5;\n"
        "\n"
        "    // Centering the coordinates with the hexagon centers above.\n"
        "    vec4 h = vec4(p - hC.xy*s, p - (hC.zw + .5)*s);\n"
        "\n"
        "    // Nearest hexagon center (with respect to p) to the current point. In other words, when\n"
        "    // \"h.xy\" is zero, we're at the center. We're also returning the corresponding hexagon ID -\n"
        "    // in the form of the hexagonal central point. Note that a random constant has been added to\n"
        "    // \"hC.zw\" to further distinguish it from \"hC.xy.\"\n"
        "    //\n"
        "    // On a side note, I sometimes compare hex distances, but I noticed that Iomateron compared\n"
        "    // the Euclidian version, which seems neater, so I've adopted that.\n"
        "    return dot(h.xy, h.xy)<dot(h.zw, h.zw) ? vec4(h.xy, hC.xy) : vec4(h.zw, hC.zw + vec2(.5, 1));\n"
        "\n"
        "}\n"
        "\n"
        "// Dot pattern.\n"
        "float dots(in vec2 p){\n"
        "\n"
        "    p = abs(fract(p) - .5);\n"
        "\n"
        "    return length(p); // Circles.\n"
        "\n"
        "    //return (p.x + p.y)/1.5 + .035; // Diamonds.\n"
        "\n"
        "    //return max(p.x, p.y) + .03; // Squares.\n"
        "\n"
        "    //return max(p.x*.866025 + p.y*.5, p.y) + .01; // Hexagons.\n"
        "\n"
        "    //return min((p.x + p.y)*.7071, max(p.x, p.y)) + .08; // Stars.\n"
        "\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "// Distance field for the arcs. I think it's called poloidal rotation, or something like that.\n"
        "float dfPol(vec2 p){\n"
        "\n"
        "    return length(p); // Circular arc.\n"
        "\n"
        "    // There's no rule that says the arcs have to be rounded. Here's a hexagonal one.\n"
        "    //return hex(p);\n"
        "\n"
        "    // Dodecahedron.\n"
        "    //return max(hex(p), hex(r2(3.14159/6.)*p));\n"
        "\n"
        "    // Triangle.\n"
        "    //return max(abs(p.x)*.866025 - p.y, p.y);\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "// Truchet pattern distance field.\n"
        "float df(vec2 p, float dir){\n"
        "\n"
        "    // Weird UV coordinates. The first entry is the Truchet distance field itself,\n"
        "    // and the second is the polar angle of the arc pixel. The extra \".1\" is just a bit\n"
        "    // of mutational scaling, or something... I can't actually remember why it's there. :)\n"
        "    vec2 uv = vec2(p.x + .1, p.y);//*vec2(1, 1); // Scaling.\n"
        "\n"
        "    // A checkered dot pattern. At present the pattern needs to have flip symmetry about\n"
        "    // the center, but I'm pretty sure regular textures could be applied with a few\n"
        "    // minor changes. Due to the triangular nature of the Truchet pattern, factors of \"3\"\n"
        "    // were necessary, but factors of \"1.5\" seemed to work too. Hence the \"4.5.\"\n"
        "    return min(dots(uv*4.5), dots(uv*4.5 + .5)) - .3;\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "// Polar coordinate of the arc pixel.\n"
        "float getPolarCoord(vec2 q, float dir){\n"
        "\n"
        "    // The actual animation. You perform that before polar conversion.\n"
        "    q = r2(iTime*dir)*q;\n"
        "\n"
        "    // Polar angle.\n"
        "    const float aNum = 1.;\n"
        "    float a = atan(q.y, q.x);\n"
        "\n"
        "    // Wrapping the polar angle.\n"
        "    return mod(a/3.14159, 2./aNum) - 1./aNum;\n"
        "\n"
        "\n"
        "}\n"
        "\n"
        "void mainImage(out vec4 fragColor, in vec2 fragCoord){\n"
        "\n"
        "    // I didn't feel like tayloring the antiasing to suit every resolution, which can get tiring,\n"
        "    // so I've put a range on it. Just for the record, I coded this for the 800 by 450 pixel canvas.\n"
        "    float res = clamp(iResolution.y, 300., 600.);\n"
        "\n"
        "    // Aspect correct screen coordinates.\n"
        "    vec2 u = (fragCoord - iResolution.xy*.5)/res;\n"
        "\n"
        "    // Scaling and moving the screen coordinates.\n"
        "    vec2 sc = u*4. + s.yx*iTime/8.;\n"
        "\n"
        "    // Converting the scaled and translated pixels to a hexagonal grid cell coordinate and\n"
        "    // a unique coordinate ID. The resultant vector contains everything you need to produce a\n"
        "    // pretty pattern, so what you do from here is up to you.\n"
        "    vec4 h = getHex(sc); // + s.yx*iTime/2.\n"
        "\n"
        "    // Obtaining some offset values to do a bit of cubic shading. There are probably better ways\n"
        "    // to go about it, but it's quick and gets the job done.\n"
        "    vec4 h2 = getHex(sc - 1./s);\n"
        "    vec4 h3 = getHex(sc + 1./s);\n"
        "\n"
        "    // Storing the hexagonal coordinates in \"p\" to save having to write \"h.xy\" everywhere.\n"
        "    vec2 p = h.xy;\n"
        "\n"
        "    // The beauty of working with hexagonal centers is that the relative edge distance will simply\n"
        "    // be the value of the 2D isofield for a hexagon.\n"
        "    //\n"
        "    float eDist = hex(p); // Edge distance.\n"
        "    float cDist = dot(p, p); // Relative squared distance from the center.\n"
        "\n"
        "\n"
        "    // Using the identifying coordinate - stored in \"h.zw,\" to produce a unique random number\n"
        "    // for the hexagonal grid cell.\n"
        "    float rnd = hash21(h.zw);\n"
        "    //float aRnd = sin(rnd*6.283 + iTime*1.5)*.5 + .5; // Animating the random number.\n"
        "\n"
        "    #ifdef INTERLACING\n"
        "    // Random vec3 - used for some overlapping.\n"
        "    //vec3 lRnd = vec3(rnd*14.4 + .81, fract(rnd*21.3 + .97), fract(rnd*7.2 + .63));\n"
        "    vec3 lRnd = vec3(hash21(h.zw + .23), hash21(h.zw + .96), hash21(h.zw + .47));\n"
        "    #endif\n"
        "\n"
        "    // It's possible to control the randomness to form some kind of repeat pattern.\n"
        "    //rnd = mod(h.z + h.w, 2.);\n"
        "\n"
        "\n"
        "    // Redundant here, but I might need it later.\n"
        "    float dir = 1.;\n"
        "\n"
        "\n"
        "\n"
        "    // Storage vector.\n"
        "    vec2 q;\n"
        "\n"
        "\n"
        "    // If the grid cell's random ID is above a threshold, flip the Y-coordinates.\n"
        "    if(rnd>.5) p.y = -p.y;\n"
        "\n"
        "\n"
        "\n"
        "    // Determining the closest of the three arcs to the current point, the keeping a copy\n"
        "    // of the vector used to produce it. That way, you'll know just to render that particular\n"
        "    // decorated arc, lines, etc - instead of all three.\n"
        "    const float r = 1.;\n"
        "    const float th = .2; // Arc thickness.\n"
        "\n"
        "    // Arc one.\n"
        "    q = p - vec2(0, r)/s;\n"
        "    vec3 da = vec3(q, dfPol(q));\n"
        "\n"
        "    // Arc two. \"r2\" could be hardcoded, but this is a relatively cheap 2D example.\n"
        "    q = r2(3.14159*2./3.)*p - vec2(0, r)/s;\n"
        "    vec3 db = vec3(q, dfPol(q));\n"
        "\n"
        "     // Arc three.\n"
        "    q = r2(3.14159*4./3.)*p - vec2(0, r)/s;\n"
        "    vec3 dc = vec3(q, dfPol(q));\n"
        "\n"
        "    // Compare distance fields, and return the vector used to produce the closest one.\n"
        "    vec3 q3 = da.z<db.z && da.z<dc.z? da : db.z<dc.z ? db : dc;\n"
        "\n"
        "\n"
        "    // TRUCHET PATTERN\n"
        "    // Produce the closest arc. The result is the Truchet pattern.\n"
        "    // Set the circle radius. For the hexagonal version, use .5/2., and for triangles, .7071/2.\n"
        "    q3.z -= .57735/2. + th/2.;\n"
        "    q3.z = max(q3.z, -th - q3.z); // Chop out the smaller radius. The result is an arc.\n"
        "\n"
        "    // Store the result in \"d\" - only to save writing \"q3.z\" everywhere.\n"
        "    float d = q3.z;\n"
        "\n"
        "    // If you'd like to see the maze by itself.\n"
        "    #ifdef MAZE_ONLY\n"
        "    d += 1e5;\n"
        "    #endif\n"
        "\n"
        "    // Truchet border.\n"
        "    float dBord = max(d - .015, -d);\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "    // MAZE BORDERS\n"
        "    // Producing the stright-line arc borders. Basically, we're rendering some hexagonal borders around\n"
        "    // the arcs. The result is the hexagonal maze surrounding the Truchet pattern.\n"
        "    q = q3.xy;\n"
        "    const float lnTh = .05;\n"
        "    q = abs(q);\n"
        "\n"
        "    float arcBord = hex(q);\n"
        "    //float arcBord = length(q); // Change arc length to \".57735.\"\n"
        "    //float arcBord = max(hex(q), hex(r2(3.14159/6.)*q)); // Change arc length to \".57735.\"\n"
        "\n"
        "    // Making the hexagonal arc.\n"
        "    float lnOuter = max(arcBord - .5, -(arcBord - .5 + lnTh)); //.57735\n"
        "\n"
        "\n"
        "    #ifdef INTERLACING\n"
        "    float ln = min(lnOuter, (q.y*.866025 + q.x*.5, q.x) - lnTh);\n"
        "    #else\n"
        "    float ln = min(lnOuter, arcBord - lnTh);\n"
        "    #endif\n"
        "    float lnBord = ln - .03; // Border lines to the maze border, if that makes any sense. :)\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "    ///////\n"
        "    // The moving Truchet pattern. The polar coordinates consist of a wrapped angular coordinate,\n"
        "    // and the distance field itself.\n"
        "    float a = getPolarCoord(q3.xy, dir);\n"
        "    float d2 = df(vec2(q3.z, a), dir);\n"
        "\n"
        "    // Smoothstepped Truchet mask.\n"
        "    float dMask = smoothstep(0., .015, d);\n"
        "    ///////\n"
        "\n"
        "    // Producing the background with some subtle gradients.\n"
        "    vec3 bg =  mix(vec3(0, .4, .6), vec3(0, .3, .7), dot(sin(u*6. - cos(u*3.)), vec2(.4/2.)) + .4);\n"
        "    bg = mix(bg, bg.xzy, dot(sin(u*6. - cos(u*3.)), vec2(.4/2.)) + .4);\n"
        "    bg = mix(bg, bg.zxy, dot(sin(u*3. + cos(u*3.)), vec2(.1/2.)) + .1);\n"
        "\n"
        "    #ifdef INTERLACING\n"
        "    // Putting in background cube lines for the interlaced version.\n"
        "    float hLines = smoothstep(0., .02, eDist - .5 + .02);\n"
        "    bg = mix(bg, vec3(0), smoothstep(0., .02, ln)*dMask*hLines);\n"
        "    #endif\n"
        "\n"
        "    // Lines over the maze lines. Applying difference logic, depending on whether the\n"
        "    // pattern is interlaced or not.\n"
        "    const float tr = 1.;\n"
        "\n"
        "    float eDist2 = hex(h2.xy);\n"
        "    float hLines2 = smoothstep(0., .02, eDist2 - .5 + .02);\n"
        "    #ifdef INTERLACING\n"
        "    if(rnd>.5 && lRnd.x<.5) hLines2 *= smoothstep(0., .02, ln);\n"
        "    if(lRnd.x>.5) hLines2 *= dMask;\n"
        "    #else\n"
        "    if(rnd>.5) hLines2 *= smoothstep(0., .02, ln);\n"
        "    hLines2 *= dMask;\n"
        "    #endif\n"
        "    bg = mix(bg, vec3(0), hLines2*tr);\n"
        "\n"
        "    float eDist3 = hex(h3.xy);\n"
        "    float hLines3 = smoothstep(0., .02, eDist3 - .5 + .02);\n"
        "    #ifdef INTERLACING\n"
        "    if(rnd<=.5 && lRnd.x>.5) hLines3 *= smoothstep(0., .02, ln);\n"
        "    if(lRnd.x>.5) hLines3 *= dMask;\n"
        "    #else\n"
        "    if(rnd<=.5) hLines3 *= smoothstep(0., .02, ln);\n"
        "    hLines3 *= dMask;\n"
        "    #endif\n"
        "    bg = mix(bg, vec3(0), hLines3*tr);\n"
        "\n"
        "\n"
        "    // Using the two off-centered hex coordinates to give the background a bit of highlighting.\n"
        "    float shade = max(1.25 - dot(h2.xy, h2.xy)*2., 0.);\n"
        "    shade = min(shade, max(dot(h3.xy, h3.xy)*3. + .25, 0.));\n"
        "    bg = mix(bg, vec3(0), (1.-shade)*.5);\n"
        "\n"
        "    // I wanted to change the colors of everything at the last minute. It's pretty hacky, so\n"
        "    // when I'm feeling less lazy, I'll tidy it up. :)\n"
        "    vec3 dotCol = bg.zyx*vec3(1.5, .4, .4);\n"
        "    vec3 bCol = mix(bg.zyx, bg.yyy, .25);\n"
        "    bg = mix(bg.yyy, bg.zyx, .25);\n"
        "\n"
        "\n"
        "    // Under the random threshold, and we draw the lines under the Truchet pattern.\n"
        "    #ifdef INTERLACING\n"
        "    if(lRnd.x>.5){\n"
        "       bg = mix(bg, vec3(0), (1. - smoothstep(0., .015, lnBord)));\n"
        "       bg = mix(bg, bCol, (1. - smoothstep(0., .015, ln)));\n"
        "       // Center lines.\n"
        "       bg = mix(bg, vec3(0), smoothstep(0., .02, eDist3 - .5 + .02)*tr);\n"
        "    }\n"
        "    #else\n"
        "    bg = mix(bg, vec3(0), (1. - smoothstep(0., .015, lnBord)));\n"
        "    bg = mix(bg, bCol, (1. - smoothstep(0., .015, ln)));\n"
        "    #endif\n"
        "\n"
        "\n"
        "\n"
        "    // Apply the Truchet shadow to the background.\n"
        "    bg = mix(bg, vec3(0), (1. - smoothstep(0., .07, d))*.5);\n"
        "\n"
        "\n"
        "    // Place the Truchet field to the background, with some additional shading to give it a\n"
        "    // slightly rounded, raised feel.\n"
        "    vec3 col = mix(bg, vec3(1)*max(-d*3. + .7, 0.), (1. - dMask)*.65);\n"
        "\n"
        "\n"
        "    // Apply the moving dot pattern to the Truchet.\n"
        "    //dotCol = mix(dotCol, dotCol.xzy, dot(sin(u*3.14159*2. - cos(u.yx*3.14159*2.)*3.14159), vec2(.25)) + .5);\n"
        "    col = mix(col, vec3(0), (1. - dMask)*(1. - smoothstep(0., .02, d2)));\n"
        "    col = mix(col, dotCol, (1. - dMask)*(1. - smoothstep(0., .02, d2 + .125)));\n"
        "\n"
        "    // Truchet border.\n"
        "    col = mix(col, vec3(0), 1. - smoothstep(0., .015, dBord));\n"
        "\n"
        "    #ifdef INTERLACING\n"
        "    // Over the random threshold, and we draw the lines over the Truchet.\n"
        "    if(lRnd.x<=.5){\n"
        "        col = mix(col, vec3(0), (1. - smoothstep(0., .015, lnBord)));\n"
        "        col = mix(col, bCol, (1. - smoothstep(0., .015, ln)));\n"
        "        // Center lines.\n"
        "        col = mix(col, vec3(0), smoothstep(0., .02, eDist2 - .5 + .02)*tr);\n"
        "    }\n"
        "    #endif\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "    // Using the offset hex values for a bit of fake 3D highlighting.\n"
        "    //if(rnd>.5) h3.y = -h3.y; // All raised edges. Spoils the mild 3D illusion.\n"
        "    #ifdef INTERLACING\n"
        "    float trSn = max(dMask, 1. - smoothstep(0., .015, lnBord))*.75 + .25;\n"
        "    #else\n"
        "    float trSn = dMask*.75 + .25;\n"
        "    #endif\n"
        "    col = mix(col, vec3(0), trSn*(1. - hex(s/2.+h2.xy)));\n"
        "    col = mix(col, vec3(0), trSn*(1. - hex(s/2.-h3.xy)));\n"
        "\n"
        "\n"
        "    // Using the edge distance to produce some repeat contour lines. Standard stuff.\n"
        "    //if (rnd>.5) h.xy = -h.yx;\n"
        "    //float cont = clamp(cos(hex(h.xy)*6.283*12.)*1.5 + 1.25, 0., 1.);\n"
        "    //col = mix(col, vec3(0), (1. - smoothstep(0., .015, ln))*(smoothstep(0., .015, d))*(1.-cont)*.5);\n"
        "\n"
        "\n"
        "    // Very basic hatch line effect.\n"
        "    float gr = dot(col, vec3(.299, .587, .114));\n"
        "    float hatch = (gr<.45)? clamp(sin((sc.x - sc.y)*3.14159*40.)*2. + 1.5, 0., 1.) : 1.;\n"
        "    float hatch2 = (gr<.25)? clamp(sin((sc.x + sc.y)*3.14159*40.)*2. + 1.5, 0., 1.) : 1.;\n"
        "\n"
        "    col *= min(hatch, hatch2)*.5 + .5;\n"
        "    col *= clamp(sin((sc.x - sc.y)*3.14159*80.)*1.5 + .75, 0., 1.)*.25 + 1.;\n"
        "\n"
        "\n"
        "    // Subtle vignette.\n"
        "    u = fragCoord/iResolution.xy;\n"
        "    col *= pow(16.*u.x*u.y*(1. - u.x)*(1. - u.y) , .125) + .25;\n"
        "    // Colored varation.\n"
        "    //col = mix(pow(min(vec3(1.5, 1, 1)*col, 1.), vec3(1, 3, 16)), col,\n"
        "            //pow(16.*u.x*u.y*(1. - u.x)*(1. - u.y) , .25)*.75 + .25);\n"
        "\n"
        "\n"
        "\n"
        "    // Rough gamma correction.\n"
        "    fragColor = vec4(sqrt(max(col, 0.)), 1);\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "\n"
     );

     n->create_file("ShaderToy/JellyTubes.glsl",
        "// https://www.shadertoy.com/view/tsBSzc\n"
        "\n"
        "#define AA 2 // Square root of the number of anti-aliasing samples to make.\n"
        "\n"
        "vec2 intersectSphere(vec3 ro, vec3 rd, vec3 org, float rad)\n"
        "{\n"
        "    float a = dot(rd, rd);\n"
        "    float b = 2. * dot(rd, ro - org);\n"
        "    float c = dot(ro - org, ro - org) - rad * rad;\n"
        "    float desc = b * b - 4. * a * c;\n"
        "    if (desc < 0.)\n"
        "        return vec2(1, 0);\n"
        "\n"
        "    return vec2((-b - sqrt(desc)) / (2. * a), (-b + sqrt(desc)) / (2. * a));\n"
        "}\n"
        "\n"
        "vec2 intersectCylinder(vec2 ro, vec2 rd, vec2 org, float rad)\n"
        "{\n"
        "    return intersectSphere(vec3(ro, 0), vec3(rd, 0), vec3(org, 0), rad);\n"
        "}\n"
        "\n"
        "vec3 nn = vec3(0);\n"
        "float u = 0.;\n"
        "\n"
        "vec3 tr2(vec3 o, vec3 r, vec2 t)\n"
        "{\n"
        "    o += r * (1e-4 + .5 - o.y) / r.y;\n"
        "    for(int i = 0; i < 38; ++i)\n"
        "    {\n"
        "        vec3 c = vec3(floor(o.x), 0, floor(o.z));\n"
        "\n"
        "        vec3 ofs = vec3(cos(c.z) * .1, 0, cos(c.x) * .1);\n"
        "\n"
        "        float rad = .3+cos(c.x) * .1;\n"
        "        ofs.x = cos(t.y * 8. + c.z * 2.5) * rad / 4.;\n"
        "\n"
        "        float h = -(cos(c.x + 3. + c.z * 65.) * .5 + .5) * 11.8;\n"
        "\n"
        "        u = h;\n"
        "\n"
        "        float ht = (h - o.y) / r.y;\n"
        "        float ft = (-2.2 - o.y) / r.y;\n"
        "\n"
        "        vec2 cyl = intersectCylinder(o.xz, r.xz, (c + ofs).xz + .5, rad);\n"
        "        vec2 sph = intersectSphere(o, r, (c + ofs) + .5 + vec3(0, -.5 + h, 0), rad);\n"
        "\n"
        "        cyl.x = max(cyl.x, ht);\n"
        "\n"
        "        if(sph.x < cyl.x && sph.y > 0. && sph.x < sph.y)\n"
        "        {\n"
        "            nn = normalize(o + r * sph.x - ((c + ofs) + .5 + vec3(0, -.5 + h, 0)));\n"
        "            return o + r * sph.x;\n"
        "        }\n"
        "\n"
        "        if((cyl.x < sph.y || sph.x >= sph.y) && cyl.y > 0. && cyl.x < cyl.y)\n"
        "        {\n"
        "            nn.xz = o.xz + r.xz * cyl.x - ((c + ofs).xz + .5);\n"
        "            nn.y = 0.;\n"
        "            nn = normalize(nn);\n"
        "            return o + r * cyl.x;\n"
        "        }\n"
        "\n"
        "        c.xz = ((c.xz + max(sign(r.xz), 0.)) - o.xz) / r.xz;\n"
        "        float t = (dot(c.xz, step(c.xz, c.zx)) + 1e-4);\n"
        "        //      if(ft<t){nn=vec3(0,1,0);return o+r*ft;}\n"
        "        o += t * r;\n"
        "    }\n"
        "    return o;\n"
        "}\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{\n"
        "    vec2 uv = fragCoord / iResolution.xy * 2. - 1.;\n"
        "    uv.y *= iResolution.y / iResolution.x;\n"
        "\n"
        "    vec3 acc = vec3(0);\n"
        "    float wsum = 0.;\n"
        "\n"
        "    float time = iTime;\n"
        "\n"
        "    for(int y = 0; y < AA; ++y)\n"
        "        for(int x = 0; x < AA; ++x)\n"
        "        {\n"
        "            vec2 t = uv.xy + vec2(x, y) / float(AA) * vec2(2.2) / iResolution.x;\n"
        "\n"
        "            vec3 o = vec3(1.4 + time / 3., 2.5, 0), r = normalize(vec3(t.xy + vec2(0, -1), -3.5));\n"
        "\n"
        "            {\n"
        "                float ang = -3.14159 / 5.;\n"
        "                r.xz *= mat2(cos(ang), sin(ang), -sin(ang), cos(ang));\n"
        "            }\n"
        "\n"
        "            vec3 rp;\n"
        "            fragColor.rgb = vec3(0);\n"
        "\n"
        "            rp = tr2(o, r, t);\n"
        "            u += o.y * 75.;\n"
        "            u += rp.y / 4.;\n"
        "\n"
        "            {\n"
        "                vec3 rd = r;\n"
        "                vec3 n = normalize(nn);\n"
        "                vec3 r = reflect(rd, n);\n"
        "                float fresnel = pow(clamp(1. - dot(n, -rd), 0., 1.), 2.);\n"
        "\n"
        "                float spec = step(max(abs(3. + r.x * o.y / r.y) - 4., abs(+r.z * o.y / r.y)), 1.4) * step(0., r.y);\n"
        "                spec += step(max(abs(-6.6 + r.x * o.y / r.y) - 2., abs(+r.z * o.y / r.y)), 1.4) * step(0., r.y) / 3.;\n"
        "\n"
        "                spec += step(abs(r.x-1.),.4)/7.;\n"
        "\n"
        "                fragColor.rgb += (vec3(cos(u), cos(u * 2.), cos(u * 3.)) * .5 + .5) * mix(.9, 1., fresnel);\n"
        "\n"
        "                vec3 rp2 = rp * 10.;\n"
        "                fragColor.rgb = mix(fragColor.rgb, vec3(1), .1 - .1 * smoothstep(.0, .05, length(rp2 - (floor(rp2) + cos(time + floor(rp2.zxy) * 9.) * .4 + .5)) - .1));\n"
        "\n"
        "                vec3 rp3 = rp * 3.;\n"
        "                fragColor.rgb *= mix(.7, 1., smoothstep(.0, .01, length(rp3 - (floor(rp3) + cos(floor(rp3.zxy) * 9.) * .25 + .5)) - .2));\n"
        "\n"
        "                fragColor.rgb *= rp.y / 10. + 1.5;\n"
        "\n"
        "                fragColor.rgb += 1.5 * spec * fresnel + fresnel / 15.;\n"
        "            }\n"
        "\n"
        "            acc += clamp(fragColor.rgb, 0., 1.);\n"
        "            wsum += 1.;\n"
        "        }\n"
        "    fragColor.rgb = pow(acc / wsum, vec3(1. / 2.2));\n"
        "}\n"
        "\n"
     );

     n->create_file("ShaderToy/MengerTunnel.glsl",
        "// https://www.shadertoy.com/view/4scXzn\n"
        "/*\n"
        "\n"
        "    Winding Menger Tunnel\n"
        "    ---------------------\n"
        "\n"
        "    I got bored and decided to wrap a Menger object around a curvy tunnel, then I got even more bored and\n"
        "    incorporated some tubing and some curved screens... I have no idea what they're for either. :)\n"
        "\n"
        "    Anyway, if you put aside the cheesy, Quake-2-style graphics, it's nothing more than a couple of\n"
        "    interwoven fractal objects perturbed sinusoidally about the \"XY\" plane. In code:\n"
        "\n"
        "    pos.xy -= sinPath(pos.z);\n"
        "    dist = FractalObjects(pos);\n"
        "\n"
        "    Obviously, the camera has to follow the path as well, but that's basically it. You can ignore everything\n"
        "    else, which is just less-than-adequate window dressing. I've been on a bit of an oldschool demo trip\n"
        "    lately, which probably explains the simplistic lighting style.\n"
        "\n"
        "    Other tunnel related examples worth looking at:\n"
        "\n"
        "    // Awesome example. Makes the lighting effort in this one look lazy... which it is. :)\n"
        "    Castle Tunnel - Hamneggs\n"
        "    https://www.shadertoy.com/view/Xs3Xzn\n"
        "\n"
        "    // Love this. It inspired me to interweave the metal tubing in this particular shader.\n"
        "    Metro Tunnel - fb39ca4\n"
        "    https://www.shadertoy.com/view/ldsGRS\n"
        "\n"
        "    // Like all of dr2's stuff, it has a higher level of difficulty. :)\n"
        "    Gotthard Tunnel - dr2\n"
        "    https://www.shadertoy.com/view/MlSXRR\n"
        "\n"
        "*/\n"
        "\n"
        "\n"
        "// Used to identify individual scene objects. In this case, there are only three: The metal framework, the walls,\n"
        "// and the lights.\n"
        "float objID = 0.; // Metal = 1., Walls = 2., Screens = 3..\n"
        "\n"
        "// Simple hash function.\n"
        "float hash( float n ){ return fract(cos(n)*45758.5453); }\n"
        "\n"
        "\n"
        "// Tri-Planar blending function. Based on an old Nvidia writeup:\n"
        "// GPU Gems 3 - Ryan Geiss: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch01.html\n"
        "vec3 tex3D( sampler2D tex, in vec3 p, in vec3 n ){\n"
        "   /*\n"
        "    n = max(abs(n), 0.001); // n = max((abs(n) - 0.2)*7., 0.001); // n = max(abs(n), 0.001), etc.\n"
        "    n /= (n.x + n.y + n.z);\n"
        "    return (texture2D(tex, p.yz)*n.x + texture2D(tex, p.zx)*n.y + texture2D(tex, p.xy)*n.z).xyz;\n"
        "    */\n"
        "    return vec3(0.0, 0.0, 0.0); // [BL] removed texturing to make it \"embeddable\" in geoshade.\n"
        "}\n"
        "\n"
        "// Common formula for rounded squares, for all intended purposes.\n"
        "float lengthN(in vec2 p, in float n){ p = pow(abs(p), vec2(n)); return pow(p.x + p.y, 1.0/n); }\n"
        "\n"
        "// 2D path displacement.\n"
        "vec2 path(in float x){\n"
        "\n"
        "    //return vec2(0); // Trivial, straight path.\n"
        "    //return vec2(cos(x*0.25)*1.8 + cos(x*0.15)*2., 0); // Perturbing \"X\" only.\n"
        "    return vec2(cos(x*0.25)*1.8 + cos(x*0.15)*1.5, sin(x*0.25)*1.2 + sin(x*0.15)); // Perturbing \"X\" and \"Y.\"\n"
        "\n"
        "\n"
        "}\n"
        "\n"
        "// Camera path. Arranged to coincide with the frequency of the tunnel.\n"
        "vec3 camPath(float t){\n"
        "\n"
        "    return vec3(path(t), t);\n"
        "\n"
        "}\n"
        "\n"
        "// Smooth minimum function. There are countless articles, but IQ explains it best here:\n"
        "// http://iquilezles.org/www/articles/smin/smin.htm\n"
        "float sminP( float a, float b, float s ){\n"
        "\n"
        "    float h = clamp( 0.5+0.5*(b-a)/s, 0.0, 1.0 );\n"
        "    return mix( b, a, h ) - s*h*(1.0-h);\n"
        "}\n"
        "\n"
        "// I have a \"Menger Sponge Variation\" example somewhere, if you'd like to look into this.\n"
        "float Menger(in vec3 q){\n"
        "\n"
        "    float s = 4.;\n"
        "    // Layer one. The \".05\" on the end varies the hole size.\n"
        "     vec3 p = abs(fract(q/s)*s - s*.5);\n"
        "     float d = min(max(p.x, p.y), min(max(p.y, p.z), max(p.x, p.z))) - s/3.;// + .05;\n"
        "\n"
        "    s /= 2.;\n"
        "    // Layer two.\n"
        "    p = abs(fract(q/s)*s - s*.5);\n"
        "     d = max(d, min(max(p.x, p.y), min(max(p.y, p.z), max(p.x, p.z))) - s/3.);//+ .05\n"
        "\n"
        "    s /= 3.;\n"
        "    // Layer three. 3D space is divided by two, instead of three, to give some variance.\n"
        "    p = abs(fract(q/s)*s - s*.5);\n"
        "     d = max(d, min(max(p.x, p.y), min(max(p.y, p.z), max(p.x, p.z))) - s/3.); //- .015\n"
        "\n"
        "\n"
        "    //float floor = max(abs(q.x) - 2., abs(q.y) - 1.5);//abs(q.x) - 2.;//\n"
        "    //return q.y + .8;\n"
        "    return min(d, q.y + .8);\n"
        "\n"
        "}\n"
        "\n"
        "// I have a \"Steel Lattice\" example somewhere, if you'd like to look into this. There's not\n"
        "// much to it, though.\n"
        "float tubing(in vec3 p){\n"
        "\n"
        "    // SECTION 1\n"
        "    //\n"
        "    // Repeat field entity one, which is just some tubes repeated in all directions every\n"
        "    // two units, then combined with a smooth minimum function. Otherwise known as a lattice.\n"
        "    p = fract(p/2.)*2. - 1.;\n"
        "    float x1 = sminP(length(p.xy),sminP(length(p.yz),length(p.xz), 0.25), 0.25)-0.5; // EQN 1\n"
        "    //float x1 = sqrt(min(dot(p.xy, p.xy),min(dot(p.yz, p.yz),dot(p.xz, p.xz))))-0.5; // EQN 2\n"
        "    //p = abs(p); float x1 = min(max(p.x, p.y),min(max(p.y, p.z),max(p.x, p.z)))-0.5; // EQN 3\n"
        "\n"
        "    // SECTION 2\n"
        "    //\n"
        "    // Repeat field entity two, which is just an abstract object repeated every half unit.\n"
        "    p = abs(fract(p*2.)*.5 - .25);\n"
        "    //float x2 = min(p.x,min(p.y,p.z)); // EQN 1\n"
        "    //float x2 = min(max(p.x, p.y),min(max(p.y, p.z),max(p.x, p.z)))-0.15; //-0.175, etc. // EQN 2\n"
        "    float x2 = min(p.x, min(p.y,p.z))-.025; // EQN 1\n"
        "\n"
        "    // SECTION 3\n"
        "    //\n"
        "    // Combining the two entities above.\n"
        "    return max(abs(x1), abs(x2)) - .0175;\n"
        "\n"
        "}\n"
        "\n"
        "// Creating the scene geometry. This is the process:\n"
        "//\n"
        "// Use the sinusoidal path function to perturb the original position. Create the Menger object\n"
        "// using the perturbed postion. Do the same for the tubing and again with the screens.\n"
        "// Return the minimum of the objects, and also use the relative minimums to return the object's\n"
        "// individual ID. That's basically it.\n"
        "float map(in vec3 p){\n"
        "\n"
        "\n"
        "    // Partial anti-warping solution, based on Gaz's \"Square Sin Curve\" shader below:\n"
        "    // https://www.shadertoy.com/view/MscGzf\n"
        "    //\n"
        "    // As you could imagine, tunnels (columns) get a little warped when you bend them. Countering\n"
        "    // that by taking the curvature into account helps quite a bit. Unfortunately, it slows things\n"
        "    // down, so isn't being used here, which is a shame, because I like it a lot more. Anyway, if\n"
        "    // you can spare the cycles, it gives the tunnel's \"X\" and \"Y\" (width and height) dimensions a\n"
        "    // little more consistency.\n"
        "    //vec2 g = (path(p.z + 0.01) - path(p.z - 0.01))/0.02;\n"
        "    //g = cos(atan(g));\n"
        "\n"
        "\n"
        "    // \"Windy Tunnels 101\" - Use \"Z\" to perturb the \"XY\" plane. If you're not sure how it'd done,\n"
        "    // I have a few tunnel examples where I explain the process.\n"
        "    p.xy -= path(p.z);\n"
        "\n"
        "    //p.xy *= g; // See the anti-warping explanation above.\n"
        "\n"
        "\n"
        "    // A bit of tubing, using a combination of repeat objects.\n"
        "    float tube = tubing(p);\n"
        "\n"
        "\n"
        "    // Again a little expensive, but it's a surprisingly effective way to bump the tunnel walls.\n"
        "    // This is a variation, but you can thank \"aeikick\" for this little snippet. :)\n"
        "    //vec3 u = p;\n"
        "    //p.x -= sign(u.x)*(texture2D(iChannel0, u.yz/8.).x - .0)*.03;//-.2;\n"
        "    //p.y -= sign(u.y)*(texture2D(iChannel0, u.xz/8.).x - .0)*.03;\n"
        "\n"
        "\n"
        "    // The walls. I have another Menger example, if you'd like to look into that more closely.\n"
        "    float walls = Menger(p);\n"
        "    // Simpler alternatives.\n"
        "    //float walls = 1. - max(abs(p.x), abs(p.y));\n"
        "    //float walls = 1.25 - lengthN(p.xy, 4.0);\n"
        "\n"
        "    // The curved screens. Kind of worth the effort, but not really. Fine details always overcomplicate\n"
        "    // things, not to mention, halve the frame rate. :) Anyway, it's basically repeated square box-related\n"
        "    // stuff... Add this, take that, etc. Fiddly, hacky, not all that interesting, and probably not the\n"
        "    // best way to do it. Chipping away at a cylinder might raymarch better.\n"
        "    //\n"
        "    p += vec3(sign(p.x)*(-.11 + (sin(p.z*3.14159*2. + 1.57/1.))*.05), 0., 0.); // Screen curve, and repositioning.\n"
        "    vec3 q = abs(mod(p + vec3(.0, .5, 0.), vec3(1., 1., 2.)) - vec3(.5, .5, 1.)); // Repeat space.\n"
        "    float screen = max(max(q.y, q.z) - .22, q.x-.05); // Box.\n"
        "    screen = max(screen, max(abs(p.x) - .5, abs(p.y) - .22)); // Chopping off anything outside the tunnel... Kind of.\n"
        "\n"
        "    // Object ID: Equivalent to: if(tube<walls)objID=2; else objID = 1.; //etc.\n"
        "    //\n"
        "    // By the way, if you need to identify multiple objects, you're better off doing it in a seperate pass,\n"
        "    // after the raymarching function. Having multiple \"if\" statements in a distance field equation can slow\n"
        "    // things down considerably. Alternatively, there's the \"vec2 objA = vec2(objectADist, objAID)\" option\n"
        "    // that many are fond of. It seems to be slower on my machines, but seems to work well enough.\n"
        "    objID = 1. + step(tube, walls) + step(screen, tube)*step(screen, walls)*2.;\n"
        "\n"
        "\n"
        "    // Returning the minimum of the three objects.\n"
        "    return min(min(tube, walls), screen);\n"
        "\n"
        "/*\n"
        "    //Two object combinations. Spoils the illusion, but helps visualize things.\n"
        "\n"
        "    //objID = 2. + step(screen, tube);\n"
        "    //return min(tube, screen);\n"
        "\n"
        "\n"
        "    //objID = 1. + step(tube, walls);\n"
        "    //return min(tube, walls);\n"
        "\n"
        "    objID = 1. + step(screen, walls)*2.;\n"
        "    return min(screen, walls);\n"
        "*/\n"
        "\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "\n"
        "// Tetrahedral normal, to save a couple of \"map\" calls. Courtesy of IQ.\n"
        "vec3 calcNormal(in vec3 p){\n"
        "\n"
        "    // Note the slightly increased sampling distance, to alleviate artifacts due to hit point inaccuracies.\n"
        "    vec2 e = vec2(0.0025, -0.0025);\n"
        "    return normalize(e.xyy * map(p + e.xyy) + e.yyx * map(p + e.yyx) + e.yxy * map(p + e.yxy) + e.xxx * map(p + e.xxx));\n"
        "}\n"
        "\n"
        "/*\n"
        "// Standard normal function.\n"
        "vec3 calcNormal(in vec3 p) {\n"
        "    const vec2 e = vec2(0.005, 0);\n"
        "    return normalize(vec3(map(p + e.xyy) - map(p - e.xyy), map(p + e.yxy) - map(p - e.yxy),    map(p + e.yyx) - map(p - e.yyx)));\n"
        "}\n"
        "*/\n"
        "\n"
        "// I keep a collection of occlusion routines... OK, that sounded really nerdy. :)\n"
        "// Anyway, I like this one. I'm assuming it's based on IQ's original .\n"
        "float calcAO(in vec3 pos, in vec3 nor)\n"
        "{\n"
        "    float sca = 2.0, occ = 0.0;\n"
        "    for( int i=0; i<5; i++ ){\n"
        "\n"
        "        float hr = 0.01 + float(i)*0.5/4.0;\n"
        "        float dd = map(nor * hr + pos);\n"
        "        occ += (hr - dd)*sca;\n"
        "        sca *= 0.7;\n"
        "    }\n"
        "    return clamp( 1.0 - occ, 0.0, 1.0 );\n"
        "}\n"
        "\n"
        "\n"
        "// Texture bump mapping. Four tri-planar lookups, or 12 texture lookups in total. I tried to\n"
        "// make it as concise as possible. Whether that translate to speed, or not, I couldn't say.\n"
        "vec3 texBump( sampler2D tx, in vec3 p, in vec3 n, float bf){\n"
        "\n"
        "    const vec2 e = vec2(0.002, 0);\n"
        "\n"
        "    // Three gradient vectors rolled into a matrix, constructed with offset greyscale texture values.\n"
        "    mat3 m = mat3( tex3D(tx, p - e.xyy, n), tex3D(tx, p - e.yxy, n), tex3D(tx, p - e.yyx, n));\n"
        "\n"
        "    vec3 g = vec3(0.299, 0.587, 0.114)*m; // Converting to greyscale.\n"
        "    g = (g - dot(tex3D(tx,  p , n), vec3(0.299, 0.587, 0.114)) )/e.x; g -= n*dot(n, g);\n"
        "\n"
        "    return normalize( n + g*bf ); // Bumped normal. \"bf\" - bump factor.\n"
        "    \n"
        "}\n"
        "\n"
        "// Standard hue rotation formula.\n"
        "vec3 rotHue(vec3 p, float a){\n"
        "\n"
        "    vec2 cs = sin(vec2(1.570796, 0) + a);\n"
        "\n"
        "    mat3 hr = mat3(0.299,  0.587,  0.114,  0.299,  0.587,  0.114,  0.299,  0.587,  0.114) +\n"
        "              mat3(0.701, -0.587, -0.114, -0.299,  0.413, -0.114, -0.300, -0.588,  0.886) * cs.x +\n"
        "              mat3(0.168,  0.330, -0.497, -0.328,  0.035,  0.292,  1.250, -1.050, -0.203) * cs.y;\n"
        "                            \n"
        "    return clamp(p*hr, 0., 1.);\n"
        "}\n"
        "\n"
        "// Screen pattern. Simple, but effective. The idea to go with this was inspired by Dmitry Andreev's\n"
        "// really cool \"pixelScreen\" shader, here: https://www.shadertoy.com/view/XdG3Wc\n"
        "//\n"
        "// His example is a little fancier, mainly because he's using way more code... The fact that he won\n"
        "// Assembly a couple of times might also be a factor. :)\n"
        "float dotPattern(vec2 p){\n"
        "\n"
        "    // Partition space into multiple squares.\n"
        "    vec2 fp = abs(fract(p)-0.5)*2.;\n"
        "\n"
        "    // Rounded circle, for the overlay, or vignette, if you prefer.\n"
        "    fp = pow(fp, vec2(8.));\n"
        "    float r = max(1. - pow(fp.x + fp.y, 1.), 0.);\n"
        "\n"
        "    // More squarish (Chebyshev) version of the above.\n"
        "    //fp = pow(fp, vec2(8.));\n"
        "    //float r = 1. - max(fp.x, fp.y);\n"
        "\n"
        "    // Single value for each square. Used for IDs and a bunch of other things, but in this\n"
        "    // case it'll give the square a homogeneous color.\n"
        "    p = floor(p);\n"
        "\n"
        "    // The blocky pattern value. Made up, but you could use all kinds of things, like Voronoi, etc.\n"
        "    float c = dot(sin(p/4. - cos(p.yx/.2 + iTime/4.)), vec2(.5));\n"
        "\n"
        "    c = fract(c * 7.0); // Mixing it up, for no particular reason.\n"
        "\n"
        "    return c*r; // Pixel shade, multiplied by the rounded square vignette. Range: [0, 1].\n"
        "\n"
        "}\n"
        "\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord ){\n"
        "\n"
        "\n"
        "    // Screen coordinates.\n"
        "    vec2 u = (fragCoord - iResolution.xy*0.5)/iResolution.y;\n"
        "    \n"
        "    // Camera Setup.\n"
        "    vec3 ro = camPath(iTime*1.5); // Camera position, doubling as the ray origin.\n"
        "    vec3 lk = camPath(iTime*1.5 + .1);  // \"Look At\" position.\n"
        "    vec3 lp = camPath(iTime*1.5 + 2.) + vec3(0, 2, 0); // Light position, somewhere near the moving camera.\n"
        "\n"
        "\n"
        "    // Using the above to produce the unit ray-direction vector.\n"
        "    float FOV = 1.57; // FOV - Field of view.\n"
        "    vec3 fwd = normalize(lk-ro);\n"
        "    vec3 rgt = normalize(vec3(fwd.z, 0., -fwd.x ));\n"
        "    vec3 up = cross(fwd, rgt);\n"
        "\n"
        "    // Unit direction ray.\n"
        "    vec3 rd = normalize(fwd + FOV*(u.x*rgt + u.y*up));\n"
        "\n"
        "    vec2 a = sin(vec2(1.5707963, 0) - camPath(lk.z).x/12.);\n"
        "    mat2 rM = mat2(a, -a.y, a.x);\n"
        "    rd.xy = rd.xy*rM; // Apparently, \"rd.xy *= rM\" doesn't work on some setups. Crazy.\n"
        "\n"
        "    // Mouse controls, as per Dave Hoskins's suggestion. A bit hacky, but I'll fix them.\n"
        "    vec2 ms = vec2(0);\n"
        "    if (iMouse.z > 1.0) ms = (2.*iMouse.xy - iResolution.xy)/iResolution.xy;\n"
        "    a = sin(vec2(1.5707963, 0) - ms.x);\n"
        "    rM = mat2(a, -a.y, a.x);\n"
        "    rd.xz = rd.xz*rM;\n"
        "    a = sin(vec2(1.5707963, 0) - ms.y);\n"
        "    rM = mat2(a, -a.y, a.x);\n"
        "    rd.yz = rd.yz*rM;\n"
        "\n"
        "\n"
        "\n"
        "    // Raymarching.\n"
        "    const float FAR = 50.0;\n"
        "    float t = 0.0, h;\n"
        "    for(int i = 0; i < 96; i++){\n"
        "\n"
        "        h = map(ro+rd*t);\n"
        "        // Note the \"t*b + a\" addition. Basically, we're putting less emphasis on accuracy, as\n"
        "        // \"t\" increases. It's a cheap trick that works in most situations... Not all, though.\n"
        "        if(abs(h)<0.001*(t*.75 + .25) || t>FAR) break;//*(t*.5 + 1.)\n"
        "        t += h*.75;\n"
        "        //t += step(.5, t)*h*.25 + h*.5;\n"
        "\n"
        "    }\n"
        "\n"
        "    // Initialize the scene color.\n"
        "    vec3 col = vec3(0);\n"
        "\n"
        "    // Scene hit, so color the pixel.\n"
        "    if(t<FAR){\n"
        "\n"
        "        // This looks a little messy and haphazard, but it's really just some basic lighting, and application\n"
        "        // of the following material properties: Metal = 1., Walls = 2., Screens = 3..\n"
        "\n"
        "        float ts = 2.;\n"
        "        // Global object ID. It needs to be saved just after the raymarching equation, since other \"map\" calls,\n"
        "        // like normal calculations will give incorrect results. Found that out the hard way. :)\n"
        "        float saveObjID = objID;\n"
        "\n"
        "\n"
        "        vec3 pos = ro + rd*t; // Scene postion.\n"
        "        vec3 pOffs = pos - vec3(camPath(pos.z).xy, 0); // Postion, offset by the path.\n"
        "        vec3 nor = calcNormal(pos); // Normal.\n"
        "\n"
        "        // Apply some subtle texture bump mapping to the walls and the metal tubing, but not the screen.\n"
        "        // I should probably get rid of that \"if\" statement later, but it seems OK for now.\n"
        "        if(saveObjID<2.5) nor = texBump(iChannel0, pOffs*ts, nor, 0.002 + step(saveObjID, 1.5)*0.012);\n"
        "\n"
        "\n"
        "    //    col = tex3D(iChannel0, pOffs*ts, nor); // Texture pixel at the scene postion.\n"
        "    col = vec3(0.5, 0.5, 0.5);\n"
        "        col = smoothstep(-.3, .8, col)*vec3(1., .8, .7); // Process the color a little.\n"
        "\n"
        "        // More fake lighting. This was just a bit of trial-and-error to produce some repetitive,\n"
        "        // slightly overhead, spotlights in each of the modules. Cylinder in XY, sine repeat\n"
        "        // in the Z direction... Something like that.\n"
        "        float spot = max(2. - length(pOffs.xy - vec2(0, 1)), 0.)*(sin((pOffs.z)*3.14159 + 1.57)*.5+.5);\n"
        "        spot = smoothstep(0.25, 1., spot);\n"
        "\n"
        "\n"
        "\n"
        "        float occ = calcAO( pos, nor ); // Occlusion.\n"
        "        vec3  li = normalize( lp - pos ); // Point light.\n"
        "        float dif = clamp(dot(nor, li), 0.0, 1.0); // Diffuse.\n"
        "        float spe = pow(max(dot(reflect(-li, nor), -rd), 0.), 8.); // Object specular.\n"
        "        float spe2 = 0.; // Global specular.\n"
        "\n"
        "\n"
        "\n"
        "        vec3  rCol = vec3(0); // Reflection color. Mostly fake.\n"
        "\n"
        "        // If the metal tubing or the screen is hit, apply the individual properties.\n"
        "        if(saveObjID>1.5){\n"
        "            \n"
        "            // Grey out the limestone wall color.\n"
        "            col = vec3(1)*dot(col*.7+.2, vec3(.299, .587, .114));\n"
        "            // Add some fake reflection. Not reliable, but it's subtle.\n"
        "            rCol = tex3D(iChannel0, (pOffs + reflect(rd, nor))*ts, nor);\n"
        "            col += rCol*.25 + spot*.25;\n"
        "            spe2 = spe*spe*.25; // Ramp up the global specular a bit.\n"
        "\n"
        "        }\n"
        "\n"
        "        // If just the screen has been hit, apply some extra properties, then draw the screen image.\n"
        "        // I could just write \"saveObjID == 3.,\" but I get a little paranoid where floats are concerned. :)\n"
        "        if(saveObjID>2.5){\n"
        "\n"
        "            // For the screen image, we're interested in the offset height and depth positions. Ie: pOffs.zy.\n"
        "\n"
        "            // Pixelized dot pattern shade.\n"
        "            float c = dotPattern(pOffs.zy*36.+.5);\n"
        "\n"
        "            // Applying some color to the shade.\n"
        "            col = vec3(min(c*1.5, 1.), pow(c, 2.5), pow(c, 12.));\n"
        "            // Mixing the colors around a little. Made up.\n"
        "            col = mix(col.zyx, col, sin(dot(pos, vec3(.333))*3.14159*6.)*.34+.66);\n"
        "            \n"
        "            // Individual screen ID or sorts.\n"
        "            float id = hash(dot(floor(pOffs + vec3(.0, .5, .5)), vec3(7, 157, 113)));\n"
        "\n"
        "            // Use the screen ID to give it a different random hue.\n"
        "            col = rotHue(col, floor(id*12.)/12.*6.283/2.);\n"
        "\n"
        "            col += rCol*rCol*.5; // Screen reflection.\n"
        "\n"
        "            dif += .5; // Make the screen appear self illuminating, but increasing the diffuse.\n"
        "            spe += .25;\n"
        "\n"
        "        }\n"
        "\n"
        "        // Combining everything together to produce the scene color.\n"
        "        col *= (dif + .25 + spot*.5 + vec3(.25, .3, .5)*spe) + spe2;\n"
        "        col *= occ; // Applying occlusion.\n"
        "\n"
        "\n"
        "    }\n"
        "\n"
        "    // Applying some very slight fog in the distance. This is technically an inside scene...\n"
        "    // Or is it underground... Who cares, it's just a shader. :)\n"
        "    col = mix(min(col, 1.), vec3(0), 1.-exp(-t*t/FAR/FAR*15.));//smoothstep(0., FAR-20., t)\n"
        "\n"
        "    // Done.\n"
        "    fragColor = vec4(col, 1.0);\n"
        "\n"
        "}\n"
        "\n"
     );

     n->create_file("ShaderToy/ProteanClouds.glsl",
        "// https://www.shadertoy.com/view/3l23Rh\n"
        "// Protean clouds by nimitz (twitter: @stormoid)\n"
        "// https://www.shadertoy.com/view/3l23Rh\n"
        "// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License\n"
        "// Contact the author for other licensing options\n"
        "\n"
        "/*\n"
        "    Technical details:\n"
        "\n"
        "    The main volume noise is generated from a deformed periodic grid, which can produce\n"
        "    a large range of noise-like patterns at very cheap evalutation cost. Allowing for multiple\n"
        "    fetches of volume gradient computation for improved lighting.\n"
        "\n"
        "    To further accelerate marching, since the volume is smooth, more than half the the density\n"
        "    information isn't used to rendering or shading but only as an underlying volume    distance to\n"
        "    determine dynamic step size, by carefully selecting an equation    (polynomial for speed) to\n"
        "    step as a function of overall density (not necessarialy rendered) the visual results can be\n"
        "    the    same as a naive implementation with ~40% increase in rendering performance.\n"
        "\n"
        "    Since the dynamic marching step size is even less uniform due to steps not being rendered at all\n"
        "    the fog is evaluated as the difference of the fog integral at each rendered step.\n"
        "\n"
        "*/\n"
        "\n"
        "mat2 rot(in float a){float c = cos(a), s = sin(a);return mat2(c,s,-s,c);}\n"
        "const mat3 m3 = mat3(0.33338, 0.56034, -0.71817, -0.87887, 0.32651, -0.15323, 0.15162, 0.69596, 0.61339)*1.93;\n"
        "float mag2(vec2 p){return dot(p,p);}\n"
        "float linstep(in float mn, in float mx, in float x){ return clamp((x - mn)/(mx - mn), 0., 1.); }\n"
        "float prm1 = 0.;\n"
        "vec2 bsMo = vec2(0);\n"
        "\n"
        "vec2 disp(float t){ return vec2(sin(t*0.22)*1., cos(t*0.175)*1.)*2.; }\n"
        "\n"
        "vec2 map(vec3 p)\n"
        "{\n"
        "    vec3 p2 = p;\n"
        "    p2.xy -= disp(p.z).xy;\n"
        "    p.xy *= rot(sin(p.z+iTime)*(0.1 + prm1*0.05) + iTime*0.09);\n"
        "    float cl = mag2(p2.xy);\n"
        "    float d = 0.;\n"
        "    p *= .61;\n"
        "    float z = 1.;\n"
        "    float trk = 1.;\n"
        "    float dspAmp = 0.1 + prm1*0.2;\n"
        "    for(int i = 0; i < 5; i++)\n"
        "    {\n"
        "        p += sin(p.zxy*0.75*trk + iTime*trk*.8)*dspAmp;\n"
        "        d -= abs(dot(cos(p), sin(p.yzx))*z);\n"
        "        z *= 0.57;\n"
        "        trk *= 1.4;\n"
        "        p = p*m3;\n"
        "    }\n"
        "    d = abs(d + prm1*3.)+ prm1*.3 - 2.5 + bsMo.y;\n"
        "    return vec2(d + cl*.2 + 0.25, cl);\n"
        "}\n"
        "\n"
        "vec4 render( in vec3 ro, in vec3 rd, float time )\n"
        "{\n"
        "    vec4 rez = vec4(0);\n"
        "    const float ldst = 8.;\n"
        "    vec3 lpos = vec3(disp(time + ldst)*0.5, time + ldst);\n"
        "    float t = 1.5;\n"
        "    float fogT = 0.;\n"
        "    for(int i=0; i<130; i++)\n"
        "    {\n"
        "        if(rez.a > 0.99)break;\n"
        "\n"
        "        vec3 pos = ro + t*rd;\n"
        "        vec2 mpv = map(pos);\n"
        "        float den = clamp(mpv.x-0.3,0.,1.)*1.12;\n"
        "        float dn = clamp((mpv.x + 2.),0.,3.);\n"
        "\n"
        "        vec4 col = vec4(0);\n"
        "        if (mpv.x > 0.6)\n"
        "        {\n"
        "\n"
        "            col = vec4(sin(vec3(5.,0.4,0.2) + mpv.y*0.1 +sin(pos.z*0.4)*0.5 + 1.8)*0.5 + 0.5,0.08);\n"
        "            col *= den*den*den;\n"
        "            col.rgb *= linstep(4.,-2.5, mpv.x)*2.3;\n"
        "            float dif =  clamp((den - map(pos+.8).x)/9., 0.001, 1. );\n"
        "            dif += clamp((den - map(pos+.35).x)/2.5, 0.001, 1. );\n"
        "            col.xyz *= den*(vec3(0.005,.045,.075) + 1.5*vec3(0.033,0.07,0.03)*dif);\n"
        "        }\n"
        "        \n"
        "        float fogC = exp(t*0.2 - 2.2);\n"
        "        col.rgba += vec4(0.06,0.11,0.11, 0.1)*clamp(fogC-fogT, 0., 1.);\n"
        "        fogT = fogC;\n"
        "        rez = rez + col*(1. - rez.a);\n"
        "        t += clamp(0.5 - dn*dn*.05, 0.09, 0.3);\n"
        "    }\n"
        "    return clamp(rez, 0.0, 1.0);\n"
        "}\n"
        "\n"
        "float getsat(vec3 c)\n"
        "{\n"
        "    float mi = min(min(c.x, c.y), c.z);\n"
        "    float ma = max(max(c.x, c.y), c.z);\n"
        "    return (ma - mi)/(ma+ 1e-7);\n"
        "}\n"
        "\n"
        "//from my \"Will it blend\" shader (https://www.shadertoy.com/view/lsdGzN)\n"
        "vec3 iLerp(in vec3 a, in vec3 b, in float x)\n"
        "{\n"
        "    vec3 ic = mix(a, b, x) + vec3(1e-6,0.,0.);\n"
        "    float sd = abs(getsat(ic) - mix(getsat(a), getsat(b), x));\n"
        "    vec3 dir = normalize(vec3(2.*ic.x - ic.y - ic.z, 2.*ic.y - ic.x - ic.z, 2.*ic.z - ic.y - ic.x));\n"
        "    float lgt = dot(vec3(1.0), ic);\n"
        "    float ff = dot(dir, normalize(ic));\n"
        "    ic += 1.5*dir*sd*ff*lgt;\n"
        "    return clamp(ic,0.,1.);\n"
        "}\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{    \n"
        "    vec2 q = fragCoord.xy/iResolution.xy;\n"
        "    vec2 p = (gl_FragCoord.xy - 0.5*iResolution.xy)/iResolution.y;\n"
        "    bsMo = (iMouse.xy - 0.5*iResolution.xy)/iResolution.y;\n"
        "\n"
        "    float time = iTime*3.;\n"
        "    vec3 ro = vec3(0,0,time);\n"
        "\n"
        "    ro += vec3(sin(iTime)*0.5,sin(iTime*1.)*0.,0);\n"
        "\n"
        "    float dspAmp = .85;\n"
        "    ro.xy += disp(ro.z)*dspAmp;\n"
        "    float tgtDst = 3.5;\n"
        "\n"
        "    vec3 target = normalize(ro - vec3(disp(time + tgtDst)*dspAmp, time + tgtDst));\n"
        "    ro.x -= bsMo.x*2.;\n"
        "    vec3 rightdir = normalize(cross(target, vec3(0,1,0)));\n"
        "    vec3 updir = normalize(cross(rightdir, target));\n"
        "    rightdir = normalize(cross(updir, target));\n"
        "    vec3 rd=normalize((p.x*rightdir + p.y*updir)*1. - target);\n"
        "    rd.xy *= rot(-disp(time + 3.5).x*0.2 + bsMo.x);\n"
        "    prm1 = smoothstep(-0.4, 0.4,sin(iTime*0.3));\n"
        "    vec4 scn = render(ro, rd, time);\n"
        "        \n"
        "    vec3 col = scn.rgb;\n"
        "    col = iLerp(col.bgr, col.rgb, clamp(1.-prm1,0.05,1.));\n"
        "\n"
        "    col = pow(col, vec3(.55,0.65,0.6))*vec3(1.,.97,.9);\n"
        "\n"
        "    col *= pow( 16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.12)*0.7+0.3; //Vign\n"
        "\n"
        "    fragColor = vec4( col, 1.0 );\n"
        "}\n"
     );

     n->create_file("ShaderToy/QuadTreeTruchet.glsl",
        "// https://www.shadertoy.com/view/4t3BW4\n"
        "/*\n"
        "\n"
        "    Quadtree Truchet\n"
        "    ----------------\n"
        "\n"
        "    A multiscale, multitile, overlapped, weaved Truchet pattern -- However, since\n"
        "    that description is a little verbose, I figured that a quadtree Truchet was as\n"
        "    good a description as any. :) The mild weave effect is provided via the\n"
        "    \"INCLUDE_LINE_TILES\" define.\n"
        "\n"
        "    In order to produce a varied looking Truchet pattern, there are a couple of\n"
        "    simple things you can try: One is to use more than one tile, and the other is\n"
        "    to stitch weaved tiles together to produce a cool under-over effect. There are\n"
        "    a few examples on Shadertoy of each, which are easy enough to find -- Just do\n"
        "    a search for \"Truchet\" and look for the multitile and weaved examples.\n"
        "\n"
        "    Lesser known variations include using Truchet tiles that overlap one another,\n"
        "    and stitching together multiscaled tiles -- usually on something like a quadtree\n"
        "    grid. This example uses elements of all of the aforementioned.\n"
        "\n"
        "    In the past, I've combined two non-overlapping tile scales, but had never\n"
        "    considered taking it beyond that... until I came across Christopher Carlson's\n"
        "    article, \"Multi-Scale Truchet Patterns.\" If you follow the link below and refer\n"
        "    to the construction process, you'll see that the idea behind it is almost\n"
        "    rundimentary. As a consequence, I figured that it'd take me five minutes to put\n"
        "    the ideas into pixel shader form. Unfortunately, they say the dumber you are,\n"
        "    the more overconfident you'll be, and to cut a long story short... It took me\n"
        "    longer than five minutes. :D\n"
        "\n"
        "    The code below is somewhat obfuscated and strewn with defines - The defines are\n"
        "    my fault, since I wanted to provide a few rendering options. However, the\n"
        "    remaining complication boils down to the necessity to render overlapping tiles\n"
        "    on a repeat quadtree grid in an environment that doesn't allow random pixel\n"
        "    access. The only example along those lines I could find on here was IQ's\n"
        "    hierachical Voronoi demonstration, which is pretty cool, but I needed to render\n"
        "    things in a way that involved less nesting, which complicated things.\n"
        "\n"
        "    Either way, the idea is pretty simple: Construct a grid, randomly render some\n"
        "    Truchet tiles, subdivide the remaining squares into four, randomly render some\n"
        "    more tiles in reverse color order, then continue ad infinitum. By the way, I\n"
        "    constructed this on the fly using the best method I could think of at the time.\n"
        "    However, if anyone out there has a more elegant solution, feel free to post it. :)\n"
        "    \n"
        "    Naturally, the idea can be extended to 3D. Three levels with this particular\n"
        "    setup might be a little slow. However, two levels using a non overlapping tile\n"
        "    is definitely doable, so I intend to produce an example along those lines in the\n"
        "    near future.\n"
        "\n"
        "\n"
        "    Based on the following:\n"
        "\n"
        "    Multi-Scale Truchet Patterns  - Christopher Carlson\n"
        "    https://christophercarlson.com/portfolio/multi-scale-truchet-patterns/\n"
        "    Linking paper containing more detail:\n"
        "    http://archive.bridgesmathart.org/2018/bridges2018-39.pdf\n"
        "\n"
        "    Quadtree Related:\n"
        "\n"
        "    // Considers overlap.\n"
        "    https://www.shadertoy.com/view/Xll3zX\n"
        "    Voronoi - hierarchical - IQ\n"
        "\n"
        "    // No overlap, but I really like this one.\n"
        "    SDF Raymarch Quadtree - Paniq\n"
        "    https://www.shadertoy.com/view/MlffW8\n"
        "\n"
        "    // Multilevel, and nice and simple.\n"
        "    quadtree - 4 - FabriceNeyret2\n"
        "    https://www.shadertoy.com/view/ltlyRH\n"
        "\n"
        "*/\n"
        "\n"
        "\n"
        "// DEFINES: Feel free to try them out.\n"
        "\n"
        "// Default colored setting. Not applicable when using the stacked tiles option.\n"
        "// When turned off, the color is white.\n"
        "#define SPECTRUM_COLORED\n"
        "\n"
        "// Showing the different tile layers stacked on top of one another. Aesthetically, I prefer\n"
        "// this more, because it has a raised look about it. However, you can't make out the general\n"
        "// pattern as well, so it's off by default.\n"
        "//#define STACKED_TILES\n"
        "\n"
        "// Pink -- Less bland than white, and has a velvety feel... Gets overridden by the spectrum\n"
        "// color option, so only works when \"SPECTRUM_COLORED\" is commented out.\n"
        "//#define PINK\n"
        "\n"
        "// This option produces art deco looking patterns, which are probably more interesting, but\n"
        "// I wanted the default pattern to be more simplistic.\n"
        "//#define INCLUDE_LINE_TILES\n"
        "\n"
        "\n"
        "\n"
        "// vec2 to vec2 hash.\n"
        "vec2 hash22(vec2 p) {\n"
        "\n"
        "    // Faster, but doesn't disperse things quite as nicely. However, when framerate\n"
        "    // is an issue, and it often is, this is a good one to use. Basically, it's a tweaked\n"
        "    // amalgamation I put together, based on a couple of other random algorithms I've\n"
        "    // seen around... so use it with caution, because I make a tonne of mistakes. :)\n"
        "    float n = sin(dot(p, vec2(57, 27)));\n"
        "\n"
        "    return fract(vec2(262144, 32768)*n);\n"
        "\n"
        "    /*\n"
        "    // Animated.\n"
        "    p = fract(vec2(262144, 32768)*n);\n"
        "    // Note the \".35,\" insted of \".5\" that you'd expect to see. .\n"
        "    return sin(p*6.2831853 + iTime/2.)*.24;\n"
        "    */\n"
        "}\n"
        "\n"
        "// Standard 2D rotation formula.\n"
        "mat2 r2(in float a){ float c = cos(a), s = sin(a); return mat2(c, s, -s, c); }\n"
        "\n"
        "/*\n"
        "// IQ's 2D unsigned box formula.\n"
        "float sBox(vec2 p, vec2 b){ return length(max(abs(p) - b, 0.)); }\n"
        "\n"
        "// IQ's 2D signed box formula.\n"
        "float sBoxU(vec2 p, vec2 b){\n"
        "\n"
        "  vec2 d = abs(p) - b;\n"
        "  return min(max(d.x, d.y), 0.) + length(max(d, 0.));\n"
        "}\n"
        "*/\n"
        "\n"
        "void mainImage(out vec4 fragColor, in vec2 fragCoord){\n"
        "\n"
        "    // Screen coordinates.\n"
        "    vec2 uv = (fragCoord - iResolution.xy*.5)/iResolution.y;\n"
        "\n"
        "    // Scaling, rotation and transalation.\n"
        "    vec2 oP = uv*5.;\n"
        "    oP *= r2(sin(iTime/8.)*3.14159/8.);\n"
        "    oP -= vec2(cos(iTime/8.)*0., -iTime);\n"
        "\n"
        "\n"
        "    // Distance field values -- One for each color. They're \"vec4\"s to hold the three\n"
        "    // layers and an an unused spare. The other is for the grid.\n"
        "    vec4 d = vec4(1e5), d2 = vec4(1e5), grid = vec4(1e5);\n"
        "\n"
        "    // Final entry needs to fill in the rest, so you give it a 100% chance of success.\n"
        "    // I'd rather not say how long it took me to figure that out. :D\n"
        "    vec2 rndTh[3];\n"
        "    rndTh[0] = vec2(.5, .35);\n"
        "    rndTh[1] = vec2(.5, .7);\n"
        "    rndTh[2] = vec2(.5, 1);\n"
        "\n"
        "\n"
        "    // The scale dimentions. Gets multiplied by two each iteration.\n"
        "    float dim = 1.;\n"
        "\n"
        "\n"
        "\n"
        "    // If you didn't need to worry about overlap, you wouldn't need to consider neighboring\n"
        "    // cell rendering, which would make this far less complicated - One loop and a break.\n"
        "\n"
        "    // Three tile levels.\n"
        "    for(int k=0; k<3; k++){\n"
        "\n"
        "        // Base cell ID.\n"
        "        vec2 ip = floor(oP*dim);\n"
        "\n"
        "\n"
        "        for(int j=-1; j<=1; j++){\n"
        "            for(int i=-1; i<=1; i++){\n"
        "\n"
        "                // The neighboring cell ID.\n"
        "                vec2 rndIJ = hash22(ip + vec2(i, j));\n"
        "\n"
        "                // The cell IDs for the previous dimension, or dimensions, as the case may be.\n"
        "                // Because the tiles overlap, rendering order matters. In this case, the tiles\n"
        "                // need to laid down from largest (k = 0) to smallest (k = 2). If a large tile\n"
        "                // has taken up the space, you need to check on the next iterations and skip --\n"
        "                // so as not to lay smaller tiles over the larger ones.\n"
        "                //\n"
        "                // So why not just break from the loop? Unfortunately, there are neighboring\n"
        "                // cells to check, and the IDs need to be calculated from the perspective of\n"
        "                // each cell neighbor... Yeah, I'm confused too. You can either take my word\n"
        "                // for it, or better yet, come up with a more elegant solution. :)\n"
        "                vec2 rndIJ2 = hash22(floor((ip + vec2(i, j))/2.));\n"
        "                vec2 rndIJ4 = hash22(floor((ip + vec2(i, j))/4.));\n"
        "                \n"
        "                // If the previous large tile has been rendered, continue.\n"
        "                if(k==1 && rndIJ2.y<rndTh[0].y) continue;\n"
        "                // If any of the two previous larger have been rendered, continue.\n"
        "                if(k==2 && (rndIJ2.y<rndTh[1].y || rndIJ4.y<rndTh[0].y)) continue;\n"
        "\n"
        "\n"
        "                // If the random cell ID at this particular scale is below a certain threshold,\n"
        "                // render the tile. The code below is a little messy, due to to fact that I wanted\n"
        "                // to render a few different tile styles without bloating the code too much.\n"
        "                // This meant a bunch of random coordinate flipping, reflecting, etc. As mentioned,\n"
        "                // I'll provide a much simpler example later.\n"
        "                //\n"
        "                if(rndIJ.y<rndTh[k].y){\n"
        "\n"
        "                    vec2 p = mod(oP, 1./dim) - .5/dim - vec2(i, j)/dim;\n"
        "\n"
        "\n"
        "                    // The grid square.\n"
        "                    float square = max(abs(p.x), abs(p.y)) - .5/dim;\n"
        "                 \n"
        "                    // The grid lines.\n"
        "                    const float lwg = .01;\n"
        "                    float gr = abs(square) - lwg/2.;\n"
        "                    grid.x = min(grid.x, gr);\n"
        "\n"
        "                    \n"
        "                    // TILE COLOR ONE.\n"
        "\n"
        "                    // Standard Truchet rotation and flipping -- based on a random cell ID.\n"
        "                    if(rndIJ.x<rndTh[k].x) p.xy = p.yx;\n"
        "                    if(fract(rndIJ.x*57.543 + .37)<rndTh[k].x) p.x = -p.x;\n"
        "\n"
        "\n"
        "\n"
        "                    // Rotating by 90 degrees, then reflecting across both axes by the correct\n"
        "                    // distance to produce four circles on the midway points of the grid boundary\n"
        "                    // lines... A lot of this stuff is just practice. Do it often enough and\n"
        "                    // it'll become second nature... sometimes. :)\n"
        "                    vec2 p2 = abs(vec2(p.y - p.x, p.x + p.y)*.7071) - vec2(.5, .5)*.7071/dim;\n"
        "                    float c3 = length(p2) - .5/3./dim;\n"
        "\n"
        "                    float c, c2;\n"
        "\n"
        "                    // Truchet arc one.\n"
        "                    c = abs(length(p - vec2(-.5, .5)/dim) - .5/dim) - .5/3./dim;\n"
        "\n"
        "                    // Truchet arc two.\n"
        "                    if(fract(rndIJ.x*157.763 + .49)>.35){\n"
        "                        c2 = abs(length(p - vec2(.5, -.5)/dim) - .5/dim) - .5/3./dim;\n"
        "                    }\n"
        "                    else{\n"
        "                        // Circles at the mid boundary lines -- instead of an arc.\n"
        "                        // c2 = 1e5; // In some situations, just this would work.\n"
        "                        c2 = length(p -  vec2(.5, 0)/dim) - .5/3./dim;\n"
        "                        c2 = min(c2, length(p -  vec2(0, -.5)/dim) - .5/3./dim);\n"
        "                    }\n"
        "\n"
        "\n"
        "                    // Randomly overiding some arcs with lines.\n"
        "                    #ifdef INCLUDE_LINE_TILES\n"
        "                        if(fract(rndIJ.x*113.467 + .51)<.35){\n"
        "                            c = abs(p.x) - .5/3./dim;\n"
        "                        }\n"
        "                        if(fract(rndIJ.y*113.467 + .51)<.35){\n"
        "                            c2 = abs(p.y) - .5/3./dim;\n"
        "                        }\n"
        "                    #endif\n"
        "\n"
        "\n"
        "                    // Truch arcs, lines, or dots -- as the case may be.\n"
        "                    float truchet = min(c, c2);\n"
        "\n"
        "                    // Carving out a mild channel around the line to give a faux weave effect.\n"
        "                    #ifdef INCLUDE_LINE_TILES\n"
        "                        float lne = abs(c - .5/6./dim + .5/12./dim) - .5/12./dim;\n"
        "                         truchet = max(truchet, -lne);\n"
        "                    #endif\n"
        "\n"
        "                    // Each tile has two colors. This is the first, and it's rendered on top.\n"
        "                    c = min(c3, max(square, truchet));\n"
        "                    d[k] = min(d[k], c); // Tile color one.\n"
        "\n"
        "\n"
        "                    // TILE COLOR TWO.\n"
        "                    // Repeat trick, to render four circles at the grid vertices.\n"
        "                    p = abs(p) - .5/dim;\n"
        "                    float l = length(p);\n"
        "                    // Four circles at the grid vertices and the square.\n"
        "                    c = min(l - 1./3./dim, square);\n"
        "                    //c = max(c, -truchet);\n"
        "                    //c = max(c, -c3);\n"
        "                    d2[k] = min(d2[k], c); // Tile color two.\n"
        "\n"
        "                    // Rendering some circles at the actual grid vertices. Mouse down to see it.\n"
        "                    grid.y = min(grid.y, l - .5/9./dim); //.05/(dim*.35 + .65)\n"
        "                    grid.z = min(grid.z, l);\n"
        "\n"
        "\n"
        "                }\n"
        "\n"
        "\n"
        "\n"
        "            }\n"
        "        }\n"
        "\n"
        "\n"
        "        dim *= 2.;\n"
        "\n"
        "\n"
        "    }\n"
        "\n"
        "\n"
        "    // The scene color. Initiated to grey.\n"
        "    vec3 col = vec3(.25);\n"
        "\n"
        "\n"
        "    // Just a simple lined pattern.\n"
        "    float pat3 = clamp(sin((oP.x - oP.y)*6.283*iResolution.y/24.)*1. + .9, 0., 1.)*.25 + .75;\n"
        "    // Resolution based falloff... Insert \"too may different devices these days\" rant here. :D\n"
        "    float fo = 5./iResolution.y;\n"
        "\n"
        "\n"
        "    // Tile colors.\n"
        "    vec3 pCol2 = vec3(.125);\n"
        "    vec3 pCol1 = vec3(1);\n"
        "\n"
        "    //The spectrum color option overides the pink option.\n"
        "    #ifdef SPECTRUM_COLORED\n"
        "    pCol1 = vec3(.7, 1.4, .4);\n"
        "    #else\n"
        "    // Pink version.\n"
        "        #ifdef PINK\n"
        "        pCol1 = mix(vec3(1, .1, .2), vec3(1, .1, .5), uv.y*.5 + .5);;\n"
        "        pCol2 = vec3(.1, .02, .06);\n"
        "        #endif\n"
        "    #endif\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "    #ifdef STACKED_TILES\n"
        "        // I provided this as an option becaue I thought it might be useful\n"
        "        // to see the tile layering process.\n"
        "\n"
        "        float pw = .02;\n"
        "        d -= pw/2.;\n"
        "        d2 -= pw/2.;\n"
        "\n"
        "        // Render each two-colored tile, switching colors on alternating iterations.\n"
        "        for (int k=0; k<3; k++){\n"
        "\n"
        "            col = mix(col, vec3(0), (1. - smoothstep(0., fo*5., d2[k]))*.35);\n"
        "            col = mix(col, vec3(0), 1. - smoothstep(0., fo, d2[k]));\n"
        "            col = mix(col, pCol2, 1. - smoothstep(0., fo, d2[k] + pw));\n"
        "\n"
        "            col = mix(col, vec3(0), (1. - smoothstep(0., fo*5., d[k]))*.35);\n"
        "            col = mix(col, vec3(0), 1. - smoothstep(0., fo, d[k]));\n"
        "            col = mix(col, pCol1, 1. - smoothstep(0., fo, d[k] + pw));\n"
        "\n"
        "            vec3 temp = pCol1; pCol1 = pCol2; pCol2 = temp;\n"
        "        }\n"
        "\n"
        "        col *= pat3;\n"
        "\n"
        "    #else\n"
        "\n"
        "        // Combining the tile layers into a continuous surface. I'd like to say that\n"
        "        // I applied years of topological knowledge to arrive at this, but like most\n"
        "        // things, I threw a bunch of formulas at the screen in frustration until I\n"
        "        // fluked the solution. :D There was a bit of logic applied though. :)\n"
        "        d.x = max(d2.x, -d.x);\n"
        "        d.x = min(max(d.x, -d2.y), d.y);\n"
        "        d.x = max(min(d.x, d2.z), -d.z);\n"
        "\n"
        "        // A couple of distance field patterns and a shade.\n"
        "        float pat = clamp(-sin(d.x*6.283*20.) - .0, 0., 1.);\n"
        "        float pat2 = clamp(sin(d.x*6.283*16.)*1. + .9, 0., 1.)*.3 + .7;\n"
        "        float sh = clamp(.75 + d.x*2., 0., 1.);\n"
        "\n"
        "        #ifdef SPECTRUM_COLORED\n"
        "\n"
        "            col *= pat;\n"
        "\n"
        "            // Render the combined shape.\n"
        "            d.x = -(d.x + .03);\n"
        "\n"
        "            col = mix(col, vec3(0), (1. - smoothstep(0., fo*5., d.x)));\n"
        "            col = mix(col, vec3(0), 1. - smoothstep(0., fo, d.x));\n"
        "            col = mix(col, vec3(.8, 1.2, .6), 1. - smoothstep(0., fo*2., d.x + .02));\n"
        "            col = mix(col, vec3(0), 1. - smoothstep(0., fo*2., d.x + .03));\n"
        "            col = mix(col, vec3(.7, 1.4, .4)*pat2, 1. - smoothstep(0., fo*2., d.x + .05));\n"
        "\n"
        "            col *= sh;\n"
        "\n"
        "        #else\n"
        "\n"
        "            //d.x -= .01;\n"
        "            col = pCol1;\n"
        "\n"
        "            // Render the combined shape.\n"
        "            col = mix(col, vec3(0), (1. - smoothstep(0., fo*5., d.x))*.35);\n"
        "            col = mix(col, vec3(0), 1. - smoothstep(0., fo, d.x));\n"
        "            col = mix(col, pCol2, 1. - smoothstep(0., fo, d.x + .02));\n"
        "\n"
        "\n"
        "            col *= pat3; // Line decroation.\n"
        "        #endif\n"
        "\n"
        "    #endif\n"
        "\n"
        "\n"
        "\n"
        "    // Mild spotlight.\n"
        "    col *= max(1.15 - length(uv)*.5, 0.);\n"
        "\n"
        "\n"
        "    // Click the left mouse button to show the underlying quadtree grid structure. It's\n"
        "    // helpful to see the cell borders to see the random tile constructions.\n"
        "    if(iMouse.z>0.){\n"
        "\n"
        "\n"
        "        vec3 vCol1 = vec3(.8, 1, .7);\n"
        "        vec3 vCol2 = vec3(1, .7, .4);\n"
        "\n"
        "        #ifdef PINK\n"
        "        vCol1 = vCol1.zxy;\n"
        "        vCol2 = vCol2.zyx;\n"
        "        #endif\n"
        "\n"
        "        // Grid lines.\n"
        "        vec3 bg = col;\n"
        "        col = mix(col, vec3(0), (1. - smoothstep(0., .02, grid.x - .02))*.7);\n"
        "        col = mix(col, vCol1 + bg/2., 1. - smoothstep(0., .015, grid.x));\n"
        "\n"
        "        // Circles on the grid vertices.\n"
        "        float fo = .5/iResolution.y/grid.z;\n"
        "        col = mix(col, vec3(0), (1. - smoothstep(0., fo*3., grid.y - .02))*.5);\n"
        "        col = mix(col, vec3(0), 1. - smoothstep(0., fo, grid.y - .02));\n"
        "        col = mix(col, vCol2, 1. - smoothstep(0., fo, grid.y));\n"
        "        col = mix(col, vec3(0), 1. - smoothstep(0., fo, grid.z - .001));\n"
        "    }\n"
        "\n"
        "\n"
        "    // Mix the colors, if the spectrum option is chosen.\n"
        "    #ifdef SPECTRUM_COLORED\n"
        "    col = mix(col, col.yxz, uv.y*.75 + .5); //.zxy\n"
        "    col = mix(col, col.zxy, uv.x*.7 + .5); //.zxy\n"
        "    #endif\n"
        "\n"
        "\n"
        "    // Rough gamma correction, and output to the screen.\n"
        "    fragColor = vec4(sqrt(max(col, 0.)), 1);\n"
        "}\n"
     );

     n->create_file("ShaderToy/rabbit.glsl",
        "// https://www.shadertoy.com/view/XlccWH\n"
        "\n"
        "float time;\n"
        "\n"
        "// polynomial smooth min (k = 0.1) (from IQ)\n"
        "float smin( float a, float b, float k )\n"
        "{\n"
        "    float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );\n"
        "    return mix( b, a, h ) - k*h*(1.0-h);\n"
        "}\n"
        "\n"
        "\n"
        "float smax(float a,float b, float k)\n"
        "{\n"
        "    return -smin(-a,-b,k);\n"
        "}\n"
        "\n"
        "mat2 rotmat(float a)\n"
        "{\n"
        "    return mat2(cos(a),sin(a),-sin(a),cos(a));\n"
        "}\n"
        "\n"
        "float cylinder(vec3 p,vec3 dir,float h,float r)\n"
        "{\n"
        "    float t=dot(p,dir);\n"
        "    float d=distance(p,dir*t);\n"
        "    return length(max(abs(vec2(d,t))-vec2(r,h),vec2(0)));\n"
        "    d=max(d,-t);\n"
        "    d=max(d,t-h);\n"
        "    return d;\n"
        "}\n"
        "\n"
        "float pupdist=1e4;\n"
        "\n"
        "float rabdist(vec3 p)\n"
        "{\n"
        "    float an=.5*.5*2.*6. +iMouse.x/iResolution.x*6.;\n"
        "    p.xz=mat2(cos(an),sin(an),sin(an),-cos(an))*p.xz;\n"
        "\n"
        "    float time2=time*2.4;\n"
        "\n"
        "    p.y+=2.3;\n"
        "    p.xy*=rotmat(cos(time2+1.)*.04);\n"
        "    p.y-=2.3;\n"
        "\n"
        "    vec3 op=p;\n"
        "\n"
        "    vec3 p2=p;\n"
        "    p2.xy*=rotmat(cos(time2)*.1);\n"
        "\n"
        "    vec3 p3=p;\n"
        "    p3.xy*=rotmat(cos(time2-.0-length(p)/2.)*.13);\n"
        "\n"
        "    float d=1e4;\n"
        "    p.x=abs(p.x);\n"
        "    p2.x=abs(p2.x);\n"
        "    p3.x=abs(p3.x);\n"
        "\n"
        "    d=smin(length(p2-vec3(-.75,0.,-.1))-.4,length(p2-vec3(.75,0.,-.1))-.5,2.);\n"
        "    d=smin(d,length(p2-vec3(0,0.4,-.1))-.9,1.6);\n"
        "    d+=.1;\n"
        "    // ears 1\n"
        "    d=smin(d,distance(vec3(.7,clamp(p3.y,0.,2.2),0.),p3.xyz)-.4,.14);\n"
        "    d=smax(d,-(length(p3-vec3(.7,1.7,-0.5))-.5),.2);\n"
        "\n"
        "    d=smin(d,distance(vec3(0.,clamp(p.y,-1.6,-1.1),0.),p.xyz)-.6,.04);\n"
        "    d=smin(d,distance(vec3(.3,clamp(p.y,-2.6,-1.5),0.),p.xyz)-.3,.1);\n"
        "    d=smin(d,distance(vec3(0.,-1.5,-.2),p)-.5+cos(time*3.)*.03,.4);\n"
        "\n"
        "    // ears 2\n"
        "    d=smin(d,distance(vec3(1.1,2.3,-.1),p3)-.2,.8);\n"
        "\n"
        "    // tail\n"
        "    d=smin(d,distance(vec3(0,-1.7,.6),p)-.3,.1);\n"
        "\n"
        "    vec3 q=vec3(0.35,.4,-1);\n"
        "\n"
        "    if(mod(time-1.,4.)>.04)\n"
        "    {\n"
        "        d=smax(d,-(cylinder(p2-q,normalize(q-p2),.3,.1)-.0001),.05);\n"
        "        d=smin(d,(length(p2-q*.9)-.2),.24);\n"
        "\n"
        "        // eye pupils\n"
        "        if(op.x>0.)\n"
        "            pupdist=(length(p2-vec3(.39,.32,-1.))-.2);\n"
        "        else\n"
        "            pupdist=(length(p2-vec3(.28,.32,-1.02))-.2);\n"
        "\n"
        "        d=smin(d,pupdist,.005);\n"
        "    }\n"
        "\n"
        "    // nose\n"
        "    d=smin(d,(length(p2-vec3(0,.1,-1.02))-.2),.02);\n"
        "\n"
        "    float d3=smax(-(length(p-vec3(-.05,-.29,-1.02))-.1),-(length(p-vec3(.05,-.29,-1.02))-.1),.1);\n"
        "\n"
        "    float d2=max(p2.z,distance(p2,vec3(clamp(p2.x,0.,.3),-.2,clamp(p2.z,-2.,2.)))+.01);\n"
        "\n"
        "    float time4=time/8.;\n"
        "    float gg=smoothstep(0.,1.,clamp((min(fract(time4),1.-fract(time4))-.25)*64.,0.,1.));\n"
        "    d=smax(d,mix(-d2,d3,gg),.1);\n"
        "\n"
        "    // tooth\n"
        "    d=min(d,(length(p-vec3(.0,-.2,-1.02))-.08));\n"
        "\n"
        "    p.y+=.2;\n"
        "    p.xy*=rotmat(.4+cos(time2*2.)*.02);\n"
        "\n"
        "    // arms\n"
        "    float armd=smin(distance(vec3(.2,clamp(p.y,-1.8,-0.),0.),p.xyz)-.2,\n"
        "                    distance(p,vec3(0.2,-1.7,0))-.2,.2);\n"
        "\n"
        "    d=smin(d,armd,.05);\n"
        "\n"
        "    return d;\n"
        "}\n"
        "\n"
        "float floordist(vec3 p)\n"
        "{\n"
        "    return p.y+2.85;\n"
        "}\n"
        "\n"
        "float f(vec3 p)\n"
        "{\n"
        "    return min(rabdist(p),floordist(p));\n"
        "}\n"
        "\n"
        "float sceneDist(vec3 p) { return f(p); }\n"
        "\n"
        "vec3 sceneNorm(vec3 p)\n"
        "{\n"
        "    vec3 e=vec3(1e-2,0,0);\n"
        "    float d = sceneDist(p);\n"
        "    return normalize(vec3(sceneDist(p + e.xyy) - d, sceneDist(p + e.yxy) - d,\n"
        "                          sceneDist(p + e.yyx) - d));\n"
        "}\n"
        "\n"
        "\n"
        "// from simon green and others\n"
        "float ambientOcclusion(vec3 p, vec3 n)\n"
        "{\n"
        "    const int steps = 18;\n"
        "    const float delta = 1.5;\n"
        "\n"
        "    float a = 0.0;\n"
        "    float weight = .5;\n"
        "    for(int i=1; i<=steps; i++) {\n"
        "        float d = (float(i) / float(steps)) * delta;\n"
        "        a += weight*(d - sceneDist(p + n*d));\n"
        "        weight *= 0.6;\n"
        "    }\n"
        "    return clamp(1.0 - a, 0.0, 1.0);\n"
        "}\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{\n"
        "    vec2 uv = (fragCoord/iResolution.xy * 2. - 1.) * .75;\n"
        "    uv.x *= iResolution.x / iResolution.y;\n"
        "    vec2 vt=uv;\n"
        "    float an;\n"
        "    time=iTime;\n"
        "\n"
        "    vec3 ro=vec3(0.,-.1,-8.+iMouse.y/iResolution.y*2.);\n"
        "    vec3 rd=normalize(vec3(uv,1.8));\n"
        "\n"
        "\n"
        "    float s=20.;\n"
        "\n"
        "    float t=2.,d=0.;\n"
        "    for(int i=0;i<120;++i)\n"
        "    {\n"
        "        d=f(ro+rd*t);\n"
        "        if(d<1e-4)break;\n"
        "        if(t>50.)break;\n"
        "        t+=d;\n"
        "    }\n"
        "\n"
        "    float d2=f(ro+rd*t+normalize(vec3(1,2,-2))*5e-2);\n"
        "    float l=.5+.5*(d2-d)/5e-2;\n"
        "\n"
        "    vec3 rp=(ro+rd*t);\n"
        "\n"
        "    vec3 n=sceneNorm(rp);\n"
        "\n"
        "    vec3 col=vec3(1);\n"
        "\n"
        "    col*=mix(.1,1.,smoothstep(0.0,.01,pupdist));\n"
        "\n"
        "    vec3 bcol=vec3(1,.4,.18);\n"
        "\n"
        "    if(floordist(rp)<rabdist(rp))\n"
        "        col=max(mix(bcol+(.1-length(vt.xy)/3.),vec3(1),.1),0.);\n"
        "\n"
        "    col*=l;\n"
        "\n"
        "    col+=pow(clamp(-n.y,0.,1.),2.)*bcol/1.5;\n"
        "    if(n.y<.9999)col+=pow(clamp(-rp.y-1.8,0.,1.),4.)*vec3(1,.4,.18)/3.;\n"
        "\n"
        "    if(n.y>.99999)\n"
        "    {\n"
        "        col*=pow(ambientOcclusion(rp,n),1.);\n"
        "        col*=mix(.7,1.,smoothstep(0.,2.,length(rp.xz)));\n"
        "    }\n"
        "    else\n"
        "    {\n"
        "     //   vec3 r=reflect(rd,n);\n"
        "     //   col += texture(iChannel0, r).rgb*.2*pow(clamp(0.,1.,1.-dot(-rd,n)),2.);\n"
        "     //   col*=pow(ambientOcclusion(rp,n),2.);\n"
        "    }\n"
        "\n"
        "    fragColor.rgb=max(col,0.);\n"
        "    fragColor.rgb=sqrt(fragColor.rgb+.01);\n"
        "}\n"
        "\n"
        "\n"
     );

     n->create_file("ShaderToy/RayMarchingPrimitives.glsl",
        "// https://www.shadertoy.com/view/Xds3zN\n"
        "\n"
        "// The MIT License\n"
        "// Copyright © 2013 Inigo Quilez\n"
        "// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
        "\n"
        "\n"
        "// A list of useful distance function to simple primitives, and an example on how to\n"
        "// do some interesting boolean operations, repetition and displacement.\n"
        "//\n"
        "// More info here: http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm\n"
        "\n"
        "// make this 1 is your machine is too slow\n"
        "#define AA 1\n"
        "\n"
        "//------------------------------------------------------------------\n"
        "\n"
        "float sdPlane( in vec3 p )\n"
        "{\n"
        "    return p.y;\n"
        "}\n"
        "\n"
        "float sdSphere( in vec3 p, in float s )\n"
        "{\n"
        "    return length(p)-s;\n"
        "}\n"
        "\n"
        "float sdBox( in vec3 p, in vec3 b )\n"
        "{\n"
        "    vec3 d = abs(p) - b;\n"
        "    return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));\n"
        "}\n"
        "\n"
        "float sdEllipsoid( in vec3 p, in vec3 r )\n"
        "{\n"
        "    return (length( p/r ) - 1.0) * min(min(r.x,r.y),r.z);\n"
        "}\n"
        "\n"
        "float udRoundBox( in vec3 p, in vec3 b, in float r )\n"
        "{\n"
        "    return length(max(abs(p)-b,0.0))-r;\n"
        "}\n"
        "\n"
        "float sdTorus( in vec3 p, in vec2 t )\n"
        "{\n"
        "    return length( vec2(length(p.xz)-t.x,p.y) )-t.y;\n"
        "}\n"
        "\n"
        "float sdHexPrism( vec3 p, vec2 h )\n"
        "{\n"
        "    vec3 q = abs(p);\n"
        "#if 0\n"
        "    return max(q.z-h.y,max((q.x*0.866025+q.y*0.5),q.y)-h.x);\n"
        "#else\n"
        "    float d1 = q.z-h.y;\n"
        "    float d2 = max((q.x*0.866025+q.y*0.5),q.y)-h.x;\n"
        "    return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.);\n"
        "#endif\n"
        "}\n"
        "\n"
        "float sdCapsule( vec3 p, vec3 a, vec3 b, float r )\n"
        "{\n"
        "    vec3 pa = p-a, ba = b-a;\n"
        "    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n"
        "    return length( pa - ba*h ) - r;\n"
        "}\n"
        "\n"
        "float sdEquilateralTriangle(  in vec2 p )\n"
        "{\n"
        "    const float k = sqrt(3.0);\n"
        "    p.x = abs(p.x) - 1.0;\n"
        "    p.y = p.y + 1.0/k;\n"
        "    if( p.x + k*p.y > 0.0 ) p = vec2( p.x - k*p.y, -k*p.x - p.y )/2.0;\n"
        "    p.x += 2.0 - 2.0*clamp( (p.x+2.0)/2.0, 0.0, 1.0 );\n"
        "    return -length(p)*sign(p.y);\n"
        "}\n"
        "\n"
        "float sdTriPrism( vec3 p, vec2 h )\n"
        "{\n"
        "    vec3 q = abs(p);\n"
        "    float d1 = q.z-h.y;\n"
        "#if 1\n"
        "    // distance bound\n"
        "    float d2 = max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5;\n"
        "#else\n"
        "    // correct distance\n"
        "    h.x *= 0.866025;\n"
        "    float d2 = sdEquilateralTriangle(p.xy/h.x)*h.x;\n"
        "#endif\n"
        "    return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.);\n"
        "}\n"
        "\n"
        "float sdCylinder( vec3 p, vec2 h )\n"
        "{\n"
        "  vec2 d = abs(vec2(length(p.xz),p.y)) - h;\n"
        "  return min(max(d.x,d.y),0.0) + length(max(d,0.0));\n"
        "}\n"
        "\n"
        "float sdCone( in vec3 p, in vec3 c )\n"
        "{\n"
        "    vec2 q = vec2( length(p.xz), p.y );\n"
        "    float d1 = -q.y-c.z;\n"
        "    float d2 = max( dot(q,c.xy), q.y);\n"
        "    return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.);\n"
        "}\n"
        "\n"
        "float sdConeSection( in vec3 p, in float h, in float r1, in float r2 )\n"
        "{\n"
        "    float d1 = -p.y - h;\n"
        "    float q = p.y - h;\n"
        "    float si = 0.5*(r1-r2)/h;\n"
        "    float d2 = max( sqrt( dot(p.xz,p.xz)*(1.0-si*si)) + q*si - r2, q );\n"
        "    return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.);\n"
        "}\n"
        "\n"
        "float sdPryamid4(vec3 p, vec3 h ) // h = { cos a, sin a, height }\n"
        "{\n"
        "    // Tetrahedron = Octahedron - Cube\n"
        "    float box = sdBox( p - vec3(0,-2.0*h.z,0), vec3(2.0*h.z) );\n"
        "\n"
        "    float d = 0.0;\n"
        "    d = max( d, abs( dot(p, vec3( -h.x, h.y, 0 )) ));\n"
        "    d = max( d, abs( dot(p, vec3(  h.x, h.y, 0 )) ));\n"
        "    d = max( d, abs( dot(p, vec3(  0, h.y, h.x )) ));\n"
        "    d = max( d, abs( dot(p, vec3(  0, h.y,-h.x )) ));\n"
        "    float octa = d - h.z;\n"
        "    return max(-box,octa); // Subtraction\n"
        " }\n"
        "\n"
        "float length2( vec2 p )\n"
        "{\n"
        "    return sqrt( p.x*p.x + p.y*p.y );\n"
        "}\n"
        "\n"
        "float length6( vec2 p )\n"
        "{\n"
        "    p = p*p*p; p = p*p;\n"
        "    return pow( p.x + p.y, 1.0/6.0 );\n"
        "}\n"
        "\n"
        "float length8( vec2 p )\n"
        "{\n"
        "    p = p*p; p = p*p; p = p*p;\n"
        "    return pow( p.x + p.y, 1.0/8.0 );\n"
        "}\n"
        "\n"
        "float sdTorus82( vec3 p, vec2 t )\n"
        "{\n"
        "    vec2 q = vec2(length2(p.xz)-t.x,p.y);\n"
        "    return length8(q)-t.y;\n"
        "}\n"
        "\n"
        "float sdTorus88( vec3 p, vec2 t )\n"
        "{\n"
        "    vec2 q = vec2(length8(p.xz)-t.x,p.y);\n"
        "    return length8(q)-t.y;\n"
        "}\n"
        "\n"
        "float sdCylinder6( vec3 p, vec2 h )\n"
        "{\n"
        "    return max( length6(p.xz)-h.x, abs(p.y)-h.y );\n"
        "}\n"
        "\n"
        "//------------------------------------------------------------------\n"
        "\n"
        "float opS( float d1, float d2 )\n"
        "{\n"
        "    return max(-d2,d1);\n"
        "}\n"
        "\n"
        "vec2 opU( vec2 d1, vec2 d2 )\n"
        "{\n"
        "    return (d1.x<d2.x) ? d1 : d2;\n"
        "}\n"
        "\n"
        "vec3 opRep( vec3 p, vec3 c )\n"
        "{\n"
        "    return mod(p,c)-0.5*c;\n"
        "}\n"
        "\n"
        "vec3 opTwist( vec3 p )\n"
        "{\n"
        "    float  c = cos(10.0*p.y+10.0);\n"
        "    float  s = sin(10.0*p.y+10.0);\n"
        "    mat2   m = mat2(c,-s,s,c);\n"
        "    return vec3(m*p.xz,p.y);\n"
        "}\n"
        "\n"
        "//------------------------------------------------------------------\n"
        "\n"
        "vec2 map( in vec3 pos )\n"
        "{\n"
        "    vec2 res = opU( vec2( sdPlane(     pos), 1.0 ),\n"
        "                    vec2( sdSphere(    pos-vec3( 0.0,0.25, 0.0), 0.25 ), 46.9 ) );\n"
        "    res = opU( res, vec2( sdBox(       pos-vec3( 1.0,0.25, 0.0), vec3(0.25) ), 3.0 ) );\n"
        "    res = opU( res, vec2( udRoundBox(  pos-vec3( 1.0,0.25, 1.0), vec3(0.15), 0.1 ), 41.0 ) );\n"
        "    res = opU( res, vec2( sdTorus(     pos-vec3( 0.0,0.25, 1.0), vec2(0.20,0.05) ), 25.0 ) );\n"
        "    res = opU( res, vec2( sdCapsule(   pos,vec3(-1.3,0.10,-0.1), vec3(-0.8,0.50,0.2), 0.1  ), 31.9 ) );\n"
        "    res = opU( res, vec2( sdTriPrism(  pos-vec3(-1.0,0.25,-1.0), vec2(0.25,0.05) ),43.5 ) );\n"
        "    res = opU( res, vec2( sdCylinder(  pos-vec3( 1.0,0.30,-1.0), vec2(0.1,0.2) ), 8.0 ) );\n"
        "    res = opU( res, vec2( sdCone(      pos-vec3( 0.0,0.50,-1.0), vec3(0.8,0.6,0.3) ), 55.0 ) );\n"
        "    res = opU( res, vec2( sdTorus82(   pos-vec3( 0.0,0.25, 2.0), vec2(0.20,0.05) ),50.0 ) );\n"
        "    res = opU( res, vec2( sdTorus88(   pos-vec3(-1.0,0.25, 2.0), vec2(0.20,0.05) ),43.0 ) );\n"
        "    res = opU( res, vec2( sdCylinder6( pos-vec3( 1.0,0.30, 2.0), vec2(0.1,0.2) ), 12.0 ) );\n"
        "    res = opU( res, vec2( sdHexPrism(  pos-vec3(-1.0,0.20, 1.0), vec2(0.25,0.05) ),17.0 ) );\n"
        "    res = opU( res, vec2( sdPryamid4(  pos-vec3(-1.0,0.15,-2.0), vec3(0.8,0.6,0.25) ),37.0 ) );\n"
        "    res = opU( res, vec2( opS( udRoundBox(  pos-vec3(-2.0,0.2, 1.0), vec3(0.15),0.05),\n"
        "                               sdSphere(    pos-vec3(-2.0,0.2, 1.0), 0.25)), 13.0 ) );\n"
        "    res = opU( res, vec2( opS( sdTorus82(  pos-vec3(-2.0,0.2, 0.0), vec2(0.20,0.1)),\n"
        "                               sdCylinder(  opRep( vec3(atan(pos.x+2.0,pos.z)/6.2831, pos.y, 0.02+0.5*length(pos-vec3(-2.0,0.2, 0.0))), vec3(0.05,1.0,0.05)), vec2(0.02,0.6))), 51.0 ) );\n"
        "    res = opU( res, vec2( 0.5*sdSphere(    pos-vec3(-2.0,0.25,-1.0), 0.2 ) + 0.03*sin(50.0*pos.x)*sin(50.0*pos.y)*sin(50.0*pos.z), 65.0 ) );\n"
        "    res = opU( res, vec2( 0.5*sdTorus( opTwist(pos-vec3(-2.0,0.25, 2.0)),vec2(0.20,0.05)), 46.7 ) );\n"
        "    res = opU( res, vec2( sdConeSection( pos-vec3( 0.0,0.35,-2.0), 0.15, 0.2, 0.1 ), 13.67 ) );\n"
        "    res = opU( res, vec2( sdEllipsoid( pos-vec3( 1.0,0.35,-2.0), vec3(0.15, 0.2, 0.05) ), 43.17 ) );\n"
        "\n"
        "    return res;\n"
        "}\n"
        "\n"
        "vec2 castRay( in vec3 ro, in vec3 rd )\n"
        "{\n"
        "    float tmin = 1.0;\n"
        "    float tmax = 20.0;\n"
        "\n"
        "#if 1\n"
        "    // bounding volume\n"
        "    float tp1 = (0.0-ro.y)/rd.y; if( tp1>0.0 ) tmax = min( tmax, tp1 );\n"
        "    float tp2 = (1.6-ro.y)/rd.y; if( tp2>0.0 ) { if( ro.y>1.6 ) tmin = max( tmin, tp2 );\n"
        "                                                 else           tmax = min( tmax, tp2 ); }\n"
        "#endif\n"
        "\n"
        "    float t = tmin;\n"
        "    float m = -1.0;\n"
        "    for( int i=0; i<64; i++ )\n"
        "    {\n"
        "        float precis = 0.0005*t;\n"
        "        vec2 res = map( ro+rd*t );\n"
        "        if( res.x<precis || t>tmax ) break;\n"
        "        t += res.x;\n"
        "        m = res.y;\n"
        "    }\n"
        "\n"
        "    if( t>tmax ) m=-1.0;\n"
        "    return vec2( t, m );\n"
        "}\n"
        "\n"
        "\n"
        "float calcSoftshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax )\n"
        "{\n"
        "    float res = 1.0;\n"
        "    float t = mint;\n"
        "    for( int i=0; i<16; i++ )\n"
        "    {\n"
        "        float h = map( ro + rd*t ).x;\n"
        "        res = min( res, 8.0*h/t );\n"
        "        t += clamp( h, 0.02, 0.10 );\n"
        "        if( h<0.001 || t>tmax ) break;\n"
        "    }\n"
        "    return clamp( res, 0.0, 1.0 );\n"
        "}\n"
        "\n"
        "vec3 calcNormal( in vec3 pos )\n"
        "{\n"
        "    vec2 e = vec2(1.0,-1.0)*0.5773*0.0005;\n"
        "    return normalize( e.xyy*map( pos + e.xyy ).x +\n"
        "                      e.yyx*map( pos + e.yyx ).x +\n"
        "                      e.yxy*map( pos + e.yxy ).x +\n"
        "                      e.xxx*map( pos + e.xxx ).x );\n"
        "    /*\n"
        "    vec3 eps = vec3( 0.0005, 0.0, 0.0 );\n"
        "    vec3 nor = vec3(\n"
        "        map(pos+eps.xyy).x - map(pos-eps.xyy).x,\n"
        "        map(pos+eps.yxy).x - map(pos-eps.yxy).x,\n"
        "        map(pos+eps.yyx).x - map(pos-eps.yyx).x );\n"
        "    return normalize(nor);\n"
        "    */\n"
        "}\n"
        "\n"
        "float calcAO( in vec3 pos, in vec3 nor )\n"
        "{\n"
        "    float occ = 0.0;\n"
        "    float sca = 1.0;\n"
        "    for( int i=0; i<5; i++ )\n"
        "    {\n"
        "        float hr = 0.01 + 0.12*float(i)/4.0;\n"
        "        vec3 aopos =  nor * hr + pos;\n"
        "        float dd = map( aopos ).x;\n"
        "        occ += -(dd-hr)*sca;\n"
        "        sca *= 0.95;\n"
        "    }\n"
        "    return clamp( 1.0 - 3.0*occ, 0.0, 1.0 );\n"
        "}\n"
        "\n"
        "// http://iquilezles.org/www/articles/checkerfiltering/checkerfiltering.htm\n"
        "float checkersGradBox( in vec2 p )\n"
        "{\n"
        "    // filter kernel\n"
        "    vec2 w = fwidth(p) + 0.001;\n"
        "    // analytical integral (box filter)\n"
        "    vec2 i = 2.0*(abs(fract((p-0.5*w)*0.5)-0.5)-abs(fract((p+0.5*w)*0.5)-0.5))/w;\n"
        "    // xor pattern\n"
        "    return 0.5 - 0.5*i.x*i.y;\n"
        "}\n"
        "\n"
        "vec3 render( in vec3 ro, in vec3 rd )\n"
        "{\n"
        "    vec3 col = vec3(0.7, 0.9, 1.0) +rd.y*0.8;\n"
        "    vec2 res = castRay(ro,rd);\n"
        "    float t = res.x;\n"
        "    float m = res.y;\n"
        "    if( m>-0.5 )\n"
        "    {\n"
        "        vec3 pos = ro + t*rd;\n"
        "        vec3 nor = calcNormal( pos );\n"
        "        vec3 ref = reflect( rd, nor );\n"
        "\n"
        "        // material\n"
        "        col = 0.45 + 0.35*sin( vec3(0.05,0.08,0.10)*(m-1.0) );\n"
        "        if( m<1.5 )\n"
        "        {\n"
        "\n"
        "            float f = checkersGradBox( 5.0*pos.xz );\n"
        "            col = 0.3 + f*vec3(0.1);\n"
        "        }\n"
        "\n"
        "        // lighitng\n"
        "        float occ = calcAO( pos, nor );\n"
        "        vec3  lig = normalize( vec3(-0.4, 0.7, -0.6) );\n"
        "        vec3  hal = normalize( lig-rd );\n"
        "        float amb = clamp( 0.5+0.5*nor.y, 0.0, 1.0 );\n"
        "        float dif = clamp( dot( nor, lig ), 0.0, 1.0 );\n"
        "        float bac = clamp( dot( nor, normalize(vec3(-lig.x,0.0,-lig.z))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0);\n"
        "        float dom = smoothstep( -0.1, 0.1, ref.y );\n"
        "        float fre = pow( clamp(1.0+dot(nor,rd),0.0,1.0), 2.0 );\n"
        "\n"
        "        dif *= calcSoftshadow( pos, lig, 0.02, 2.5 );\n"
        "        dom *= calcSoftshadow( pos, ref, 0.02, 2.5 );\n"
        "\n"
        "        float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0)*\n"
        "                    dif *\n"
        "                    (0.04 + 0.96*pow( clamp(1.0+dot(hal,rd),0.0,1.0), 5.0 ));\n"
        "\n"
        "        vec3 lin = vec3(0.0);\n"
        "        lin += 1.30*dif*vec3(1.00,0.80,0.55);\n"
        "        lin += 0.40*amb*vec3(0.40,0.60,1.00)*occ;\n"
        "        lin += 0.50*dom*vec3(0.40,0.60,1.00)*occ;\n"
        "        lin += 0.50*bac*vec3(0.25,0.25,0.25)*occ;\n"
        "        lin += 0.25*fre*vec3(1.00,1.00,1.00)*occ;\n"
        "        col = col*lin;\n"
        "        col += 10.00*spe*vec3(1.00,0.90,0.70);\n"
        "\n"
        "        col = mix( col, vec3(0.8,0.9,1.0), 1.0-exp( -0.0002*t*t*t ) );\n"
        "    }\n"
        "\n"
        "    return vec3( clamp(col,0.0,1.0) );\n"
        "}\n"
        "\n"
        "mat3 setCamera( in vec3 ro, in vec3 ta, float cr )\n"
        "{\n"
        "    vec3 cw = normalize(ta-ro);\n"
        "    vec3 cp = vec3(sin(cr), cos(cr),0.0);\n"
        "    vec3 cu = normalize( cross(cw,cp) );\n"
        "    vec3 cv = normalize( cross(cu,cw) );\n"
        "    return mat3( cu, cv, cw );\n"
        "}\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{\n"
        "    vec2 mo = iMouse.xy/iResolution.xy;\n"
        "    float time = 15.0 + iTime;\n"
        "\n"
        "\n"
        "    vec3 tot = vec3(0.0);\n"
        "#if AA>1\n"
        "    for( int m=0; m<AA; m++ )\n"
        "    for( int n=0; n<AA; n++ )\n"
        "    {\n"
        "        // pixel coordinates\n"
        "        vec2 o = vec2(float(m),float(n)) / float(AA) - 0.5;\n"
        "        vec2 p = (-iResolution.xy + 2.0*(fragCoord+o))/iResolution.y;\n"
        "#else\n"
        "        vec2 p = (-iResolution.xy + 2.0*fragCoord)/iResolution.y;\n"
        "#endif\n"
        "\n"
        "        // camera    \n"
        "        vec3 ro = vec3( -0.5+3.5*cos(0.1*time + 6.0*mo.x), 1.0 + 2.0*mo.y, 0.5 + 4.0*sin(0.1*time + 6.0*mo.x) );\n"
        "        vec3 ta = vec3( -0.5, -0.4, 0.5 );\n"
        "        // camera-to-world transformation\n"
        "        mat3 ca = setCamera( ro, ta, 0.0 );\n"
        "        // ray direction\n"
        "        vec3 rd = ca * normalize( vec3(p.xy,2.0) );\n"
        "\n"
        "        // render    \n"
        "        vec3 col = render( ro, rd );\n"
        "\n"
        "        // gamma\n"
        "        col = pow( col, vec3(0.4545) );\n"
        "\n"
        "        tot += col;\n"
        "#if AA>1\n"
        "    }\n"
        "    tot /= float(AA*AA);\n"
        "#endif\n"
        "\n"
        "\n"
        "    fragColor = vec4( tot, 1.0 );\n"
        "}\n"
        "\n"
     );

     n->create_file("ShaderToy/SeaScape.glsl",
        "// https://www.shadertoy.com/view/Ms2SD1\n"
        "/*\n"
        " * \"Seascape\" by Alexander Alekseev aka TDM - 2014\n"
        " * License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.\n"
        " * Contact: tdmaav@gmail.com\n"
        " */\n"
        "\n"
        "const int NUM_STEPS = 8;\n"
        "const float PI         = 3.141592;\n"
        "const float EPSILON    = 1e-3;\n"
        "#define EPSILON_NRM (0.1 / iResolution.x)\n"
        "\n"
        "// sea\n"
        "const int ITER_GEOMETRY = 3;\n"
        "const int ITER_FRAGMENT = 5;\n"
        "const float SEA_HEIGHT = 0.6;\n"
        "const float SEA_CHOPPY = 4.0;\n"
        "const float SEA_SPEED = 0.8;\n"
        "const float SEA_FREQ = 0.16;\n"
        "const vec3 SEA_BASE = vec3(0.1,0.19,0.22);\n"
        "const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6);\n"
        "#define SEA_TIME (1.0 + iTime * SEA_SPEED)\n"
        "const mat2 octave_m = mat2(1.6,1.2,-1.2,1.6);\n"
        "\n"
        "// math\n"
        "mat3 fromEuler(vec3 ang) {\n"
        "    vec2 a1 = vec2(sin(ang.x),cos(ang.x));\n"
        "    vec2 a2 = vec2(sin(ang.y),cos(ang.y));\n"
        "    vec2 a3 = vec2(sin(ang.z),cos(ang.z));\n"
        "    mat3 m;\n"
        "    m[0] = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x);\n"
        "    m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);\n"
        "    m[2] = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y);\n"
        "    return m;\n"
        "}\n"
        "float hash( vec2 p ) {\n"
        "    float h = dot(p,vec2(127.1,311.7));    \n"
        "    return fract(sin(h)*43758.5453123);\n"
        "}\n"
        "float noise( in vec2 p ) {\n"
        "    vec2 i = floor( p );\n"
        "    vec2 f = fract( p );    \n"
        "    vec2 u = f*f*(3.0-2.0*f);\n"
        "    return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ),\n"
        "                     hash( i + vec2(1.0,0.0) ), u.x),\n"
        "                mix( hash( i + vec2(0.0,1.0) ),\n"
        "                     hash( i + vec2(1.0,1.0) ), u.x), u.y);\n"
        "}\n"
        "\n"
        "// lighting\n"
        "float diffuse(vec3 n,vec3 l,float p) {\n"
        "    return pow(dot(n,l) * 0.4 + 0.6,p);\n"
        "}\n"
        "float specular(vec3 n,vec3 l,vec3 e,float s) {\n"
        "    float nrm = (s + 8.0) / (PI * 8.0);\n"
        "    return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;\n"
        "}\n"
        "\n"
        "// sky\n"
        "vec3 getSkyColor(vec3 e) {\n"
        "    e.y = max(e.y,0.0);\n"
        "    return vec3(pow(1.0-e.y,2.0), 1.0-e.y, 0.6+(1.0-e.y)*0.4);\n"
        "}\n"
        "\n"
        "// sea\n"
        "float sea_octave(vec2 uv, float choppy) {\n"
        "    uv += noise(uv);\n"
        "    vec2 wv = 1.0-abs(sin(uv));\n"
        "    vec2 swv = abs(cos(uv));\n"
        "    wv = mix(wv,swv,wv);\n"
        "    return pow(1.0-pow(wv.x * wv.y,0.65),choppy);\n"
        "}\n"
        "\n"
        "float map(vec3 p) {\n"
        "    float freq = SEA_FREQ;\n"
        "    float amp = SEA_HEIGHT;\n"
        "    float choppy = SEA_CHOPPY;\n"
        "    vec2 uv = p.xz; uv.x *= 0.75;\n"
        "\n"
        "    float d, h = 0.0;\n"
        "    for(int i = 0; i < ITER_GEOMETRY; i++) {\n"
        "        d = sea_octave((uv+SEA_TIME)*freq,choppy);\n"
        "        d += sea_octave((uv-SEA_TIME)*freq,choppy);\n"
        "        h += d * amp;\n"
        "        uv *= octave_m; freq *= 1.9; amp *= 0.22;\n"
        "        choppy = mix(choppy,1.0,0.2);\n"
        "    }\n"
        "    return p.y - h;\n"
        "}\n"
        "\n"
        "float map_detailed(vec3 p) {\n"
        "    float freq = SEA_FREQ;\n"
        "    float amp = SEA_HEIGHT;\n"
        "    float choppy = SEA_CHOPPY;\n"
        "    vec2 uv = p.xz; uv.x *= 0.75;\n"
        "\n"
        "    float d, h = 0.0;\n"
        "    for(int i = 0; i < ITER_FRAGMENT; i++) {\n"
        "        d = sea_octave((uv+SEA_TIME)*freq,choppy);\n"
        "        d += sea_octave((uv-SEA_TIME)*freq,choppy);\n"
        "        h += d * amp;\n"
        "        uv *= octave_m; freq *= 1.9; amp *= 0.22;\n"
        "        choppy = mix(choppy,1.0,0.2);\n"
        "    }\n"
        "    return p.y - h;\n"
        "}\n"
        "\n"
        "vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {\n"
        "    float fresnel = clamp(1.0 - dot(n,-eye), 0.0, 1.0);\n"
        "    fresnel = pow(fresnel,3.0) * 0.65;\n"
        "\n"
        "    vec3 reflected = getSkyColor(reflect(eye,n));\n"
        "    vec3 refracted = SEA_BASE + diffuse(n,l,80.0) * SEA_WATER_COLOR * 0.12;\n"
        "\n"
        "    vec3 color = mix(refracted,reflected,fresnel);\n"
        "\n"
        "    float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0);\n"
        "    color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;\n"
        "\n"
        "    color += vec3(specular(n,l,eye,60.0));\n"
        "\n"
        "    return color;\n"
        "}\n"
        "\n"
        "// tracing\n"
        "vec3 getNormal(vec3 p, float eps) {\n"
        "    vec3 n;\n"
        "    n.y = map_detailed(p);\n"
        "    n.x = map_detailed(vec3(p.x+eps,p.y,p.z)) - n.y;\n"
        "    n.z = map_detailed(vec3(p.x,p.y,p.z+eps)) - n.y;\n"
        "    n.y = eps;\n"
        "    return normalize(n);\n"
        "}\n"
        "\n"
        "float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {\n"
        "    float tm = 0.0;\n"
        "    float tx = 1000.0;\n"
        "    float hx = map(ori + dir * tx);\n"
        "    if(hx > 0.0) return tx;\n"
        "    float hm = map(ori + dir * tm);\n"
        "    float tmid = 0.0;\n"
        "    for(int i = 0; i < NUM_STEPS; i++) {\n"
        "        tmid = mix(tm,tx, hm/(hm-hx));\n"
        "        p = ori + dir * tmid;\n"
        "        float hmid = map(p);\n"
        "        if(hmid < 0.0) {\n"
        "            tx = tmid;\n"
        "            hx = hmid;\n"
        "        } else {\n"
        "            tm = tmid;\n"
        "            hm = hmid;\n"
        "        }\n"
        "    }\n"
        "    return tmid;\n"
        "}\n"
        "\n"
        "// main\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord ) {\n"
        "    vec2 uv = fragCoord.xy / iResolution.xy;\n"
        "    uv = uv * 2.0 - 1.0;\n"
        "    uv.x *= iResolution.x / iResolution.y;\n"
        "    float time = iTime * 0.3 + iMouse.x*0.01;\n"
        "\n"
        "    // ray\n"
        "    vec3 ang = vec3(sin(time*3.0)*0.1,sin(time)*0.2+0.3,time);\n"
        "    vec3 ori = vec3(0.0,3.5,time*5.0);\n"
        "    vec3 dir = normalize(vec3(uv.xy,-2.0)); dir.z += length(uv) * 0.15;\n"
        "    dir = normalize(dir) * fromEuler(ang);\n"
        "\n"
        "    // tracing\n"
        "    vec3 p;\n"
        "    heightMapTracing(ori,dir,p);\n"
        "    vec3 dist = p - ori;\n"
        "    vec3 n = getNormal(p, dot(dist,dist) * EPSILON_NRM);\n"
        "    vec3 light = normalize(vec3(0.0,1.0,0.8));\n"
        "\n"
        "    // color\n"
        "    vec3 color = mix(\n"
        "        getSkyColor(dir),\n"
        "        getSeaColor(p,n,light,dir,dist),\n"
        "        pow(smoothstep(0.0,-0.05,dir.y),0.3));\n"
        "\n"
        "    // post\n"
        "    fragColor = vec4(pow(color,vec3(0.75)), 1.0);\n"
        "}\n"
     );

     n->create_file("ShaderToy/RoundedVoronoiEdges.glsl",
        "// https://www.shadertoy.com/view/ll3GRM\n"
        "\n"
        "/*\n"
        "    Rounded Voronoi Borders\n"
        "    -----------------------\n"
        "\n"
        "    Fabrice came up with an interesting formula to produce more evenly distributed Voronoi values.\n"
        "    I'm sure there are more interesting ways to use it, but I like the fact that it facilitates\n"
        "    the creation of more rounded looking borders. I'm sure there are more sophisticated ways to\n"
        "    produce more accurate borders, but Fabrice's version is simple and elegant.\n"
        "\n"
        "    The process is explained below. The link to the original is below also.\n"
        "\n"
        "    I didn't want to cloud the example with too much window dressing, so just for fun, I tried\n"
        "    to pretty it up by using as little code as possible.\n"
        "\n"
        "    // 2D version\n"
        "    2D trabeculum - FabriceNeyret2\n"
        "    https://www.shadertoy.com/view/4dKSDV\n"
        "\n"
        "    // 3D version\n"
        "    hypertexture - trabeculum - FabriceNeyret2\n"
        "    https://www.shadertoy.com/view/ltj3Dc\n"
        "\n"
        "    // Straight borders - accurate geometric solution.\n"
        "    Voronoi - distances - iq\n"
        "    https://www.shadertoy.com/view/ldl3W8\n"
        "\n"
        "*/\n"
        "\n"
        "// vec2 to vec2 hash.\n"
        "vec2 hash22(vec2 p) {\n"
        "\n"
        "    // Faster, but doesn't disperse things quite as nicely as other combinations. :)\n"
        "    float n = sin(dot(p, vec2(41, 289)));\n"
        "    //return fract(vec2(262144, 32768)*n)*.75 + .25;\n"
        "\n"
        "    // Animated.\n"
        "    p = fract(vec2(262144, 32768)*n);\n"
        "    return sin( p*6.2831853 + iTime )*.35 + .65;\n"
        "\n"
        "}\n"
        "\n"
        "// IQ's polynomial-based smooth minimum function.\n"
        "float smin( float a, float b, float k ){\n"
        "\n"
        "    float h = clamp(.5 + .5*(b - a)/k, 0., 1.);\n"
        "    return mix(b, a, h) - k*h*(1. - h);\n"
        "}\n"
        "\n"
        "// 2D 3rd-order Voronoi: This is just a rehash of Fabrice Neyret's version, which is in\n"
        "// turn based on IQ's original. I've simplified it slightly, and tidied up the \"if-statements,\"\n"
        "// but the clever bit at the end came from Fabrice.\n"
        "//\n"
        "// Using a bit of science and art, Fabrice came up with the following formula to produce a more\n"
        "// rounded, evenly distributed, cellular value:\n"
        "\n"
        "// d1, d2, d3 - First, second and third closest points (nodes).\n"
        "// val = 1./(1./(d2 - d1) + 1./(d3 - d1));\n"
        "//\n"
        "float Voronoi(in vec2 p){\n"
        "\n"
        "    vec2 g = floor(p), o; p -= g;\n"
        "    \n"
        "    vec3 d = vec3(1); // 1.4, etc.\n"
        "\n"
        "    float r = 0.;\n"
        "\n"
        "    for(int y = -1; y <= 1; y++){\n"
        "        for(int x = -1; x <= 1; x++){\n"
        "\n"
        "            o = vec2(x, y);\n"
        "            o += hash22(g + o) - p;\n"
        "\n"
        "            r = dot(o, o);\n"
        "\n"
        "            // 1st, 2nd and 3rd nearest squared distances.\n"
        "            d.z = max(d.x, max(d.y, min(d.z, r))); // 3rd.\n"
        "            d.y = max(d.x, min(d.y, r)); // 2nd.\n"
        "            d.x = min(d.x, r); // Closest.\n"
        "\n"
        "        }\n"
        "    }\n"
        "\n"
        "    d = sqrt(d); // Squared distance to distance.\n"
        "\n"
        "    // Fabrice's formula.\n"
        "    return min(2./(1./max(d.y - d.x, .001) + 1./max(d.z - d.x, .001)), 1.);\n"
        "    // Dr2's variation - See \"Voronoi Of The Week\": https://www.shadertoy.com/view/lsjBz1\n"
        "    //return min(smin(d.z, d.y, .2) - d.x, 1.);\n"
        "\n"
        "}\n"
        "\n"
        "vec2 hMap(vec2 uv){\n"
        "\n"
        "    // Plain Voronoi value. We're saving it and returning it to use when coloring.\n"
        "    // It's a little less tidy, but saves the need for recalculation later.\n"
        "    float h = Voronoi(uv*6.);\n"
        "\n"
        "    // Adding some bordering and returning the result as the height map value.\n"
        "    float c = smoothstep(0., fwidth(h)*2., h - .09)*h;\n"
        "    c += (1.-smoothstep(0., fwidth(h)*3., h - .22))*c*.5;\n"
        "\n"
        "    // Returning the rounded border Voronoi, and the straight Voronoi values.\n"
        "    return vec2(c, h);\n"
        "\n"
        "}\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord ){\n"
        "\n"
        "    // Moving screen coordinates.\n"
        "    vec2 uv = fragCoord/iResolution.y + vec2(-.2, .05)*iTime;\n"
        "\n"
        "    // Obtain the height map (rounded Voronoi border) value, then another nearby.\n"
        "    vec2 c = hMap(uv);\n"
        "    vec2 c2 = hMap(uv + .004);\n"
        "\n"
        "    // Take a factored difference of the values above to obtain a very, very basic gradient value.\n"
        "    // Ie. - a measurement of the bumpiness, or bump value.\n"
        "    float b = max(c2.x - c.x, 0.)*16.;\n"
        "\n"
        "    // Use the height map value to produce some color. It's all made up on the spot, so don't pay it\n"
        "    // too much attention.\n"
        "    //\n"
        "    vec3 col = vec3(1, .05, .25)*c.x; // Red base.\n"
        "    float sv = Voronoi(uv*16. + c.y)*.66 + (1.-Voronoi(uv*48. + c.y*2.))*.34; // Finer overlay pattern.\n"
        "    col = col*.85 + vec3(1, .7, .5)*sv*sqrt(sv)*.3; // Mix in a little of the overlay.\n"
        "    col += (1. - col)*(1.-smoothstep(0., fwidth(c.y)*3., c.y - .22))*c.x; // Highlighting the border.\n"
        "    col *= col; // Ramping up the contrast, simply because the deeper color seems to look better.\n"
        "\n"
        "    // Taking a pattern sample a little off to the right, ramping it up, then combining a bit of it\n"
        "    // with the color above. The result is the flecks of yellowy orange that you see. There's no physics\n"
        "    // behind it, but the offset tricks your eyes into believing something's happening. :)\n"
        "    sv = col.x*Voronoi(uv*6. + .5);\n"
        "    col += vec3(.7, 1, .3)*pow(sv, 4.)*8.;\n"
        "\n"
        "    // Apply the bump - or a powered variation of it - to the color for a bit of highlighting.\n"
        "    col += vec3(.5, .7, 1)*(b*b*.5 + b*b*b*b*.5);\n"
        "    \n"
        "\n"
        "    // Basic gamma correction\n"
        "    fragColor = vec4(sqrt(clamp(col, 0., 1.)), 1);\n"
        "\n"
        "}\n"
     );

     n->create_file("ShaderToy/RounderVoronoi.glsl",
        "// https://www.shadertoy.com/view/ld3yRn\n"
        "\n"
        "// ST_MODE = \"ShaderToy mode\". Do not undefine. It is here for PolyCube compatibility.\n"
        "#define ST_MODE\n"
        "\n"
        "// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.\n"
        "// by Tomasz Dobrowolski' 2018\n"
        "\n"
        "// Use mouse (X/Y) to control two smoothness parameters.\n"
        "\n"
        "// PolyCube edition:\n"
        "// http://polycu.be/edit/?h=X3sd5D\n"
        "\n"
        "// This is continuation of a quest to formulate\n"
        "// smooth and continuous across whole domain\n"
        "// distance function to edges of random Voronoi cells.\n"
        "\n"
        "// I just had a very simple idea today (2018-02-03)\n"
        "// how to make this function continuous and smooth\n"
        "// at non-zero distance at the same time, and it works!\n"
        "// See \"voronoi_rounder\" function for details.\n"
        "\n"
        "// My previous shader with analysis of discontinuities\n"
        "// in Shane's attempt.\n"
        "// https://www.shadertoy.com/view/MdSfzD\n"
        "\n"
        "// Shane's original shader.\n"
        "// https://www.shadertoy.com/view/lsSfz1\n"
        "\n"
        "// My previous attempt to optimize distance to edges.\n"
        "// https://www.shadertoy.com/view/llG3zy\n"
        "\n"
        "// Smooth cell noise function by TinyTexel.\n"
        "// https://www.shadertoy.com/view/MdByzD\n"
        "\n"
        "// Play with some options (1 = enable, 0 = disable).\n"
        "#define DOMAIN_DEFORM 0\n"
        "#define ANIMATE 1\n"
        "\n"
        "// How far cells can go off center during animation (must be <= .5)\n"
        "#define ANIMATE_D .45\n"
        "\n"
        "// Points cannot be closer than sqrt(EPSILON)\n"
        "#define EPSILON .00001\n"
        "\n"
        "#ifdef ST_MODE\n"
        "#define template_time iTime\n"
        "#endif\n"
        "\n"
        "vec2 hash2(vec2 p)\n"
        "{\n"
        "    #if 1\n"
        "       // Dave Hoskin's hash as in https://www.shadertoy.com/view/4djSRW\n"
        "       vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));\n"
        "       p3 += dot(p3, p3.yzx+19.19);\n"
        "       vec2 o = fract(vec2((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y));\n"
        "    #else\n"
        "       // Texture-based\n"
        "       vec2 o = texture( iChannel0, (p+0.5)/256.0, -100.0 ).xy;\n"
        "    #endif\n"
        "    #if ANIMATE\n"
        "       o = 0.5 + ANIMATE_D*sin( template_time*.5 + o*6.2831853 );\n"
        "    #endif\n"
        "   return o;\n"
        "}\n"
        "\n"
        "// Commutative smin function taken\n"
        "// from Alex Evans aka Statix talk\n"
        "// http://media.lolrus.mediamolecule.com/AlexEvans_SIGGRAPH-2015.pdf\n"
        "// credited to Dave Smith @media molecule\n"
        "float smin(float a, float b, float r)\n"
        "{\n"
        "#if 0\n"
        "   // Preventing division by zero.\n"
        "   float f = max(0.,1.-abs(b-a)/max(1e-32,r));\n"
        "#else\n"
        "   float f = max(0.,1.-abs(b-a)/r);\n"
        "#endif\n"
        "   return min(a,b) - r*.25*f*f;\n"
        "}\n"
        "\n"
        "// Smooth abs.\n"
        "// This one is equivalent to -smin(x, -x, r) - r*.25\n"
        "float sabs(float x, float r)\n"
        "{\n"
        "   float f = max(0.,1.-abs(x + x)/r);\n"
        "   return abs(x) + r*.25*(f*f - 1.);\n"
        "}\n"
        "\n"
        "// This is bullet-proof version of finding closest point\n"
        "// in 4x4 area around query point \"q\".\n"
        "// In fact 12 cells (4x4 without corners) would be enough,\n"
        "// but it's less elegant to implement.\n"
        "// We pass n=|q|, f=q-n, as an optimization.\n"
        "float closest( in vec2 n, in vec2 f, out vec2 mr, out vec2 mg )\n"
        "{\n"
        "    // take half-cell position\n"
        "    vec2 h = step(.5,f) - 2.;\n"
        "    vec2 n2 = n + h;\n"
        "    vec2 f2 = f - h;\n"
        "\n"
        "    float md = 8.0;\n"
        "\n"
        "    //----------------------------------\n"
        "    // first pass: regular voronoi\n"
        "    //----------------------------------\n"
        "    for( int j=0; j<=3; j++ )\n"
        "    for( int i=0; i<=3; i++ )\n"
        "    {\n"
        "        vec2 g = vec2(float(i),float(j));\n"
        "        vec2 o = hash2( n2 + g );\n"
        "        vec2 r = g + o - f2;\n"
        "        float d = dot(r,r);\n"
        "\n"
        "        if( d<md )\n"
        "        {\n"
        "            md = d;\n"
        "            mr = r;\n"
        "            mg = g;\n"
        "        }\n"
        "    }\n"
        "    mg += h; // return cell position relative to \"n\"\n"
        "\n"
        "    return md;\n"
        "}\n"
        "\n"
        "// A continuous and smooth at non-zero distance\n"
        "// distance function to Voronoi edges.\n"
        "// by Tomasz Dobrowolski' 2018\n"
        "// Extending it to 3d (and more) is trivial.\n"
        "// x = input coordinate\n"
        "// s = smooth min cutoff parameter (smoothness inside cell)\n"
        "// e = smooth abs cutoff parameter (smoothness between cells)\n"
        "vec3 voronoi_rounder( in vec2 x, in float s, in float e )\n"
        "{\n"
        "#if DOMAIN_DEFORM\n"
        "    x += sin(x.yx*10.)*.07;\n"
        "#endif\n"
        "\n"
        "    vec2 n = floor(x);\n"
        "    vec2 f = fract(x);\n"
        "\n"
        "    vec2 mr, mg;\n"
        "    float md = closest(n,f,mr,mg);\n"
        "\n"
        "    //----------------------------------\n"
        "    // second pass: distance to edges\n"
        "    //----------------------------------\n"
        "    md = 8.0;\n"
        "    for( int j=-2; j<=2; j++ )\n"
        "    for( int i=-2; i<=2; i++ )\n"
        "    {\n"
        "        vec2 g = mg + vec2(float(i),float(j));\n"
        "        vec2 o = hash2( n + g );\n"
        "        vec2 r = g + o - f;\n"
        "\n"
        "        if( dot(mr-r,mr-r)>EPSILON ) // skip the same cell\n"
        "        {\n"
        "            float d = dot( 0.5*(mr+r), normalize(r-mr) );\n"
        "\n"
        "            // The whole trick to get continuous function\n"
        "            // across whole domain and smooth at non-zero distance\n"
        "            // is to use smooth minimum (as usual)\n"
        "            // and multiple smoothness factor by distance,\n"
        "            // so it becomes minimum at zero distance.\n"
        "            // Simple as that!\n"
        "            // If you keep smoothness factor constant (i.e. multiple by \"s\" only),\n"
        "            // the distance function becomes discontinuous\n"
        "            // (see https://www.shadertoy.com/view/MdSfzD).\n"
        "            md = smin(d, md, s*d);\n"
        "        }\n"
        "    }\n"
        "\n"
        "    // Totally empirical compensation for\n"
        "    // smoothing scaling side-effect.\n"
        "    md *= .5 + s;\n"
        "\n"
        "    // At the end do some smooth abs\n"
        "    // on the distance value.\n"
        "    // This is really optional, since distance function\n"
        "    // is already continuous, but we can get extra\n"
        "    // smoothness from it.\n"
        "    md = sabs(md, e);\n"
        "\n"
        "    return vec3( md, mr );\n"
        "}\n"
        "\n"
        "#ifdef ST_MODE\n"
        "vec3 plot( vec2 p, float ss )\n"
        "{\n"
        "#else\n"
        "vec3 plot( vec2 p )\n"
        "{\n"
        "    float ss = template_tr.z;\n"
        "#endif\n"
        "#ifdef ST_MODE\n"
        "    float s = clamp(iMouse.x/iResolution.x,.0,1.)*.95+.05;\n"
        "    float e = max(.01,iMouse.y/iResolution.y)*.5;\n"
        "    if (length(iMouse.xy) < .5) {\n"
        "        s = .5;\n"
        "        e = .005;\n"
        "    }\n"
        "#else\n"
        "    const float s = .5;\n"
        "    const float e = .01;\n"
        "#endif\n"
        "    vec3 c = voronoi_rounder(p, s, e);\n"
        "\n"
        "    const float pd = 40.;\n"
        "#if 0\n"
        "    vec3 norm = normalize(vec3(dFdx(c.x),dFdy(c.x),ss*1.5));\n"
        "    float fw1 = fwidth(c.x);\n"
        "#else\n"
        "    const vec2 eps = vec2(.001,0);\n"
        "    float fdx = (voronoi_rounder(p + eps.xy, s, e).x - c.x)/eps.x;\n"
        "    float fdy = (voronoi_rounder(p + eps.yx, s, e).x - c.x)/eps.x;\n"
        "    vec3 norm = normalize(vec3(fdx, fdy, 1.5));\n"
        "    float fw1 = (abs(fdx) + abs(fdy))*ss;\n"
        "#endif\n"
        "    float fw2 = fw1*(pd/3.141592653589793*2.7);\n"
        "\n"
        "    const float f0 = sin(.7/pd);\n"
        "    float f = sin(c.x*pd-.7);\n"
        "    float od = abs(f);\n"
        "    vec3 ldir = normalize(vec3(-.2,-.3,.6));\n"
        "    float dd = dot(norm,ldir);\n"
        "    float rd = pow(max(0.,reflect(-ldir,norm).z),16.);\n"
        "    float ld = dd*dd*.7+.35;\n"
        "    float c0 = c.x*.7-step(0.,f)*.05+.6;\n"
        "    float c1 = c.x*.7+.33;\n"
        "    vec3 col = mix(vec3(c0*ld+rd*.23), vec3(c1*ld), smoothstep(fw2,0.,od)*.7);\n"
        "    col = mix(col, vec3(.1,.15,.1), smoothstep(f0+fw1,f0,c.x)*.5);\n"
        "    col = sqrt(col)*1.5-.53; // some final grading\n"
        "    return col;\n"
        "}\n"
        "\n"
        "#ifdef ST_MODE\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{\n"
        "    float sc = step(0.5, iResolution.y)*2. + 3.; // scale differently for fullscreen\n"
        "    float ss =  sc / iResolution.y; // size of 1 pixel\n"
        "    vec2 uv = (fragCoord.xy - iResolution.xy*.5) * ss;\n"
        "    fragColor = vec4(plot(uv, ss), 1.);\n"
        "}\n"
        "#endif\n"
     );

     n->create_file("ShaderToy/SiggraphLogo.glsl",
        "// https://www.shadertoy.com/view/4sl3zn\n"
        "\n"
        "// Created by inigo quilez - iq/2013\n"
        "// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.\n"
        "\n"
        "vec2 disp( in vec3 p )\n"
        "{\n"
        "    return vec2( pow( 0.5 + 0.5*cos( 1.0*iTime ), 2.0 ),\n"
        "                 pow( 0.5 + 0.5*cos( 25.0*p.x  + 1.5*iTime)*\n"
        "                                sin( 25.0*p.y  + 2.0*iTime )*\n"
        "                                sin( 25.0*p.z  + 1.0*iTime ), 3.0) );\n"
        "}\n"
        "\n"
        "float obj( in vec3 p )\n"
        "{\n"
        "    vec3 ax = vec3(-2.0,2.0,1.0)/3.0;\n"
        "    vec3 ce = vec3(0.0,-0.2,-0.2);\n"
        "\n"
        "    float d1 = dot(p,ax) - 0.1;\n"
        "    float d2 = length(p) - 1.0;\n"
        "    float d3 = length( p-ce - ax*dot(p-ce,ax)) - 1.0;\n"
        "\n"
        "    return max( max( d1, d2 ), -d3 );\n"
        "}\n"
        "\n"
        "vec2 map( in vec3 p )\n"
        "{\n"
        "    float d1 = obj( p );\n"
        "    float d2 = obj( p*vec3(-1.0,-1.0,1.0) );\n"
        "\n"
        "    vec2        res = vec2( d1, 0.0 );\n"
        "    if( d2<d1 ) res = vec2( d2, 1.0 );\n"
        "\n"
        "    vec2 di = disp( p );\n"
        "    res.x -= 0.04*di.x*di.y;\n"
        "\n"
        "    return res;\n"
        "}\n"
        "\n"
        "vec2 intersect( in vec3 ro, in vec3 rd )\n"
        "{\n"
        "    float t = 0.0;\n"
        "    vec2 h = vec2( -1.0 );\n"
        "    for( int i=0; i<32; i++ )\n"
        "    {\n"
        "        h = map(ro+rd*t);\n"
        "        t += h.x;\n"
        "    }\n"
        "    \n"
        "    if( h.x<0.1 ) return vec2(t,h.y);\n"
        "\n"
        "    return vec2(-1.0);\n"
        "}\n"
        "\n"
        "vec3 calcNormal( in vec3 pos )\n"
        "{\n"
        "    vec3 eps = vec3(0.02,0.0,0.0);\n"
        "\n"
        "    return normalize( vec3(\n"
        "           map(pos+eps.xyy).x - map(pos-eps.xyy).x,\n"
        "           map(pos+eps.yxy).x - map(pos-eps.yxy).x,\n"
        "           map(pos+eps.yyx).x - map(pos-eps.yyx).x ) );\n"
        "}\n"
        "\n"
        "float softshadow( in vec3 ro, in vec3 rd, float mint, float k )\n"
        "{\n"
        "    float res = 1.0;\n"
        "    float t = mint;\n"
        "    for( int i=0; i<16; i++ )\n"
        "    {\n"
        "        float h = map(ro + rd*t).x;\n"
        "        res = min( res, k*h/t );\n"
        "        t += h;\n"
        "    }\n"
        "    return clamp(res,0.0,1.0);\n"
        "}\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{\n"
        "    vec2 p = -1.0 + 2.0 * fragCoord.xy / iResolution.xy;\n"
        "    p.x *= iResolution.x/iResolution.y;\n"
        "\n"
        "    vec2 m = iMouse.xy/iResolution.xy;\n"
        "    if( iMouse.z<0.0 ) m = vec2(0.0);\n"
        "    \n"
        "    // camera\n"
        "    float an = -6.2*m.x + 0.2*sin(0.5*iTime) + 6.5;\n"
        "    vec3 ro = 1.5*normalize(vec3(sin(an),-6.0*m.y, cos(an)));\n"
        "\n"
        "    vec3 ww = normalize( vec3(0.0,0.0,0.0) - ro );\n"
        "    vec3 uu = normalize( cross(ww,vec3(0.0,1.0,0.0) ) );\n"
        "    vec3 vv = normalize( cross(uu,ww));\n"
        "    vec3 rd = normalize( p.x*uu + p.y*vv + 1.0*ww );\n"
        "\n"
        "    vec3 col = vec3(1.0);\n"
        "\n"
        "    // raymarch\n"
        "    vec2 tmat = intersect(ro,rd);\n"
        "    if( tmat.y>-0.5 )\n"
        "    {\n"
        "        // geometry\n"
        "        vec3 pos = ro + tmat.x*rd;\n"
        "        vec3 nor = calcNormal(pos);\n"
        "        vec3 ref = reflect(rd,nor);\n"
        "        vec3 lig = normalize(vec3(-0.6,0.5,0.2));\n"
        "        vec2 dis = disp( pos );\n"
        "\n"
        "        // lights\n"
        "        float con = 1.0;\n"
        "        float amb = 0.5 + 0.5*nor.y;\n"
        "        float dif = max(dot(nor,lig),0.0);\n"
        "        float bac = max(0.2 + 0.8*dot(nor,vec3(-lig.x,lig.y,-lig.z)),0.0);\n"
        "        float rim = pow(1.0+dot(nor,rd),8.0);\n"
        "        float spe = pow(clamp(dot(lig,ref),0.0,1.0),8.0);\n"
        "        float occ = mix( 1.0, 0.9 + 3.0*dis.y, dis.x );\n"
        "\n"
        "        // shadow\n"
        "        float sh = softshadow( pos, lig, 0.01, 8.0 );\n"
        "        dif *= sh;\n"
        "        spe *= sh;\n"
        "        rim *= sh;\n"
        "        \n"
        "        col  = 0.10*con*vec3(1.0)*occ;\n"
        "        col += 1.00*dif*vec3(1.0,0.8,0.6);\n"
        "        col += 0.40*bac*vec3(1.0)*occ;\n"
        "        col += 0.25*amb*vec3(0.6,0.8,1.0)*occ;\n"
        "\n"
        "        // material\n"
        "        col *= mix( vec3(0.7,0.1,0.1), vec3(0.0,0.2,1.0), tmat.y );\n"
        "        \n"
        "        // speculars\n"
        "        col += 0.50*spe*vec3(1.0);\n"
        "        col += 1.00*rim*vec3(1.0);\n"
        "            \n"
        "        // gamma\n"
        "        col = sqrt(col);\n"
        "    }\n"
        "\n"
        "\n"
        "    fragColor = vec4( col,1.0 );\n"
        "}\n"     );

     n->create_file("ShaderToy/TentacleObject.glsl",
        "// https://www.shadertoy.com/view/3tXXRn\n"
        "\n"
        "// Spherical Fibonnacci points, as described by Benjamin Keinert, Matthias Innmann,\n"
        "// Michael Sanger and Marc Stamminger in their paper (below)\n"
        "\n"
        "//=================================================================================================\n"
        "// http://lgdv.cs.fau.de/uploads/publications/spherical_fibonacci_mapping_opt.pdf\n"
        "//=================================================================================================\n"
        "const float PI  = 3.14159265359;\n"
        "const float PHI = 1.61803398875;\n"
        "\n"
        "// Originally from https://www.shadertoy.com/view/lllXz4\n"
        "// Modified by fizzer to put out the vector q.\n"
        "vec2 inverseSF( vec3 p, float n, out vec3 outq )\n"
        "{\n"
        "    float m = 1.0 - 1.0/n;\n"
        "\n"
        "    float phi = min(atan(p.y, p.x), PI), cosTheta = p.z;\n"
        "\n"
        "    float k  = max(2.0, floor( log(n * PI * sqrt(5.0) * (1.0 - cosTheta*cosTheta))/ log(PHI+1.0)));\n"
        "    float Fk = pow(PHI, k)/sqrt(5.0);\n"
        "    vec2  F  = vec2( round(Fk), round(Fk * PHI) ); // k, k+1\n"
        "\n"
        "    vec2 ka = 2.0*F/n;\n"
        "    vec2 kb = 2.0*PI*( fract((F+1.0)*PHI) - (PHI-1.0) );\n"
        "\n"
        "    mat2 iB = mat2( ka.y, -ka.x,\n"
        "                    kb.y, -kb.x ) / (ka.y*kb.x - ka.x*kb.y);\n"
        "\n"
        "    vec2 c = floor( iB * vec2(phi, cosTheta - m));\n"
        "    float d = 8.0;\n"
        "    float j = 0.0;\n"
        "    for( int s=0; s<4; s++ )\n"
        "    {\n"
        "        vec2 uv = vec2( float(s-2*(s/2)), float(s/2) );\n"
        "\n"
        "        float i = round(dot(F, uv + c));\n"
        "\n"
        "        float phi = 2.0*PI*fract(i*PHI);\n"
        "        float cosTheta = m - 2.0*i/n;\n"
        "        float sinTheta = sqrt(1.0 - cosTheta*cosTheta);\n"
        "\n"
        "        vec3 q = vec3( cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta );\n"
        "        float squaredDistance = dot(q-p, q-p);\n"
        "        if (squaredDistance < d)\n"
        "        {\n"
        "            outq = q;\n"
        "            d = squaredDistance;\n"
        "            j = i;\n"
        "        }\n"
        "    }\n"
        "    return vec2( j, sqrt(d) );\n"
        "}\n"
        "\n"
        "vec2 intersectSphere(vec3 ro, vec3 rd, vec3 org, float rad)\n"
        "{\n"
        "   float a = dot(rd, rd);\n"
        "   float b = 2. * dot(rd, ro - org);\n"
        "   float c = dot(ro - org, ro - org) - rad * rad;\n"
        "   float desc = b * b - 4. * a * c;\n"
        "   if (desc < 0.)\n"
        "      return vec2(1, 0);\n"
        "\n"
        "   return vec2((-b - sqrt(desc)) / (2. * a), (-b + sqrt(desc)) / (2. * a));\n"
        "}\n"
        "\n"
        "// polynomial smooth min (k = 0.1);\n"
        "// from iq: https://www.iquilezles.org/www/articles/smin/smin.htm\n"
        "float smin( float a, float b, float k )\n"
        "{\n"
        "    float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );\n"
        "    return mix( b, a, h ) - k*h*(1.0-h);\n"
        "}\n"
        "\n"
        "//float smin(float a,float b,float k){ return -log2(exp2(-k*a)+exp2(-k*b))/k;}//from iq\n"
        "float smax(float a,float b,float k){ return -smin(-a,-b,k);}\n"
        "\n"
        "mat3 rotX(float a)\n"
        "{\n"
        "    return mat3(1., 0., 0.,\n"
        "                0., cos(a), sin(a),\n"
        "                0., -sin(a), cos(a));\n"
        "}\n"
        "\n"
        "mat3 rotY(float a)\n"
        "{\n"
        "    return mat3(cos(a), 0., sin(a),\n"
        "                0., 1., 0.,\n"
        "                -sin(a), 0., cos(a));\n"
        "}\n"
        "\n"
        "mat3 rotZ(float a)\n"
        "{\n"
        "    return mat3(cos(a), sin(a), 0.,\n"
        "                -sin(a), cos(a), 0.,\n"
        "                0., 0., 1.);\n"
        "}\n"
        "\n"
        "// Anti-aliasing samples count sqrt\n"
        "#define AA 2\n"
        "\n"
        "float time;\n"
        "\n"
        "// Rotation matrix for spherical layer.\n"
        "mat3 rot(float r)\n"
        "{\n"
        "    float t = time - r * 2.;\n"
        "    float s = .5 + .5 * r;\n"
        "    return rotX(cos(t / 1.5) * s) * rotY(sin(t / 3.) * s);\n"
        "}\n"
        "\n"
        "// Scene SDF\n"
        "float dist(vec3 p)\n"
        "{\n"
        "    const float precis = 35.0;\n"
        "\n"
        "    vec3 op = p;\n"
        "\n"
        "    p = rot(length(p)) * p;\n"
        "\n"
        "    // Rotational velocity estimation.\n"
        "    float diff = distance(p, rot(length(op) - 1e-2) * op);\n"
        "\n"
        "    // A scaling factor based on the rotational velocity to\n"
        "    // simulate a 'bunching up' of the tentacles when they are spinning fast.\n"
        "    float k = max(1e-3, 1. + diff * 1.);\n"
        "\n"
        "    p *= k;\n"
        "    op *= k;\n"
        "\n"
        "    vec3 q;\n"
        "    vec2 sf = inverseSF( normalize(p), precis, q );\n"
        "\n"
        "    q *= k;\n"
        "\n"
        "    float d = length(p);\n"
        "\n"
        "    // Alternating tentacle lengths based on spiral point ID.\n"
        "    float r3 = (mod(sf.x, 3.) < 1.) ? 1. : 1.45;\n"
        "    float r2 = r3 / k;\n"
        "\n"
        "    d = smax(sf.y - diff * 2.2 - .04 / dot(p, p), d - r3, 32. / 200.);\n"
        "\n"
        "    // Add spheres at the ends of the tentacles using the unrotated\n"
        "    // sample space, to keep them spherical.\n"
        "    q = transpose(rot(r2 + .05)) * q;\n"
        "    d = smin(d,  length(op - q * r2) - .1, 32. / 200.);\n"
        "\n"
        "    return min(d * .6 / k, .2);\n"
        "}\n"
        "\n"
        "// A special field which is only applied when extracing surface normals.\n"
        "float bump(vec3 p)\n"
        "{\n"
        "   return 0.0;\n"
        "}\n"
        "\n"
        "vec3 getNormal(vec3 p)\n"
        "{\n"
        "    // Here the epsilon used for scene normal extraction is larger than the detailed\n"
        "    // bump epsilon. The larger geometry epsilon results in a smoothing effect which helps\n"
        "    // to blend the bases of the tentacles together.\n"
        "\n"
        "    const vec2 eps = vec2(1e-1, 0);\n"
        "    const vec2 eps2 = vec2(1e-3, 0);\n"
        "    return normalize(vec3(dist(p + eps.xyy) + bump(p + eps2.xyy) - dist(p - eps.xyy) - bump(p - eps2.xyy),\n"
        "                          dist(p + eps.yxy) + bump(p + eps2.yxy) - dist(p - eps.yxy) - bump(p - eps2.yxy),\n"
        "                          dist(p + eps.yyx) + bump(p + eps2.yyx) - dist(p - eps.yyx) - bump(p - eps2.yyx)));\n"
        "}\n"
        "\n"
        "// Pyramid waveform\n"
        "float tri(float x)\n"
        "{\n"
        "    return min(fract(x) * 2., 2. - 2. * fract(x));\n"
        "}\n"
        "\n"
        "vec3 render(vec2 fragCoord)\n"
        "{\n"
        "    // Jittered time sample for motionblur\n"
        "    time = iTime + texelFetch(iChannel1, ivec2(fragCoord * 2.) & 1023, 0).r * .025;\n"
        "\n"
        "    vec3 fragColor = vec3(0);\n"
        "\n"
        "    vec2 uv = fragCoord / iResolution.xy * 2. - 1.;\n"
        "    uv.x *= iResolution.x / iResolution.y;\n"
        "\n"
        "    vec3 ro = vec3(0, 0, 3), rd = normalize(vec3(uv, -1.8));\n"
        "\n"
        "    ro.y += sin(time / 4.) * .03;\n"
        "    ro.x += sin(time / 5.) * .03;\n"
        "\n"
        "    // Clip to a bounding sphere\n"
        "    vec2 spheret = intersectSphere(ro, rd, vec3(0), 1.6);\n"
        "\n"
        "    // Background colour\n"
        "    vec3 bg = vec3(.75) * mix(vec3(.5, .5, 1.), vec3(1), .6) * (1. - smoothstep(0., 7., length(uv)));\n"
        "\n"
        "    if(spheret.x > spheret.y)\n"
        "        return bg;\n"
        "\n"
        "    float t = spheret.x;\n"
        "    float maxt = spheret.y;\n"
        "\n"
        "    // Raymarch\n"
        "    for(int i = 0; i < 80; ++i)\n"
        "    {\n"
        "        float d = dist(ro + rd * t);\n"
        "        if(abs(d) < 1e-4 || t > maxt)\n"
        "            break;\n"
        "        t += d;\n"
        "    }\n"
        "\n"
        "    if(t > maxt)\n"
        "    {\n"
        "        fragColor.rgb = bg;\n"
        "    }\n"
        "    else\n"
        "    {\n"
        "        vec3 rp = ro + rd * t;\n"
        "        vec3 n = getNormal(rp);\n"
        "        vec3 r = reflect(rd, n);\n"
        "        float l = length(rp);\n"
        "        float fr = clamp(1. - dot(n, -rd), 0., 1.);\n"
        "\n"
        "        // Apply some fake shadowing to the specular highlight and the backlight,\n"
        "        // by simulating a spherical occluder for the 'body' at the center of the object.\n"
        "        float bodyR = .5;\n"
        "        float cone = cos(atan(bodyR / l));\n"
        "\n"
        "        float specshad = 1. - smoothstep(-.1, .1, dot(r, normalize(vec3(0) - rp)) - cone) * 1.;\n"
        "        float specshad2 = 1. - smoothstep(-.3, .3, dot(r, normalize(vec3(0) - rp)) - cone) * 1.;\n"
        "\n"
        "        // Backlight / fake SSS\n"
        "        fragColor.rgb = bg * mix(vec3(.2, .5, 1.) / 2., vec3(1., .9, .8).bgr, specshad2 * pow(fr, .8));\n"
        "\n"
        "        // Fake AO from center of body\n"
        "        fragColor.rgb *= vec3(pow(mix(.5 + .5 * dot(n, normalize(vec3(0) - rp)), 1., smoothstep(0., 1.5, l)), .5));\n"
        "\n"
        "        // Slight AO / diffuse bleeding\n"
        "        fragColor.rgb *= mix(vec3(.75,1.,.75), vec3(1), smoothstep(0.1, .8, l));\n"
        "\n"
        "        vec3 c = fragColor.rgb;\n"
        "\n"
        "        // Blue / green alternating pattern\n"
        "        fragColor.rgb = mix(c.bbb * vec3(.5,1.,.5), fragColor.rgb, smoothstep(.3, .7, tri(l * 4.)));\n"
        "\n"
        "        // Yellow tips\n"
        "        fragColor.rgb = mix(fragColor.rgb, c.bbb * vec3(1,1,.5), smoothstep(1.4, 1.5, l));\n"
        "\n"
        "        // Yellow tips self-illumination\n"
        "        fragColor.rgb += vec3(1,1,.4) * smoothstep(1.4, 1.5, l) * .11;\n"
        "\n"
        "        // Specular highlight\n"
        "        fragColor.rgb += specshad * .9 * smoothstep(.4, .7, dot(r, normalize(vec3(1)))) * fr;\n"
        "\n"
        "        // Mist\n"
        "        fragColor.rgb += vec3(mix(vec3(.5, .5, 1.), vec3(0), exp(-t / 25.)));\n"
        "    }\n"
        "\n"
        "    return fragColor;\n"
        "}\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{\n"
        "    fragColor.rgb = vec3(0);\n"
        "\n"
        "    // Anti-aliasing sample loop\n"
        "    for(int y = 0; y < AA; ++y)\n"
        "        for(int x = 0; x < AA; ++x)\n"
        "        {\n"
        "            fragColor.rgb += clamp(render(fragCoord + vec2(x, y) / float(AA)), 0., 1.);\n"
        "        }\n"
        "\n"
        "    fragColor.rgb /= float(AA * AA);\n"
        "\n"
        "    // Contrast\n"
        "    fragColor.rgb = (fragColor.rgb * 1.2 - .05);\n"
        "\n"
        "    // Clamp, gamma, dither\n"
        "    fragColor.rgb = pow(clamp(fragColor.rgb, 0., 1.), vec3(1. / 2.2)) + texelFetch(iChannel1, ivec2(fragCoord) & 1023, 0).gba / 200.;\n"
        "}\n"
     );

     n->create_file("ShaderToy/ThePopularShader.glsl",
        "// https://www.shadertoy.com/view/XdB3Dw\n"
        "#define USE_IQ_SMIN 0\n"
        "\n"
        "float time;\n"
        "\n"
        "vec2 leg0[3];\n"
        "vec2 leg1[3];\n"
        "\n"
        "vec2 arm0[3];\n"
        "vec2 arm1[3];\n"
        "\n"
        "float wlen=15.0;\n"
        "float bob;\n"
        "float wc_scale=0.5;\n"
        "float scroll;\n"
        "float scene_scale=15.0;\n"
        "\n"
        "// Finds the entry and exit points of a 2D ray with a circle of radius 1\n"
        "// centered at the origin.\n"
        "vec2 intersectCircle(vec2 ro, vec2 rd)\n"
        "{\n"
        "    float a = dot(rd, rd);\n"
        "    float b = 2.0 * dot(rd, ro);\n"
        "    float ds = b * b - 4.0 * a * (dot(ro, ro) - 1.0);\n"
        "    \n"
        "    if(ds < 0.0)\n"
        "        return vec2(1e3);\n"
        "    \n"
        "    return ((-b - sqrt(ds) * vec2(-1.0, 1.0))) / (2.0 * a);\n"
        "}\n"
        "\n"
        "mat3 rotateXMat(float a)\n"
        "{\n"
        "    return mat3(1.0, 0.0, 0.0, 0.0, cos(a), -sin(a), 0.0, sin(a), cos(a));\n"
        "}\n"
        "\n"
        "mat3 rotateYMat(float a)\n"
        "{\n"
        "    return mat3(cos(a), 0.0, -sin(a), 0.0, 1.0, 0.0, sin(a), 0.0, cos(a));\n"
        "}\n"
        "\n"
        "// Adapted from https://www.shadertoy.com/view/ldlGR7\n"
        "vec2 solve( vec2 p, float l1, float l2, float side )\n"
        "{\n"
        "    vec2 q = p*( 0.5 + 0.5*(l1*l1-l2*l2)/dot(p,p) );\n"
        "    \n"
        "    float s = l1*l1/dot(q,q) - 1.0;\n"
        "    \n"
        "    if( s<0.0 ) return vec2(-100.0);\n"
        "    \n"
        "    return q + q.yx*vec2(-1.0,1.0)*side*sqrt( s );\n"
        "}\n"
        "\n"
        "// Returns a pyramid-like periodic signal.\n"
        "float pyramid(float x)\n"
        "{\n"
        "    x = fract(x);\n"
        "    return min(x * 2.0, (1.0 - x) * 2.0);\n"
        "}\n"
        "\n"
        "// Returns a semicircular periodic signal.\n"
        "float circ(float x)\n"
        "{\n"
        "    x = fract(x) * 2.0 - 1.0;\n"
        "    return sqrt(1.0 - x * x);\n"
        "}\n"
        "\n"
        "#if USE_IQ_SMIN\n"
        "float smin(float a,float b,float k){ return -log(exp(-k*a)+exp(-k*b))/k;}//from iq\n"
        "#else\n"
        "// http://www.johndcook.com/blog/2010/01/20/how-to-compute-the-soft-maximum/\n"
        "float smin(in float a, in float b, in float k) { return a - log(1.0+exp(k*(a-b))) / k; }\n"
        "#endif\n"
        "\n"
        "float mp(float x)\n"
        "{\n"
        "    float y=0.3;\n"
        "    return clamp((pyramid(x)-0.5)*2.0-0.4,-y,y);\n"
        "}\n"
        "\n"
        "float mosaic(vec3 p)\n"
        "{\n"
        "    // Disabled because it causes a compilation failure due to time-out or size limit.\n"
        "    return 0.0;//max(mp(p.y*10.0),mp(p.z*10.0))*0.01;\n"
        "}\n"
        "/*\n"
        "mat3 transpose(mat3 m)\n"
        "{\n"
        "    return mat3(vec3(m[0].x,m[1].x,m[2].x),\n"
        "                vec3(m[0].y,m[1].y,m[2].y),\n"
        "                vec3(m[0].z,m[1].z,m[2].z));\n"
        "}*/\n"
        "\n"
        "float capsuleDist(vec3 p,vec3 o,vec3 d,float h0,float h1,float r0,float r1)\n"
        "{\n"
        "    vec3 u=cross(d,vec3(1.0,0.0,0.0));\n"
        "    vec3 v=cross(u,d);\n"
        "    u=cross(v,d);\n"
        "    mat3 m=transpose(mat3(normalize(u),normalize(v),normalize(d)));\n"
        "    d=normalize(d);\n"
        "    float t=clamp(dot(p-o,d),h0,h1);\n"
        "    vec3 np=o+t*d;\n"
        "    return distance(np,p)-mix(r0,r1,t)+mosaic(m*(p-o));\n"
        "}\n"
        "\n"
        "float boxDist(vec3 p,vec3 s,float r)\n"
        "{\n"
        "    return length(max(vec3(0.0),abs(p)-s))-r+mosaic(p);\n"
        "}\n"
        "\n"
        "float sphereDist(vec3 p,vec3 o,float r)\n"
        "{\n"
        "    return distance(p,o)-r+mosaic(p-o);\n"
        "}\n"
        "\n"
        "float sceneDist(vec3 p)\n"
        "{\n"
        "    float d=1e3;\n"
        "    \n"
        "    p+=vec3(0.0,0.07,0.0)*scene_scale;\n"
        "    p=rotateYMat(3.1415926*0.5)*p;\n"
        "    \n"
        "    p.z+=cos(p.y*2.0+time)*0.1;\n"
        "    float tm=fract(time*wc_scale*2.0-0.1);\n"
        "    p.x-=(smoothstep(0.0,0.3,tm)-smoothstep(0.4,1.0,tm))*smoothstep(0.5,2.0,p.y)*0.2+scroll;\n"
        "    \n"
        "    // Leg 0\n"
        "    {\n"
        "        float g=0.08;\n"
        "        vec3 o=vec3(0.0,0.0,0.2);\n"
        "        float d0=capsuleDist(p+o,vec3(leg0[0],0.0),vec3(leg0[1]-leg0[0],0.0),0.0,1.0-g,0.1,0.1);\n"
        "        float d1=capsuleDist(p+o,vec3(leg0[1],0.0),vec3(leg0[2]-leg0[1],0.0),g,1.0,0.1,0.2);\n"
        "        d=min(d,smin(d0,d1,15.0));\n"
        "    }\n"
        "    \n"
        "    // Leg 1\n"
        "    {\n"
        "        float g=0.08;\n"
        "        vec3 o=vec3(0.0,0.0,-0.2);\n"
        "        float d0=capsuleDist(p+o,vec3(leg1[0],0.0),vec3(leg1[1]-leg1[0],0.0),0.0,1.0-g,0.1,0.1);\n"
        "        float d1=capsuleDist(p+o,vec3(leg1[1],0.0),vec3(leg1[2]-leg1[1],0.0),g,1.0,0.1,0.2);\n"
        "        d=min(d,smin(d0,d1,15.0));\n"
        "    }\n"
        "    \n"
        "    p.y-=bob;\n"
        "    \n"
        "    // Arm 0\n"
        "    {\n"
        "        float g=0.08;\n"
        "        vec3 o=vec3(0.0,0.0,0.4);\n"
        "        mat3 m=rotateXMat(-0.3)*rotateYMat((cos((time*wc_scale+0.5)*3.1415926*2.0)-0.6)*0.5);\n"
        "        float d0=capsuleDist(p+o,vec3(arm0[0],0.0),m*vec3(arm0[1]-arm0[0],0.0),0.0,0.7-g,0.03,0.03);\n"
        "        float d1=capsuleDist(p+o,vec3(arm0[0],0.0)+m*vec3(arm0[1]-arm0[0],0.0),m*vec3(arm0[2]-arm0[1],0.0),g,0.7,0.03,0.06);\n"
        "        d=min(d,smin(d0,d1,15.0));\n"
        "    }\n"
        "    \n"
        "    // Arm 1\n"
        "    {\n"
        "        float g=0.08;\n"
        "        vec3 o=vec3(0.0,0.0,-0.4);\n"
        "        mat3 m=rotateXMat(0.3)*rotateYMat(-(cos(time*wc_scale*3.1415926*2.0)-0.6)*0.5);\n"
        "        float d0=capsuleDist(p+o,vec3(arm1[0],0.0),m*vec3(arm1[1]-arm1[0],0.0),0.0,0.7-g,0.03,0.03);\n"
        "        float d1=capsuleDist(p+o,vec3(arm1[0],0.0)+m*vec3(arm1[1]-arm1[0],0.0),m*vec3(arm1[2]-arm1[1],0.0),g,0.7,0.03,0.06);\n"
        "        d=min(d,smin(d0,d1,15.0));\n"
        "    }\n"
        "    \n"
        "    // Torso\n"
        "    d=smin(d,boxDist(p+vec3(0.0,-0.7,0.0),vec3(0.05,0.7,0.15),0.1),15.0);\n"
        "    d=smin(d,boxDist(p+vec3(-0.1,-1.1,0.0),vec3(0.05,0.2,0.15)*0.1,0.1),5.0);\n"
        "    \n"
        "    // Head\n"
        "    d=smin(d,sphereDist(p,vec3(0.0,1.825,0.0),0.2),15.0);\n"
        "    \n"
        "    \n"
        "    return d;\n"
        "}\n"
        "\n"
        "vec3 sceneNorm(vec3 p)\n"
        "{\n"
        "    p*=scene_scale;\n"
        "    float c=sceneDist(p);\n"
        "    float e=1e-3;\n"
        "    return normalize(vec3(sceneDist(p+vec3(e,0,0))-c,\n"
        "                          sceneDist(p+vec3(0,e,0))-c,\n"
        "                          sceneDist(p+vec3(0,0,e))-c));\n"
        "}\n"
        "\n"
        "float robot(vec3 ro,vec3 rd)\n"
        "{\n"
        "    float t=0.0;\n"
        "    float tm;\n"
        "    \n"
        "    tm=time*wc_scale;\n"
        "    \n"
        "    leg0[0]=vec2(0.0,bob);\n"
        "    leg0[2]=vec2(pyramid(tm)-0.3,-1.8+0.3*circ(tm*2.0)*step(fract(tm),0.5));\n"
        "    leg0[1]=(leg0[0]+solve(leg0[2]-leg0[0],1.0,1.0,1.0));\n"
        "    \n"
        "    arm1[0]=vec2(0.0,1.4);\n"
        "    arm1[2]=vec2(pyramid(tm)-0.3,0.1+pow(pyramid(tm),2.0)*0.7);\n"
        "    arm1[1]=(arm1[0]+solve(arm1[2]-arm1[0],0.7,0.7,-1.0));\n"
        "    \n"
        "    tm+=0.5;\n"
        "    \n"
        "    leg1[0]=vec2(0.0,bob);\n"
        "    leg1[2]=vec2(pyramid(tm)-0.3,-1.8+0.3*circ(tm*2.0)*step(fract(tm),0.5));\n"
        "    leg1[1]=(leg1[0]+solve(leg1[2]-leg1[0],1.0,1.0,1.0));\n"
        "    \n"
        "    arm0[0]=vec2(0.0,1.4);\n"
        "    arm0[2]=vec2(pyramid(tm)-0.3,0.1+pow(pyramid(tm),2.0)*0.7);\n"
        "    arm0[1]=(arm0[0]+solve(arm0[2]-arm0[0],0.7,0.7,-1.0));\n"
        "    \n"
        "    float rt=1e4;\n"
        "    \n"
        "    ro*=scene_scale;\n"
        "    rd*=scene_scale;\n"
        "    \n"
        "    for(int i=0;i<15;i+=1)\n"
        "    {\n"
        "        vec3 rp=ro+rd*t;\n"
        "        \n"
        "        float d=sceneDist(rp);\n"
        "        \n"
        "        if(d<1e-2)\n"
        "        {\n"
        "            rt=t;\n"
        "        }\n"
        "        \n"
        "        t+=d/scene_scale;\n"
        "    }\n"
        "    \n"
        "    \n"
        "    return rt;\n"
        "}\n"
        "\n"
        "\n"
        "vec2 unitSquareInterval(vec2 ro, vec2 rd)\n"
        "{    \n"
        "    vec2 slabs0 = (vec2(+1.0) - ro) / rd;    \n"
        "    vec2 slabs1 = (vec2(-1.0) - ro) / rd;\n"
        "    \n"
        "    vec2 mins = min(slabs0, slabs1);\n"
        "    vec2 maxs = max(slabs0, slabs1);\n"
        "    \n"
        "    return vec2(max(mins.x, mins.y),\n"
        "                min(maxs.x, maxs.y));\n"
        "}\n"
        "\n"
        "vec3 squaresColours(vec2 p)\n"
        "{\n"
        "    p+=vec2(time*0.2);\n"
        "    \n"
        "    vec3 orange=vec3(1.0,0.4,0.1)*2.0;\n"
        "    vec3 purple=vec3(1.0,0.2,0.5)*0.8;\n"
        "    \n"
        "    float l=pow(0.5+0.5*cos(p.x*7.0+cos(p.y)*8.0)*sin(p.y*2.0),4.0)*2.0;\n"
        "    vec3 c=pow(l*(mix(orange,purple,0.5+0.5*cos(p.x*40.0+sin(p.y*10.0)*3.0))+\n"
        "                  mix(orange,purple,0.5+0.5*cos(p.x*20.0+sin(p.y*3.0)*3.0))),vec3(1.2))*0.7;\n"
        "    \n"
        "    c+=vec3(1.0,0.8,0.4)*pow(0.5+0.5*cos(p.x*20.0)*sin(p.y*12.0),20.0)*2.0;\n"
        "    \n"
        "    c+=vec3(0.1,0.5+0.5*cos(p*20.0))*vec3(0.05,0.1,0.4).bgr*0.7;\n"
        "    \n"
        "    return c;\n"
        "}\n"
        "\n"
        "vec3 squaresTex(vec2 p,float border)\n"
        "{\n"
        "    float sm=0.02;\n"
        "    vec2 res=vec2(8.0);\n"
        "    vec2 ip=floor(p*res)/res;\n"
        "    vec2 fp=fract(p*res);\n"
        "    float m=1.0-max(smoothstep(border-sm,border,abs(fp.x-0.5)),smoothstep(border-sm,border,abs(fp.y-0.5)));\n"
        "    m+=1.0-smoothstep(0.0,0.56,distance(fp,vec2(0.5)));\n"
        "    return m*squaresColours(ip);\n"
        "}\n"
        "\n"
        "vec3 room(vec3 ro,vec3 rd,out vec3 rp,out vec3 n)\n"
        "{\n"
        "    vec2 box_size=vec2(1.0,5.0+3.0/8.0);\n"
        "    \n"
        "    vec2 cp=vec2(0.0),ct=vec2(1e3);\n"
        "    \n"
        "    for(int i=0;i<4;i+=1)\n"
        "    {\n"
        "        float cr=0.03;\n"
        "        vec2 tcp=vec2(2.5/8.0*float(-1),float(i)-2.0+0.5/8.0);\n"
        "        vec2 tct=intersectCircle((ro.xz-tcp)/cr,rd.xz/cr);\n"
        "        \n"
        "        if(tct.y > 0.0 && tct.y<ct.y)\n"
        "        {\n"
        "            ct=tct;\n"
        "            cp=tcp;\n"
        "        }\n"
        "    }\n"
        "\n"
        "    for(int i=0;i<4;i+=1)\n"
        "    {\n"
        "        float cr=0.03;\n"
        "        vec2 tcp=vec2(2.5/8.0*float(+1),float(i)-2.0+0.5/8.0);\n"
        "        vec2 tct=intersectCircle((ro.xz-tcp)/cr,rd.xz/cr);\n"
        "        \n"
        "        if(tct.y > 0.0 && tct.y<ct.y)\n"
        "        {\n"
        "            ct=tct;\n"
        "            cp=tcp;\n"
        "        }\n"
        "    }\n"
        "    \n"
        "    ct.y=max(0.0,ct.y);\n"
        "    \n"
        "    vec3 ci=ro+rd*ct.y;\n"
        "    vec2 cu=vec2(atan(ci.z-cp.y,ci.x-cp.x)/3.1415926*0.5,(ci.y+0.5/8.0)*4.0);\n"
        "    \n"
        "    float wt=max(0.0,unitSquareInterval(ro.xy * box_size, rd.xy * box_size).y);\n"
        "    float t=min(ct.y,wt);\n"
        "    \n"
        "    rp=ro+rd*(t-1e-4);\n"
        "    \n"
        "    n.z=0.0;\n"
        "    if(abs(rp.x*box_size.x)>abs(rp.y*box_size.y))\n"
        "        n.xy=vec2(rp.x/abs(rp.x),0.0);\n"
        "    else\n"
        "        n.xy=vec2(0.0,rp.y/abs(rp.y));\n"
        "    \n"
        "    if(ct.y<wt)\n"
        "    {\n"
        "        n.y=0.0;\n"
        "        n.xz=normalize(rp.xz-ci.xz);\n"
        "    }\n"
        "    \n"
        "    float l=1.0-smoothstep(0.0,3.0,abs(rp.z-ro.z));\n"
        "    \n"
        "    vec3 wc=mix(squaresTex(rp.zy+vec2(0.0,0.5/8.0),0.5),squaresTex(rp.xz,0.44),step(0.999/box_size.y,abs(rp.y)));\n"
        "    vec3 cc=squaresTex(cu,0.45)+0.8*vec3(smoothstep(0.83/5.0,0.86/5.0,abs(rp.y)));\n"
        "    \n"
        "    return l*mix(cc,wc,step(wt,t));\n"
        "}\n"
        "\n"
        "vec3 scene(vec2 p)\n"
        "{\n"
        "    mat3 cam = rotateXMat(cos(time * 0.2) * 0.1) * rotateYMat(time * 0.5);\n"
        "    float lt=mod(time*wc_scale,wlen)/wlen;\n"
        "    \n"
        "    vec3 ro = cam*vec3(0.0,-0.15+lt*0.15, 0.15+lt*0.2)+vec3(0.0,0.0,scroll/scene_scale);\n"
        "    vec3 rd = cam*vec3(p, -1.0);\n"
        "    \n"
        "    rd=normalize(rd);\n"
        "    \n"
        "    float robot_t=robot(ro,rd);\n"
        "    \n"
        "    vec3 n,rp;\n"
        "    \n"
        "    vec3 c;\n"
        "    vec3 c0=room(ro,rd,rp,n);\n"
        "    \n"
        "    if(robot_t < distance(ro,rp))\n"
        "    {\n"
        "        rp=ro+rd*robot_t;\n"
        "        n=sceneNorm(rp);\n"
        "        vec3 r=reflect(rd,n);\n"
        "        c=vec3(0.5+0.5*n.y)*0.5*vec3(1.0,0.8,0.5);\n"
        "        vec3 c1=room(rp,r,rp,n);\n"
        "        c+=c1*0.5;\n"
        "    }\n"
        "    else\n"
        "    {\n"
        "        vec3 r=reflect(rd,n);\n"
        "        vec3 c1=room(rp,r,rp,n);\n"
        "        c=c0+c1*c0*0.4;\n"
        "    }\n"
        "        \n"
        "    vec3 ll=vec3(1.0-(smoothstep(0.0,0.07,lt)-smoothstep(0.93,1.0,lt)));\n"
        "    \n"
        "    return ll+c+\n"
        "        0.6*((sin(p.y)*cos(p.x+time*2.0)*0.5+0.5)*\n"
        "             pow(mix(vec3(1.0,0.7,0.1),vec3(1.0,0.2,0.6),0.5+0.5*cos(p.x+sin(time*3.0+p.y*2.0))),vec3(2.0)));\n"
        "}\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{\n"
        "    time=iTime+1.0;\n"
        "    bob=cos(time*12.0)*0.05;\n"
        "    scroll=-15.0+mod(time*wc_scale,wlen)*2.0;\n"
        "    vec2 uv = fragCoord.xy / iResolution.xy;\n"
        "    vec2 q=uv;\n"
        "    vec2 t=uv*2.0-vec2(1.0);\n"
        "    t.x*=iResolution.x/iResolution.y;\n"
        "    fragColor.rgb = scene(t.xy) * 1.3;\n"
        "    \n"
        "    // vignet\n"
        "    fragColor.rgb *= 0.5 + 0.5*pow( 16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.1 );\n"
        "}\n"
        "\n"
        "\n"
     );

     n->create_file("ShaderToy/TracedMinkwskiTube.glsl",
        "// https://www.shadertoy.com/view/4lSXzh\n"
        "/*\n"
        "    Simplified, Traced Minkowski Tube.\n"
        "    ----------------------------------\n"
        "\n"
        "    This was inspired by Shadertoy user Akaitora's \"Worley Tunnel\" which you can find here:\n"
        "    https://www.shadertoy.com/view/XtjSzR\n"
        "\n"
        "    Akaitora had a question, but I didn't have room to answer, so this is for anyone who's interested\n"
        "    in understanding the reasoning behind the oldschool tunnel effect. I see a \"lot\" of them around.\n"
        "\n"
        "    I'll assume most know that the endless tunnel effect is a simplification of a raytraced,\n"
        "    cylindrically-mapped inner cylinder. Without going into detail, by restricting the \"XY\" coordinates\n"
        "    of the ray origin (camera position) \"ro\" to zero, the ray intersection equation becomes almost\n"
        "    trivial. For a 3D unit ray-direction vector, \"rd,\" the solution is something along the lines of:\n"
        "\n"
        "    float distance = 1./length(rd.xy);\n"
        "\n"
        "    Applying the interestion point formula (sp = ro + rd*dist), the 3D surface point is simply:\n"
        "    vec3 sp = vec3(0, 0, time) + rd/length(rd.xy); // ro.xy is fixed to the origin moving along Z.\n"
        "\n"
        "    The surface point coordinates enable you to color the surface using a 3D method, or in the case of\n"
        "    the endless tunnel effect, cylindrically map a texture, or texture-function, (preferably seamless)\n"
        "    onto the surface:\n"
        "\n"
        "    vec3 color = TexFunction(vec3 sp) { return texUV(scaleU*atan(sp.y, sp.x)/6.2832, scaleV*sp.z); }\n"
        "\n"
        "    You can see that \"sp.z\" is equal to: ro.z(time)*scaleV + rd.z*scaleV(constant)/length(rd.xy);\n"
        "\n"
        "    The light attenuation is usually a scaled inverse of the distance, or \"k*length(rd.xy)\" and the\n"
        "    normal vector is about as straight forward as it gets: normalize(vec3(-sp.xy, 0.));\n"
        "\n"
        "    Anyway, to save cycles, 1990s demo coders threw out the 3D surface information, bypassed the\n"
        "    normalization of the ray-direction vector, and a bunch of other stuff, until there was virtually\n"
        "    nothing left to calculate other than the texture coordinates and distance attenuation.\n"
        "\n"
        "    The point is, for the price of just a few extra lines and almost no extra effort on the part of the\n"
        "    GPU, you could have a 3D \"lit\" tunnel, which is more visually enticing. Like the oldschool tunnel\n"
        "    demos, you could also have square, rounded square tunnels, etc.\n"
        "\n"
        "    Hence, this simple demonstration. It's a point lit, rounded square tunnel, produced without the use\n"
        "    of raymarching. As a point of interest that's probably not interesting, there's not a single \"for\n"
        "    loop\" or \"if statement\" used in the code. Do I get points for that? :)\n"
        "\n"
        "    If you ignore the 3D Voronesque function (which I'll explain another time), bump mapping, amateur\n"
        "    camera movement and extra lighting, there's barely any code here. In fact, I believe you could fit\n"
        "    a 3D lit, 3D-function mapped, possibly bumped, tunnel into a tweet or two... but I'll leave that to\n"
        "    Fabrice Neyret, Greg Rostami, etc. ;-)\n"
        "\n"
        "    \n"
        "    Update: Here's a private link to a cylindrically mapped tube I put together. It's for those who'd\n"
        "    like to see how to apply repeated 2D functions and textures:\n"
        "    https://www.shadertoy.com/view/ltSSR1\n"
        "\n"
        "*/\n"
        "\n"
        "\n"
        "// 2D rotation. Always handy.\n"
        "mat2 rot(float th){ float cs = cos(th), si = sin(th); return mat2(cs, -si, si, cs); }\n"
        "\n"
        "// 3D Voronoi-like function. Cheap, low quality, 1st and 2nd order 3D Voronoi imitation.\n"
        "//\n"
        "// I wrote this a while back because I wanted a stand-alone algorithm fast enough to produce regular, or 2nd order,\n"
        "// Voronoi-looking patterns in a raymarching setting. Anyway, this is what I came up with. Obviously, it wouldn't\n"
        "// pass as genuine 3D Voronoi, but there's only so much you can do with a few lines. Even so, it has a Voronoi feel\n"
        "// to it. Hence, Voronesque.\n"
        "//\n"
        "// Here's a rough explanation of how it works: Instead of partitioning space into cubes, partition it into its\n"
        "// simplex form, namely tetrahedrons. Use the four tetrahedral vertices to create some random falloff values, then\n"
        "// pick off the two highest, or lowest, depending on perspective. That's it. If you'd like to know more, the\n"
        "// function is roughly commented, plus there's a simplex noise related link below that should make it more clear.\n"
        "//\n"
        "// Credits: Ken Perlin, the creator of simplex noise, of course. Stefan Gustavson's paper - \"Simplex Noise Demystified.\"\n"
        "// IQ, other \"ShaderToy.com\" people, Brian Sharpe (does interesting work), etc.\n"
        "//\n"
        "// My favorite simplex-related write up: \"Simplex Noise, keeping it simple.\" - Jasper Flick?\n"
        "// http://catlikecoding.com/unity/tutorials/simplex-noise/\n"
        "//\n"
        "float Voronesque( in vec3 p ){\n"
        "\n"
        "    // Skewing the cubic grid, then determining the first vertice.\n"
        "    vec3 i  = floor(p + dot(p, vec3(0.333333)) );  p -= i - dot(i, vec3(0.166666)) ;\n"
        "\n"
        "    // Breaking the skewed cube into tetrahedra with partitioning planes, then determining which side of the\n"
        "    // intersecting planes the skewed point is on. Ie: Determining which tetrahedron the point is in.\n"
        "    vec3 i1 = step(0., p-p.yzx), i2 = max(i1, 1.0-i1.zxy); i1 = min(i1, 1.0-i1.zxy);\n"
        "\n"
        "    // Using the above to calculate the other three vertices. Now we have all four tetrahedral vertices.\n"
        "    vec3 p1 = p - i1 + 0.166666, p2 = p - i2 + 0.333333, p3 = p - 0.5;\n"
        "\n"
        "    vec3 rnd = vec3(7, 157, 113); // I use this combination to pay homage to Shadertoy.com. :)\n"
        "\n"
        "    // Falloff values from the skewed point to each of the tetrahedral points.\n"
        "    vec4 v = max(0.5 - vec4(dot(p, p), dot(p1, p1), dot(p2, p2), dot(p3, p3)), 0.);\n"
        "\n"
        "    // Assigning four random values to each of the points above.\n"
        "    vec4 d = vec4( dot(i, rnd), dot(i + i1, rnd), dot(i + i2, rnd), dot(i + 1., rnd) );\n"
        "\n"
        "    // Further randomizing \"d,\" then combining it with \"v\" to produce the final random falloff values. Range [0, 1]\n"
        "    d = fract(sin(d)*262144.)*v*2.;\n"
        "\n"
        "    // Reusing \"v\" to determine the largest, and second largest falloff values. Analogous to distance.\n"
        "    v.x = max(d.x, d.y), v.y = max(d.z, d.w), v.z = max(min(d.x, d.y), min(d.z, d.w)), v.w = min(v.x, v.y);\n"
        "\n"
        "    return  max(v.x, v.y)- max(v.z, v.w); // Maximum minus second order, for that beveled Voronoi look. Range [0, 1].\n"
        "    //return max(v.x, v.y); // Maximum, or regular value for the regular Voronoi aesthetic.  Range [0, 1].\n"
        "}\n"
        "\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord ){\n"
        "\n"
        "    // Screen coordinates, plus some movement about the center.\n"
        "    vec2 uv = (fragCoord.xy - iResolution.xy*0.5)/iResolution.y + vec2(0.5*cos(iTime*0.5), 0.25*sin(iTime*0.5));\n"
        "\n"
        "    // Unit direction ray.\n"
        "    vec3 rd = normalize(vec3(uv, 1.));\n"
        "    rd.xy *= rot(sin(iTime*0.25)*0.5); // Very subtle look around, just to show it's a 3D effect.\n"
        "    rd.xz *= rot(sin(iTime*0.25)*0.5);\n"
        "\n"
        "    // Screen color. Initialized to black.\n"
        "    vec3 col = vec3(0);\n"
        "\n"
        "    // Ray intersection of a cylinder (radius one) - centered at the origin - from a ray-origin that has XY coordinates\n"
        "    // also centered at the origin.\n"
        "    //float sDist = max(dot(rd.xy, rd.xy), 1e-16); // Analogous to the surface function.\n"
        "    //sDist = 1./sqrt(sDist); // Ray origin to surface distance.\n"
        "\n"
        "    // Same as above, but using a Minkowski distance and scaling factor. I tried it on a whim, and it seemed to work.\n"
        "    // I know, not scientific at all, but it kind of makes sense. They'll let anyone get behind a computer these days. :)\n"
        "    vec2 scale = vec2(0.75, 1.);\n"
        "    float power = 6.;\n"
        "    float sDist = max(dot( pow(abs(rd.xy)*scale, vec2(power)), vec2(1.) ), 1e-16); // Analogous to the surface function.\n"
        "    sDist = 1./pow( sDist, 1./power ); // Ray origin to surface distance.\n"
        "\n"
        "    //if(sDist>1e-8){\n"
        "\n"
        "        // Using the the distance \"sDist\" above to calculate the surface position. Ie: sp = ro + rd*t;\n"
        "        // I've hardcoded \"ro\" to reduce line count. Note that \"ro.xy\" is centered on zero. The cheap\n"
        "        // ray-intersection formula above relies on that.\n"
        "        vec3 sp = vec3(0.0, 0.0, iTime*2.) + rd*sDist;\n"
        "\n"
        "        // The surface normal. Based on the derivative of the surface description function. See above.\n"
        "        //vec3 sn = normalize(vec3(-sp.xy, 0.)); // Cylinder normal.\n"
        "        vec3 sn = normalize(-sign(sp)*vec3(pow(abs(sp.xy)*scale, vec2(power-1.)), 0.)); // Minkowski normal.\n"
        "\n"
        "        // Bump mapping.\n"
        "        //\n"
        "        // I wanted to make this example as simple as possible, but it's only a few extra lines. Note the larger\n"
        "        // \"eps\" number. Increasing the value spreads the samples out, which effectively blurs the result, thus\n"
        "        // reducing the jaggies. The downside is loss of bump precision, which isn't noticeable in this particular\n"
        "        // example. Decrease the value to \"0.001\" to see what I'm talking about.\n"
        "        const vec2 eps = vec2(0.025, 0.);\n"
        "        float c = Voronesque(sp*2.5); // Base value. Used below to color the surface.\n"
        "        // 3D gradient vector... of sorts. Based on the bump function. In this case, Voronoi.\n"
        "        vec3 gr = (vec3(Voronesque((sp-eps.xyy)*2.5), Voronesque((sp-eps.yxy)*2.5), Voronesque((sp-eps.yyx)*2.5))-c)/eps.x;\n"
        "        gr -= sn*dot(sn, gr); // There's a reason for this... but I need more room. :)\n"
        "        sn = normalize(sn + gr*0.1); // Combining the bump gradient vector with the object surface normal.\n"
        "\n"
        "        // Lighting.\n"
        "        //\n"
        "        // The light is hovering just in front of the viewer.\n"
        "        vec3 lp = vec3(0.0, 0.0, iTime*2. + 3.);\n"
        "        vec3 ld = lp - sp; // Light direction.\n"
        "        float dist = max(length(ld), 0.001); // Distance from light to the surface.\n"
        "        ld /= dist; // Use the distance to normalize \"ld.\"\n"
        "\n"
        "        // Light attenuation, based on the distance above.\n"
        "        float atten = min(1.0/max(0.75 + dist*0.25 + dist*dist*0.05, 0.001), 1.0);\n"
        "\n"
        "\n"
        "        float diff = max(dot(sn, ld), 0.); // Diffuse light value.\n"
        "        float spec = pow(max(dot(reflect(-ld, sn), -rd), 0.), 16.); // Specular highlighting.\n"
        "        // Adding some fake, reflective environment information.\n"
        "        float ref = Voronesque((sp + reflect(rd, sn)*0.5)*2.5);\n"
        "\n"
        "        // Coloring the surface with the Voronesque function that is used to bump the surface. See \"bump mapping\" above.\n"
        "        vec3 objCol = vec3(min(c*1.5, 1.), pow(c, 2.5), pow(c, 12.)); // Cheap, but effective, red palette.\n"
        "        //vec3 objCol = vec3(c*c*0.9, c, c*c*0.4); // Cheap green palette.\n"
        "        //vec3 objCol = vec3(pow(c, 1.6), pow(c, 1.7), c); // Purpley blue.\n"
        "        //vec3 objCol = vec3(c); // Grey scale.\n"
        "\n"
        "        // Using the values above to produce the final color.\n"
        "        //col = (objCol*(diff + ref*0.25 + 0.25) + vec3(1., 0.8, 0.9)*ref*0.25 + spec*vec3(0.75, 0.9, 1.))*atten;\n"
        "        col = (objCol*(vec3(1.0, 0.97, 0.92)*diff + ref*0.5 + 0.25) + vec3(1., 0.8, 0.9)*ref*0.3 + vec3(1., 0.9, 0.7)*spec)*atten;\n"
        "        //col = ((vec3(1.0, 0.97, 0.92)*diff + ref*0.5 + 0.25)*c + vec3(1., 0.8, 0.9)*ref*0.3 + vec3(0.75, 0.9, 1.)*spec)*atten;\n"
        "\n"
        "\n"
        "    //}\n"
        "\n"
        "    fragColor = vec4(min(col, 1.), 1.);\n"
        "}\n"
        "\n"
     );

     n->create_file("ShaderToy/VoxelPacMan.glsl",
        "// https://www.shadertoy.com/view/MlfGR4\n"
        "\n"
        "///////////////////////////////////////////////////////////////////////////////\n"
        "//                                                                           //\n"
        "//  GGGG IIIII  AAA  N   N TTTTT     PPPP   AAA   CCCC     M   M  AAA  N   N //\n"
        "// G       I   A   A NN  N   T       P   P A   A C         MM MM A   A NN  N //\n"
        "// G  GG   I   AAAAA N N N   T       PPPP  AAAAA C     --- M M M AAAAA N N N //\n"
        "// G   G   I   A   A N  NN   T       P     A   A C         M   M A   A N  NN //\n"
        "//  GGGG IIIII A   A N   N   T       P     A   A  CCCC     M   M A   A N   N //\n"
        "//                                                                           //\n"
        "///////////////////////////////////////////////////////////////////////////////\n"
        "\n"
        "// Parameters\n"
        "#define VOXEL_RESOLUTION    1.5\n"
        "#define VOXEL_LIGHTING\n"
        "#define SHADOW\n"
        "#define GROUND\n"
        "#define GHOST\n"
        "#define MOUSE\n"
        "#define HSV2RGB_FAST\n"
        "\n"
        "#define CAMERA_FOCAL_LENGTH    2.0\n"
        "#define DELTA                0.01\n"
        "#define RAY_LENGTH_MAX        500.0\n"
        "#define RAY_STEP_MAX        100.0\n"
        "#define AMBIENT                0.2\n"
        "#define SPECULAR_POWER        2.0\n"
        "#define SPECULAR_INTENSITY    0.3\n"
        "#define SHADOW_LENGTH        150.0\n"
        "#define SHADOW_POWER        3.0\n"
        "#define FADE_POWER            1.0\n"
        "#define BACKGROUND            0.7\n"
        "#define GLOW                0.4\n"
        "#define GAMMA                0.8\n"
        "\n"
        "// Math constants\n"
        "#define PI        3.14159265359\n"
        "#define SQRT3    1.73205080757\n"
        "\n"
        "// Global variable to handle the glow effect\n"
        "float glowCounter;\n"
        "\n"
        "// PRNG (from https://www.shadertoy.com/view/4djSRW)\n"
        "float rand (in vec3 seed) {\n"
        "    seed = fract (seed * vec3 (5.3983, 5.4427, 6.9371));\n"
        "    seed += dot (seed.yzx, seed.xyz + vec3 (21.5351, 14.3137, 15.3219));\n"
        "    return fract (seed.x * seed.y * seed.z * 95.4337);\n"
        "}\n"
        "\n"
        "// Distance to the voxel\n"
        "float distVoxel (in vec3 p) {\n"
        "\n"
        "    // Update the glow counter\n"
        "    ++glowCounter;\n"
        "\n"
        "    // Rounded box\n"
        "    const float voxelRadius = 0.25;\n"
        "    return length (max (abs (p) - 0.5 + voxelRadius, 0.0)) - voxelRadius;\n"
        "}\n"
        "\n"
        "// Distance to the scene and color of the closest point\n"
        "vec2 distScene (in vec3 p, out vec3 P) {\n"
        "\n"
        "    // Update the glow counter\n"
        "    ++glowCounter;\n"
        "\n"
        "    // Scaling\n"
        "    p *= VOXEL_RESOLUTION;\n"
        "\n"
        "    // Velocity, period of the waves, spacing of the gums\n"
        "    float v = VOXEL_RESOLUTION * floor (iTime * 100.0 / VOXEL_RESOLUTION);\n"
        "    const float k1 = 0.05;\n"
        "    const float k2 = 60.0;\n"
        "\n"
        "    // Giant Pac-Man\n"
        "    float body = length (p);\n"
        "    body = max (body - 32.0, 27.0 - body);\n"
        "    float eyes = 6.0 - length (vec3 (abs (p.x) - 12.5, p.y - 19.5, p.z - 20.0));\n"
        "    float mouthAngle = PI * (0.07 + 0.07 * cos (2.0 * v * PI / k2));\n"
        "    float mouthTop = dot (p, vec3 (0.0, -cos (mouthAngle), sin (mouthAngle))) - 2.0;\n"
        "    mouthAngle *= 2.5;\n"
        "    float mouthBottom = dot (p, vec3 (0.0, cos (mouthAngle), sin (mouthAngle)));\n"
        "    float pacMan = max (max (body, eyes), min (mouthTop, mouthBottom));\n"
        "    vec2 d = vec2 (pacMan, 0.13);\n"
        "    P = p;\n"
        "\n"
        "    // Gums\n"
        "    vec3 q = vec3 (p.xy, mod (p.z + v, k2) - k2 * 0.5);\n"
        "    float gum = max (length (q) - 6.0, -p.z);\n"
        "    if (gum < d.x) {\n"
        "        d = vec2 (gum, 0.35);\n"
        "        P = q;\n"
        "    }\n"
        "\n"
        "    // Ground\n"
        "    #ifdef GROUND\n"
        "    q = vec3 (p.xy, p.z + v);\n"
        "    float ground = (q.y + 50.0 + 14.0 * cos (q.x * k1) * cos (q.z * k1)) * 0.7;\n"
        "    if (ground < d.x) {\n"
        "        d = vec2 (ground, 0.55);\n"
        "        P = q;\n"
        "    }\n"
        "    #endif\n"
        "\n"
        "    // Ghost\n"
        "    #ifdef GHOST\n"
        "    v = VOXEL_RESOLUTION * floor ((130.0 + 60.0 * cos (iTime * 3.0)) / VOXEL_RESOLUTION);\n"
        "    q = vec3 (p.xy, p.z + v);\n"
        "    body = length (vec3 (q.x, max (q.y - 4.0, 0.0), q.z));\n"
        "    body = max (body - 28.0, 22.0 - body);\n"
        "    eyes = 8.0 - length (vec3 (abs (q.x) - 12.0, q.y - 10.0, q.z - 22.0));\n"
        "    float bottom = (q.y + 28.0 + 4.0 * cos (p.x * 0.4) * cos (p.z * 0.4)) * 0.7;\n"
        "    float ghost = max (max (body, eyes), -bottom);\n"
        "    if (ghost < d.x) {\n"
        "        d = vec2 (ghost, 0.76);\n"
        "        P = q;\n"
        "    }\n"
        "    #endif\n"
        "\n"
        "    // Scaling\n"
        "    d.x /= VOXEL_RESOLUTION;\n"
        "    return d;\n"
        "}\n"
        "\n"
        "// Distance to the (voxelized?) scene\n"
        "vec4 dist (inout vec3 p, in vec3 ray, in float voxelized, in float rayLengthMax) {\n"
        "    vec3 P = p;\n"
        "    vec2 d = vec2 (1.0 / 0.0, 0.0);\n"
        "    float rayLength = 0.0;\n"
        "    float rayLengthInVoxel = 0.0;\n"
        "    float rayLengthCheckVoxel = 0.0;\n"
        "    vec3 raySign = sign (ray);\n"
        "    vec3 rayDeltaVoxel = raySign / ray;\n"
        "    for (float rayStep = 0.0; rayStep < RAY_STEP_MAX; ++rayStep) {\n"
        "        if (rayLength < rayLengthInVoxel) {\n"
        "            d.x = distVoxel (fract (p + 0.5) - 0.5);\n"
        "            if (d.x < DELTA) {\n"
        "                break;\n"
        "            }\n"
        "        } else if (rayLength < rayLengthCheckVoxel) {\n"
        "            vec3 rayDelta = (0.5 - raySign * (fract (p + 0.5) - 0.5)) * rayDeltaVoxel;\n"
        "            float dNext = min (rayDelta.x, min (rayDelta.y, rayDelta.z));\n"
        "            d = distScene (floor (p + 0.5), P);\n"
        "            if (d.x < 0.0) {\n"
        "                rayDelta = rayDeltaVoxel - rayDelta;\n"
        "                d.x = max (rayLengthInVoxel - rayLength, DELTA - min (rayDelta.x, min (rayDelta.y, rayDelta.z)));\n"
        "                rayLengthInVoxel = rayLength + dNext;\n"
        "            } else {\n"
        "                d.x = DELTA + dNext;\n"
        "            }\n"
        "        } else {\n"
        "            d = distScene (p, P);\n"
        "            if (voxelized > 0.5) {\n"
        "                if (d.x < SQRT3 * 0.5) {\n"
        "                    rayLengthCheckVoxel = rayLength + abs (d.x) + SQRT3 * 0.5;\n"
        "                    d.x = max (rayLengthInVoxel - rayLength + DELTA, d.x - SQRT3 * 0.5);\n"
        "                }\n"
        "            } else if (d.x < DELTA) {\n"
        "                break;\n"
        "            }\n"
        "        }\n"
        "        rayLength += d.x;\n"
        "        if (rayLength > rayLengthMax) {\n"
        "            break;\n"
        "        }\n"
        "        p += d.x * ray;\n"
        "    }\n"
        "    return vec4 (d, rayLength, rand (P));\n"
        "}\n"
        "\n"
        "// Normal at a given point\n"
        "vec3 normal (in vec3 p, in float voxelized) {\n"
        "    vec2 h = vec2 (DELTA, -DELTA);\n"
        "    vec3 n;\n"
        "    if (voxelized > 0.5) {\n"
        "        p = fract (p + 0.5) - 0.5;\n"
        "        n = h.xxx * distVoxel (p + h.xxx) +\n"
        "            h.xyy * distVoxel (p + h.xyy) +\n"
        "            h.yxy * distVoxel (p + h.yxy) +\n"
        "            h.yyx * distVoxel (p + h.yyx);\n"
        "    } else {\n"
        "        n = h.xxx * distScene (p + h.xxx, n).x +\n"
        "            h.xyy * distScene (p + h.xyy, n).x +\n"
        "            h.yxy * distScene (p + h.yxy, n).x +\n"
        "            h.yyx * distScene (p + h.yyx, n).x;\n"
        "    }\n"
        "    return normalize (n);\n"
        "}\n"
        "\n"
        "// HSV to RGB\n"
        "vec3 hsv2rgb (in vec3 hsv) {\n"
        "    #ifdef HSV2RGB_SAFE\n"
        "    hsv.yz = clamp (hsv.yz, 0.0, 1.0);\n"
        "    #endif\n"
        "    #ifdef HSV2RGB_FAST\n"
        "    return hsv.z * (1.0 + 0.5 * hsv.y * (cos (2.0 * PI * (hsv.x + vec3 (0.0, 2.0 / 3.0, 1.0 / 3.0))) - 1.0));\n"
        "    #else\n"
        "    return hsv.z * (1.0 + hsv.y * clamp (abs (fract (hsv.x + vec3 (0.0, 2.0 / 3.0, 1.0 / 3.0)) * 6.0 - 3.0) - 2.0, -1.0, 0.0));\n"
        "    #endif\n"
        "}\n"
        "\n"
        "// Main function\n"
        "void mainImage (out vec4 fragColor, in vec2 fragCoord) {\n"
        "\n"
        "    // Get the fragment\n"
        "    vec2 frag = (2.0 * fragCoord.xy - iResolution.xy) / iResolution.y;\n"
        "\n"
        "    // Define the rendering mode\n"
        "    float modeTiming = iTime * 0.234;\n"
        "    float modeAngle = PI * cos (iTime * 0.2);\n"
        "    modeAngle = dot (frag - vec2 (cos (iTime * 2.0), 0.0), vec2 (cos (modeAngle), sin (modeAngle)));\n"
        "    float modeVoxel = step (0.5, fract (modeTiming / (4.0 * PI)));\n"
        "    modeTiming = cos (modeTiming);\n"
        "    float mode3D = smoothstep (0.8, 0.5, modeTiming);\n"
        "    float modeSwitch = smoothstep (0.995, 1.0, modeTiming) + smoothstep (0.02, 0.0, abs (modeAngle)) * (1.0 - modeVoxel);\n"
        "    modeVoxel += step (0.0, modeAngle) * (1.0 - modeVoxel);\n"
        "\n"
        "    // Define the ray corresponding to this fragment\n"
        "    vec3 ray = normalize (vec3 (frag, mix (8.0, CAMERA_FOCAL_LENGTH, mode3D)));\n"
        "\n"
        "    // Compute the orientation of the camera\n"
        "    float yawAngle = PI * (1.2 + 0.2 * cos (iTime * 0.5));\n"
        "    float pitchAngle = PI * (0.1 * cos (iTime * 0.3) - 0.05);\n"
        "    #ifdef MOUSE\n"
        "    yawAngle += 4.0 * PI * iMouse.x / iResolution.x;\n"
        "    pitchAngle += PI * 0.3 * (1.0 - iMouse.y / iResolution.y);\n"
        "    #endif\n"
        "    yawAngle = mix (PI * 1.5, yawAngle, mode3D);\n"
        "    pitchAngle *= mode3D;\n"
        "\n"
        "    float cosYaw = cos (yawAngle);\n"
        "    float sinYaw = sin (yawAngle);\n"
        "    float cosPitch = cos (pitchAngle);\n"
        "    float sinPitch = sin (pitchAngle);\n"
        "\n"
        "    mat3 cameraOrientation;\n"
        "    cameraOrientation [0] = vec3 (cosYaw, 0.0, -sinYaw);\n"
        "    cameraOrientation [1] = vec3 (sinYaw * sinPitch, cosPitch, cosYaw * sinPitch);\n"
        "    cameraOrientation [2] = vec3 (sinYaw * cosPitch, -sinPitch, cosYaw * cosPitch);\n"
        "\n"
        "    ray = cameraOrientation * ray;\n"
        "\n"
        "    // Compute the origin of the ray\n"
        "    float cameraDist = mix (300.0, 95.0 + 50.0 * cos (iTime * 0.8), mode3D);\n"
        "    vec3 origin = (vec3 (0.0, 0.0, 40.0 * sin (iTime * 0.2)) - cameraOrientation [2] * cameraDist) / VOXEL_RESOLUTION;\n"
        "\n"
        "    // Compute the distance to the scene\n"
        "    glowCounter = 0.0;\n"
        "    vec4 d = dist (origin, ray, modeVoxel, RAY_LENGTH_MAX / VOXEL_RESOLUTION);\n"
        "\n"
        "    // Set the background color\n"
        "    vec3 finalColor = hsv2rgb (vec3 (0.2 * ray.y + 0.4 * modeVoxel - 0.37, 1.0, mode3D * BACKGROUND));\n"
        "    vec3 glowColor = GLOW * vec3 (1.0, 0.3, 0.0) * glowCounter / RAY_STEP_MAX;\n"
        "    if (d.x < DELTA) {\n"
        "\n"
        "        // Set the object color\n"
        "        vec3 color = hsv2rgb (vec3 (d.y + 0.1 * d.w * modeVoxel, 0.5 + 0.5 * modeVoxel, 1.0));\n"
        "\n"
        "        // Lighting\n"
        "        vec3 l = normalize (mix (vec3 (1.0, 0.0, 0.0), vec3 (1.25 + cos (iTime * 0.2), 1.0, 1.0), mode3D));\n"
        "        #ifdef VOXEL_LIGHTING\n"
        "        if (modeVoxel > 0.5) {\n"
        "            vec3 n = normal (floor (origin + 0.5), 0.0);\n"
        "            float diffuse = max (0.0, dot (n, l));\n"
        "            float specular = pow (max (0.0, dot (reflect (ray, n), l)), SPECULAR_POWER) * SPECULAR_INTENSITY;\n"
        "            color = (AMBIENT + diffuse) * color + specular;\n"
        "        }\n"
        "        #endif\n"
        "        vec3 n = normal (origin, modeVoxel);\n"
        "        float diffuse = dot (n, l);\n"
        "        float specular;\n"
        "        if (diffuse < 0.0) {\n"
        "            diffuse = 0.0;\n"
        "            specular = 0.0;\n"
        "        } else {\n"
        "            specular = pow (max (0.0, dot (reflect (ray, n), l)), SPECULAR_POWER) * SPECULAR_INTENSITY;\n"
        "            #ifdef SHADOW\n"
        "            origin += n * DELTA * 2.0;\n"
        "            vec4 shadow = dist (origin, l, modeVoxel, SHADOW_LENGTH / VOXEL_RESOLUTION);\n"
        "            if (shadow.x < DELTA) {\n"
        "                shadow.z = pow (min (1.0, shadow.z * VOXEL_RESOLUTION / SHADOW_LENGTH), SHADOW_POWER);\n"
        "                diffuse *= shadow.z;\n"
        "                specular *= shadow.z;\n"
        "            }\n"
        "            #endif\n"
        "        }\n"
        "        color = (AMBIENT + diffuse) * color + specular;\n"
        "\n"
        "        // Fading\n"
        "        float fade = pow (max (0.0, 1.0 - d.z * VOXEL_RESOLUTION / RAY_LENGTH_MAX), FADE_POWER);\n"
        "        finalColor = mix (finalColor, color, fade);\n"
        "    }\n"
        "\n"
        "    // Set the fragment color\n"
        "    finalColor = mix (pow (finalColor, vec3 (GAMMA)) + glowColor, vec3 (1.0), modeSwitch);\n"
        "    fragColor = vec4 (finalColor, 1.0);\n"
        "}\n"
     );

     n->create_file("ShaderToy/Voxels.glsl",
        "// https://www.shadertoy.com/view/4ds3zr\n"
        "// voxels!\n"
        "// @simesgreen\n"
        "\n"
        "// CSG operations\n"
        "float _union(float a, float b)\n"
        "{\n"
        "    return min(a, b);\n"
        "}\n"
        "\n"
        "float intersect(float a, float b)\n"
        "{\n"
        "    return max(a, b);\n"
        "}\n"
        "\n"
        "float diff(float a, float b)\n"
        "{\n"
        "    return max(a, -b);\n"
        "}\n"
        "\n"
        "// primitive functions\n"
        "// these all return the distance to the surface from a given point\n"
        "\n"
        "float plane(vec3 p, vec3 planeN, vec3 planePos)\n"
        "{\n"
        "    return dot(p - planePos, planeN);\n"
        "}\n"
        "\n"
        "float box( vec3 p, vec3 b )\n"
        "{\n"
        "  vec3 d = abs(p) - b;\n"
        "  return min(max(d.x,max(d.y,d.z)),0.0) +\n"
        "         length(max(d,0.0));\n"
        "}\n"
        "\n"
        "float sphere(vec3 p, float r)\n"
        "{\n"
        "    return length(p) - r;\n"
        "}\n"
        "\n"
        "// http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm\n"
        "\n"
        "float sdCone( vec3 p, vec2 c )\n"
        "{\n"
        "    // c must be normalized\n"
        "    float q = length(p.xz);\n"
        "    return dot(c, vec2(q, p.y));\n"
        "}\n"
        "\n"
        "float sdTorus( vec3 p, vec2 t )\n"
        "{\n"
        "  vec2 q = vec2(length(p.xz)-t.x,p.y);\n"
        "  return length(q)-t.y;\n"
        "}\n"
        "\n"
        "// transforms\n"
        "vec3 rotateX(vec3 p, float a)\n"
        "{\n"
        "    float sa = sin(a);\n"
        "    float ca = cos(a);\n"
        "    vec3 r;\n"
        "    r.x = p.x;\n"
        "    r.y = ca*p.y - sa*p.z;\n"
        "    r.z = sa*p.y + ca*p.z;\n"
        "    return r;\n"
        "}\n"
        "\n"
        "vec3 rotateY(vec3 p, float a)\n"
        "{\n"
        "    float sa = sin(a);\n"
        "    float ca = cos(a);\n"
        "    vec3 r;\n"
        "    r.x = ca*p.x + sa*p.z;\n"
        "    r.y = p.y;\n"
        "    r.z = -sa*p.x + ca*p.z;\n"
        "    return r;\n"
        "}\n"
        "\n"
        "// distance to scene\n"
        "float scene(vec3 p)\n"
        "{    \n"
        "    float d;\n"
        "    //d = box(p, vec3(1.0));\n"
        "    //p.z += sin(time)*1.5;\n"
        "    //d = diff( d, sphere(p, sin(time*0.5)*1.5) );\n"
        "    \n"
        "    //d = sphere(p, 1.0);    \n"
        "    d = sphere(p, sin(iTime)*0.5+0.5);\n"
        "\n"
        "    vec3 pr = p - vec3(1.5, 0.0, 0.0);\n"
        "    pr = rotateX(pr, iTime);\n"
        "    pr = rotateY(pr, iTime*0.3);    \n"
        "    d= _union(d, diff(box(pr , vec3(0.6)), sphere(pr, 0.7)) );\n"
        "\n"
        "    //d = _union(d, sdCone(p + vec3(1.5, -0.5, 0.0), vec2(1.0, 0.5)));\n"
        "    pr = p + vec3(1.5, 0.0, 0.0);\n"
        "    pr = rotateX(pr, iTime);\n"
        "    d = _union(d, sdTorus(pr, vec2(0.5, 0.25)));\n"
        "    \n"
        "    d = _union(d, plane(p, vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0)) );\n"
        "    return d;\n"
        "}\n"
        "\n"
        "// calculate scene normal\n"
        "vec3 sceneNormal(vec3 pos )\n"
        "{\n"
        "    float eps = 0.0001;\n"
        "    vec3 n;\n"
        "#if 0\n"
        "    n.x = scene( vec3(pos.x+eps, pos.y, pos.z) ) - scene( vec3(pos.x-eps, pos.y, pos.z) );\n"
        "    n.y = scene( vec3(pos.x, pos.y+eps, pos.z) ) - scene( vec3(pos.x, pos.y-eps, pos.z) );\n"
        "    n.z = scene( vec3(pos.x, pos.y, pos.z+eps) ) - scene( vec3(pos.x, pos.y, pos.z-eps) );\n"
        "#else\n"
        "    float d = scene(pos);\n"
        "    n.x = scene( vec3(pos.x+eps, pos.y, pos.z) ) - d;\n"
        "    n.y = scene( vec3(pos.x, pos.y+eps, pos.z) ) - d;\n"
        "    n.z = scene( vec3(pos.x, pos.y, pos.z+eps) ) - d;\n"
        "#endif\n"
        "    return normalize(n);\n"
        "}\n"
        "\n"
        "// ambient occlusion approximation\n"
        "float ambientOcclusion(vec3 p, vec3 n)\n"
        "{\n"
        "    const int steps = 3;\n"
        "    const float delta = 0.5;\n"
        "\n"
        "    float a = 0.0;\n"
        "    float weight = 1.0;\n"
        "    for(int i=1; i<=steps; i++) {\n"
        "        float d = (float(i) / float(steps)) * delta;\n"
        "        a += weight*(d - scene(p + n*d));\n"
        "        weight *= 0.5;\n"
        "    }\n"
        "    return clamp(1.0 - a, 0.0, 1.0);\n"
        "}\n"
        "\n"
        "// lighting\n"
        "vec3 shade(vec3 pos, vec3 n, vec3 eyePos)\n"
        "{\n"
        "    const vec3 lightPos = vec3(4.0, 3.0, 5.0);\n"
        "    const vec3 color = vec3(1.0, 1.0, 0.0);\n"
        "    const float shininess = 40.0;\n"
        "\n"
        "    vec3 l = normalize(lightPos - pos);\n"
        "    vec3 v = normalize(eyePos - pos);\n"
        "    vec3 h = normalize(v + l);\n"
        "    float diff = dot(n, l);\n"
        "    float spec = max(0.0, pow(dot(n, h), shininess)) * float(diff > 0.0);\n"
        "    diff = max(0.0, diff);\n"
        "    //diff = 0.5+0.5*diff;\n"
        "\n"
        "    float fresnel = pow(1.0 - dot(n, v), 5.0);\n"
        "    float ao = ambientOcclusion(pos, n);\n"
        "\n"
        "//    return vec3(diff);\n"
        "//    return vec3(diff*ao)*color + vec3(spec + fresnel*0.5);\n"
        "    return vec3(diff*ao)*color;    \n"
        "//    return vec3(diff*ao)*color + vec3(spec);\n"
        "//    return vec3(ao);\n"
        "//    return vec3(fresnel);\n"
        "}\n"
        "\n"
        "// trace ray using sphere tracing\n"
        "vec3 trace(vec3 ro, vec3 rd, out bool hit)\n"
        "{\n"
        "    const int maxSteps = 128;\n"
        "    const float hitThreshold = 0.001;\n"
        "    hit = false;\n"
        "    vec3 pos = ro;\n"
        "    vec3 hitPos = ro;\n"
        "\n"
        "    for(int i=0; i<maxSteps; i++)\n"
        "    {\n"
        "        float d = scene(pos);\n"
        "    //d = max(d, 0.000001);\n"
        "        if (d < hitThreshold) {\n"
        "            hit = true;\n"
        "            hitPos = pos;\n"
        "            //return pos;\n"
        "        }\n"
        "        pos += d*rd;\n"
        "    }\n"
        "    return hitPos;\n"
        "}\n"
        "\n"
        "// Amanatides & Woo style voxel traversal\n"
        "const vec3 voxelSize = vec3(0.1); // in world space\n"
        "//const vec3 voxelSize = vec3(0.2);\n"
        "\n"
        "vec3 worldToVoxel(vec3 i)\n"
        "{\n"
        "    return floor(i/voxelSize);\n"
        "}\n"
        "\n"
        "vec3 voxelToWorld(vec3 i)\n"
        "{\n"
        "    return i*voxelSize;    \n"
        "}\n"
        "\n"
        "vec3 voxelTrace(vec3 ro, vec3 rd, out bool hit, out vec3 hitNormal)\n"
        "{\n"
        "    const int maxSteps = 64;\n"
        "    const float isoValue = 0.0;\n"
        "\n"
        "    vec3 voxel = worldToVoxel(ro);\n"
        "    vec3 step = sign(rd);\n"
        "\n"
        "    vec3 nearestVoxel = voxel + vec3(rd.x > 0.0, rd.y > 0.0, rd.z > 0.0);\n"
        "    vec3 tMax = (voxelToWorld(nearestVoxel) - ro) / rd;\n"
        "    vec3 tDelta = voxelSize / abs(rd);\n"
        "\n"
        "    vec3 hitVoxel = voxel;\n"
        "    \n"
        "    hit = false;\n"
        "    float hitT = 0.0;\n"
        "    for(int i=0; i<maxSteps; i++) {\n"
        "        float d = scene(voxelToWorld(voxel));\n"
        "        if (d <= isoValue && !hit) {\n"
        "            hit = true;\n"
        "            hitVoxel = voxel;\n"
        "            //break;\n"
        "        }\n"
        "\n"
        "        if (tMax.x < tMax.y && tMax.x < tMax.z) {\n"
        "            voxel.x += step.x;\n"
        "            tMax.x += tDelta.x;\n"
        "            if (!hit) {\n"
        "                hitNormal = vec3(-step.x, 0.0, 0.0);\n"
        "                hitT = tMax.x;\n"
        "            }\n"
        "        } else if (tMax.y < tMax.z) {\n"
        "            voxel.y += step.y;\n"
        "            tMax.y += tDelta.y;\n"
        "            if (!hit) {\n"
        "                hitNormal = vec3(0.0, -step.y, 0.0);        \n"
        "                hitT = tMax.y;\n"
        "            }\n"
        "        } else {\n"
        "            voxel.z += step.z;\n"
        "            tMax.z += tDelta.z;\n"
        "            if (!hit) {\n"
        "                hitNormal = vec3(0.0, 0.0, -step.z);        \n"
        "                hitT = tMax.z;\n"
        "            }\n"
        "        }\n"
        "\n"
        "#if 0\n"
        "        if ((voxel.x < 0) || (voxel.x >= size.width) ||\n"
        "            (voxel.y < 0) || (voxel.y >= size.height) ||\n"
        "            (voxel.z < 0) || (voxel.z >= size.depth)) {\n"
        "            break;\n"
        "        }\n"
        "#endif    \n"
        "    }\n"
        "\n"
        "    //return voxelToWorld(hitVoxel);\n"
        "    return ro + hitT*rd;\n"
        "}\n"
        "\n"
        "\n"
        "vec3 background(vec3 rd)\n"
        "{\n"
        "     //return mix(vec3(1.0), vec3(0.0), rd.y);\n"
        "     return mix(vec3(1.0, 1.0, 1.0), vec3(0.0, 0.5, 1.0), abs(rd.y));\n"
        "     //return vec3(0.0);\n"
        "}\n"
        "\n"
        "void mainImage( out vec4 fragColor, in vec2 fragCoord )\n"
        "{\n"
        "    vec2 pixel = (fragCoord.xy / iResolution.xy)*2.0-1.0;\n"
        "\n"
        "    // compute ray origin and direction\n"
        "    float asp = iResolution.x / iResolution.y;\n"
        "    vec3 rd = normalize(vec3(asp*pixel.x, pixel.y, -2.0));\n"
        "    vec3 ro = vec3(0.0, 0.0, 4.0);\n"
        "    ro += rd*2.0;\n"
        "        \n"
        "    vec2 mouse = iMouse.xy / iResolution.xy;\n"
        "\n"
        "    vec2 a = vec2(0.0, 0.0);\n"
        "    if (iMouse.x > 0.0) {\n"
        "        a.x = -(1.0 - mouse.y)*1.5;\n"
        "        a.y = 4.5 -(mouse.x-0.5)*3.0;\n"
        "    }\n"
        "    \n"
        "    rd = rotateX(rd, a.x);\n"
        "    ro = rotateX(ro, a.x);\n"
        "        \n"
        "    rd = rotateY(rd, a.y);\n"
        "    ro = rotateY(ro, a.y);\n"
        "\n"
        "    // trace ray\n"
        "    bool hit;\n"
        "    //vec3 pos = trace(ro, rd, hit);\n"
        "    vec3 n;\n"
        "    vec3 pos = voxelTrace(ro, rd, hit, n);\n"
        "\n"
        "    vec3 rgb;\n"
        "    if(hit)\n"
        "    {\n"
        "        // calc normal\n"
        "        //vec3 n = sceneNormal(pos);\n"
        "    \n"
        "        // shade\n"
        "        rgb = shade(pos, n, ro);\n"
        "\n"
        "#if 0\n"
        "        // reflection\n"
        "        vec3 v = normalize(ro - pos);\n"
        "        float fresnel = 0.1 + 0.9*pow(1.0 - dot(n, v), 5.0);\n"
        "\n"
        "        ro = pos + n*0.2; // offset to avoid self-intersection\n"
        "        rd = reflect(-v, n);\n"
        "        //pos = trace(ro, rd, hit);\n"
        "        pos = voxelTrace(ro, rd, hit, n);\n"
        "    \n"
        "        if (hit) {\n"
        "            //vec3 n = sceneNormal(pos);\n"
        "            rgb += shade(pos, n, ro) * vec3(fresnel);\n"
        "        } else {\n"
        "            rgb += background(rd) * vec3(fresnel);\n"
        "        }\n"
        "#endif\n"
        "\n"
        "     } else {\n"
        "        rgb = background(rd);\n"
        "     }\n"
        "\n"
        "    // vignetting\n"
        "    //rgb *= 0.5+0.5*smoothstep(2.0, 0.5, dot(pixel, pixel));\n"
        "\n"
        "    fragColor=vec4(rgb, 1.0);\n"
        "}\n"
     );

}
