Nudge Simulator v2 — flow & logic

How the Smart Nudge system decides which Pro feature to pitch, when to interrupt, and what to say. Every weight and threshold below is read straight out of simulator/index.html on main.

← all simulators

The pipeline

A user action enters at the top. It either exits as a nudge card at the bottom, or it dies at one of the two gates: the relevance filter or the guardrails.

1
Signal Collectorproduct event → signal
Turns clicks into named signals. Repeatable ones (editing, regenerating, sharing) keep a running count. Boolean ones (returning user, company domain) fire once.
2
Context Profiler3 layers
Mindset = role × audience stakes → a 0–5 weight per feature. Stakes = audience bucketed into critical / external / internal. Prompt synthesis = the prompt scored 0–5 per feature by a local LLM, a lookup table, or keyword fallback.
3
Relevance Filtergate one
mindset + prompt ≥ 3 or the feature never enters scoring. Clicking a lot cannot make a feature relevant — only who you are and what you're building can. hire-team is exempt; it rides on struggle signals.
4
Scoring Engineper feature
direct + (universal × 0.4). Direct weights are feature-specific; universal weights lift every feature equally and get damped so raw intent can't drown out what the user is actually doing.
5
Milestone Selectorrank & pick
Sort the relevant features by score. Take the top one if it clears 14 and hasn't already been shown this session. One winner, not a list.
6
Guardrailsgate two
Six checks, all must pass: not Pro, under the 3-per-session cap, past the 60s cooldown, feature not already shown, intent floor ≥ 3, and the user idle for 3s.
7
Copy Engine20 variants
The winning feature has 1–4 sub-features. Each candidate is scored by how many of its trigger signals are live right now; the best match writes the card. Title names the pain, never the feature.
8
Rendererthe card
Pro card or Service card. CTA → user becomes Pro, all nudges die. "Not now" → dismissals++ and the zero-dismissals signal is dropped, which lowers every future score.
Suppression happens at fire time, not dismiss time. The moment a card is shown, the feature is added to featuresShownThisSession and the session counter ticks. Ignoring the card costs the user that feature for the rest of the session just as much as dismissing it does.

The math

Two maps, one multiplier, one threshold. That's the whole scoring model.

// for each of the 7 features, over every active signal s: direct += DIRECT_MAP[s][feature] // 0 if this signal doesn't touch this feature universal += UNIVERSAL_MAP[s] // 0 if not a universal signal // repeatable signals are log-scaled by how many times they fired: contribution = base × log₂(count + 1) total = direct + (universal × 0.4) fires when: relevant AND total ≥ 14 AND guardrails pass

Why log-scaling

The first edit is the informative one. The tenth tells you a little more, not ten times more. Log₂ gives the first occurrence full weight and then flattens, which replaced a pile of threshold signals like edit-count-5 and slides-15plus that used to create cliff behavior.

1× → ×1.00
2× → ×1.58
3× → ×2.00
5× → ×2.58
8× → ×3.17
10× → ×3.46
20× → ×4.39

Try the logic

This runs the real calculateScores(), computeRelevantFeatures() and checkGuardrails() math with the actual weight maps. Change the person, the prompt, and what they're doing, and watch which feature wins.

These two are the only inputs to relevance. Actions below can raise a score but never make a feature eligible.

Feature scores

▪ red line = threshold 14 ▪ greyed = failed the relevance filter

Guardrails

Guardrails in full

Scoring decides what. Guardrails decide whether. Any single failure holds the nudge.

CheckThresholdWhy it exists
Pro userisProUserKill switch. Once they convert, nudges are off permanently.
Session cap3 / sessionThree interruptions is the ceiling on one visit.
Cooldown60sNo back-to-back cards, even if two features both clear 14.
Feature repeatonce / sessionNever pitch the same feature twice in a session.
Intent flooruniversal ≥ 3Behavior alone isn't enough. There has to be some independent buying signal — low credits, a pricing visit, a return session.
Activity pause3s idleDon't interrupt mid-drag. Wait for a natural beat.
One quirk worth knowing: the intent floor sums the raw universal weights, while scoring log-scales the repeatable ones first. So pricing-visit visited three times counts as 3 toward the floor but contributes 3 × log₂(4) × 0.4 = 2.4 to each score. The floor is a check on which intent signals exist, not how hard they fired.

The seven features

FeatureTypeSub-featuresThe signals that actually move it
🧠 Better AI ModelsPRO3deck-regenerate (5), undo-redo (3), insert-slide-prompt (3)
🎨 Brand KitPRO4theme-global (4), style-change (3), doc-upload (3), deck-switch (3)
✨ Remove WatermarkPRO2share-link-copy (3), play-preview (3), deck-publisher (3)
📄 PowerPoint/PDF ExportPRO3export-download (5), doc-upload (4), export-click (3)
👥 Invite CollaboratorsPRO4invite-attempt (5), prompt-team (5), acq-referral (3)
📈 Viewer AnalyticsPRO3share-link-copy (3), deck-sharer (3), doc-upload (2)
🤝 Hire Our TeamSERVICE1deck-regenerate (5), doc-upload-long (4), undo-redo (3)
Hire Our Team is the struggle detector. Notice it shares its top signals with ai-models — regenerating the deck and undoing repeatedly. The difference is that AI Models says "unlock a better model" while Hire Our Team says "let us handle it." It's also the only feature exempt from the relevance filter, because struggle isn't something a role or a prompt can predict.

The feedback loop

User doesSystem does
Clicks the CTAisProUser = true. Every future nudge is killed at the first guardrail.
Clicks "Not now"dismissals++ and zero-dismissals (a universal, +1) is removed, so every feature's score drops slightly. Rejection makes the system quieter.
Ignores it (10s)Auto-closes. Costs the same as a dismissal in feature suppression, but doesn't drop zero-dismissals.