Traffic Desk: AI-written text ads alongside banners

Text placements out-perform banners on this network — 357 text ads average
~171 clicks each against ~150 for banners, on far less inventory — so
members can now run them too.

The format is measured, not guessed. Across 60 live text ads: Subject caps
at 20 characters and Body is ALWAYS exactly three <br>-joined lines of at
most 24 characters. Every ad in the sample obeyed it.

Emoji: the NAS columns are latin1, but so is the connection, so UTF-8 bytes
pass through and render — which is how the existing emoji ads got there. The
bridge's clean() would have deleted every emoji via iconv //TRANSLIT//IGNORE,
so text copy now uses clean_ad_text(), which preserves them and strips angle
brackets instead. The bridge builds the <br> separators itself from a lines[]
array, so a member can never inject markup.

The engine writes plain text to a tight budget and we apply emoji ourselves:
models cannot count characters, least of all with emoji, so decoration is
arithmetic we control. It also lets the emoji rotate independently of the
copy. The palette carries no money emoji — the network is full of them, but
implying earnings outranks matching the neighbours.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-08-28 10:19:36 -05:00
parent 931eb4336b
commit d5c9e33e0e
7 changed files with 420 additions and 29 deletions
+28 -5
View File
@@ -29,6 +29,14 @@
.tf-live th{text-align:left;padding:8px 10px;font-size:11px;letter-spacing:1px;text-transform:uppercase;color:var(--muted);border-bottom:2px solid var(--line)}
.tf-live td{padding:9px 10px;border-bottom:1px solid var(--line);color:var(--muted);font-variant-numeric:tabular-nums}
.tf-live td b{color:var(--text)}
.tf-ads{display:grid;grid-template-columns:repeat(auto-fill,minmax(215px,1fr));gap:10px;margin-top:14px}
.tf-ad{border:2px solid var(--line);border-radius:10px;padding:12px 13px;cursor:pointer;
background:var(--bg,#0b1d2e);transition:border-color .12s}
.tf-ad:hover{border-color:var(--muted)}
.tf-ad.on{border-color:var(--gold);background:rgba(212,175,55,.07)}
.tf-ad .s{font-weight:800;font-size:15px;color:var(--gold);line-height:1.25;margin-bottom:5px;word-break:break-word}
.tf-ad .l{font-size:13px;line-height:1.5;color:var(--text);word-break:break-word}
.tf-ad .cnt{margin-top:8px;font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums}
.tf-note{margin-top:22px;font-size:12.5px;color:var(--muted);line-height:1.6;border-top:1px solid var(--line);padding-top:12px}
.spin{display:inline-block;width:13px;height:13px;border:2px solid rgba(255,255,255,.25);border-top-color:var(--gold);
border-radius:50%;animation:sp .8s linear infinite;vertical-align:-2px;margin-right:7px}
@@ -40,7 +48,7 @@
<main class="tw">
<div class="eyebrow" style="color:var(--gold)">CIRCLE SUITE · INCLUDED AT EVERY PAID LEVEL</div>
<h1>Traffic <span class="gold">Desk.</span></h1>
<p class="lede">Put a team banner on our own advertising network, pointed at your invite link. Impressions are included with your position and scale as you level up — nothing to buy, nothing to configure.</p>
<p class="lede">Run a team banner or an AI-written text ad on our own advertising network, pointed at your invite link. Impressions are included with your position and scale as you level up — nothing to buy, nothing to configure.</p>
<div id="tfGate"></div>
@@ -51,10 +59,25 @@
</div>
<div class="tf-card" id="tfCard">
<label class="tf-lab">Banner size</label>
<div class="tf-chips" id="tfSizes"></div>
<label class="tf-lab">Pick a design</label>
<div class="tf-creatives" id="tfCreatives"></div>
<label class="tf-lab">Ad format</label>
<div class="tf-chips" id="tfFormat"></div>
<div id="tfBannerPane">
<label class="tf-lab">Banner size</label>
<div class="tf-chips" id="tfSizes"></div>
<label class="tf-lab">Pick a design</label>
<div class="tf-creatives" id="tfCreatives"></div>
</div>
<div id="tfTextPane" style="display:none">
<label class="tf-lab">What angle should they take?</label>
<div class="tf-chips" id="tfAngles"></div>
<div class="tf-row">
<button id="tfWrite" class="btn btn-secondary">&#9997;&#65039; Write me 5 ads</button>
<span class="tf-hint" id="tfWriteMeter" style="margin:0"></span>
</div>
<div id="tfVariants"></div>
</div>
<label class="tf-lab">Where should it send people?</label>
<div class="tf-chips" id="tfTargets"></div>
<label class="tf-lab" for="tfImp">How many impressions?</label>
+134 -10
View File
@@ -3,7 +3,13 @@
(function () {
'use strict';
var $ = function (id) { return document.getElementById(id); };
var state = { size: null, creative: null, target: 'join', creatives: {}, remaining: 0, id: null };
function esc(s) {
return String(s == null ? '' : s).replace(/[&<>"']/g, function (ch) {
return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[ch];
});
}
var state = { size: null, creative: null, target: 'join', creatives: {}, remaining: 0, id: null,
format: 'banner', angle: 'general', angles: [], variants: [], variant: null, hasPage: false };
var busy = false;
function chip(label, on, fn) {
@@ -63,6 +69,95 @@
}
}
function renderFormat() {
var host = $('tfFormat');
host.innerHTML = '';
[['banner', 'Banner image'], ['text', 'Text ad']].forEach(function (f) {
host.appendChild(chip(f[1], state.format === f[0], function () {
state.format = f[0];
renderFormat();
goLabel();
$('tfBannerPane').style.display = f[0] === 'banner' ? '' : 'none';
$('tfTextPane').style.display = f[0] === 'text' ? '' : 'none';
}));
});
}
function renderAngles() {
var host = $('tfAngles');
host.innerHTML = '';
state.angles.forEach(function (a) {
host.appendChild(chip(a.label, state.angle === a.key, function () {
state.angle = a.key; renderAngles();
}));
});
}
function renderVariants() {
var host = $('tfVariants');
host.innerHTML = '';
if (!state.variants.length) return;
var grid = document.createElement('div');
grid.className = 'tf-ads';
state.variants.forEach(function (v, i) {
var card = document.createElement('div');
card.className = 'tf-ad' + (state.variant === i ? ' on' : '');
var s = document.createElement('div');
s.className = 's'; s.textContent = v.subject;
card.appendChild(s);
v.lines.forEach(function (l) {
if (!l) return;
var d = document.createElement('div');
d.className = 'l'; d.textContent = l;
card.appendChild(d);
});
card.addEventListener('click', function () { state.variant = i; renderVariants(); });
grid.appendChild(card);
});
host.appendChild(grid);
var hint = document.createElement('div');
hint.className = 'tf-hint';
hint.textContent = 'Pick the one you want to run, then set your impressions below and launch it.';
host.appendChild(hint);
}
async function writeAds(btn) {
btn.disabled = true;
btn.innerHTML = '<span class="spin"></span>Writing…';
$('tfErr').style.display = 'none';
try {
var r = await fetch('/api/public/suite-textads', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ angle: state.angle })
});
var d = await r.json();
if (!r.ok) {
$('tfErr').textContent = d.error || 'The writer could not produce ads just now.';
$('tfErr').style.display = 'block';
} else {
state.variants = d.variants || [];
state.variant = state.variants.length ? 0 : null;
renderVariants();
if (d.meter) showWriteMeter(d.meter);
}
} catch (e) {
$('tfErr').textContent = 'Connection hiccup — try again.';
$('tfErr').style.display = 'block';
}
btn.disabled = false;
btn.innerHTML = state.variants.length ? '✍️ Write 5 more' : '✍️ Write me 5 ads';
}
function showWriteMeter(m) {
if (!m) return;
$('tfWriteMeter').textContent = m.remaining + ' of ' + m.limit + ' batches left this month';
}
function goLabel() {
if ($('tfGo').disabled && state.remaining <= 0) return;
$('tfGo').textContent = state.format === 'text' ? '🚦 Launch my text ad' : '🚦 Launch my banner';
}
function gate(msg) {
$('tfGate').style.display = 'block';
$('tfGate').innerHTML = msg;
@@ -83,7 +178,10 @@
var statusCell = c.stopped
? 'stopped <span style="opacity:.7">(' + Number(c.refunded || 0).toLocaleString() + ' returned)</span>'
: (l.live ? '<span style="color:var(--teal)">running</span>' : 'finished');
tr.innerHTML = '<td><b>' + c.size + '</b></td>' +
var label = c.kind === 'text'
? '<b>Text</b><br><span style="font-size:12px">' + esc(c.subject || '') + '</span>'
: '<b>' + c.size + '</b>';
tr.innerHTML = '<td>' + label + '</td>' +
'<td>' + (c.target.indexOf('/p/') !== -1 ? 'personal page' : 'invite page') + '</td>' +
'<td>' + Number(c.bought != null ? c.bought : c.impressions).toLocaleString() + '</td>' +
'<td><b>' + Number(c.stopped ? (c.served || 0) : served).toLocaleString() + '</b></td>' +
@@ -121,7 +219,14 @@
Number(st.limit).toLocaleString() + '</b> impressions a month on the network. Each upgrade raises it — Apex is where it jumps to 50,000.';
$('tfImp').max = st.remaining;
$('tfImp').value = Math.min(Number($('tfImp').value) || st.remaining, st.remaining) || 100;
renderSizes(st.sizes || []); renderCreatives(); renderTargets();
state.angles = d.textAngles || state.angles;
renderFormat(); renderAngles(); renderVariants();
showWriteMeter(d.textMeter);
if (d.writerReady === false) {
$('tfWrite').disabled = true;
$('tfWriteMeter').textContent = 'The writer is warming up.';
}
renderSizes(st.sizes || []); renderCreatives(); renderTargets(); goLabel();
renderLive(st.campaigns || [], d.live || []);
if (st.remaining <= 0) {
$('tfGo').disabled = true;
@@ -174,21 +279,39 @@
$('tfOk').style.display = 'none';
$('tfGo').disabled = true;
$('tfGo').innerHTML = '<span class="spin"></span>Launching on the network…';
var payload = { target: state.target, impressions: Number($('tfImp').value) || 0 };
if (state.format === 'text') {
var v = state.variants[state.variant];
if (!v) {
$('tfErr').textContent = 'Write some ads first, then pick the one you want to run.';
$('tfErr').style.display = 'block';
busy = false; $('tfGo').disabled = false; goLabel();
return;
}
payload.kind = 'text';
payload.subject = v.subject;
payload.lines = v.lines;
} else {
payload.kind = 'banner';
payload.size = state.size;
payload.creative = state.creative;
}
try {
var r = await fetch('/api/public/suite-traffic', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
size: state.size, creative: state.creative, target: state.target,
impressions: Number($('tfImp').value) || 0
})
body: JSON.stringify(payload)
});
var d = await r.json();
if (!r.ok) {
$('tfErr').textContent = d.error || 'That didn’t go through — try again.';
$('tfErr').style.display = 'block';
} else {
$('tfOk').innerHTML = '✅ <b>Your banner is live on the network.</b><br>' +
Number(d.campaign.impressions).toLocaleString() + ' impressions of ' + d.campaign.size +
var what = d.campaign.kind === 'text' ? 'text ad' : 'banner';
$('tfOk').innerHTML = '✅ <b>Your ' + what + ' is live on the network.</b><br>' +
Number(d.campaign.impressions).toLocaleString() + ' impressions of ' +
(d.campaign.kind === 'text' ? 'your text ad' : d.campaign.size) +
' pointed at your ' + (d.campaign.target.indexOf('/p/') !== -1 ? 'personal page' : 'invite page') +
'. It starts rotating immediately — check back here to watch it serve.';
$('tfOk').style.display = 'block';
@@ -201,11 +324,12 @@
$('tfErr').style.display = 'block';
}
busy = false;
if (state.remaining > 0) { $('tfGo').disabled = false; $('tfGo').textContent = '🚦 Launch my banner'; }
if (state.remaining > 0) { $('tfGo').disabled = false; goLabel(); }
}
document.addEventListener('DOMContentLoaded', function () {
boot();
$('tfGo').addEventListener('click', run);
$('tfWrite').addEventListener('click', function () { writeAds(this); });
});
})();
+1 -1
View File
@@ -18,7 +18,7 @@
{ lv: 3, ico: '📧', name: 'Email Engine', desc: 'Welcome series, follow-up sequences and broadcasts in the team voice — exportable to any autoresponder.', href: '/suite/email', live: true },
{ lv: 3, ico: '🎥', name: 'Video Maker', desc: 'The team’s master promo videos rendered with your personal end-card — your name, your QR, your link.', href: '/suite/video', live: true },
{ lv: 4, ico: '🗣️', name: 'Voice Profile + Funnels', desc: 'Output that sounds like YOU, plus multi-page funnels on your own team subdomain.', live: false },
{ lv: 1, ico: '🚦', name: 'Traffic Desk', desc: 'Syndicated network display advertising — put a banner on the team’s own ad network. Monthly impressions scale with your level: 2,500 at Scintilla up to 150,000 at Corona.', href: '/suite/traffic', live: true },
{ lv: 1, ico: '🚦', name: 'Traffic Desk', desc: 'Syndicated network display advertising — run banners or AI-written text ads on the team’s own ad network. Monthly impressions scale with your level: 2,500 at Scintilla up to 150,000 at Corona.', href: '/suite/traffic', live: true },
{ lv: 6, ico: '🏭', name: 'Funnel Factory', desc: 'Complete hosted funnels with A/B variants, replay funnels (your team webinar as an on-demand registration page with a timed CTA), and a lead CRM.', live: false },
{ lv: 7, ico: '🧭', name: 'Leader Ops', desc: 'Team radar, AI coaching digests for your legs, and cohort training rooms.', live: false },
{ lv: 8, ico: '👑', name: 'Founder Desk', desc: 'Your own AI operator running your promotion, API access, and the inner circle.', live: false }