A 30-Line JavaScript Tone Checker for Text Messages (and Where Regex Breaks)
Disclosure: I make Honne, an iPhone app mentioned at the end. The code below is a standalone toy and is not how Honne works. Most text-message fights don't start with what someone said. They start with how it read. "k."
Disclosure: I make Honne, an iPhone app mentioned at the end. The code below is a standalone toy and is not how Honne works.
Most text-message fights don't start with what someone said. They start with how it read. "k." is fine in your head and icy on the other person's lock screen.
Rules of thumb for this are well known (one-word replies, "always/never", "per my last email"), so I turned the common ones into a small JavaScript linter you can run on your own message before you hit send.
The code
// tonecheck.js: flag phrases that often read colder than you meant
const RULES = [
{ re: /^(ok|k|fine|sure)\.?$/i, note: "One-word replies can read as annoyed. Add a reason or a next step." },
{ re: /\b(always|never)\b/i, note: "'Always/never' sounds like blame. Describe one specific time instead." },
{ re: /\byou (need to|should|have to)\b/i, note: "Commands put people on the defensive. Try 'could weβ¦' or 'would it help ifβ¦'." },
{ re: /\bper my last (email|message)\b/i, note: "Widely read as passive-aggressive. Just restate the point." },
{ re: /\bwhatever\b/i, note: "'Whatever' usually reads as dismissive." },
{ re: /!{2,}|\?{2,}/, note: "Stacked punctuation reads as shouting." },
{ re: /\b[A-Z]{4,}\b/, note: "ALL CAPS reads as shouting." },
{ re: /\bno offense,? but\b/i, note: "The 'but' cancels the 'no offense'." },
];
function toneCheck(message) {
const text = message.trim();
const hits = RULES.filter(r => r.re.test(text)).map(r => r.note);
if (text.length > 0 && text.length < 12 && !/[!?ππ]/u.test(text)) {
hits.push("Very short replies can feel cold over text. A short 'thanks' or emoji softens it.");
}
return { message: text, flags: [...new Set(hits)] };
}
What it flags
> k.
- One-word replies can read as annoyed. Add a reason or a next step.
- Very short replies can feel cold over text. A short 'thanks' or emoji softens it.
> You never answer my calls!!
- 'Always/never' sounds like blame. Describe one specific time instead.
- Stacked punctuation reads as shouting.
> Per my last email, the deadline is Friday.
- Widely read as passive-aggressive. Just restate the point.
> Thanks, that works for me. See you at 7?
(no flags)
Where regex breaks
- Context. "Fine." after "Want pizza?" is neutral. After an argument it isn't. A regex sees one message, not the thread.
- Relationship. A blunt colleague and a blunt partner mean different things. The same words can be normal for one person and a warning sign from another.
- Sarcasm and in-jokes. "Great, love that for me" passes every rule.
- Language. These patterns are English-only. Tone markers differ a lot between languages.
Good uses: a pre-send check in a chat tool you're building, a Slack bot that nudges before a 1-word reply to a long message, or a writing-assistant demo. Don't use it to judge other people's messages. It will be confidently wrong.
If you want the AI version
I built Honne for the other direction: you paste a message someone sent you, and its AI suggests the likely emotion behind it (anger, anxiety, loneliness, hope) and drafts a calm reply. There are modes for partner, friend, family and colleague. The free tier gives 3 analyses a day. It's an AI's read, not mind-reading, so treat it as a second opinion.
What rules would you add to the list? I'm collecting them in the comments.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.