228

Leafy Sea Dragon

Phycodurus eques syngnathid anatomy displaying an armored tubular pipe snout, an Archimedean/logarithmic prehensile tail curl, and undulating leafy camouflage lobes.

Playground
60 FPS Canvas 2D
Click + Drag to interact with field
</>

Full Executable Algorithm Code

// 054 - Leafy Sea Dragon (creatures)
// 1:1 Original algorithm engine source
function createLeafySeaDragon() {
  return {
    setup() {
    },
    render(context, timeState, params) {
      const { ctx, width, height } = context;
      const swellSpeed = Number(params.swellSpeed || 1.1);
      const leafFlutter = Number(params.foliageSway || 1.2);
      const t = timeState.time * swellSpeed;
      ctx.fillStyle = "#020307";
      ctx.fillRect(0, 0, width, height);
      const cx = width * 0.46 + Math.sin(t * 0.4) * (width * 0.04);
      const cy = height * 0.45 + Math.sin(t * 1.4) * 10;
      const dragonScale = Math.min(width, height) / 500;
      ctx.save();
      ctx.translate(cx, cy);
      ctx.globalCompositeOperation = "screen";
      const baseHue = (45 + Math.sin(t * 0.4) * 15) % 360;
      function drawLushLeafAppendage(rootX, rootY, angle, length, phase) {
        const wave = Math.sin(t * 2.8 + phase) * (18 * leafFlutter * dragonScale);
        const tipX = rootX + Math.cos(angle) * length + wave;
        const tipY = rootY + Math.sin(angle) * length + wave;
        for (let str = -1; str <= 1; str++) {
          ctx.beginPath();
          ctx.moveTo(rootX + str * 2, rootY);
          ctx.quadraticCurveTo((rootX + tipX) * 0.5 + wave, (rootY + tipY) * 0.5 - 12, tipX + str * 2, tipY);
          ctx.strokeStyle = hsla(baseHue, 95, 75, str === 0 ? 0.9 : 0.4);
          ctx.lineWidth = str === 0 ? 2.2 * dragonScale : 1;
          ctx.stroke();
        }
        for (let lobe = 1; lobe <= 4; lobe++) {
          const normL = lobe / 4.5;
          const lx = rootX + (tipX - rootX) * normL;
          const ly = rootY + (tipY - rootY) * normL;
          for (let s = -1; s <= 1; s += 2) {
            const lobeAngle = angle + s * 0.85 + Math.sin(t * 3.2 + lobe + s) * 0.25;
            const lobeLen = (22 - lobe * 3.5) * leafFlutter * dragonScale;
            for (let lf = 1; lf <= 4; lf++) {
              const normLF = lf / 4;
              ctx.beginPath();
              ctx.moveTo(lx, ly);
              ctx.quadraticCurveTo(
                lx + Math.cos(lobeAngle) * (lobeLen * normLF),
                ly + Math.sin(lobeAngle) * (lobeLen * normLF),
                lx + Math.cos(lobeAngle + 0.35) * (lobeLen * 0.6 * normLF),
                ly + Math.sin(lobeAngle + 0.35) * (lobeLen * 0.6 * normLF)
              );
              ctx.strokeStyle = hsla(110 + lobe * 12, 90, 65, 0.2 + normLF * 0.6);
              ctx.lineWidth = lf === 4 ? 1.6 : 0.8;
              ctx.stroke();
            }
          }
        }
      }
      ctx.beginPath();
      ctx.moveTo(-50 * dragonScale, -65 * dragonScale);
      ctx.lineTo(-145 * dragonScale, -100 * dragonScale);
      ctx.lineTo(-142 * dragonScale, -90 * dragonScale);
      ctx.lineTo(-45 * dragonScale, -50 * dragonScale);
      ctx.closePath();
      ctx.fillStyle = "rgba(234, 179, 8, 0.4)";
      ctx.fill();
      ctx.strokeStyle = hsla(baseHue, 95, 75, 0.95);
      ctx.lineWidth = 2.4 * dragonScale;
      ctx.stroke();
      ctx.fillStyle = "#0f172a";
      ctx.beginPath();
      ctx.arc(-55 * dragonScale, -60 * dragonScale, 5.5 * dragonScale, 0, Math.PI * 2);
      ctx.fill();
      ctx.strokeStyle = "#38bdf8";
      ctx.lineWidth = 1.6;
      ctx.stroke();
      ctx.fillStyle = "#38bdf8";
      ctx.beginPath();
      ctx.arc(-56 * dragonScale, -61 * dragonScale, 2.5 * dragonScale, 0, Math.PI * 2);
      ctx.fill();
      for (let r = 0; r < 12; r++) {
        const normR = r / 11;
        const rx = -45 * dragonScale + normR * (75 * dragonScale);
        const ry = -50 * dragonScale + Math.sin(normR * Math.PI) * (45 * dragonScale) + normR * (65 * dragonScale);
        ctx.beginPath();
        ctx.ellipse(rx, ry, (16 - normR * 4) * dragonScale, (22 - normR * 4) * dragonScale, normR * 0.5, 0, Math.PI * 2);
        ctx.strokeStyle = hsla(baseHue, 95, 72, 0.6);
        ctx.lineWidth = 1.4;
        ctx.stroke();
        ctx.fillStyle = "#fde047";
        ctx.beginPath();
        ctx.arc(rx, ry - 14 * dragonScale, 2.5 * dragonScale, 0, Math.PI * 2);
        ctx.fill();
      }
      const tailRoots = [25 * dragonScale, 28 * dragonScale, 31 * dragonScale];
      for (let tr = 0; tr < 3; tr++) {
        ctx.beginPath();
        ctx.moveTo(tailRoots[tr], (45 + tr * 3) * dragonScale);
        const tailSteps = 45;
        for (let s = 1; s <= tailSteps; s++) {
          const normS = s / tailSteps;
          const theta = normS * Math.PI * 3.6;
          const r = (55 - tr * 4) * dragonScale * Math.exp(-0.45 * theta);
          const tx = 25 * dragonScale + 35 * dragonScale - Math.cos(theta) * r;
          const ty = 45 * dragonScale + 25 * dragonScale + Math.sin(theta) * r;
          ctx.lineTo(tx, ty);
        }
        ctx.strokeStyle = hsla(baseHue, 95, 75, 0.9 - tr * 0.25);
        ctx.lineWidth = tr === 1 ? 2.6 * dragonScale : 1.2 * dragonScale;
        ctx.stroke();
      }
      drawLushLeafAppendage(-40 * dragonScale, -65 * dragonScale, -Math.PI * 0.7, 75 * dragonScale, 0);
      drawLushLeafAppendage(0, -35 * dragonScale, -Math.PI * 0.42, 92 * dragonScale, 1.2);
      drawLushLeafAppendage(28 * dragonScale, 12 * dragonScale, -Math.PI * 0.22, 105 * dragonScale, 2.4);
      drawLushLeafAppendage(38 * dragonScale, 65 * dragonScale, Math.PI * 0.12, 85 * dragonScale, 3.6);
      ctx.restore();
    }
  };
}

