{"id":1982,"date":"2025-06-03T16:40:52","date_gmt":"2025-06-03T15:40:52","guid":{"rendered":"https:\/\/janxhopkins.com\/?page_id=1982"},"modified":"2025-06-04T09:47:53","modified_gmt":"2025-06-04T08:47:53","slug":"vespidae","status":"publish","type":"page","link":"https:\/\/janxhopkins.com\/index.php\/process\/vespidae\/","title":{"rendered":"vespidae"},"content":{"rendered":"\n<div class=\"wp-block-gutenbergp5-p5js gutenbergp5-align-center\"><iframe srcdoc=\"\n        <!DOCTYPE html&gt;\n        <html&gt;\n            <body style=&quot;padding: 0; margin: 0;&quot;&gt;<\/body&gt;\n            <script src=&quot;https:\/\/janxhopkins.com\/wp-content\/plugins\/easy-p5-js-block\/\/assets\/js\/p5.min.js&quot;&gt;<\/script&gt;\n            <script&gt;\n                let maxDepth = 7; \/\/ Recursion depth\nlet gasketPoints = []; \/\/ Stores unique points\nlet gasketAdjacency = []; \/\/ Adjacency relationships\nlet currentPath = []; \/\/ Current set of edges to draw\nlet currentEdgeIndex = 0; \/\/ Tracks which edge is being drawn\nlet edgesPerBatch = 200; \/\/ Number of edges per batch\nlet drawnEdges = new Set(); \/\/ Tracks drawn edges\nlet totalEdges = 0; \/\/ Total number of edges in the gasket\nlet lastPoint = null; \/\/ Stores the last point of the previous batch\nlet animatingRedLine = false; \/\/ State: Is the red line currently animating?\nlet redLineProgress = 0; \/\/ Progress of the red line animation (0 to 1)\nlet redLineStart = null; \/\/ Start point of the red line\nlet redLineEnd = null; \/\/ End point of the red line\nlet redLineNoiseIntensity = 10; \/\/ Controls the noisiness of the red line\nlet redLineNoiseFrequency = 0.02; \/\/ Controls the frequency of noise for the red line\n\nfunction setup() {\n  createCanvas(600, 600);\n  noFill();\n  strokeWeight(1);\n  \/\/background(240);\n  \/\/ Generate the gasket data\n  let p1 = createVector(width \/ 2, 50);\n  let p2 = createVector(50, height - 50);\n  let p3 = createVector(width - 50, height - 50);\n  generateGasketData(p1, p2, p3, maxDepth);\n\n  \/\/ Calculate the total number of edges\n  totalEdges = gasketAdjacency.reduce((sum, neighbors) =&gt; sum + neighbors.length, 0) \/ 2;\n\n  \/\/ Start the first path\n  startPathFromRandomEdge();\n}\n\nfunction draw() {\n  if (animatingRedLine) {\n    \/\/ Animate the red line\n    drawRedLineAnimation();\n  } else if (currentEdgeIndex < currentPath.length) {\n    \/\/ Draw the current edge\n    let edge = currentPath[currentEdgeIndex];\n    stroke(random(100, 200)); \/\/ Black for edges\n    drawSmoothNoisyLine(gasketPoints[edge[0]], gasketPoints[edge[1]]);\n    currentEdgeIndex++;\n  } else if (drawnEdges.size < totalEdges) {\n    \/\/ Prepare to animate the red line\n    let nextPath = generateNextPath(); \/\/ Preview the next group of edges\n\n    if (lastPoint !== null &amp;&amp; nextPath.length &gt; 0) {\n      let firstPointIndex = nextPath[0][0];\n      let firstPoint = gasketPoints[firstPointIndex];\n\n      \/\/ Set up the red line animation\n      animatingRedLine = true;\n      redLineProgress = 0;\n      redLineStart = lastPoint;\n      redLineEnd = firstPoint;\n\n      \/\/ Update `lastPoint` to the last point of the new group\n      let lastEdge = nextPath[nextPath.length - 1];\n      lastPoint = gasketPoints[lastEdge[1]];\n\n      \/\/ Update `currentPath` to the new group\n      currentPath = nextPath;\n      currentEdgeIndex = 0; \/\/ Reset for the new group\n    }\n  } else {\n    \/\/ Stop the loop when all edges are drawn\n    noLoop();\n\n    \/\/ Confirmation message\n    console.log(&quot;All edges have been drawn!&quot;);\n  }\n}\n\n\/\/ Function to draw a noisy line\nfunction noisyLine(x1, y1, x2, y2, amp, freq) {\n  let p1 = createVector(x1, y1);\n  let p2 = createVector(x2, y2);\n  let line = createVector(p2.x - p1.x, p2.y - p1.y);\n\n  let theta = line.heading() - PI \/ 2;\n  let length = line.mag();\n\n  push();\n  strokeWeight(1);\n  stroke(255, 0, 0, random(100, 200));\n  noFill();\n  translate(p1.x, p1.y);\n  rotate(theta);\n\n  let start = random(1000);\n\n  beginShape();\n  for (let i = 0; i <= length; i++) {\n    let x =\n      amp *\n        (noise(\n          start + freq * cos((2 * PI * i) \/ length),\n          start + freq * sin((2 * PI * i) \/ length)\n        ) -\n          1 \/ 2) -\n      amp * (noise(start + freq, start) - 1 \/ 2);\n    let y = i;\n    vertex(x, y);\n  }\n  endShape();\n\n  pop();\n}\n\nfunction drawRedLineAnimation() {\n  if (redLineProgress < 1) {\n    redLineProgress += 0.02; \/\/ Adjust the speed of animation (smaller is slower)\n\n    let totalLength = dist(redLineStart.x, redLineStart.y, redLineEnd.x, redLineEnd.y);\n    let currentLength = redLineProgress * totalLength;\n\n    let dotSpacing = 10; \/\/ Fixed distance between dots in pixels\n    let steps = floor(currentLength \/ dotSpacing); \/\/ Number of dots to draw\n    let startNoise = 1000; \/\/ Fixed noise seed for consistency\n\n    stroke(205, 100, 100, random(100, 200)); \/\/ Red with fixed alpha\n    strokeWeight(2); \/\/ Ensure thin dots\n\n    for (let i = 0; i <= steps; i++) {\n      let t = i * dotSpacing \/ totalLength; \/\/ Normalize distance to [0, 1]\n      let basePoint = p5.Vector.lerp(redLineStart, redLineEnd, t);\n\n      \/\/ Apply noise to create chaotic motion\n      let noiseX = (noise(startNoise + t * 10) - 0.5) * redLineNoiseIntensity;\n      let noiseY = (noise(startNoise + t * 10 + 100) - 0.5) * redLineNoiseIntensity;\n\n      point(basePoint.x + noiseX, basePoint.y + noiseY); \/\/ Draw the dot\n    }\n  } else {\n    \/\/ Animation is complete\n    animatingRedLine = false;\n    redLineProgress = 0; \/\/ Reset progress for the next animation\n  }\n}\n\n\/\/ Generate the next group of edges without updating `currentPath`\nfunction generateNextPath() {\n  let path = [];\n  let startIndex = floor(random(gasketPoints.length)); \/\/ Random start\n  let visited = new Set(); \/\/ Track visited points\n  let currentIndex = startIndex;\n\n  for (let i = 0; i < edgesPerBatch; i++) {\n    let neighbors = gasketAdjacency[currentIndex]; \/\/ Get neighbors\n    if (!neighbors || neighbors.length === 0) break; \/\/ Stop if no neighbors\n\n    let nextIndex = neighbors.find((n) =&gt; !drawnEdges.has(edgeKey(currentIndex, n)));\n\n    if (nextIndex === undefined) nextIndex = random(neighbors);\n\n    if (nextIndex !== undefined) {\n      let key = edgeKey(currentIndex, nextIndex); \/\/ Unique edge key\n      if (!drawnEdges.has(key)) {\n        path.push([currentIndex, nextIndex]); \/\/ Add edge to the group\n        drawnEdges.add(key); \/\/ Mark edge as drawn\n      }\n      visited.add(currentIndex); \/\/ Mark current point as visited\n      currentIndex = nextIndex; \/\/ Move to next point\n    } else {\n      break; \/\/ Stop if no progress\n    }\n  }\n  return path;\n}\n\n\/\/ Generate the gasket points and adjacency relationships\nfunction generateGasketData(p1, p2, p3, depth) {\n  if (depth === 0) {\n    addEdge(p1, p2);\n    addEdge(p2, p3);\n    addEdge(p3, p1);\n  } else {\n    let mid1 = p5.Vector.add(p1, p2).mult(0.5);\n    let mid2 = p5.Vector.add(p2, p3).mult(0.5);\n    let mid3 = p5.Vector.add(p3, p1).mult(0.5);\n\n    generateGasketData(p1, mid1, mid3, depth - 1);\n    generateGasketData(mid1, p2, mid2, depth - 1);\n    generateGasketData(mid3, mid2, p3, depth - 1);\n  }\n}\n\n\/\/ Add an edge between two points\nfunction addEdge(p1, p2) {\n  let i1 = addPoint(p1);\n  let i2 = addPoint(p2);\n\n  \/\/ Ensure adjacency lists exist\n  if (!gasketAdjacency[i1]) gasketAdjacency[i1] = [];\n  if (!gasketAdjacency[i2]) gasketAdjacency[i2] = [];\n\n  \/\/ Add the connection\n  gasketAdjacency[i1].push(i2);\n  gasketAdjacency[i2].push(i1);\n}\n\n\/\/ Add a point to the list if it doesn't already exist\nfunction addPoint(point) {\n  for (let i = 0; i < gasketPoints.length; i++) {\n    if (gasketPoints[i].equals(point)) {\n      return i; \/\/ Return existing index\n    }\n  }\n  gasketPoints.push(point);\n  return gasketPoints.length - 1; \/\/ Return new index\n}\n\n\/\/ Start a path from a random edge\nfunction startPathFromRandomEdge() {\n  currentPath = [];\n  currentEdgeIndex = 0; \/\/ Reset for new path\n  let startIndex = floor(random(gasketPoints.length));\n  let visited = new Set();\n  let currentIndex = startIndex;\n\n  for (let i = 0; i < edgesPerBatch; i++) {\n    let neighbors = gasketAdjacency[currentIndex];\n    if (!neighbors || neighbors.length === 0) break; \/\/ No neighbors to continue\n\n    let nextIndex = neighbors.find((n) =&gt; !drawnEdges.has(edgeKey(currentIndex, n)));\n\n    \/\/ If no unvisited neighbors, pick any neighbor to keep drawing\n    if (nextIndex === undefined) nextIndex = random(neighbors);\n\n    if (nextIndex !== undefined) {\n      let key = edgeKey(currentIndex, nextIndex);\n      if (!drawnEdges.has(key)) {\n        currentPath.push([currentIndex, nextIndex]);\n        drawnEdges.add(key); \/\/ Mark edge as drawn\n      }\n      visited.add(currentIndex);\n      currentIndex = nextIndex;\n    } else {\n      break; \/\/ Stop if no progress can be made\n    }\n  }\n\n  \/\/ Update lastPoint to the last point in the new batch\n  if (currentPath.length &gt; 0) {\n    let lastEdge = currentPath[currentPath.length - 1];\n    lastPoint = gasketPoints[lastEdge[1]]; \/\/ Last point of the last edge\n  }\n}\n\n\/\/ Draw a smooth noisy line between two points\nfunction drawSmoothNoisyLine(p1, p2) {\n  let segments = 50; \/\/ Number of segments for the noisy line\n  let step = p5.Vector.sub(p2, p1).div(segments);\n  strokeWeight(1);\n  beginShape();\n  for (let i = 0; i <= segments; i++) {\n    let point = p1.copy().add(step.copy().mult(i));\n    let noiseX = (noise(point.x * 0.01, point.y * 0.01) - 0.5) * 8;\n    let noiseY = (noise(point.y * 0.01, point.x * 0.01) - 0.5) * 8;\n    vertex(point.x + noiseX, point.y + noiseY);\n  }\n  endShape();\n}\n\n\/\/ Helper to generate a unique key for an edge\nfunction edgeKey(a, b) {\n  return [min(a, b), max(a, b)].join(&quot;-&quot;);\n}\n            <\/script&gt;\n        <\/html&gt;\" sandbox=\"allow-scripts allow-same-origin\" scrolling=\"no\" style=\"overflow:hidden;\" width=\"\" height=\"\" class=\"\" title=\"p5.js canvas\"><\/iframe><\/div>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><br>tracing the vespidae\u2019s invisible labor, a non-conforming scaffold of fractal paths* their fury constructs a sanctuary, a geometry of care, born from aggression\u2019s raw, determined grace&gt;&gt;&gt;both fortress and cradle&lt;&amp;&gt;a recursive ode to their fierce__ fragile continuum&gt;&gt;bzzt<\/p>\n<\/blockquote>\n\n\n\n<div style=\"height:16px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The vespidae are architects of fractal precision and organic insurgency. Their invisible labor charts a non-conforming scaffold of recursive paths, each line echoing the raw, determined grace of instinct. What might be seen as aggression is, in truth, a geometry of care\u2014anger repurposed as a mechanism for life\u2019s quiet flourishing. The wasps build not from calm intention, but from the unstoppable drive to shelter, nurture, and sustain. Each comb is a cradle and a fortress, each flight an assertion of both defiance and belonging.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I watch their movements, these unseen artisans, and find a model of fierce reciprocity. Their labor is not passive. It is cyclical, voracious, alive with urgency. Their fury becomes a cipher, a code that reveals itself only in the repeating angles and looping paths of the gasket they build. Predation tempers their purpose: what they take fuels what they create. Within their scaffold, every edge is both boundary and threshold, a marker of survival and a testament to continuity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this dance of construction, the vespidae remind me that even the sharpest aggression can be an agent of care. They whisper a lesson of balance: that nurture may be born from fury, and that life\u2019s most tenacious architectures emerge from the spaces where instinct and recursion meet.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>tracing the vespidae\u2019s invisible labor, a non-conforming scaffold of fractal paths* their fury constructs a sanctuary, a geometry of care, born from aggression\u2019s raw, determined grace&gt;&gt;&gt;both fortress and cradle&lt;&amp;&gt;a recursive ode to their fierce__ fragile continuum&gt;&gt;bzzt The vespidae are architects of fractal precision and organic insurgency. Their invisible labor charts a non-conforming scaffold of recursive [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1933,"parent":1948,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","footnotes":""},"class_list":["post-1982","page","type-page","status-publish","has-post-thumbnail","hentry"],"_links":{"self":[{"href":"https:\/\/janxhopkins.com\/index.php\/wp-json\/wp\/v2\/pages\/1982","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/janxhopkins.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/janxhopkins.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/janxhopkins.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/janxhopkins.com\/index.php\/wp-json\/wp\/v2\/comments?post=1982"}],"version-history":[{"count":7,"href":"https:\/\/janxhopkins.com\/index.php\/wp-json\/wp\/v2\/pages\/1982\/revisions"}],"predecessor-version":[{"id":1995,"href":"https:\/\/janxhopkins.com\/index.php\/wp-json\/wp\/v2\/pages\/1982\/revisions\/1995"}],"up":[{"embeddable":true,"href":"https:\/\/janxhopkins.com\/index.php\/wp-json\/wp\/v2\/pages\/1948"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/janxhopkins.com\/index.php\/wp-json\/wp\/v2\/media\/1933"}],"wp:attachment":[{"href":"https:\/\/janxhopkins.com\/index.php\/wp-json\/wp\/v2\/media?parent=1982"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}