diff --git a/public/assets/my.js b/public/assets/my.js
index 89c94b6..6c187df 100644
--- a/public/assets/my.js
+++ b/public/assets/my.js
@@ -42,10 +42,10 @@
// achievement badges: the milestone ladder as unlockable medals + share-to-image
const BADGES = [
- { key: 'payouts', label: 'Payouts On', sub: 'wallet linked', emblem: '⚡', icon: ' ' },
- { key: 'firstBuyer', label: 'First Buyer', sub: 'first qualified referral', emblem: '🎯', icon: ' ' },
- { key: 'level2', label: 'Level 2', sub: '2 qualifying buyers', emblem: '⭐', icon: ' ' },
- { key: 'level3', label: 'Level 3', sub: 'fully qualified', emblem: '🏆', icon: ' ' }
+ { key: 'payouts', label: 'Spark', sub: 'payouts on', img: '/badges/badge-spark.jpg' },
+ { key: 'firstBuyer', label: 'Surge', sub: 'first qualifying buyer', img: '/badges/badge-surge.jpg' },
+ { key: 'level2', label: 'Circuit', sub: '2 qualifying buyers', img: '/badges/badge-circuit.jpg' },
+ { key: 'level3', label: 'Nexus', sub: 'fully qualified', img: '/badges/badge-nexus.jpg' }
];
let lastMilestones = [];
function renderBadges(d) {
@@ -57,9 +57,9 @@
strip.innerHTML = BADGES.map(b => {
const got = reached.includes(b.key);
return '
'
- + '
' + b.icon + '
'
+ + '
'
+ '
' + b.label + '
' + b.sub + '
'
- + (got ? '
Share ' : '') + '
';
+ + (got ? 'Share ' : '🔒 locked
') + '';
}).join('');
strip.querySelectorAll('[data-badge]').forEach(btn =>
btn.addEventListener('click', () => shareBadge(btn.dataset.badge, d)));
@@ -71,40 +71,35 @@
}
}
// compose a shareable badge image on a canvas (zero-dep) and download it
+ // composite the ornate badge template with the member's @username on the ribbon
function shareBadge(key, d) {
const b = BADGES.find(x => x.key === key); if (!b) return;
- const c = document.createElement('canvas'); c.width = 1200; c.height = 630;
- const x = c.getContext('2d');
- const g = x.createLinearGradient(0, 0, 1200, 630);
- g.addColorStop(0, '#041109'); g.addColorStop(1, '#0b2018');
- x.fillStyle = g; x.fillRect(0, 0, 1200, 630);
- x.strokeStyle = 'rgba(67,232,195,.5)'; x.lineWidth = 6; x.strokeRect(24, 24, 1152, 582);
- x.fillStyle = '#43e8c3'; x.font = 'bold 34px Sora, sans-serif'; x.fillText('InstantAdPay', 70, 100);
- x.fillStyle = '#8ba69c'; x.font = '22px Sora, sans-serif'; x.fillText('ACHIEVEMENT UNLOCKED', 70, 150);
- // medal with the milestone emblem
- x.beginPath(); x.arc(600, 300, 112, 0, Math.PI * 2);
- const mg = x.createRadialGradient(600, 270, 20, 600, 300, 112);
- mg.addColorStop(0, 'rgba(67,232,195,.5)'); mg.addColorStop(1, 'rgba(9,26,19,.92)');
- x.fillStyle = mg; x.fill(); x.strokeStyle = '#43e8c3'; x.lineWidth = 6; x.stroke();
- x.save(); x.shadowColor = 'rgba(67,232,195,.6)'; x.shadowBlur = 24;
- x.font = '90px "Segoe UI Emoji","Noto Color Emoji",sans-serif'; x.textAlign = 'center'; x.textBaseline = 'middle';
- x.fillText(b.emblem || '', 600, 300); x.restore(); x.textBaseline = 'alphabetic';
- x.fillStyle = '#eef7f3'; x.textAlign = 'center';
- x.font = 'bold 60px Sora, sans-serif'; x.fillText(b.label, 600, 485);
- x.font = '25px Sora, sans-serif'; x.fillStyle = '#8ba69c'; x.fillText(b.sub, 600, 527);
const who = d.username ? '@' + d.username : d.memberId ? 'member #' + d.memberId : '';
- if (who) { x.fillStyle = '#43e8c3'; x.font = 'bold 30px Sora, sans-serif'; x.fillText(who, 600, 575); }
- x.textAlign = 'left';
- try {
- c.toBlob(bl => {
- const a = document.createElement('a');
- a.href = URL.createObjectURL(bl);
- a.download = 'instantadpay-' + key + '-badge.png';
- a.click();
- setTimeout(() => URL.revokeObjectURL(a.href), 5000);
- IAP.status('Badge image saved — share it anywhere.', 'ok');
- }, 'image/png');
- } catch (e) { IAP.status('Could not generate the image.', 'bad'); }
+ const img = new Image();
+ img.onload = () => {
+ const c = document.createElement('canvas'); c.width = img.width; c.height = img.height;
+ const x = c.getContext('2d');
+ x.drawImage(img, 0, 0);
+ if (who) { // the blank ribbon sits at ~76% down; name it in dark ink on the mint banner
+ x.textAlign = 'center';
+ x.fillStyle = '#04231b';
+ x.font = 'bold ' + Math.round(c.width * 0.052) + 'px Sora, "Segoe UI", sans-serif';
+ x.fillText(who, c.width / 2, c.height * 0.78);
+ x.textAlign = 'left';
+ }
+ try {
+ c.toBlob(bl => {
+ const a = document.createElement('a');
+ a.href = URL.createObjectURL(bl);
+ a.download = 'instantadpay-' + b.label.toLowerCase() + '-badge.jpg';
+ a.click();
+ setTimeout(() => URL.revokeObjectURL(a.href), 5000);
+ IAP.status('Your ' + b.label + ' badge is saved — share it anywhere.', 'ok');
+ }, 'image/jpeg', 0.9);
+ } catch (e) { IAP.status('Could not generate the image.', 'bad'); }
+ };
+ img.onerror = () => IAP.status('Could not load the badge art.', 'bad');
+ img.src = b.img; // same-origin, canvas stays untainted
}
// milestone stepper under "Your next move": lit nodes for what's done,
@@ -115,10 +110,10 @@
const b = d.buyerCount || 0;
const steps = [
{ label: 'Joined', sub: 'free account', hit: true },
- { label: 'Payouts on', sub: 'wallet linked', hit: !!d.memberId },
- { label: 'First buyer', sub: '50% of every pack', hit: b >= 1 },
- { label: 'Level 2', sub: '2 buyers · +20%', hit: b >= 2 },
- { label: 'Level 3', sub: '5 buyers · +10%', hit: b >= 5 }
+ { label: 'Spark', sub: 'payouts on', hit: !!d.memberId },
+ { label: 'Surge', sub: 'first buyer · 50%', hit: b >= 1 },
+ { label: 'Circuit', sub: '2 buyers · +20%', hit: b >= 2 },
+ { label: 'Nexus', sub: '5 buyers · +10%', hit: b >= 5 }
];
const cur = steps.findIndex(s => !s.hit);
el.innerHTML = steps.map((s, i) =>
diff --git a/public/assets/site.css b/public/assets/site.css
index 3cc55b6..299ead6 100644
--- a/public/assets/site.css
+++ b/public/assets/site.css
@@ -280,8 +280,10 @@ textarea{resize:vertical;font:inherit}
.feat-strip a:hover{border-color:var(--mint)}
.feat-strip .by{font-size:12px;color:var(--muted);font-weight:500;white-space:nowrap}
/* ── achievement badges ── */
-.badges{display:flex;gap:16px;flex-wrap:wrap;margin-top:12px}
-.badge-a{display:flex;flex-direction:column;align-items:center;gap:8px;width:120px;text-align:center}
+.badges{display:flex;gap:18px;flex-wrap:wrap;margin-top:12px}
+.badge-a{display:flex;flex-direction:column;align-items:center;gap:6px;width:150px;text-align:center}
+.badge-a .badge-img{width:150px;height:150px;border-radius:14px;object-fit:cover;border:1px solid var(--line-strong)}
+.badge-a.locked .badge-img{filter:grayscale(.85) brightness(.5);opacity:.7}
.badge-a .medal{width:76px;height:76px;border-radius:50%;display:grid;place-items:center;position:relative;
background:radial-gradient(circle at 50% 35%,rgba(67,232,195,.28),rgba(9,26,19,.9));
border:2px solid var(--mint);box-shadow:0 0 18px rgba(67,232,195,.3)}
diff --git a/public/badges/badge-circuit.jpg b/public/badges/badge-circuit.jpg
new file mode 100644
index 0000000..b75d43d
Binary files /dev/null and b/public/badges/badge-circuit.jpg differ
diff --git a/public/badges/badge-nexus.jpg b/public/badges/badge-nexus.jpg
new file mode 100644
index 0000000..31ce810
Binary files /dev/null and b/public/badges/badge-nexus.jpg differ
diff --git a/public/badges/badge-spark.jpg b/public/badges/badge-spark.jpg
new file mode 100644
index 0000000..fe3b15c
Binary files /dev/null and b/public/badges/badge-spark.jpg differ
diff --git a/public/badges/badge-surge.jpg b/public/badges/badge-surge.jpg
new file mode 100644
index 0000000..13da958
Binary files /dev/null and b/public/badges/badge-surge.jpg differ
diff --git a/public/contract.html b/public/contract.html
index af86125..0bf7e6d 100644
--- a/public/contract.html
+++ b/public/contract.html
@@ -16,7 +16,7 @@
-
+
@@ -140,8 +140,8 @@
Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never spend what you cannot afford.
-
-
-
+
+
+