Manta Ray Glide
Elasmobranch batoid kinematics capturing the 2D traveling oscillation waves along flexible pectoral wing margins and fluid wake vortex shedding.
60 FPS • Canvas 2D
Click + Drag to interact with field
</>
Full Executable Algorithm Code
132 lines
4711 chars
// 029 - Manta Ray Glide (creatures)
// 1:1 Original algorithm engine source
function createMantaRayGlide() {
const WING_RIBBONS = 36;
const TAIL_NODES = 45;
return {
setup() {
},
render(context, timeState, params) {
const { ctx, width, height } = context;
const speed = Number(params.glideSpeed || 1.1);
const wingSpan = Number(params.wingSpan || 190);
const t = timeState.time * speed;
ctx.fillStyle = "#020409";
ctx.fillRect(0, 0, width, height);
const cx = width * 0.5;
const cy = height * 0.48;
const rotY = Math.sin(t * 0.6) * 0.35;
const rotX = 0.45 + Math.sin(t * 0.8) * 0.22;
const rotZ = Math.sin(t * 0.6) * 0.25;
ctx.save();
ctx.globalCompositeOperation = "screen";
const baseHue = (200 + Math.sin(t * 0.7) * 20) % 360;
for (let r = 0; r < WING_RIBBONS; r++) {
const normR = (r + 1) / WING_RIBBONS;
const curSpan = wingSpan * normR;
const wingFlap = Math.sin(t * 2.8 - normR * 1.6) * (36 * Math.pow(normR, 1.4));
const wingCurl = Math.cos(t * 2.8 - normR * 1.6) * (20 * normR);
const steps = 50;
ctx.beginPath();
let avgDepth = 0;
for (let i = 0; i <= steps; i++) {
const u = i / steps;
const angle = u * Math.PI * 2;
const rawX = Math.sin(angle) * curSpan;
const rawY = -Math.cos(angle) * (65 * normR) + Math.abs(rawX) / curSpan * 25 * normR;
const rawZ = Math.abs(rawX) / curSpan * wingFlap + rawY / 65 * wingCurl;
const p = project3D(rawX, rawY, rawZ, rotX, rotY, rotZ, cx, cy, 460, 520);
avgDepth += p.depth;
if (i === 0) ctx.moveTo(p.x, p.y);
else ctx.lineTo(p.x, p.y);
}
avgDepth /= steps + 1;
const ribbonHue = (baseHue + normR * 32) % 360;
const alpha = (0.05 + normR * 0.32) * avgDepth;
ctx.strokeStyle = hsla(ribbonHue, 95, 68, alpha);
ctx.lineWidth = Math.max(0.8, (normR > 0.88 ? 1.8 : 0.9) * avgDepth);
ctx.stroke();
if (r % 5 === 0) {
ctx.fillStyle = hsla(ribbonHue, 90, 50, 0.035 * avgDepth);
ctx.fill();
}
}
for (let s = -1; s <= 1; s += 2) {
for (let h = 0; h < 6; h++) {
const normH = h / 5;
ctx.beginPath();
const hornSteps = 12;
for (let st = 0; st <= hornSteps; st++) {
const nst = st / hornSteps;
const hx = s * (12 + normH * 10 + nst * 14);
const hy = -50 - nst * 30;
const hz = Math.sin(t * 3.5 + normH * 2 + s + nst * 3) * (8 * nst);
const p = project3D(hx, hy, hz, rotX, rotY, rotZ, cx, cy, 460, 520);
if (st === 0) ctx.moveTo(p.x, p.y);
else ctx.lineTo(p.x, p.y);
}
ctx.strokeStyle = hsla((baseHue + 40) % 360, 95, 75, 0.5);
ctx.lineWidth = 1.2;
ctx.stroke();
}
}
ctx.beginPath();
const tailLen = 185;
for (let n = 0; n <= TAIL_NODES; n++) {
const normN = n / TAIL_NODES;
const tx = Math.sin(t * 3.2 - normN * 5) * (26 * normN);
const ty = 65 + normN * tailLen;
const tz = Math.cos(t * 2.5 - normN * 6) * (32 * normN);
const p = project3D(tx, ty, tz, rotX, rotY, rotZ, cx, cy, 460, 520);
if (n === 0) ctx.moveTo(p.x, p.y);
else ctx.lineTo(p.x, p.y);
}
ctx.strokeStyle = hsla((baseHue + 20) % 360, 95, 80, 0.85);
ctx.lineWidth = 1.6;
ctx.stroke();
ctx.restore();
}
};
}
// Default parameters from content metadata
const defaultParams = [
{
"key": "glideSpeed",
"label": "Gliding Rhythm",
"type": "range",
"min": 0.4,
"max": 2.2,
"step": 0.1,
"defaultValue": 1.1,
"description": "Wing flap oscillation cycle"
},
{
"key": "wingSpan",
"label": "Pectoral Wingspan",
"type": "range",
"min": 100,
"max": 240,
"step": 10,
"defaultValue": 180,
"description": "Hydrodynamic wing tip reach"
}
];
if (!window.__art_instances) window.__art_instances = {};
if (!window.__art_instances['manta-ray-glide']) {
const inst = typeof createMantaRayGlide === 'function' ? createMantaRayGlide() : null;
if (inst && inst.setup) {
inst.setup({ ctx, width, height, dpr: 1, aspectRatio: width / height }, defaultParams);
}
window.__art_instances['manta-ray-glide'] = inst;
}
const instance = window.__art_instances['manta-ray-glide'];
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
medium
Analytical Equation
z(x,y,t)=A(x)sin(kx−ωt)exp(−σ2y2),ptail(s,t)=s+Awsin(ωtt−s⋅kt)
Click to expand
∑
Manta Ray Glide
Full Mathematical System • creatures
100%
Complete System of Equations
[Governing Law][Discrete Progression][Domain & Space][Parameter State]z(x,y,t)=A(x)sin(kx−ωt)exp(−σ2y2),ptail(s,t)=s+Awsin(ωtt−s⋅kt)wingz=A(x)⋅sin(kx−ωt)⋅exp(−y2/σ2),tail=sin(3t−4s)⋅20sx∈R2,t∈R+,ω∈[0,2π]λglideSpeed=1.1(Gliding Rhythm),λwingSpan=180(Pectoral Wingspan)
z(x,y,t)=A(x)sin(kx−ωt)exp(−σ2y2),ptail(s,t)=s+Awsin(ωtt−s⋅kt)
Computational Implementation (JavaScript Engine Equivalent)
wing_z = A(x)*sin(kx - ωt)*exp(-y²/σ²), tail = sin(3t - 4s)*20s Compact Formula
wing_z = A(x)*sin(kx - ωt)*exp(-y²/σ²), tail = sin(3t - 4s)*20s Mathematical Tags
#manta-ray
#ray
#creatures
#hydrodynamics
#wings
#marine
Author: Math Art Core Target: 60 FPS
Press ESC or F to exit