Odoo 18 introduces an effect system that enables developers to enhance user interaction with dynamic visual cues. In this blog post, we’ll walk through creating a custom firework animation using Odoo’s OWL framework, JavaScript, and SCSS. This firework effect can be used to visually celebrate key actions, such as submitting a form or reaching a specific milestone, by displaying an animated explosion of particles on the screen.
What You'll Need
- A basic understanding of how to create a custom module in Odoo 18.
- Some experience with JavaScript, OWL, and SCSS.
- An Odoo 18 development environment set up and ready to go.
Step 1: Set Up Your Module
First, you need to create a new module and organize your files. Create a folder structure that looks like this:
custom_firework_effect/
+-- static/
¦ +-- src/
¦ ¦ +-- js/
¦ ¦ ¦ +-- effect.js
¦ ¦ ¦ +-- firework_effect.js
¦ ¦ +-- scss/
¦ ¦ ¦ +-- firework_effect.scss
¦ ¦ +-- xml/
¦ ¦ ¦ +-- templates.xml
+-- __manifest__.py
Update __manifest__.py to include dependencies and assets:
{
'name': "Custom Firework Effect",
'depends': ['web'],
'assets': {
'web.assets_backend': [
'custom_firework_effect/static/src/js/effect.js',
'custom_firework_effect/static/src/js/firework_effect.js',
'custom_firework_effect/static/src/scss/firework_effect.scss',
'custom_firework_effect/static/src/xml/templates.xml',
],
},
}
Step 2: Register the New Effect
Now, we need to let Odoo know that our firework effect exists. We'll do this in the effect.js file.
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { FireworkEffect } from "./firework_effect";
import { user } from "@web/core/user";
const effectRegistry = registry.category("effects");
function fireworkEffect(env, params = {}) {
const message = params.message || "Congratulations!";
const duration = params.duration || 3000;
if (user.showEffect) {
return {
Component: FireworkEffect,
props: { message, duration },
};
}
env.services.notification.add(message, { type: "success", title: "Success" });
}
effectRegistry.add("firework_effect", fireworkEffect);
This code adds our firework_effect to Odoo's list of available effects. It also includes a nice fallback: if a user has disabled effects in their preferences, they’ll see a standard success notification instead of the animation.
Step 3: Build the Firework Component
The main logic for our animation goes in firework_effect.js. This OWL component will create and manage the firework particles.
/** @odoo-module **/
import { Component, useState, useEffect } from "@odoo/owl";
import { browser } from "@web/core/browser/browser";
export class FireworkEffect extends Component {
setup() {
this.state = useState({
particles: [],
isAnimating: true,
});
this.particleCount = 30;
this.duration = this.props.duration || 3000;
useEffect(() => {
// Generate particles
const particles = Array.from({ length: this.particleCount }, () => ({
x: Math.random() * 100,
y: Math.random() * 100,
angle: Math.random() * 360,
speed: Math.random() * 5 + 2,
color: `hsl(${Math.random() * 360}, 70%, 50%)`,
}));
this.state.particles = particles;
// Animate particles
const animationInterval = browser.setInterval(() => {
this.state.particles = this.state.particles.map(particle => ({
...particle,
x: particle.x + Math.cos(particle.angle * Math.PI / 180) * particle.speed,
y: particle.y + Math.sin(particle.angle * Math.PI / 180) * particle.speed,
speed: particle.speed * 0.98, // Slow down particles
}));
}, 30);
// Close effect after duration
const closeTimeout = browser.setTimeout(() => {
this.state.isAnimating = false;
browser.clearInterval(animationInterval);
this.props.close();
}, this.duration);
return () => {
browser.clearInterval(animationInterval);
browser.clearTimeout(closeTimeout);
};
}, () => []);
}
}
FireworkEffect.template = "custom_firework_effect.FireworkEffect";
FireworkEffect.props = {
close: Function,
message: String,
duration: { type: Number, optional: true },
};
This component creates 30 particles, each with a random starting point and color. It then uses a timer (setInterval) to update their positions, making them fly out from the center and slow down, just like a real firework.
Step 4: Create the XML Template
The template is the HTML structure for our effect. In templates.xml, we'll define how the message and particles are displayed.
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="custom_firework_effect.FireworkEffect">
<div class="o_firework_effect" t-att-class="{ 'o_animating': state.isAnimating }">
<div class="o_firework_container">
<div class="o_firework_message"><t t-esc="props.message"/></div>
<t t-foreach="state.particles" t-as="particle" t-key="particle_index">
<div class="o_firework_particle"
t-att-style="'transform: translate(' + particle.x + 'vw, ' + particle.y + 'vh); background-color: ' + particle.color + ';'"/>
</t>
</div>
</div>
</t>
</templates>
This template creates a main container, a spot for the message, and then loops through all the particles we created in our JavaScript to draw each one on the screen.
Step 5: Add Styling with SCSS
To make it all look good, we need to add some CSS. Open firework_effect.scss and add the following styles.
.o_firework_effect {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 1200;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.5);
opacity: 0;
transition: opacity 0.5s ease;
&.o_animating {
opacity: 1;
}
}
.o_firework_container {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.o_firework_message {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24px;
font-weight: bold;
color: #fff;
text-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
z-index: 1;
}
.o_firework_particle {
position: absolute;
width: 8px;
height: 8px;
border-radius: 50%;
opacity: 0.8;
transition: transform 0.1s linear, opacity 0.5s ease;
}
This code styles the effect to cover the whole screen with a dark, semi-transparent background. It centers the message and styles the particles as small, colorful dots.
Step 6: How to Use Your New Effect
You can now trigger your firework effect from anywhere in Odoo!
In Js:
this.env.services.effect.add({
message: "Task Completed Successfully!",
type: "firework_effect",
duration: 3000,
});
In Python:
return {
'effect': {
'type': 'firework_effect',
'message': _("Task Completed Successfully!"),
'duration': 3000,
}
}
This displays a firework animation with the specified message for 3 seconds.
Conclusion
To create a custom firework effect in Odoo 18, you’ll register a new effect, design an OWL component with animated particles, build the corresponding template, and apply styles using SCSS. This animation brings a festive feel to user actions, making the interface more interactive. The same technique can be adapted to develop other visual enhancements like confetti, sparkles, or progress indicators, helping elevate the overall user experience in Odoo.
To read more about How to Create a Custom Effect in Odoo 17, refer to our blog How to Create a Custom Effect in Odoo 17.