Deploy MEIDNet Studio
Browse files- meidnet/studio/landing.html +2 -1
- site/assets/prism-hero.js +112 -38
meidnet/studio/landing.html
CHANGED
|
@@ -48,7 +48,8 @@ h1.mh .ln{display:block}h1.mh .for{font-weight:700;letter-spacing:-.01em}
|
|
| 48 |
.mol{background:linear-gradient(90deg,#2f6fe4,#8b5cf6);-webkit-background-clip:text;background-clip:text;color:transparent}
|
| 49 |
.mol.mol-on{background:none;color:inherit}.mol.mol-on>span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
|
| 50 |
.mol svg{display:inline-block;height:auto;max-width:100%;overflow:visible}
|
| 51 |
-
.mol-shadow{fill:none;stroke:rgba(30,41,90,.13);stroke-width:.
|
|
|
|
| 52 |
:root[data-theme="dark"] .mol-shadow{stroke:rgba(0,0,0,.45)}
|
| 53 |
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]) .mol-shadow{stroke:rgba(0,0,0,.45)}}
|
| 54 |
.tag{font-size:clamp(16.5px,1.45vw,19px);line-height:1.62;color:var(--muted);margin:0 0 24px;max-width:50ch}
|
|
|
|
| 48 |
.mol{background:linear-gradient(90deg,#2f6fe4,#8b5cf6);-webkit-background-clip:text;background-clip:text;color:transparent}
|
| 49 |
.mol.mol-on{background:none;color:inherit}.mol.mol-on>span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
|
| 50 |
.mol svg{display:inline-block;height:auto;max-width:100%;overflow:visible}
|
| 51 |
+
.mol-shadow{fill:none;stroke:rgba(30,41,90,.13);stroke-width:.13;stroke-linecap:round;stroke-linejoin:round}
|
| 52 |
+
.mol-lat{fill:currentColor;opacity:.16}
|
| 53 |
:root[data-theme="dark"] .mol-shadow{stroke:rgba(0,0,0,.45)}
|
| 54 |
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]) .mol-shadow{stroke:rgba(0,0,0,.45)}}
|
| 55 |
.tag{font-size:clamp(16.5px,1.45vw,19px);line-height:1.62;color:var(--muted);margin:0 0 24px;max-width:50ch}
|
site/assets/prism-hero.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
/* MEIDNet Prism landing page: the
|
| 2 |
No libraries: the lettering is SVG built from stroke glyphs, the scene a small canvas renderer (painter's algorithm).
|
| 3 |
The headline stays real text for search engines and screen readers; without JavaScript it shows as plain text. */
|
| 4 |
(function () {
|
|
@@ -11,10 +11,12 @@
|
|
| 11 |
return !!(window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches);
|
| 12 |
}
|
| 13 |
|
| 14 |
-
/* โโโโโโโโโโโ
|
|
|
|
|
|
|
| 15 |
var ASC = 1.42, DESC = 0.48, PAD = 0.24, GAP = 0.36, U = 0.76; // x-height = 1 unit; U = unit in em
|
| 16 |
|
| 17 |
-
function arc(cx, cy, rx, ry, a0, a1, every) {
|
| 18 |
var n = Math.max(8, Math.ceil(Math.abs(a1 - a0) / 6)), pts = [], beads = [];
|
| 19 |
for (var i = 0; i <= n; i++) {
|
| 20 |
var a = (a0 + (a1 - a0) * i / n) * Math.PI / 180;
|
|
@@ -22,12 +24,12 @@
|
|
| 22 |
}
|
| 23 |
var k = Math.max(1, Math.round(n * every / Math.abs(a1 - a0)));
|
| 24 |
for (var j = 0; j <= n; j += k) beads.push(pts[j]);
|
| 25 |
-
beads.push(pts[n]);
|
| 26 |
return {pts: pts, beads: beads};
|
| 27 |
}
|
| 28 |
function line() { var p = Array.prototype.slice.call(arguments); return {pts: p, beads: p}; }
|
| 29 |
function dot(x, y) { return {pts: [], beads: [[x, y]]}; }
|
| 30 |
-
var ring = function () { return arc(0.5, 0.5, 0.5, 0.5, 0, 360,
|
| 31 |
|
| 32 |
var G = {
|
| 33 |
a: {w: 1.0, s: function () { return [ring(), line([1, 1], [1, 0])]; }},
|
|
@@ -37,13 +39,13 @@
|
|
| 37 |
i: {w: 0.2, s: function () { return [line([0.1, 0], [0.1, 1]), dot(0.1, 1.34)]; }},
|
| 38 |
l: {w: 0.2, s: function () { return [line([0.1, 0], [0.1, 0.71], [0.1, ASC])]; }},
|
| 39 |
m: {w: 1.3, s: function () {
|
| 40 |
-
return [line([0, 0], [0, 1]), arc(0.325, 0.62, 0.325, 0.38, 180, 0,
|
| 41 |
-
arc(0.975, 0.62, 0.325, 0.38, 180, 0,
|
| 42 |
o: {w: 1.0, s: function () { return [arc(0.5, 0.5, 0.5, 0.5, 90, 450, 60)]; }},
|
| 43 |
r: {w: 0.68, s: function () { return [line([0, 0], [0, 1]), arc(0.42, 0.55, 0.42, 0.42, 180, 60, 60)]; }},
|
| 44 |
s: {w: 0.82, s: function () { return [arc(0.41, 0.75, 0.36, 0.25, 20, 270, 85), arc(0.41, 0.25, 0.39, 0.25, 90, -160, 85)]; }},
|
| 45 |
t: {w: 0.72, s: function () { return [line([0.28, 1.32], [0.28, 1], [0.28, 0]), line([0, 1], [0.66, 1])]; }},
|
| 46 |
-
u: {w: 0.92, s: function () { return [line([0, 1], [0, 0.46]), arc(0.46, 0.46, 0.46, 0.46, 180, 360,
|
| 47 |
v: {w: 0.92, s: function () { return [line([0, 1], [0.46, 0], [0.92, 1])]; }},
|
| 48 |
y: {w: 0.92, s: function () { return [line([0, 1], [0.46, 0]), line([0.92, 1], [0.46, 0], [0.24, -0.48])]; }},
|
| 49 |
A: {w: 1.16, s: function () { return [line([0, 0], [0.58, ASC], [1.16, 0]), line([0.25, 0.55], [0.91, 0.55])]; }},
|
|
@@ -51,52 +53,124 @@
|
|
| 51 |
" ": {w: 0.38, s: function () { return []; }}
|
| 52 |
};
|
| 53 |
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
var id = "mol" + (++lettering), x = PAD, paths = [], beads = [];
|
| 57 |
for (var c = 0; c < text.length; c++) {
|
| 58 |
var g = G[text[c]];
|
| 59 |
-
if (!g) return null;
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
st.beads.forEach(function (b) {
|
| 63 |
-
var q = [b[0] + x, b[1]];
|
| 64 |
-
if (!beads.some(function (o) { return Math.hypot(o[0] - q[0], o[1] - q[1]) < 0.06; })) beads.push(q);
|
| 65 |
-
});
|
| 66 |
-
});
|
| 67 |
x += g.w + GAP;
|
| 68 |
}
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
var svg = document.createElementNS(NS, "svg");
|
| 73 |
-
svg.setAttribute("viewBox", "0 0 " +
|
| 74 |
svg.setAttribute("aria-hidden", "true");
|
| 75 |
svg.setAttribute("focusable", "false");
|
| 76 |
-
svg.style.width = (W * U)
|
| 77 |
-
svg.style.verticalAlign = (-(DESC + PAD) * U)
|
| 78 |
svg.innerHTML =
|
| 79 |
-
'<defs><linearGradient id="' + id + 'g" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="' +
|
| 80 |
stops.map(function (s) { return '<stop offset="' + s[0] + '" stop-color="' + s[1] + '"/>'; }).join("") + "</linearGradient>" +
|
| 81 |
'<radialGradient id="' + id + 's" cx=".36" cy=".32" r=".68"><stop offset="0" stop-color="#fff" stop-opacity=".95"/>' +
|
| 82 |
'<stop offset=".38" stop-color="#fff" stop-opacity=".28"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></radialGradient></defs>' +
|
| 83 |
-
|
| 84 |
-
'<path d="' + d + '" fill="none" stroke="url(#' + id + 'g)" stroke-width=".2" stroke-linecap="round" stroke-linejoin="round"/>' +
|
| 85 |
-
'<path d="' + d + '" fill="none" stroke="#fff" stroke-opacity=".45" stroke-width=".05" stroke-linecap="round" stroke-linejoin="round" transform="translate(-.03 -.04)"/>' +
|
| 86 |
-
beads.map(function (b) {
|
| 87 |
-
var cx = b[0].toFixed(3), cy = Y(b[1]);
|
| 88 |
-
return '<circle cx="' + cx + '" cy="' + cy + '" r=".158" fill="url(#' + id + 'g)"/>' +
|
| 89 |
-
'<circle cx="' + cx + '" cy="' + cy + '" r=".158" fill="url(#' + id + 's)"/>';
|
| 90 |
-
}).join("");
|
| 91 |
return svg;
|
| 92 |
}
|
| 93 |
|
| 94 |
-
var
|
| 95 |
-
a: [[0, "#2f6fe4"], [0.45, "#6366f1"], [0.8, "#8b5cf6"], [1, "#a855f7"]],
|
| 96 |
-
b: [[0, "#2563eb"], [0.3, "#0e7490"], [0.55, "#0d9488"], [1, "#10b981"]]
|
| 97 |
};
|
| 98 |
document.querySelectorAll("[data-mol]").forEach(function (span) {
|
| 99 |
-
var
|
|
|
|
| 100 |
if (!svg) return;
|
| 101 |
span.classList.add("mol-on");
|
| 102 |
span.insertBefore(svg, span.firstChild);
|
|
|
|
| 1 |
+
/* MEIDNet Prism landing page: the lettering of the headline (a neural network, a crystal) and the 3D crystal scene of the hero.
|
| 2 |
No libraries: the lettering is SVG built from stroke glyphs, the scene a small canvas renderer (painter's algorithm).
|
| 3 |
The headline stays real text for search engines and screen readers; without JavaScript it shows as plain text. */
|
| 4 |
(function () {
|
|
|
|
| 11 |
return !!(window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches);
|
| 12 |
}
|
| 13 |
|
| 14 |
+
/* โโโโโโโโโโโ the lettering: one glyph skeleton, two renderings โโโโโโโโโโโ
|
| 15 |
+
"neural": nodes at regular spacing along the strokes, thin connections, faint synapses inside each letter
|
| 16 |
+
"crystal": faceted strokes (arcs become polygons), two alternating atom species, glass in closed rings, a lattice behind */
|
| 17 |
var ASC = 1.42, DESC = 0.48, PAD = 0.24, GAP = 0.36, U = 0.76; // x-height = 1 unit; U = unit in em
|
| 18 |
|
| 19 |
+
function arc(cx, cy, rx, ry, a0, a1, every) { // fine points for the curve; vertices every `every` degrees for the facets
|
| 20 |
var n = Math.max(8, Math.ceil(Math.abs(a1 - a0) / 6)), pts = [], beads = [];
|
| 21 |
for (var i = 0; i <= n; i++) {
|
| 22 |
var a = (a0 + (a1 - a0) * i / n) * Math.PI / 180;
|
|
|
|
| 24 |
}
|
| 25 |
var k = Math.max(1, Math.round(n * every / Math.abs(a1 - a0)));
|
| 26 |
for (var j = 0; j <= n; j += k) beads.push(pts[j]);
|
| 27 |
+
if (beads[beads.length - 1] !== pts[n]) beads.push(pts[n]);
|
| 28 |
return {pts: pts, beads: beads};
|
| 29 |
}
|
| 30 |
function line() { var p = Array.prototype.slice.call(arguments); return {pts: p, beads: p}; }
|
| 31 |
function dot(x, y) { return {pts: [], beads: [[x, y]]}; }
|
| 32 |
+
var ring = function () { return arc(0.5, 0.5, 0.5, 0.5, 0, 360, 60); };
|
| 33 |
|
| 34 |
var G = {
|
| 35 |
a: {w: 1.0, s: function () { return [ring(), line([1, 1], [1, 0])]; }},
|
|
|
|
| 39 |
i: {w: 0.2, s: function () { return [line([0.1, 0], [0.1, 1]), dot(0.1, 1.34)]; }},
|
| 40 |
l: {w: 0.2, s: function () { return [line([0.1, 0], [0.1, 0.71], [0.1, ASC])]; }},
|
| 41 |
m: {w: 1.3, s: function () {
|
| 42 |
+
return [line([0, 0], [0, 1]), arc(0.325, 0.62, 0.325, 0.38, 180, 0, 60), line([0.65, 0.62], [0.65, 0]),
|
| 43 |
+
arc(0.975, 0.62, 0.325, 0.38, 180, 0, 60), line([1.3, 0.62], [1.3, 0])]; }},
|
| 44 |
o: {w: 1.0, s: function () { return [arc(0.5, 0.5, 0.5, 0.5, 90, 450, 60)]; }},
|
| 45 |
r: {w: 0.68, s: function () { return [line([0, 0], [0, 1]), arc(0.42, 0.55, 0.42, 0.42, 180, 60, 60)]; }},
|
| 46 |
s: {w: 0.82, s: function () { return [arc(0.41, 0.75, 0.36, 0.25, 20, 270, 85), arc(0.41, 0.25, 0.39, 0.25, 90, -160, 85)]; }},
|
| 47 |
t: {w: 0.72, s: function () { return [line([0.28, 1.32], [0.28, 1], [0.28, 0]), line([0, 1], [0.66, 1])]; }},
|
| 48 |
+
u: {w: 0.92, s: function () { return [line([0, 1], [0, 0.46]), arc(0.46, 0.46, 0.46, 0.46, 180, 360, 60), line([0.92, 1], [0.92, 0])]; }},
|
| 49 |
v: {w: 0.92, s: function () { return [line([0, 1], [0.46, 0], [0.92, 1])]; }},
|
| 50 |
y: {w: 0.92, s: function () { return [line([0, 1], [0.46, 0]), line([0.92, 1], [0.46, 0], [0.24, -0.48])]; }},
|
| 51 |
A: {w: 1.16, s: function () { return [line([0, 0], [0.58, ASC], [1.16, 0]), line([0.25, 0.55], [0.91, 0.55])]; }},
|
|
|
|
| 53 |
" ": {w: 0.38, s: function () { return []; }}
|
| 54 |
};
|
| 55 |
|
| 56 |
+
function layout(text) { // the word's strokes in word coordinates, with the glyph each belongs to
|
| 57 |
+
var x = PAD, strokes = [];
|
|
|
|
| 58 |
for (var c = 0; c < text.length; c++) {
|
| 59 |
var g = G[text[c]];
|
| 60 |
+
if (!g) return null; // a glyph we do not draw: keep the plain text
|
| 61 |
+
var sh = function (p) { return [p[0] + x, p[1]]; };
|
| 62 |
+
g.s().forEach(function (st) { strokes.push({pts: st.pts.map(sh), beads: st.beads.map(sh), glyph: c}); });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
x += g.w + GAP;
|
| 64 |
}
|
| 65 |
+
return {strokes: strokes, W: x - GAP + PAD, H: ASC + DESC + 2 * PAD};
|
| 66 |
+
}
|
| 67 |
+
var near = function (p, q, e) { return Math.hypot(p[0] - q[0], p[1] - q[1]) < e; };
|
| 68 |
+
var f3 = function (v) { return v.toFixed(3); };
|
| 69 |
+
var Y = function (y) { return f3(ASC + PAD - y); };
|
| 70 |
+
var XY = function (p) { return f3(p[0]) + " " + Y(p[1]); };
|
| 71 |
+
|
| 72 |
+
function neural(L, id) {
|
| 73 |
+
var nodes = [], edges = [], syn = [], SP = 0.32;
|
| 74 |
+
function node(p, glyph) {
|
| 75 |
+
for (var i = 0; i < nodes.length; i++) if (near(nodes[i].p, p, 0.12)) return i;
|
| 76 |
+
nodes.push({p: p, glyph: glyph}); return nodes.length - 1;
|
| 77 |
+
}
|
| 78 |
+
L.strokes.forEach(function (st) {
|
| 79 |
+
if (!st.pts.length) { node(st.beads[0], st.glyph); return; }
|
| 80 |
+
var prev = node(st.pts[0], st.glyph), acc = 0;
|
| 81 |
+
for (var i = 1; i < st.pts.length; i++) {
|
| 82 |
+
var a = st.pts[i - 1], b = st.pts[i], seg = Math.hypot(b[0] - a[0], b[1] - a[1]), t = SP - acc;
|
| 83 |
+
while (t <= seg - 1e-9) {
|
| 84 |
+
var n = node([a[0] + (b[0] - a[0]) * t / seg, a[1] + (b[1] - a[1]) * t / seg], st.glyph);
|
| 85 |
+
if (n !== prev) edges.push([prev, n]);
|
| 86 |
+
prev = n; t += SP;
|
| 87 |
+
}
|
| 88 |
+
acc = (acc + seg) % SP;
|
| 89 |
+
}
|
| 90 |
+
var last = node(st.pts[st.pts.length - 1], st.glyph);
|
| 91 |
+
if (last !== prev) edges.push([prev, last]);
|
| 92 |
+
});
|
| 93 |
+
var linked = function (i, j) { return edges.some(function (e) { return (e[0] === i && e[1] === j) || (e[0] === j && e[1] === i); }); };
|
| 94 |
+
nodes.forEach(function (n, i) { // synapses: each node to its nearest unlinked neighbour in the same letter
|
| 95 |
+
nodes.map(function (m, j) { return {j: j, d: Math.hypot(m.p[0] - n.p[0], m.p[1] - n.p[1])}; })
|
| 96 |
+
.filter(function (o) { return o.j > i && nodes[o.j].glyph === n.glyph && o.d > 0.36 && o.d < 0.8 && !linked(i, o.j); })
|
| 97 |
+
.sort(function (u, v) { return u.d - v.d; }).slice(0, 1)
|
| 98 |
+
.forEach(function (o) { syn.push([i, o.j]); });
|
| 99 |
+
});
|
| 100 |
+
var far = []; // between neighbouring letters: the closest pair, like links between layers
|
| 101 |
+
nodes.forEach(function (n, i) { nodes.forEach(function (m, j) {
|
| 102 |
+
if (m.glyph === n.glyph + 1) {
|
| 103 |
+
var d = Math.hypot(m.p[0] - n.p[0], m.p[1] - n.p[1]);
|
| 104 |
+
if (d < 0.9 && (!far[n.glyph] || d < far[n.glyph].d)) far[n.glyph] = {i: i, j: j, d: d};
|
| 105 |
+
}
|
| 106 |
+
}); });
|
| 107 |
+
far.forEach(function (f) { if (f) syn.push([f.i, f.j]); });
|
| 108 |
+
var seg = function (e) { return "M" + XY(nodes[e[0]].p) + "L" + XY(nodes[e[1]].p); };
|
| 109 |
+
return '<path d="' + syn.map(seg).join("") + '" fill="none" stroke="url(#' + id + 'g)" stroke-opacity=".55" stroke-width=".026"/>' +
|
| 110 |
+
'<path d="' + edges.map(seg).join("") + '" fill="none" stroke="url(#' + id + 'g)" stroke-width=".05" stroke-linecap="round"/>' +
|
| 111 |
+
nodes.map(function (n, i) {
|
| 112 |
+
var c = 'cx="' + f3(n.p[0]) + '" cy="' + Y(n.p[1]) + '"', r = 0.088 + 0.03 * ((i * 7919) % 5) / 4; // varied, like neurons
|
| 113 |
+
return '<circle ' + c + ' r="' + f3(r * 1.9) + '" fill="url(#' + id + 'g)" opacity=".13"/>' +
|
| 114 |
+
'<circle ' + c + ' r="' + f3(r) + '" fill="url(#' + id + 'g)"/>' +
|
| 115 |
+
'<circle ' + c + ' r="' + f3(r * 0.42) + '" fill="#fff" opacity=".92"/>';
|
| 116 |
+
}).join("");
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
function crystal(L, id) {
|
| 120 |
+
var atoms = [], bonds = [], glass = [], lat = [];
|
| 121 |
+
function atom(p, big) { // an atom keeps the species it got first: alternating along its stroke
|
| 122 |
+
for (var i = 0; i < atoms.length; i++) if (near(atoms[i].p, p, 0.07)) return atoms[i];
|
| 123 |
+
var a = {p: p, big: big}; atoms.push(a); return a;
|
| 124 |
+
}
|
| 125 |
+
L.strokes.forEach(function (st) {
|
| 126 |
+
var v = st.beads.filter(function (p, i, all) { return i === 0 || !near(p, all[i - 1], 0.02); });
|
| 127 |
+
v.forEach(function (p, i) { atom(p, i % 2 === 0); });
|
| 128 |
+
if (v.length > 1) bonds.push(v);
|
| 129 |
+
if (v.length > 3 && near(v[0], v[v.length - 1], 0.03)) glass.push(v); // a closed ring: a facet
|
| 130 |
+
});
|
| 131 |
+
for (var gx = 0.25; gx < L.W; gx += 0.5) for (var gy = -DESC + 0.1; gy < ASC + 0.1; gy += 0.5) lat.push([gx, gy]);
|
| 132 |
+
var path = function (v) { return "M" + v.map(XY).join("L"); };
|
| 133 |
+
var d = bonds.map(path).join("");
|
| 134 |
+
return '<g class="mol-lat">' + lat.map(function (p) { return '<circle cx="' + f3(p[0]) + '" cy="' + Y(p[1]) + '" r=".022"/>'; }).join("") + "</g>" +
|
| 135 |
+
glass.map(function (v) { return '<path d="' + path(v) + 'Z" fill="url(#' + id + 'g)" fill-opacity=".16" stroke="#fff" stroke-opacity=".55" stroke-width=".02"/>'; }).join("") +
|
| 136 |
+
'<path class="mol-shadow" d="' + d + '" transform="translate(.05 .07)"/>' +
|
| 137 |
+
'<path d="' + d + '" fill="none" stroke="url(#' + id + 'g)" stroke-width=".13" stroke-linecap="round" stroke-linejoin="round"/>' +
|
| 138 |
+
'<path d="' + d + '" fill="none" stroke="#fff" stroke-opacity=".4" stroke-width=".035" stroke-linecap="round" stroke-linejoin="round" transform="translate(-.02 -.03)"/>' +
|
| 139 |
+
atoms.map(function (a) {
|
| 140 |
+
var c = 'cx="' + f3(a.p[0]) + '" cy="' + Y(a.p[1]) + '"', r = a.big ? 0.17 : 0.11;
|
| 141 |
+
return '<circle ' + c + ' r="' + r + '" fill="url(#' + id + 'g)"/>' +
|
| 142 |
+
(a.big ? "" : '<circle ' + c + ' r="' + r + '" fill="#fff" opacity=".5"/>') +
|
| 143 |
+
'<circle ' + c + ' r="' + r + '" fill="url(#' + id + 's)"/>';
|
| 144 |
+
}).join("");
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
var lettering = 0;
|
| 148 |
+
function letteringSvg(text, stops, style) {
|
| 149 |
+
var L = layout(text);
|
| 150 |
+
if (!L) return null;
|
| 151 |
+
var id = "mol" + (++lettering);
|
| 152 |
var svg = document.createElementNS(NS, "svg");
|
| 153 |
+
svg.setAttribute("viewBox", "0 0 " + f3(L.W) + " " + f3(L.H));
|
| 154 |
svg.setAttribute("aria-hidden", "true");
|
| 155 |
svg.setAttribute("focusable", "false");
|
| 156 |
+
svg.style.width = f3(L.W * U) + "em";
|
| 157 |
+
svg.style.verticalAlign = f3(-(DESC + PAD) * U) + "em";
|
| 158 |
svg.innerHTML =
|
| 159 |
+
'<defs><linearGradient id="' + id + 'g" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="' + f3(L.W) + '" y2="0">' +
|
| 160 |
stops.map(function (s) { return '<stop offset="' + s[0] + '" stop-color="' + s[1] + '"/>'; }).join("") + "</linearGradient>" +
|
| 161 |
'<radialGradient id="' + id + 's" cx=".36" cy=".32" r=".68"><stop offset="0" stop-color="#fff" stop-opacity=".95"/>' +
|
| 162 |
'<stop offset=".38" stop-color="#fff" stop-opacity=".28"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></radialGradient></defs>' +
|
| 163 |
+
(style === "crystal" ? crystal(L, id) : neural(L, id));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 164 |
return svg;
|
| 165 |
}
|
| 166 |
|
| 167 |
+
var STYLES = {
|
| 168 |
+
a: {style: "neural", stops: [[0, "#2f6fe4"], [0.45, "#6366f1"], [0.8, "#8b5cf6"], [1, "#a855f7"]]},
|
| 169 |
+
b: {style: "crystal", stops: [[0, "#2563eb"], [0.3, "#0e7490"], [0.55, "#0d9488"], [1, "#10b981"]]}
|
| 170 |
};
|
| 171 |
document.querySelectorAll("[data-mol]").forEach(function (span) {
|
| 172 |
+
var st = STYLES[span.getAttribute("data-mol")] || STYLES.a;
|
| 173 |
+
var svg = letteringSvg(span.textContent.trim(), st.stops, st.style);
|
| 174 |
if (!svg) return;
|
| 175 |
span.classList.add("mol-on");
|
| 176 |
span.insertBefore(svg, span.firstChild);
|