Build
Mascot
An animated character that follows the pointer and changes expression with what the visitor does.
Mascot gives your site a small character with a face: a chatbot’s avatar, a guide beside a form, a personality in a hero. Its eyes follow the pointer, it blinks and floats on its own, and it reacts when something happens — thinking while a form sends, pleased when it has gone, bored by an empty one, asleep when nobody is around. It can also talk, wave, say a few words in a bubble and float in a corner as a chat launcher.
You choose its body and eyes, decide what it can look like, and write simple rules for when it looks that way. No code is needed, and it works straight away on the default settings. If you do write code, see For developers.
Quick start #
- Add the widgetSearch for Mascot in the Elementor panel and drag it onto the page.
- Pick a bodyUnder Character, click one of the shape tiles. The face moves to suit it.
- Set its colours and sizeUnder Style → Mascot.
- Try itOpen the page or Elementor’s Preview. Move the pointer, click the mascot four times, then leave the pointer still for five seconds.
Triggers only run on the live page and in Preview. On the editor canvas the mascot keeps moving, so you can place it, but it holds one expression. Use Preview Expression under Character to see the others there.
Body and eyes #
Body offers 26 ready-made shapes, from the Ghost to a Chat bubble, a Cloud and a Star. Each one comes with a face position that suits it, so you can switch freely.
| Setting | Default | What it does |
|---|---|---|
| Body | Ghost | A shape tile, or Custom SVG to upload your own |
| Eyes X, Eyes Y | Empty | Where the face sits, from 0 to 100% of the body. Empty uses the position that suits the chosen body |
| Eyes Size | Empty | The face’s width as a share of the body’s. Empty works the same way |
| Show Mouth | Off | Gives it a mouth. See Mouth and talking |
| Hold Expression | None | Shows one expression at all times and turns the Triggers off |
| Preview Expression | Default | Editor only: which expression the canvas shows |
| Accessible Name | Empty | What a screen reader announces. Leave it empty if the mascot is decoration |
| Mascot ID | Empty | Lets custom code talk to this mascot alone |
Using your own SVG
Bodies, eyes and mouths can all be your own artwork. A few rules decide how well a drawing animates:
| Filled shapes only | Outline any strokes in your design tool before exporting. A stroke with no fill does not show. |
| A body in one shape | One filled shape gets the wave along its bottom edge. A body of several shapes still works, but moves as one piece. |
| Eyes as separate shapes | Each eye is its own shape, drawn on the same artboard size in every expression, so the face stays in place when it changes. |
| The same number of eyes | Solid eyes morph smoothly into each other. A different number of eyes, or a hollow ring, swaps during a quick blink instead. |
An SVG that cannot be read is not shown. A custom body falls back to the bundled one; an expression is left out, along with any trigger that points at it.
Expressions #
The Expressions list is everything the mascot can look like. Change a row to restyle an expression, or add a row to create a new one. Each row has:
| Name | Triggers pick expressions by this name. |
| Eyes | One of the eight bundled pairs, or Custom SVG. |
| Mouth | Match Eyes, None, one of the eight bundled mouths, or Custom SVG. Shows once Show Mouth is on. |
| Talks | The mouth keeps moving for as long as this expression shows. |
| Talk While Speaking | Use The General Setting, On or Off — overrides Character → Talk While Speaking for this expression only. See Speech bubble. |
| Hands | None, or a pose. See Hands. |
| Effect | None, or something floating around the head. See Effects. |
| Blinks | Turn off for eyes that already look closed. |
| Reaction | None, Head Shake, Hop or Happy Jump (four hops, leaning right and left), played as the expression starts. |
| Body Colour | Keep, Solid or Gradient. The colour fades in with the expression and out after it, with a separate dark mode value. |
Out of the box, Normal, Focus, Confuse, Thinking and Shy blink. Happy hops, Upset shakes its head, steams and turns orange and red, and Sleepy shows Floating Zzz. Thinking shows a thought bubble, Shy covers its eyes, and Hello waves.
A row saved before these settings existed keeps working as it was, including one with the old Floating Zzz switch on.
Renaming an expression? Triggers remember it by name, so check the rows that use it and pick it again.
Triggers #
Each row says: Show this expression When this is true. The top row whose condition is true wins, so drag the rows to set the priority, and keep Otherwise (Default) last.
| When | It happens when | You also set |
|---|---|---|
| Pointer Over Element | The pointer is inside something on the page | Element |
| Focus In Element | The keyboard focus is inside it | Element |
| Click Or Submit On Element | It is clicked, or a form inside it is submitted | Element, Only If Empty |
| Typing In Field | Each keystroke. Clicking into the field does not count | Field |
| Field Emptied | A field that had text becomes empty | Field |
| Form Sending | A form is on its way. Only for forms that stay on the page | Element (optional) |
| Form Sent | A form was sent | Element (optional) |
| Form Invalid | A form was refused because fields are missing or wrong | Element (optional) |
| Form Failed | A form could not be sent | Element (optional) |
| Pointer Over Mascot | The pointer is on the mascot’s body | — |
| Clicks On Mascot | That many clicks within two seconds | Clicks |
| Comes Into View | The first time it is on screen, which for a mascot near the top means on page load | — |
| No Activity | No pointer, key or scroll for that long | Seconds |
| Pointer Leaves Page | The pointer moves out of the window | — |
| At Random | About that often, and only while the Default row is showing | Seconds |
| Otherwise (Default) | Always. It is what the mascot falls back to | — |
Element and Field are CSS selectors, such as
#contact or .my-class. To give something an ID, select it and set
CSS ID in its Advanced tab.
Every row can also say something. A new mascot starts with these rows, so it reacts to a form and greets the visitor with nothing to set up:
| Show | When | Setting |
|---|---|---|
| Happy | Form Sent | — |
| Sad | Form Failed | — |
| Bored | Form Invalid | — |
| Thinking | Form Sending | — |
| Shy | Focus In Element | input[type="password"] |
| Upset | Clicks On Mascot | 4 clicks |
| Hello | Comes Into View | — |
| Happy | Pointer Over Mascot | — |
| Sad | Pointer Leaves Page | — |
| Sleepy | No Activity | 5 seconds |
| Confuse | At Random | About every 12 seconds |
| Normal | Otherwise (Default) | — |
Holding an expression
There are two ways, and they do different jobs:
| Hold For, on a Trigger row | Keeps the expression for that many seconds after the row stops being true. Without it, a click would show for a single moment. |
| Hold Expression, under Character | Pins one expression for good and turns every Trigger off. Useful for a mascot that is purely decoration. |
Linking it to your page #
A contact form
Form results work with Contact Form 7, the NovaKit Newsletter form and NovaKit Custom forms. Accounts forms are not covered. Form Invalid also fires when a browser refuses an empty Required field. See Forms for setting these up. On a mascot added before these became the defaults, add these rows above the Default row:
| Show | When | Setting |
|---|---|---|
| Happy | Form Sent | Hold For 3 |
| Bored | Form Invalid | Hold For 2 |
| Sad | Form Failed | Hold For 3 |
| Focus | Typing In Field | Field: .wpcf7 textarea |
With two forms on a page, put a selector for the one you mean in Element. Left empty, a form row listens to every form.
A chat box with a Send button
For a real chat box, follow Connect a chatbot. For a Send
button of your own that is not a NovaKit Form: one button can do two different things. Order matters here: the first row that accepts the
click takes it, so the empty case goes on top. Say the field’s ID is message and the
button’s is send:
| Show | When | Setting |
|---|---|---|
| Bored | Click Or Submit On Element | Element: #sendOnly If Empty: #message |
| Happy | Click Or Submit On Element | Element: #send |
| Sad | Field Emptied | Field: #message |
| Focus | Typing In Field | Field: #message |
Several on one page
Add as many as you need. Each has its own body, expressions and rules, and they do not interfere with each other. A mascot scrolled out of view stops moving until it returns.
Mouth and talking #
Turn on Show Mouth under Character. Every expression then picks a mouth that matches its eyes, and you can change any of them on its row. The mouth rides the same head as the eyes and morphs between shapes.
| Setting | Default | What it does |
|---|---|---|
| Talk While Speaking | On | The mouth moves while a Say bubble shows words. Turn off to keep it still. Any expression row can override this — see Expressions |
| Mouth X, Mouth Y | Empty | Where it sits, as a percentage of the body. Empty places it under the eyes |
| Mouth Size | Empty | Its artboard’s width as a share of the body’s. Empty is 70% of the Eyes Size |
| Mouth Colour | Empty | Under Style → Mascot, with a dark mode value. Empty uses the Eyes Colour |
It talks while a speech bubble’s words appear, on any expression with Talks on, and when code asks it to. Each mouth talks in character: a smile opens into an open smile, a frown into an open frown, and Bored just mumbles. The Sleepy mouth snores: it swells and shrinks slowly for as long as it shows. Draw your own mouths like the eyes: filled shapes on a 120 by 50 artboard.
A Say bubble moves the mouth too, unless Talk While Speaking is off — either the general one here, or an expression row’s own override. The mouth then stays as it is while the bubble shows its words.
Hands #
Two floating hands with no arms, so they suit every body and sit against its own outline. Each expression picks a pose under Hands:
| Wave | One hand up, waving |
| Thumbs Up | One hand beside the body |
| Cheer | Both up, bobbing |
| Shrug | Both out to the sides, palms up |
| Cover Eyes | Both over the eyes, staying on them as the head turns, and now and then peeking. Shy uses it, on a password field |
| Point At Pointer | One hand, following the pointer around the body |
Hands Colour is under Style → Mascot. Left empty, it is a tint between the Body and Eyes Colours, which reads against the page and in front of the body.
Effects #
Effect on an expression row floats something around the head for as long as that expression shows, then clears it away:
| Floating Zzz | Z’s rise from the upper right |
| Thinking Dots | Three dots bounce inside a thought bubble, and the mascot looks up towards it. The bubble takes the effect colour and the dots take the Eyes Colour |
| Hearts, Sparkles | Rise, or twinkle, around the head |
| Question Mark, Exclamation Mark | Pops up beside the head |
| Sweat Drop | Slides down from the upper left |
| Steam | Puffs out of both sides |
Style → Floating Effects has Position X and Y, as a percentage of the body and set per device, and a Colour with a dark mode value. Left empty, effects use the Body Colour.
Speech bubble #
Type in Say on any Trigger row and the words appear in a bubble as that row starts, with the mouth moving. Put several lines and choose their Order: Random (the default) never repeats the same line twice running; In Order goes through them one by one and starts again at the top. Turn on Say Once for a greeting that should not repeat on the same page view. A bubble stays long enough to read, then leaves by itself.
Its look is under Style → Speech Bubble: which side it sits on, Max Width, Typography, colours with dark mode values, Padding, Corner Radius and Box Shadow. Preview In Editor shows a sample to style by. If the chosen side would run off the screen, it moves to one that fits.
Right-to-left languages work by themselves. Each message sets its own direction from its first letters, so Arabic or Hebrew reads right to left even on a left-to-right site, and English reads left to right on a right-to-left one. There is nothing to set, and one row can mix languages across its lines. Choose a font with those letters under Typography if your site’s font lacks them.
Link and floating launcher #
Link And Position turns the mascot into something to click.
| Setting | Default | What it does |
|---|---|---|
| Link | Empty | Where a press on its body or bubble goes. Set Accessible Name too, as that names the link |
| Position | In The Page | Floating, Bottom End or Bottom Start pins it to a corner of the screen, and it pops in on arrival |
| Offset From Side, From Bottom | Empty | The distance from the corner, per device. Empty is 1.5rem |
| Z-Index | Empty | What it sits above. Empty is 290, above the page and under popups, so a popup it opens covers it |
It floats on the live page and in Preview. In the editor it stays in place so you can select it. To show it on every page, put it in a footer Global Block.
Open a popup from it
- Build the popupA Popup Global Block holding your chat form. Check that its Display Conditions include this page. With none set, it is on every page.
- Set the LinkUnder Link And Position, press the dynamic tags icon on Link and choose NovaKit Trigger Link.
- Point it at the popupSet Action to Open, Target Type to Popup, then pick yours under Popup.
- Name itSet Accessible Name under Character, such as “Open chat”.
Not on an Elementor Canvas page. That template skips the theme’s header, which is where popups are added to the page, so the mascot has nothing to open. Use any other page template.
On a phone
There is no separate setup. It works by touch, and a bubble that would run off the screen moves to fit. These are worth setting with Elementor’s phone view selected:
| Size, under Style → Mascot | The 124px default is large for a corner. About 64px suits a phone |
| Offset From Side, From Bottom | Lift it clear of anything fixed at the bottom of your page, such as a cookie banner |
| Max Width, under Style → Speech Bubble | Lower it if a bubble crowds the screen |
To leave a mascot off phones altogether, use Advanced → Responsive.
Motion and style #
The defaults under Motion are tuned to feel calm, so change them one at a time.
| Setting | Default | What it does |
|---|---|---|
| Follow Pointer | On | Eyes, head and body turn towards the pointer |
| Head Turn | 24 | How far the face turns |
| Body Lean | 7 | How far the body tilts |
| Follow Speed | 1 | How quickly it catches up |
| Bounce | 0.55 | How much it overshoots and settles |
| Wave | 3.5 | The ripple along the bottom edge. Set 0 for a rigid shape, such as a Square |
| Wave Starts At (%) | 68 | How far down the body the ripple begins |
| Float | 3.5 | The gentle drift up and down |
| Blink And Glances | On | Blinks and looks around on its own |
| Idle Antics | On | Now and then, a head spin, a look around or a hop |
| Antics Every (s) | 10 | Roughly how often |
Style → Mascot has Size (124px by default), Alignment, Body Colour and Eyes Colour, each colour with a dark mode value.
Check your eye colour against every body colour. If an expression changes the body colour, the eyes must stay readable on it too, and in dark mode as well.
Accessibility and devices #
| Screen readers | With no Accessible Name the mascot is hidden from them. With one, it reads as an image of that name. Expression changes are not announced, so never rely on the mascot alone to report something, such as a form error. |
| Reduced motion | For visitors who ask their device for less motion, it stays still and expressions change at once. Effects and hands stand still, the Sleepy mouth does not snore, and a bubble simply appears. |
| Speech bubble | Screen readers announce its words as a status message. |
| Touch screens | There is no pointer to follow, so it does not follow. Everything else still works. |
For developers #
To connect a chatbot, start with Connect a chatbot, which needs less code than this. The panel covers anything a selector can reach. For everything else — a reply arriving, a game score — there is an event and a set of CSS hooks. Add the code the way you add any other: see Custom CSS and JS.
Driving it from JavaScript
Dispatch nk:mascot on document:
document.dispatchEvent( new CustomEvent( 'nk:mascot', { detail: {
expression: 'happy', // A row's name as a slug. null lets the Triggers run again.
hold: 3, // Seconds, or true for until told otherwise. Default 2.5.
mascot: 'helper', // Optional Mascot ID. Without it, every mascot on the page.
say: 'On it!', // Words in the bubble. hold applies. null takes them away.
talk: true, // The mouth moves: true, false, or seconds.
} } ) );
| The slug | The row’s Name in lower case, with anything else turned into hyphens: Cheeky Wink becomes cheeky-wink. A slug no row has is ignored. |
| Priority | The event beats every Trigger until its hold ends. Only Hold Expression beats the event. |
| Each is optional | Send only say or talk and the expression stays as it is. say without hold stays long enough to read. |
| Afterwards | When the hold ends the Triggers take over again, so there is nothing to clean up. The exception is hold: true, which needs expression: null. |
For example, a mascot that waits on a reply from something that is not a NovaKit Form:
const mascot = ( expression, hold ) => document.dispatchEvent(
new CustomEvent( 'nk:mascot', { detail: { expression, hold, mascot: 'helper' } } )
);
mascot( 'focus', true ); // Stay on Focus while the reply is on its way.
fetch( '/my-chat-endpoint' )
.then( () => mascot( 'happy', 3 ) )
.catch( () => mascot( 'sad', 3 ) );
Reporting your own form’s result
A form that NovaKit does not know about can still fire the Form rows. Dispatch one of these from
the form element, with bubbles: true so the mascot hears it and the row’s
Element can match:
form.dispatchEvent( new CustomEvent( 'nk-form:submit', { bubbles: true } ) ); // Form Sending starts
form.dispatchEvent( new CustomEvent( 'nk-form:success', { bubbles: true } ) ); // Form Sent
form.dispatchEvent( new CustomEvent( 'nk-form:error', { bubbles: true } ) ); // Form Failed
form.dispatchEvent( new CustomEvent( 'nk-form:invalid', { bubbles: true } ) ); // Form Invalid
form.dispatchEvent( new CustomEvent( 'nk-form:done', { bubbles: true } ) ); // Form Sending ends
Contact Form 7’s own events are already heard: wpcf7beforesubmit starts Form
Sending and wpcf7submit ends it, wpcf7mailsent counts as Form Sent,
wpcf7invalid as Form Invalid, and wpcf7mailfailed and
wpcf7spam as Form Failed.
Styling it from CSS
The current expression is always on the root element as data-nk-mascot-state, so CSS
or a script can respond to it. These custom properties drive the look:
| Property | Controls |
|---|---|
--nk-mascot-size | The width, with a unit |
--nk-mascot-body | The body colour |
--nk-mascot-eyes | The eye colour |
--nk-mascot-mouth | The mouth colour. Falls back to the eye colour |
--nk-mascot-hands | The hands’ colour. Falls back to a tint of the body and eyes |
--nk-mascot-bubble-bg, -bubble-text | The speech bubble’s colours |
--nk-mascot-zzz | The effects’ colour. Falls back to the body colour |
--nk-mascot-eye-x, -eye-y, -eye-size | The face position, as plain numbers meaning percent |
--nk-mascot-mouth-x, -mouth-size | The mouth’s position and size, the same way |
--nk-mascot-zzz-x, -zzz-y | The effects’ offset, as plain numbers meaning percent |
/* Pink eyes while it is upset. */
.nk-mascot[data-nk-mascot-state="upset"] {
--nk-mascot-eyes: #ffc2d1 !important;
}
Why !important? A value set in the panel is written with a very
specific selector, and Body Colour and Eyes Colour always have one. A property the panel has left
empty, such as --nk-mascot-zzz, can be set with an ordinary rule.