// Default parameters from content metadata
const defaultParams = [
  {
    "key": "swellSpeed",
    "label": "Ocean Swell Rhythm",
    "type": "range",
    "min": 0.4,
    "max": 2.5,
    "step": 0.1,
    "defaultValue": 1.1,
    "description": "Camouflage foliage sway rate"
  },
  {
    "key": "foliageSway",
    "label": "Foliage Lobe Span",
    "type": "range",
    "min": 0.6,
    "max": 1.8,
    "step": 0.1,
    "defaultValue": 1.2,
    "description": "Leafy appendage elongation"
  }
];

if (!window.__art_instances) window.__art_instances = {};
if (!window.__art_instances['leafy-sea-dragon']) {
  const inst = typeof createLeafySeaDragon === 'function' ? createLeafySeaDragon() : null;
  if (inst && inst.setup) {
    inst.setup({ ctx, width, height, dpr: 1, aspectRatio: width / height }, defaultParams);
  }
  window.__art_instances['leafy-sea-dragon'] = inst;
}

const instance = window.__art_instances['leafy-sea-dragon'];
if (instance && instance.render) {
  instance.render(
    { ctx, width, height, dpr: 1, aspectRatio: width / height },
    { time, deltaTime: dt, frameCount: Math.floor(time * 60), fps: 60 },
    defaultParams
  );
}
Edit in Interactive Playground Zero Dependencies • Standalone Canvas 2D
ƒ

Mathematical Formulation

high
Analytical Equation
rtail(θ)=r0ebθ,pleaf(s,t)=pstem(s)+[Assin(ωst+s)Ascos(ωst+s)]r_{\text{tail}}(\theta) = r_0 e^{-b \theta}, \quad \mathbf{p}_{\text{leaf}}(s, t) = \mathbf{p}_{\text{stem}}(s) + \begin{bmatrix} A_s \sin(\omega_s t + s) \\ A_s \cos(\omega_s t + s) \end{bmatrix}
Click to expand
Compact Formula
tail = tail_root + [35 - cos(θ)*r, 25 + sin(θ)*r], r = 55 * exp(-0.45*θ), leaf_sway = sin(2.5t + phase)*14

Mathematical Tags

#sea-dragon #phycodurus #syngnathid #creatures #camouflage #spiral #marine
Author: Math Art Core Target: 60 FPS

Export & Embed: Leafy Sea Dragon

4K PNG Snapshot

High-resolution single frame render

WebM Video (5s Loop)

60 FPS browser-captured stream

Standalone JS Script

Complete executable Canvas 2D algorithm

HTML Iframe Embed

<iframe src="https://art.fazleyrabbi.xyz/embed/leafy-sea-dragon" width="500" height="500" frameborder="0" loading="lazy"></iframe>
ESC
↑↓ Navigate Select
110 Mathematical Artworks
Made by Fazley Rabbi

Support the Project

Keep mathematical creative coding alive & open source

Or via Direct Payoneer ($0 Fee)
Payoneer Customer ID: $0 Fee Direct
24076084

💡 Payoneer app: Go to Pay → Pay to recipient → Enter ID 24076084.

Thank you for supporting generative mathematical animations! ✨