Member pages: send readers to the proof, not back to the same video
Marty spotted that a member's page played the angle video and then its button sent readers to /join/<id>?v=<angle> — which is a SQUEEZE step that shows that same video again before anything else. His instinct was to jump straight to /join-now. That fixes the replay but skips the proof layer: the live payout feed, the 2-4-8-16 explainer, the toolkit line and the sponsor card all live on the full invite page. Going from a personal story directly to "connect your wallet and send POL" is a big jump for somebody who arrived cold from a Traffic Desk banner. So the button now drops the ?v= and lands on the full invite page. The existing design already gives exactly the wanted behaviour — the squeeze step is skipped, the proof is kept, and no new parameter was needed. The QR deliberately keeps the angle: a scanned code often reaches someone who never saw the page, off a printout, and the hook video is what they need. Also: payout alerts now name what an upgrade unlocked, on upgrade pass-ups only. Marty noticed the toolkit was never mentioned — the unlock line was wired to `upgraded` events, which are rare next to payouts. On a pass-up the buyer below just climbed, so saying what they unlocked makes the reason for the payment concrete. Entry rewards stay silent: nobody changed level. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+46
-2
@@ -47,6 +47,36 @@ function list(id) {
|
||||
return out;
|
||||
}
|
||||
|
||||
// How many pages a position may HOLD at once, by level (index = level - 1).
|
||||
// This is a different thing from the monthly BUILD quota in suite-meter: builds
|
||||
// are how often you may run the writer, this is how many pages you may keep.
|
||||
// They used to contradict each other — an Ascensus member was allowed 3 builds
|
||||
// a month but every build overwrote the same page, so they could never have
|
||||
// more than one. Anyone who can build a page can now keep several, because the
|
||||
// moment somebody thinks about two different audiences they want two pages.
|
||||
const PAGE_LIMIT = [0, 2, 3, 5, 8, 15, 25, 50];
|
||||
function pageLimit(level) {
|
||||
const lv = Math.max(1, Math.min(8, Number(level) || 1));
|
||||
return PAGE_LIMIT[lv - 1] || 0;
|
||||
}
|
||||
|
||||
// Slug from the headline the writer produced, so the address describes the page
|
||||
// without asking the member to invent one. Falls back to the angle, then to a
|
||||
// short random suffix, and always de-duplicates against what they already hold.
|
||||
function slugFromTitle(id, title, angle) {
|
||||
let base = slugify(title || '');
|
||||
if (base.length < 3) base = slugify(angle || 'page');
|
||||
if (!base) base = 'page';
|
||||
const taken = {};
|
||||
list(id).forEach(function (p) { if (p.slug) taken[p.slug] = 1; });
|
||||
if (!taken[base]) return base;
|
||||
for (let i = 2; i < 40; i++) {
|
||||
const c = slugify(base.slice(0, 20) + '-' + i);
|
||||
if (!taken[c]) return c;
|
||||
}
|
||||
return slugify(base.slice(0, 16) + '-' + Math.floor(Date.now() / 1000).toString(36));
|
||||
}
|
||||
|
||||
// Angles reuse the team's existing hook videos + their landing variant.
|
||||
const ANGLES = {
|
||||
pocket: { label: 'Pocket change', video: '/v/rmc-pocket-change-b403fb2f75.mp4', poster: '/v/rmc-pocket-change-poster.jpg' },
|
||||
@@ -119,6 +149,20 @@ function esc(s) {
|
||||
|
||||
function render(rec) {
|
||||
const a = ANGLES[rec.angle] || ANGLES.overview;
|
||||
// The button and the QR go to DIFFERENT places on purpose.
|
||||
//
|
||||
// `?v=<angle>` is not a normal landing page — it is a SQUEEZE step that hides
|
||||
// everything except the hook video and one button. A reader of this page has
|
||||
// just watched that exact video, so sending them there replayed it before
|
||||
// they could act. Dropping the `?v=` lands them on the full invite page
|
||||
// instead: payout feed, proof, sponsor card, join button. That is the proof
|
||||
// layer, and skipping straight past it to the payment screen would be too big
|
||||
// a jump for someone who arrived cold from an ad.
|
||||
//
|
||||
// The QR keeps the angle, because a scanned code often reaches somebody who
|
||||
// never saw this page — off a printout or a screenshot — and the hook video
|
||||
// is exactly what they need first.
|
||||
const joinLink = 'https://rmcircle.team/join/' + rec.id;
|
||||
const link = 'https://rmcircle.team/join/' + rec.id + (rec.angle && rec.angle !== 'overview' ? '?v=' + rec.angle : '');
|
||||
const who = esc(rec.name || ('Member #' + rec.id));
|
||||
const c = rec.copy || {};
|
||||
@@ -156,7 +200,7 @@ function render(rec) {
|
||||
story +
|
||||
(bullets ? '<ul>' + bullets + '</ul>' : '') +
|
||||
'<div class="cta"><p>' + esc(c.closing || 'Take a look and see what you think.') + '</p>' +
|
||||
'<a class="btn btn-primary" href="' + esc(link) + '">See how it works →</a>' +
|
||||
'<a class="btn btn-primary" href="' + esc(joinLink) + '">Join ' + who + ' →</a>' +
|
||||
'<div class="qr" id="ppQr" data-link="' + esc(link) + '"></div><div class="micro" style="color:var(--muted)">or scan · ' + esc(link.replace(/^https:\/\//, '')) + '</div></div>' +
|
||||
'<div class="foot">Independent team resource shared by an individual member. Participation takes real effort and involves cryptocurrency risk, including risk of total loss. No income is guaranteed. ' +
|
||||
'<a href="/disclaimer" style="color:var(--teal)">Disclaimers</a> · <a href="/contract" style="color:var(--teal)">How the contract works</a></div>' +
|
||||
@@ -166,4 +210,4 @@ function render(rec) {
|
||||
'</body></html>';
|
||||
}
|
||||
|
||||
module.exports = { init, load, save, remove, list, slugify, generate, render, ANGLES, parseSections };
|
||||
module.exports = { init, load, save, remove, list, slugify, slugFromTitle, pageLimit, PAGE_LIMIT, generate, render, ANGLES, parseSections };
|
||||
|
||||
Reference in New Issue
Block a user