{
 "genart": "1.2",
 "id": "squall-line",
 "title": "Squall Line",
 "created": "2026-09-10T00:00:00Z",
 "modified": "2026-09-10T19:52:10.496Z",
 "renderer": {
  "type": "canvas2d",
  "version": "1.x"
 },
 "canvas": {
  "width": 1400,
  "height": 1000
 },
 "parameters": [],
 "colors": [],
 "dataChannels": [
  {
   "name": "cloud1",
   "type": "vector",
   "cols": 400,
   "rows": 300
  },
  {
   "name": "cloud2",
   "type": "vector",
   "cols": 400,
   "rows": 300
  },
  {
   "name": "cloud3",
   "type": "vector",
   "cols": 400,
   "rows": 300
  },
  {
   "name": "cloud4",
   "type": "vector",
   "cols": 400,
   "rows": 300
  },
  {
   "name": "cloud5",
   "type": "vector",
   "cols": 400,
   "rows": 300
  },
  {
   "name": "edge",
   "type": "vector",
   "cols": 400,
   "rows": 300
  },
  {
   "name": "rain1",
   "type": "vector",
   "cols": 400,
   "rows": 300
  },
  {
   "name": "rain2",
   "type": "vector",
   "cols": 400,
   "rows": 300
  },
  {
   "name": "ground1",
   "type": "vector",
   "cols": 400,
   "rows": 300
  },
  {
   "name": "ground2",
   "type": "vector",
   "cols": 400,
   "rows": 300
  }
 ],
 "state": {
  "seed": 4477,
  "params": {},
  "colorPalette": [
   "#2b1a12",
   "#5c3320",
   "#8a5a3c",
   "#c9a982",
   "#ece3d4"
  ]
 },
 "algorithm": "// Squall Line — field generation only. This code makes NO marks.\n// It publishes a tone map and an air-direction map on the ADR 062 data bridge;\n// every line in the picture is drawn by a plugin layer that reads them.\n//\n// The same two rules as the other two plates in the series:\n//   the direction of a hatch = the direction of the air it describes\n//   the density of a hatch   = how far that surface is turned from the light\n//\n// A line squall crossing open ground. The shelf cloud has already come over,\n// so it fills the sky to the top of the sheet and its base runs across the\n// plate as a hard edge — the one hard edge in the series, and hard because a\n// shelf cloud really has one. Rain falls from it in separate shafts. Ahead of\n// the front the rain has not arrived, and the only light in the picture is the\n// strip of bare paper between the cloud base and the horizon on that side.\n// Everything else is graded away from that strip: the cloud is lit from below\n// by it, so the cloud pales toward it and deepens away from it.\nfunction sketch(ctx, state) {\n  var W = state.canvas.width, H = state.canvas.height;\n  var seed = state.seed || 0;\n\n  ctx.fillStyle = state.colorPalette[4];\n  ctx.fillRect(0, 0, W, H);\n\n  var COLS = Math.round(200 * W / 700), ROWS = Math.round(150 * H / 500);\n\n  function rngFrom(a) {\n    return function () {\n      a |= 0; a = a + 0x6D2B79F5 | 0;\n      var t = Math.imul(a ^ a >>> 15, 1 | a);\n      t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;\n      return ((t ^ t >>> 14) >>> 0) / 4294967296;\n    };\n  }\n  var rand = rngFrom(seed * 2654435761 + 12345);\n  var ph = [];\n  for (var i = 0; i < 24; i++) ph.push(rand() * Math.PI * 2);\n\n  /** A lattice of random values, bilinearly sampled, indexed in [0,1] so its\n   *  features are a fixed fraction of the plate and scale with it. Inputs are\n   *  clamped: a sample past the edge returns undefined, which becomes a NaN\n   *  direction, and a NaN direction walks a flow line to a NaN position and\n   *  kills the whole render with an undefined field sample. */\n  function lattice(nx, ny) {\n    var v = new Float32Array(nx * ny);\n    for (var k = 0; k < nx * ny; k++) v[k] = rand() * 2 - 1;\n    return function (u, t) {\n      if (u < 0) u = 0; else if (u > 1) u = 1;\n      if (t < 0) t = 0; else if (t > 1) t = 1;\n      var x = u * (nx - 1), y = t * (ny - 1);\n      var x0 = Math.floor(x), y0 = Math.floor(y);\n      var x1 = x0 + 1 > nx - 1 ? nx - 1 : x0 + 1, y1 = y0 + 1 > ny - 1 ? ny - 1 : y0 + 1;\n      var fx = x - x0, fy = y - y0;\n      fx = fx * fx * (3 - 2 * fx); fy = fy * fy * (3 - 2 * fy);\n      var a = v[y0 * nx + x0], b = v[y0 * nx + x1], c = v[y1 * nx + x0], d = v[y1 * nx + x1];\n      return (a + (b - a) * fx) * (1 - fy) + (c + (d - c) * fx) * fy;\n    };\n  }\n  var mass  = lattice(13, 11);    // the slow turning of the cloud body\n  var sweep = lattice(7, 5);      // and the one broad swing of its hatch\n  var curl  = lattice(37, 29);    // ragged detail on the underside\n  var kink  = lattice(151, 113);  // finer than the spacing between lines\n  var body  = lattice(29, 23);    // the second scale of the cloud's own mass\n  // 🔴 Wide and very short on purpose. Rain has to break up ALONG its fall, not\n  // into blobs: a square-ish lattice cut the curtains into patches and they\n  // read as hanging cloth. Four pixels across and forty down gives streaks.\n  var veil  = lattice(104, 5);    // breaks the rain into separate falls\n  var dith  = [lattice(83, 63), lattice(79, 59), lattice(89, 67), lattice(73, 55)];\n\n  // --- The picture ------------------------------------------------------\n  var hyMid  = 0.822 + rand() * 0.045;          // the horizon, low: this is a sky\n  /** Open ground is not a ruled line. It lifts and falls, and a straight one\n   *  across the foot of the plate reads as a table edge under the weather. */\n  function horizon(u) {\n    return hyMid\n         + 0.011 * Math.sin(u * 2.6 + ph[3])\n         + 0.006 * Math.sin(u * 6.1 + ph[4])\n         + 0.007 * curl(u, 0.92);\n  }\n  // Which side the front came from, and therefore which side the light is on.\n  var side   = rand() < 0.5 ? -1 : 1;\n  var gapU   = side < 0 ? 0.06 + rand() * 0.16 : 0.78 + rand() * 0.16;\n  var cbMid  = 0.44 + rand() * 0.07;            // the cloud base at mid-frame\n  var cbTilt = (0.17 + rand() * 0.15) * -side;  // it lifts toward the light\n  // The nose of the shelf, where the base hangs lowest. A leading edge drawn\n  // as a straight rule cuts the plate in half and reads as a horizon, not as\n  // weather; the arc is what says this thing is coming toward you.\n  var noseU  = 0.22 + rand() * 0.50;\n  var noseA  = 0.075 + rand() * 0.070;\n  var nose2U = 0.10 + rand() * 0.80;\n\n  /** The underside of the shelf. Hard, and tilted so it lifts toward the gap. */\n  function cloudBase(u) {\n    return cbMid + cbTilt * (u - 0.5)\n         + noseA * Math.exp(-Math.pow((u - noseU) * 2.7, 2))\n         + noseA * 0.45 * Math.exp(-Math.pow((u - nose2U) * 6.5, 2))\n         + 0.017 * Math.sin(u * 3.7 + ph[0])\n         + 0.009 * Math.sin(u * 8.9 + ph[1])\n         + 0.014 * curl(u, 0.5);\n  }\n\n  // The rain. Separate shafts, because a squall line does not fall as one\n  // sheet — it falls in falls, and the gaps between them are how you read the\n  // distance into it. Each has a place, a width, and a reach: some get to the\n  // ground and some hang short of it as virga.\n  var SHAFTS = 4 + (rand() < 0.55 ? 1 : 0);\n  var shafts = [];\n  var far = side < 0 ? 1 : 0;                   // the end furthest from the light\n  // The first one is the wall: wide, heavy, and reaching the ground, so that\n  // at the far end the cloud, the rain and the ground are one continuous dark\n  // and the plate reads as a diagonal instead of as three stacked bands. It is\n  // the difference between weather standing over a landscape and weather\n  // arriving across it.\n  shafts.push({\n    u: far + (gapU - far) * (0.02 + 0.10 * rand()),\n    w: 0.11 + rand() * 0.07,\n    reach: 1.45 + rand() * 0.45,\n    wt: 1.0,\n  });\n  for (var q = 1; q < SHAFTS; q++) {\n    var t = (q + 0.22 + rand() * 0.56) / SHAFTS;\n    shafts.push({\n      // Strung out over the first three fifths of the way to the light and\n      // no further. Run right up to it and the falls close the gap off, and\n      // the one passage of bare paper in the plate — the whole of its light —\n      // becomes a few holes between curtains.\n      u: far + (gapU - far) * (0.12 + 0.58 * t),\n      w: 0.042 + rand() * 0.062,\n      reach: 0.88 + rand() * 0.58,                // >1 means it reaches the ground\n      wt: 0.42 + rand() * 0.44,\n    });\n  }\n\n  var cloudTone = new Float32Array(COLS * ROWS);\n  var cloudDir  = new Float32Array(COLS * ROWS);\n  var edgeTone  = new Float32Array(COLS * ROWS);\n  var rainTone  = new Float32Array(COLS * ROWS);\n  var rainDir   = new Float32Array(COLS * ROWS);\n  var groundTone = new Float32Array(COLS * ROWS);\n  var groundDir  = new Float32Array(COLS * ROWS);\n\n  for (var r2 = 0; r2 < ROWS; r2++) {\n    for (var c = 0; c < COLS; c++) {\n      var u = c / (COLS - 1), v = r2 / (ROWS - 1);\n      var idx = r2 * COLS + c;\n      var cb = cloudBase(u);\n      var hy = horizon(u);\n      // How far this column is from the light, 0 at the gap and 1 at the far\n      // end. Every value in the plate is graded on this one number.\n      var away = Math.abs(u - gapU) / Math.max(0.12, Math.max(gapU, 1 - gapU));\n      if (away > 1) away = 1;\n\n      if (v < cb) {\n        // ---- The cloud ------------------------------------------------\n        // Its rolls run parallel to the base, so their direction is the slope\n        // of the base itself. That slope is the only thing setting direction\n        // up here, which is what keeps a sky from turning into wallpaper.\n        var below = (cb - v) / Math.max(0.05, cb);   // 0 at the base, 1 at the top of the sheet\n\n        // Lit from below by the strip of clear sky, so the cloud is palest\n        // just above the gap and deepens away from it and up into the body.\n        // Darkest at the BASE and lifting into the body above it. Graded the\n        // other way the sky is one even weight from the top of the sheet down\n        // and there is nothing for the eye to go to; a storm cloud is heaviest\n        // where its water is, which is where it meets the air underneath.\n        var T = 0.15 + 0.36 * away - 0.11 * below;\n        // The body of it, at the scale of a whole mass rather than of a mark.\n        T += 0.26 * mass(u, v) + 0.13 * body(u, v);\n        // The rolls under the shelf: bands parallel to the base, and only\n        // near it. Run up through the whole sky they read as corduroy.\n        T += 0.085 * Math.sin(below * 11 + ph[2] + u * 1.4) * Math.exp(-below * 4.2);\n        T += 0.075 * curl(u, v);\n        // Where a shaft hangs, the cloud above it is the heaviest part of the\n        // sky — that is where the water is.\n        for (var q2 = 0; q2 < shafts.length; q2++) {\n          var dd = (u - shafts[q2].u) / shafts[q2].w;\n          T += 0.20 * shafts[q2].wt * Math.exp(-dd * dd) * Math.exp(-below * 2.2);\n        }\n        // 🔴 A floor, for the same reason the barley has one. Where there is\n        // cloud there is cloud: a thin place in it is PALER, not a hole. Let\n        // the tone fall through the first threshold and the sky comes out\n        // torn, with hard-edged patches of bare paper punched through a dark\n        // mass. The first pass covers all of the cloud and every lighter and\n        // darker place in the sky is made by which of the LATER passes return.\n        if (T < 0.235) T = 0.235;\n        cloudTone[idx] = T;\n        cloudDir[idx] = 0;                          // set from the form, in the pass below\n\n        // The leading edge. A shelf cloud has a genuinely hard underside and\n        // it is the one hard edge in the series; drawn soft, the whole sky\n        // reads as fog instead of as a front.\n        if (below < 0.055) edgeTone[idx] = 1;\n      } else if (v < hy + 0.055) {\n        // ---- Under the cloud -------------------------------------------\n        // Rain, or the bare paper that is the only light in the plate.\n        var drop = (v - cb) / Math.max(0.02, hy - cb);   // 0 at the base, 1 at the ground\n        // 🔴 The rain runs ON past the horizon and fades out inside the ground\n        // rather than stopping at it. Two masks that merely abut leave a bright\n        // hairline where both interpolate under the magnitude gate — the same\n        // fault the hedge had in Wind in the Barley — and beyond that, rain\n        // standing on ground hides the ground: a fall that stops dead on the\n        // horizon line is a curtain hung in front of the landscape.\n        var past = v > hy ? 1 - (v - hy) / 0.055 : 1;\n        var R = 0;\n        for (var q3 = 0; q3 < shafts.length; q3++) {\n          var sh = shafts[q3];\n          var d2 = (u - sh.u) / sh.w;\n          var across = Math.exp(-d2 * d2);\n          // A fall thins out as it descends, and stops where it stops.\n          var down = drop < sh.reach ? 1 - Math.pow(drop / sh.reach, 2.1) : 0;\n          R += 1.25 * sh.wt * across * down * past;\n        }\n        R *= 0.74 + 0.34 * veil(u, v);               // broken into separate falls\n        R *= 0.42 + 0.58 * away;                     // and thinning toward the light\n        rainTone[idx] = R > 1 ? 1 : R;\n        // Falling, sheared: the wind is stronger aloft, so the rain leans hard\n        // where it leaves the cloud and stands up as it nears the ground. That\n        // curve is the whole reason a squall reads as moving.\n        rainDir[idx] = Math.PI / 2 - side * (0.50 * (1 - drop) + 0.06) + 0.12 * kink(u, v);\n      }\n      if (v >= hy) {\n        // ---- The ground -------------------------------------------------\n        // A strip, level, and dark under the weather but lifting where the\n        // light reaches it.\n        var gz = (v - hy) / Math.max(0.02, 1 - hy);\n        // Wet ground under the weather and dry ground under the light, and\n        // the near edge lifting as it comes forward out of the squall's\n        // shadow. A single flat value here reads as a plinth under the sky.\n        // Ground under a fall is wet ground, and dark: the rain has to land\n        // somewhere, and a squall that stops dead at the horizon is a curtain\n        // hung in front of a landscape rather than weather standing in it.\n        var wet = 0;\n        for (var q4 = 0; q4 < shafts.length; q4++) {\n          var d3 = (u - shafts[q4].u) / (shafts[q4].w * 1.5);\n          wet += shafts[q4].wt * Math.exp(-d3 * d3) * (shafts[q4].reach > 1 ? 1 : 0.35);\n        }\n        if (wet > 1) wet = 1;\n        groundTone[idx] = 0.24 + 0.26 * away + 0.16 * gz + 0.22 * wet\n                        + 0.11 * curl(u, v) + 0.09 * mass(u, v);\n        groundDir[idx] = 0.04 + 0.20 * (u - 0.5) + 0.10 * kink(u, v);\n      }\n    }\n  }\n\n  // --- The direction of the air ----------------------------------------\n  // 🔴 Direction in the cloud is a SYSTEM, not a map of the tone. Taking it\n  // perpendicular to the gradient of the tone map — hatching along the\n  // contours, which is a real way to shade a solid form — turns a lumpy sky\n  // into a topographic survey: contours of a lumpy field are closed loops, so\n  // every lump in the cloud got its own ring of concentric ovals and the plate\n  // read as a brain. Closed cells are the failure mode to stay away from here.\n  //\n  // What carries the form is the VALUE. The direction stays broadly one thing:\n  // the air runs along the front, so the hatch runs with the slope of the\n  // shelf's own base, swinging slowly and by a little. Wide swings make waves\n  // and the sky comes out as corduroy; this is deliberately narrow.\n  for (var ry = 0; ry < ROWS; ry++) {\n    for (var cx = 0; cx < COLS; cx++) {\n      var i2 = ry * COLS + cx;\n      if (cloudTone[i2] === 0) continue;\n      var uu0 = cx / (COLS - 1), vv0 = ry / (ROWS - 1);\n      // 🔴 Measured over a WIDE span. The base carries deliberate fine wobble\n      // so its edge is ragged, and differentiating that over a hundredth of\n      // the width returns the slope of the wobble rather than the slope of the\n      // front — swinging through most of a radian at the wobble's own spatial\n      // frequency. Since this angle is then applied to the whole column of\n      // cloud standing above it, the sky came out ruled with vertical folds\n      // about twenty pixels apart and read as hanging curtain. A wide\n      // difference averages the wobble out and returns the front.\n      var fall = Math.atan((cloudBase(Math.min(1, uu0 + 0.06)) - cloudBase(Math.max(0, uu0 - 0.06))) / 0.12);\n      // The rolls lie along the front where they leave it and flatten out\n      // into the body of the cloud above.\n      var above = 1 - cloudTone[i2] * 0;          // (kept explicit: see below)\n      void above;\n      cloudDir[i2] = fall * (1 - 0.45 * (vv0 < 0.5 ? 1 - vv0 * 2 : 0))\n      // 🔴 The broad swing is kept SMALL and the fine one carries the\n      // variation. A flow line steps along the field, so wherever the\n      // direction converges the lines bunch and lay down a dark seam: a coarse\n      // lattice at any real amplitude ruled the sky with vertical creases\n      // about its own cell width apart and the cloud read as hanging curtain.\n      // Fine variation averages out over a mark instead of steering it.\n                   + 0.12 * sweep(uu0, vv0)\n                   + 0.16 * curl(uu0, vv0)\n                   + 0.26 * kink(uu0, vv0);\n    }\n  }\n\n  // --- Publish ----------------------------------------------------------\n  var g2 = (typeof globalThis !== 'undefined') ? globalThis : window;\n  g2.__genart_data = g2.__genart_data || {};\n  g2.__genart_data.cols = COLS;\n  g2.__genart_data.rows = ROWS;\n\n  function pack(name, mag, ang, skew) {\n    var f32 = new Float32Array(COLS * ROWS * 3);\n    for (var n = 0; n < COLS * ROWS; n++) {\n      var a = ang[n] + (skew || 0);\n      var m = mag[n];\n      if (!isFinite(a)) a = 0;\n      if (!isFinite(m)) m = 0;\n      f32[n * 3] = Math.cos(a);\n      f32[n * 3 + 1] = Math.sin(a);\n      f32[n * 3 + 2] = m;\n    }\n    g2.__genart_data[name] = f32;\n  }\n\n  // Tone is built by returning to the plate, as an engraver builds it. Each\n  // pass covers only what is at least as dark as its threshold and sits a\n  // little off the last, so the sky deepens by crossing. The first pass is not\n  // dithered — it is the cloud's own covering and holes punched through it\n  // show as daylight — and the ones above it are, so a pass frays out instead\n  // of ending on a contour.\n  var CLOUD_TH = [0.20, 0.20, 0.38, 0.53, 0.68];\n  // 🔴 Wide, and much wider than the other two plates in the series. Marks\n  // that all lie within a few degrees of one orientation beat against each\n  // other, and over a whole sky that beat resolves into a regular ripple: the\n  // cloud came out as corrugated iron.\n  //\n  // The first TWO share a threshold. Widening the later passes alone does not\n  // help, because the base pass covers the whole sky on its own and most of\n  // the plate is therefore carrying one orientation and nothing else — the\n  // crossing has to start at the bottom of the stack, not above it. So the\n  // ground tone of the sky is itself two passes laid across each other, and\n  // every value above it is built by returning at another angle again.\n  var CLOUD_SKEW = [0.12, -0.62, 0.70, -0.28, 1.15];\n  for (var p = 0; p < CLOUD_TH.length; p++) {\n    var m1 = new Float32Array(COLS * ROWS);\n    for (var n2 = 0; n2 < COLS * ROWS; n2++) {\n      var uu = (n2 % COLS) / (COLS - 1), vv = Math.floor(n2 / COLS) / (ROWS - 1);\n      var th = p < 2 ? CLOUD_TH[p]\n             : CLOUD_TH[p] + 0.070 * dith[p % 4](uu, vv) + 0.030 * curl(uu, vv);\n      m1[n2] = cloudTone[n2] >= th ? 1 : 0;\n    }\n    pack('cloud' + (p + 1), m1, cloudDir, CLOUD_SKEW[p]);\n  }\n  pack('edge', edgeTone, cloudDir, 0);\n\n  // Two rain passes, gated apart and crossed. A single pass of long parallel\n  // strokes is what rain wants to be and is exactly what aliases into dashes\n  // when the plate is resampled for the page, so the fall is built from short\n  // crossed marks instead.\n  var RAIN_TH = [0.12, 0.34];\n  var RAIN_SKEW = [0.05, -0.21];\n  for (var p2 = 0; p2 < RAIN_TH.length; p2++) {\n    var m2 = new Float32Array(COLS * ROWS);\n    for (var n3 = 0; n3 < COLS * ROWS; n3++) {\n      var uu2 = (n3 % COLS) / (COLS - 1), vv2 = Math.floor(n3 / COLS) / (ROWS - 1);\n      m2[n3] = rainTone[n3] >= RAIN_TH[p2] + 0.090 * dith[p2](uu2, vv2) ? 1 : 0;\n    }\n    pack('rain' + (p2 + 1), m2, rainDir, RAIN_SKEW[p2]);\n  }\n\n  var GROUND_TH = [0.30, 0.56];\n  for (var p3 = 0; p3 < GROUND_TH.length; p3++) {\n    var m3 = new Float32Array(COLS * ROWS);\n    for (var n4 = 0; n4 < COLS * ROWS; n4++) m3[n4] = groundTone[n4] >= GROUND_TH[p3] ? 1 : 0;\n    pack('ground' + (p3 + 1), m3, groundDir, p3 === 0 ? 0.03 : -0.28);\n  }\n}\n",
 "layers": [
  {
   "id": "sheet",
   "type": "textures:paper",
   "name": "Sheet",
   "visible": true,
   "locked": false,
   "opacity": 1,
   "blendMode": "normal",
   "transform": {
    "x": 0,
    "y": 0,
    "width": 1400,
    "height": 1000,
    "rotation": 0,
    "scaleX": 1,
    "scaleY": 1,
    "anchorX": 0,
    "anchorY": 0
   },
   "properties": {
    "preset": "rough",
    "roughness": -1,
    "color": "#ece3d4",
    "seed": 4477
   }
  },
  {
   "id": "cloud-1",
   "type": "painting:flow-lines",
   "name": "Sky Pass 1 — Shelf",
   "visible": true,
   "locked": false,
   "opacity": 1,
   "blendMode": "normal",
   "transform": {
    "x": 105,
    "y": 75,
    "width": 1190,
    "height": 810,
    "rotation": 0,
    "scaleX": 1,
    "scaleY": 1,
    "anchorX": 0,
    "anchorY": 0
   },
   "properties": {
    "field": "algorithm:cloud1",
    "fieldCols": 400,
    "fieldRows": 300,
    "minMagnitude": 0.5,
    "seed": 4490,
    "lineCount": 26000,
    "seedDistribution": "grid-jittered",
    "lineLength": 10,
    "stepSize": 4,
    "lineWeight": 1.16,
    "lineWeightVariation": 0.16,
    "taper": "none",
    "color": "#2b1a12",
    "colorVariation": 0.05,
    "opacity": 0.24,
    "paintMode": "multiply",
    "depthScale": false,
    "horizonY": 0.5,
    "depthWeightRange": "[1.0, 1.0]",
    "depthOpacityRange": "[1.0, 1.0]",
    "maskCenterY": -1,
    "maskSpread": 0.25
   }
  },
  {
   "id": "cloud-2",
   "type": "painting:flow-lines",
   "name": "Sky Pass 2 — Crossing the Shelf",
   "visible": true,
   "locked": false,
   "opacity": 1,
   "blendMode": "normal",
   "transform": {
    "x": 105,
    "y": 75,
    "width": 1190,
    "height": 810,
    "rotation": 0,
    "scaleX": 1,
    "scaleY": 1,
    "anchorX": 0,
    "anchorY": 0
   },
   "properties": {
    "field": "algorithm:cloud2",
    "fieldCols": 400,
    "fieldRows": 300,
    "minMagnitude": 0.5,
    "seed": 4503,
    "lineCount": 24000,
    "seedDistribution": "grid-jittered",
    "lineLength": 9,
    "stepSize": 4,
    "lineWeight": 1.16,
    "lineWeightVariation": 0.16,
    "taper": "none",
    "color": "#2b1a12",
    "colorVariation": 0.05,
    "opacity": 0.24,
    "paintMode": "multiply",
    "depthScale": false,
    "horizonY": 0.5,
    "depthWeightRange": "[1.0, 1.0]",
    "depthOpacityRange": "[1.0, 1.0]",
    "maskCenterY": -1,
    "maskSpread": 0.25
   }
  },
  {
   "id": "cloud-3",
   "type": "painting:flow-lines",
   "name": "Sky Pass 3 — Half Tone",
   "visible": true,
   "locked": false,
   "opacity": 1,
   "blendMode": "normal",
   "transform": {
    "x": 105,
    "y": 75,
    "width": 1190,
    "height": 810,
    "rotation": 0,
    "scaleX": 1,
    "scaleY": 1,
    "anchorX": 0,
    "anchorY": 0
   },
   "properties": {
    "field": "algorithm:cloud3",
    "fieldCols": 400,
    "fieldRows": 300,
    "minMagnitude": 0.5,
    "seed": 4516,
    "lineCount": 22000,
    "seedDistribution": "grid-jittered",
    "lineLength": 8,
    "stepSize": 4,
    "lineWeight": 1.2,
    "lineWeightVariation": 0.16,
    "taper": "none",
    "color": "#2b1a12",
    "colorVariation": 0.05,
    "opacity": 0.29,
    "paintMode": "multiply",
    "depthScale": false,
    "horizonY": 0.5,
    "depthWeightRange": "[1.0, 1.0]",
    "depthOpacityRange": "[1.0, 1.0]",
    "maskCenterY": -1,
    "maskSpread": 0.25
   }
  },
  {
   "id": "cloud-4",
   "type": "painting:flow-lines",
   "name": "Sky Pass 4 — Shadow",
   "visible": true,
   "locked": false,
   "opacity": 1,
   "blendMode": "normal",
   "transform": {
    "x": 105,
    "y": 75,
    "width": 1190,
    "height": 810,
    "rotation": 0,
    "scaleX": 1,
    "scaleY": 1,
    "anchorX": 0,
    "anchorY": 0
   },
   "properties": {
    "field": "algorithm:cloud4",
    "fieldCols": 400,
    "fieldRows": 300,
    "minMagnitude": 0.5,
    "seed": 4529,
    "lineCount": 21000,
    "seedDistribution": "grid-jittered",
    "lineLength": 7,
    "stepSize": 4,
    "lineWeight": 1.32,
    "lineWeightVariation": 0.16,
    "taper": "none",
    "color": "#2b1a12",
    "colorVariation": 0.05,
    "opacity": 0.39,
    "paintMode": "multiply",
    "depthScale": false,
    "horizonY": 0.5,
    "depthWeightRange": "[1.0, 1.0]",
    "depthOpacityRange": "[1.0, 1.0]",
    "maskCenterY": -1,
    "maskSpread": 0.25
   }
  },
  {
   "id": "cloud-5",
   "type": "painting:flow-lines",
   "name": "Sky Pass 5 — Cross, Deepest Only",
   "visible": true,
   "locked": false,
   "opacity": 1,
   "blendMode": "normal",
   "transform": {
    "x": 105,
    "y": 75,
    "width": 1190,
    "height": 810,
    "rotation": 0,
    "scaleX": 1,
    "scaleY": 1,
    "anchorX": 0,
    "anchorY": 0
   },
   "properties": {
    "field": "algorithm:cloud5",
    "fieldCols": 400,
    "fieldRows": 300,
    "minMagnitude": 0.5,
    "seed": 4542,
    "lineCount": 18000,
    "seedDistribution": "grid-jittered",
    "lineLength": 6,
    "stepSize": 4,
    "lineWeight": 1.4,
    "lineWeightVariation": 0.16,
    "taper": "none",
    "color": "#2b1a12",
    "colorVariation": 0.05,
    "opacity": 0.47,
    "paintMode": "multiply",
    "depthScale": false,
    "horizonY": 0.5,
    "depthWeightRange": "[1.0, 1.0]",
    "depthOpacityRange": "[1.0, 1.0]",
    "maskCenterY": -1,
    "maskSpread": 0.25
   }
  },
  {
   "id": "edge",
   "type": "painting:flow-lines",
   "name": "Leading Edge",
   "visible": true,
   "locked": false,
   "opacity": 1,
   "blendMode": "normal",
   "transform": {
    "x": 105,
    "y": 75,
    "width": 1190,
    "height": 810,
    "rotation": 0,
    "scaleX": 1,
    "scaleY": 1,
    "anchorX": 0,
    "anchorY": 0
   },
   "properties": {
    "field": "algorithm:edge",
    "fieldCols": 400,
    "fieldRows": 300,
    "minMagnitude": 0.5,
    "seed": 4548,
    "lineCount": 34000,
    "seedDistribution": "grid-jittered",
    "lineLength": 6,
    "stepSize": 4,
    "lineWeight": 1.36,
    "lineWeightVariation": 0.3,
    "taper": "none",
    "color": "#2b1a12",
    "colorVariation": 0.05,
    "opacity": 0.44,
    "paintMode": "multiply",
    "depthScale": false,
    "horizonY": 0.5,
    "depthWeightRange": "[1.0, 1.0]",
    "depthOpacityRange": "[1.0, 1.0]",
    "maskCenterY": -1,
    "maskSpread": 0.25
   }
  },
  {
   "id": "rain-1",
   "type": "painting:flow-lines",
   "name": "Rain — Curtain",
   "visible": true,
   "locked": false,
   "opacity": 1,
   "blendMode": "normal",
   "transform": {
    "x": 105,
    "y": 75,
    "width": 1190,
    "height": 810,
    "rotation": 0,
    "scaleX": 1,
    "scaleY": 1,
    "anchorX": 0,
    "anchorY": 0
   },
   "properties": {
    "field": "algorithm:rain1",
    "fieldCols": 400,
    "fieldRows": 300,
    "minMagnitude": 0.5,
    "seed": 4566,
    "lineCount": 19000,
    "seedDistribution": "grid-jittered",
    "lineLength": 34,
    "stepSize": 4,
    "lineWeight": 1.04,
    "lineWeightVariation": 0.16,
    "taper": "tail",
    "color": "#2b1a12",
    "colorVariation": 0.05,
    "opacity": 0.27,
    "paintMode": "multiply",
    "depthScale": false,
    "horizonY": 0.5,
    "depthWeightRange": "[1.0, 1.0]",
    "depthOpacityRange": "[1.0, 1.0]",
    "maskCenterY": -1,
    "maskSpread": 0.25
   }
  },
  {
   "id": "rain-2",
   "type": "painting:flow-lines",
   "name": "Rain — Squall, Crossing",
   "visible": true,
   "locked": false,
   "opacity": 1,
   "blendMode": "normal",
   "transform": {
    "x": 105,
    "y": 75,
    "width": 1190,
    "height": 810,
    "rotation": 0,
    "scaleX": 1,
    "scaleY": 1,
    "anchorX": 0,
    "anchorY": 0
   },
   "properties": {
    "field": "algorithm:rain2",
    "fieldCols": 400,
    "fieldRows": 300,
    "minMagnitude": 0.5,
    "seed": 4574,
    "lineCount": 15000,
    "seedDistribution": "grid-jittered",
    "lineLength": 24,
    "stepSize": 4,
    "lineWeight": 1.12,
    "lineWeightVariation": 0.16,
    "taper": "tail",
    "color": "#2b1a12",
    "colorVariation": 0.05,
    "opacity": 0.34,
    "paintMode": "multiply",
    "depthScale": false,
    "horizonY": 0.5,
    "depthWeightRange": "[1.0, 1.0]",
    "depthOpacityRange": "[1.0, 1.0]",
    "maskCenterY": -1,
    "maskSpread": 0.25
   }
  },
  {
   "id": "ground-1",
   "type": "painting:flow-lines",
   "name": "Ground — Level Marks",
   "visible": true,
   "locked": false,
   "opacity": 1,
   "blendMode": "normal",
   "transform": {
    "x": 105,
    "y": 75,
    "width": 1190,
    "height": 810,
    "rotation": 0,
    "scaleX": 1,
    "scaleY": 1,
    "anchorX": 0,
    "anchorY": 0
   },
   "properties": {
    "field": "algorithm:ground1",
    "fieldCols": 400,
    "fieldRows": 300,
    "minMagnitude": 0.5,
    "seed": 4590,
    "lineCount": 9000,
    "seedDistribution": "grid-jittered",
    "lineLength": 9,
    "stepSize": 4,
    "lineWeight": 1.16,
    "lineWeightVariation": 0.28,
    "taper": "none",
    "color": "#2b1a12",
    "colorVariation": 0.05,
    "opacity": 0.3,
    "paintMode": "multiply",
    "depthScale": false,
    "horizonY": 0.5,
    "depthWeightRange": "[1.0, 1.0]",
    "depthOpacityRange": "[1.0, 1.0]",
    "maskCenterY": -1,
    "maskSpread": 0.25
   }
  },
  {
   "id": "ground-2",
   "type": "painting:flow-lines",
   "name": "Ground — Under the Weather",
   "visible": true,
   "locked": false,
   "opacity": 1,
   "blendMode": "normal",
   "transform": {
    "x": 105,
    "y": 75,
    "width": 1190,
    "height": 810,
    "rotation": 0,
    "scaleX": 1,
    "scaleY": 1,
    "anchorX": 0,
    "anchorY": 0
   },
   "properties": {
    "field": "algorithm:ground2",
    "fieldCols": 400,
    "fieldRows": 300,
    "minMagnitude": 0.5,
    "seed": 4604,
    "lineCount": 7000,
    "seedDistribution": "grid-jittered",
    "lineLength": 7,
    "stepSize": 4,
    "lineWeight": 1.28,
    "lineWeightVariation": 0.28,
    "taper": "none",
    "color": "#2b1a12",
    "colorVariation": 0.05,
    "opacity": 0.4,
    "paintMode": "multiply",
    "depthScale": false,
    "horizonY": 0.5,
    "depthWeightRange": "[1.0, 1.0]",
    "depthOpacityRange": "[1.0, 1.0]",
    "maskCenterY": -1,
    "maskSpread": 0.25
   }
  },
  {
   "id": "plate-mark",
   "type": "shapes:rect",
   "name": "Plate Mark",
   "visible": true,
   "locked": false,
   "opacity": 0.55,
   "blendMode": "normal",
   "transform": {
    "x": 105,
    "y": 75,
    "width": 1190,
    "height": 810,
    "rotation": 0,
    "scaleX": 1,
    "scaleY": 1,
    "anchorX": 0,
    "anchorY": 0
   },
   "properties": {
    "fillColor": "#ffffff",
    "fillEnabled": false,
    "strokeColor": "#8a5a3c",
    "strokeWidth": 2,
    "strokeEnabled": true,
    "cornerRadius": 0
   }
  },
  {
   "id": "tone",
   "type": "filter:grain",
   "name": "Plate Tone",
   "visible": true,
   "locked": false,
   "opacity": 1,
   "blendMode": "normal",
   "transform": {
    "x": 0,
    "y": 0,
    "width": 1400,
    "height": 1000,
    "rotation": 0,
    "scaleX": 1,
    "scaleY": 1,
    "anchorX": 0,
    "anchorY": 0
   },
   "properties": {
    "intensity": 0.1,
    "size": 2,
    "seed": 4477,
    "monochrome": true
   }
  }
 ]
}