Babu09 commited on
Commit
eeada9e
ยท
verified ยท
1 Parent(s): ef5573e

Deploy MEIDNet Studio

Browse files
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:.15;stroke-linecap:round;stroke-linejoin:round}
 
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 molecular lettering of the headline 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,10 +11,12 @@
11
  return !!(window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches);
12
  }
13
 
14
- /* โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• molecular lettering: bonds along the strokes, atoms at the joints โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• */
 
 
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, 72); };
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, 90), line([0.65, 0.62], [0.65, 0]),
41
- arc(0.975, 0.62, 0.325, 0.38, 180, 0, 90), line([1.3, 0.62], [1.3, 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, 90), line([0.92, 1], [0.92, 0])]; }},
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
- var lettering = 0;
55
- function moleculeSvg(text, stops) {
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; // a glyph we do not draw: keep the plain text
60
- g.s().forEach(function (st) {
61
- if (st.pts.length) paths.push(st.pts.map(function (p) { return [p[0] + x, p[1]]; }));
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
- var W = x - GAP + PAD, H = ASC + DESC + 2 * PAD;
70
- var Y = function (y) { return (ASC + PAD - y).toFixed(3); };
71
- var d = paths.map(function (p) { return "M" + p.map(function (q) { return q[0].toFixed(3) + " " + Y(q[1]); }).join("L"); }).join("");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  var svg = document.createElementNS(NS, "svg");
73
- svg.setAttribute("viewBox", "0 0 " + W.toFixed(3) + " " + H.toFixed(3));
74
  svg.setAttribute("aria-hidden", "true");
75
  svg.setAttribute("focusable", "false");
76
- svg.style.width = (W * U).toFixed(3) + "em";
77
- svg.style.verticalAlign = (-(DESC + PAD) * U).toFixed(3) + "em";
78
  svg.innerHTML =
79
- '<defs><linearGradient id="' + id + 'g" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="' + W.toFixed(2) + '" y2="0">' +
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
- '<path class="mol-shadow" d="' + d + '" transform="translate(.05 .07)"/>' +
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 PALETTES = {
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 svg = moleculeSvg(span.textContent.trim(), PALETTES[span.getAttribute("data-mol")] || PALETTES.a);
 
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);