Skip to content

Cavai Theme Branding Enhancement

Date: 2026-03-28 Scope: Enhance the Cavai theme with brand personality — mascot (Bubbles), star decorations, gradient accents, and micro-animations. One theme, not two. Professional enough for daily use, but with character.


1. Design Decisions

All decisions made during brainstorming:

QuestionDecision
Scope levelB (Merkbart) — one Cavai theme with personality
Mascot placementsAll 7 locations
Stars usageB (decorative accents in fixed places) + future vision of per-session wandering
Gradient usageD (mix — full on small accents, subtle on surfaces, never on text backgrounds)
Animation intensityB (behagelig levende — 3-5s cycles, moderate mascot animations)
ImplementationC (Hybrid — CSS for decorative, one CavaiMascot.vue for interactive mascot)

2. Architecture

2.1 New Files

src/
├── components/common/CavaiMascot/
│   └── CavaiMascot.vue          # Single mascot component, mode-driven
├── styles/
│   └── _cavai-decorations.scss  # Stars, gradients, animations (cavai-only, SCSS for $size-* vars)

2.2 Modified Files

src/styles/theme.css                                           # New cavai gradient/star tokens
src/styles/_pages.scss                                         # Login page enhancements
src/pages/.../Configuration/ConfigurationPanel.vue             # Use CavaiMascot instead of raw <img>
src/pages/Chatbots/components/BuildProgress.vue                # Publish celebration
src/pages/Chatbots/components/CavaiFlow/CavaiFlow.vue         # Flow editor empty state
src/components/common/FileUploader.vue                         # Upload mascot
src/components/common/ImageInput.vue                           # Upload mascot (image variant)
src/components/common/MainTable.vue                            # Empty list mascot
src/pages/Authorization/SignInPage/index.vue                   # Login page (only if template changes needed beyond CSS)

2.3 Conditional Loading

_cavai-decorations.scss is imported in the app's SCSS entry point alongside other style partials. All rules are scoped under [data-theme="cavai"]. No CSS reaches other themes. This follows the existing pattern — the codebase uses _partialname.scss convention for imported style fragments.


3. New Tokens

Added to [data-theme="cavai"] in theme.css:

css
/* Cavai gradient tokens — decoration-layer, not semantic. Prefixed cavai- to signal theme-exclusive use. */
--cavai-gradient:        linear-gradient(135deg, #FF6B9E, #FFA07A, #FFDB58);
--cavai-gradient-subtle: linear-gradient(135deg, rgba(255,107,158,.06), rgba(255,160,122,.04), rgba(255,219,88,.02));
--cavai-gradient-accent: linear-gradient(135deg, rgba(255,107,158,.15), rgba(255,160,122,.10), rgba(255,219,88,.06));

/* Cavai decorative tokens — distinct from semantic --brand-coral (#e8606a, used for UI accents).
   These are the brighter brand colors from cavai.com, used only for decorative elements. */
--cavai-star-color: #FFDB58;
--cavai-star-glow:  rgba(255,219,88,.3);

Note: The existing --brand-coral token (#e8606a) is used for interactive UI accents. No new --cavai-coral token is needed — decorative elements that need coral use --brand-coral directly.


4. Gradient Usage

Following the "D (mix)" decision:

StrengthTokenWhere
Full--cavai-gradientTab-stripe/active tab underline, small badges, active button accents
Accent--cavai-gradient-accentCard header accents, sidebar hover highlights, selected state backgrounds
Subtle--cavai-gradient-subtleFlow editor background wash, config panel background, large surfaces

Never on text backgrounds where readability matters. Only decorative or small accent surfaces.


5. Star Decorations (CSS-only)

Stars use the character placed via ::before/::after pseudo-elements on selected components, scoped to [data-theme="cavai"].

Placement Targets

  • .title-section in Card.vue (1-2 stars near card section titles)
  • .empty-state in ConfigurationPanel.vue (around mascot)
  • .signin_page in _pages.scss (login page hero area)
  • Empty state areas in MainTable.vue

Animation

css
@keyframes cavai-twinkle {
  0%, 100% { opacity: 0.3; }
  50%      { opacity: 1; }
}

@keyframes cavai-glow-pulse {
  0%, 100% { filter: drop-shadow(0 0 2px var(--cavai-star-glow)); }
  50%      { filter: drop-shadow(0 0 6px var(--cavai-star-glow)); }
}

Timing: 3-5s infinite ease-in-out, staggered with animation-delay for natural feel.

Reduced Motion

All animations in _cavai-decorations.scss must respect prefers-reduced-motion:

scss
@media (prefers-reduced-motion: reduce) {
  [data-theme="cavai"] {
    *, *::before, *::after {
      animation-duration: 0s !important;
      animation-delay: 0s !important;
      transition-duration: 0s !important;
    }
  }
}

Future Extension

Stars can eventually "wander" — different elements get stars on different sessions. This is a future enhancement, not in initial scope.


6. CavaiMascot.vue Component

Interface

vue
<CavaiMascot mode="peek" size="md" :opacity="0.18" />

Props

PropTypeDefaultDescription
modeString'peek'Pose and animation behavior
sizeString'md'sm (32px), md (64px), lg (128px)
opacityNumber1Override opacity (config panel uses 0.18)
dragStateString'idle'Only for upload mode: 'idle', 'over', or 'dropped'

Modes

ModeAnimationAuto-hideUse Case
peekBob up-down (4s cycle), peeking over edgeNoConfig empty, empty lists
celebrateSlide-in from bottom + star-burstYes (3-4s)Publish success
waveWaving motion, pointing toward actionNoFlow editor empty
thinkPulsing glow + thinking animationNoLoading spinner
uploadReacts to dragState prop: idle=peek, over=bounce, dropped=celebrateNoUpload/drag zones

Theme Detection

Uses the existing useTheme composable (src/composables/useTheme.ts) to reactively access the current theme. Renders nothing (v-if="isCavaiTheme") when theme is not cavai.

Implementation

  • Uses existing bubbles.png asset (src/assets/images/bubbles.png)
  • CSS transform + opacity animations for poses — no sprite sheets
  • Auto-hide modes use setTimeout + fade-out transition
  • Emits hidden event when auto-hide completes (for parent cleanup)
  • Respects prefers-reduced-motion — skips animations, shows static pose

Pattern Compliance

Follows existing component patterns:

  • Lives in src/components/common/CavaiMascot/
  • Standard Vue 2 SFC with <script lang="ts"> and <style scoped lang="scss">
  • Props-driven, no Vuex dependency
  • Scoped styles only

7. The 7 Mascot Placements

7.1 Config Panel Empty State

File: src/pages/Chatbots/components/BuilderVisuals/Configuration/ConfigurationPanel.vueCurrent: Raw <img> of bubbles.png at 18% opacity with mascot-bob animation (local @keyframes in scoped styles). Change: Replace <img> with <CavaiMascot mode="peek" size="lg" :opacity="0.18" />. Remove the .mascot-peek, .mascot-img, and @keyframes mascot-bob CSS from the component's scoped styles (these move into CavaiMascot). Add 2-3 twinkle stars around mascot via _cavai-decorations.scss.

7.2 Publish Success Celebration

File: src/pages/Chatbots/components/BuildProgress.vueBehavior: When build completes successfully, show <CavaiMascot mode="celebrate" size="md" /> alongside the existing progress bar completion. Auto-hides after 3-4 seconds. Non-blocking — appears as an overlay near the progress indicator.

7.3 Flow Editor Empty State

File: src/pages/Chatbots/components/CavaiFlow/CavaiFlow.vueBehavior: <CavaiMascot mode="wave" size="lg" /> shown when the operator list is empty (no operators on canvas). Centered in the canvas area with helper text. Disappears when first operator is added.

7.4 Upload / Drag-and-Drop Zone

Files: src/components/common/FileUploader.vue, src/components/common/ImageInput.vueBehavior: <CavaiMascot mode="upload" size="md" :drag-state="dragState" /> placed in the drop zone area. Parent tracks drag events and passes state as prop:

  • idle → subtle peek
  • over (dragover) → bounce up
  • dropped (file dropped) → short celebrate

7.5 Empty Lists (Creatives, Campaigns)

File: src/components/common/MainTable.vue (uses Vuetify v-data-table) Behavior: In the no-data slot of v-data-table, add <CavaiMascot mode="peek" size="sm" /> with encouraging text. Only shown when Cavai theme is active — other themes see standard empty text.

7.6 Loading Spinner

Files: Components using v-progress-circular (e.g., ChatbotBuilder.vue, BulkDeliveryExportDialog.vue) Behavior: Wrap existing v-progress-circular usage with a conditional: when Cavai theme is active, show <CavaiMascot mode="think" size="md" /> instead. Other themes see the normal spinner. Start with the main builder loading state in ChatbotBuilder.vue.

7.7 Login Page

Files: src/styles/_pages.scss, src/pages/Authorization/SignInPage/index.vueCurrent: bubbles.svg as CSS background-image in .signin_page__bubbles. Change: Add twinkle stars via pseudo-elements on .signin_page (scoped to [data-theme="cavai"]), subtle gradient wash over hero area. CSS-only enhancement — no component swap needed.


8. Animation Keyframes

All defined in _cavai-decorations.scss, scoped under [data-theme="cavai"]:

css
@keyframes cavai-twinkle {
  0%, 100% { opacity: 0.3; }
  50%      { opacity: 1; }
}

@keyframes cavai-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}

@keyframes cavai-glow-pulse {
  0%, 100% { filter: drop-shadow(0 0 2px var(--cavai-star-glow)); }
  50%      { filter: drop-shadow(0 0 6px var(--cavai-star-glow)); }
}

@keyframes cavai-slide-in {
  from { transform: translateY(100%); opacity: 0; }
  to   { transform: translateY(0); opacity: 1; }
}

@keyframes cavai-star-burst {
  0%   { transform: scale(0); opacity: 1; }
  70%  { transform: scale(1.2); opacity: 0.8; }
  100% { transform: scale(1); opacity: 0; }
}

Timing (B — behagelig levende):

  • Ambient loops (twinkle, bob, glow): 3-5s infinite ease-in-out
  • One-shot transitions (slide-in): 0.4s ease-out
  • Effects (star-burst): 0.6s ease-out forwards
  • Celebrate auto-hide: 3-4s total, fade-out in last 0.5s

9. Constraints

  1. Commit first: All existing ~71 file changes must be committed in small, logical commits before any Cavai theme implementation begins. Clean git state for easy rollback.
  2. Cavai-only: All new CSS and components render nothing / apply no styles outside [data-theme="cavai"].
  3. No performance impact: CSS animations use transform and opacity only (GPU-composited). No layout thrash.
  4. Existing patterns: Follow Vue 2 SFC conventions, scoped SCSS, semantic token usage. No new architectural patterns.
  5. Asset reuse: Use existing bubbles.png and bubbles.svg. No new image assets unless SVG modifications are needed.
  6. Reduced motion: All animations respect prefers-reduced-motion: reduce. Static poses shown instead.
  7. Cleanup: When replacing existing mascot implementations (ConfigurationPanel), remove the old CSS entirely — no dead code.

10. Implementation Priority

Phase 1 (well-defined, refactoring existing code):

  • Tokens in theme.css
  • _cavai-decorations.scss with keyframes and star decorations
  • CavaiMascot.vue component
  • 7.1 Config panel (refactor existing mascot)
  • 7.7 Login page (enhance existing SVG)

Phase 2 (new integrations):

  • 7.2 Publish celebration
  • 7.3 Flow editor empty state
  • 7.5 Empty lists

Phase 3 (interactive):

  • 7.4 Upload drag-and-drop
  • 7.6 Loading spinner replacement
  • Gradient accents on UI elements (tab-stripes, card headers, etc.)

Internal documentation