🎯 Browser extension enhancing BigBlueButton with advanced messaging, reactions, and collaboration features.
Flowly is a sophisticated, cross-browser extension (Chrome/Firefox) that transforms BigBlueButton video conferencing by adding emoji reactions, mention highlighting, active user tracking, warning alerts, break announcements, GIF support, and more. Designed specifically for educational institutions using BigBlueButton.
- Features
- Quick Start
- Installation
- Technology Stack
- Project Structure
- Module Guide
- WebSocket Integration
- Configuration
- Development
- Building & Deployment
- Contributing
- Troubleshooting
- Roadmap
- License
- Add emoji reactions to any chat message
- Customizable emoji palette (default: 👍 ❤️ 😂 😮 😢 😡 🎉 🤔 👀 🔥 ✨ 👎)
- Real-time reaction updates via WebSocket
- Automatic user count per reaction
- Click-to-react and view all reactors
- Automatically highlight messages mentioning you with
@username - Visual styling distinguishes personal mentions
- Never miss an important mention
- Works with partial usernames
- Real-time display of active participants
- GitHub contributor identification and integration
- User status indicators (active, contributor, etc.)
- 10-second update frequency
- Normalized name matching (accent-insensitive)
- Report technical issues instantly
- Categories: Audio, Video, Screen sharing, Connection
- Moderator alerts with notification sound
- Cooldown protection (120 seconds per category)
- User count tracking for critical issues
- Visual alert resolution/postpone options
- Preset durations: 5, 10, 15, 30 minutes, or custom
- Full-screen pause notification to all users
- Real-time countdown display
- Moderator controls: Stop, Extend (+5/10/15 min)
- Optional break reason/notes
- Easter egg: Coffee emoji rain for coffee breaks ☕🎉
- Auto-hide after duration expires
- Visual badge on moderator messages
- Easy identification of instructor messages
- Special styling for administrative communications
- Highlight questions marked with
@questiontag - Visual distinction from regular messages
- Helps instructors identify student questions
- Search and insert GIFs directly in chat
- Powered by Tenor API (free tier)
- 5-minute response caching for performance
- Category-based browsing
- Direct message insertion with preview
- Pop-out chat window for flexible layout
- Message virtualization (max 100 displayed)
- Automatic cleanup of off-screen messages
- Message categorization (moderator, question, mention)
- Smooth scrolling experience
- Persistent across session
- Choose up to 12 custom emoji reactions
- Easy emoji picker interface
- Settings persist across sessions
- Emoji-Mart picker with search
- Works out of the box with no setup
- Automatic integration with BigBlueButton
- No account required
- Privacy-first design
Chrome/Brave/Edge:
- Visit Chrome Web Store
- Click "Add to Chrome"
- Confirm permissions
- Done! Extension loads automatically
Firefox:
- Visit Firefox Add-ons
- Click "Add to Firefox"
- Confirm permissions
- Done! Extension loads automatically
-
Join a BigBlueButton meeting on supported platforms:
- oclock.school
- lutice.online
- Custom BigBlueButton instances (if installed)
-
React to messages: Hover over a message → Click emoji button → Select emoji
-
Track active users: See real-time participant list with GitHub contributors
-
Report issues: Use warning button to alert moderators of problems
-
Configure emojis: Click extension popup → Settings → Customize emojis
https://chromewebstore.google.com/detail/flowly/onphhlbmjailmffempahbcnocelnlcmn
https://addons.mozilla.org/firefox/addon/flowly/
See Development Setup section below.
Primary Targets (Full Integration):
- oclock.school - Educational video conferencing
- lutice.online - Lutice LMS integration
Compatible With:
- BigBlueButton 2.4+
- Any BBB instance (with limitations)
- Chrome/Chromium 90+
- Firefox 112+
- Edge 90+ (Chromium-based)
- Brave 1.0+
- Opera 76+
The extension requests permissions for:
- Host Access:
*.oclock.school,*.lutice.online,theovilain.com,tenor.googleapis.com - Storage Access: Browser sync storage for emoji preferences
- Tab Access: To detect BigBlueButton meetings (content script injection)
No background scripts execute to preserve privacy.
- TypeScript 5.6.3 - Strict type safety with ES2021 target
- Webpack 5.96.1 - Module bundler with multi-target output
- Browser WebExtension API - Cross-browser compatibility
- WebSocket - Real-time communication with Flowly backend
- DOM APIs - MutationObserver for dynamic content detection
| Package | Purpose |
|---|---|
webextension-polyfill |
Browser API abstraction (Chrome/Firefox) |
@emoji-mart/react |
Emoji picker component |
emoji-picker-element |
Custom emoji picker |
adm-zip |
ZIP file handling (release scripts) |
| Tool | Purpose |
|---|---|
webpack |
Module bundling for Chrome/Firefox separately |
ts-loader |
TypeScript compilation during build |
terser-webpack-plugin |
Code minification for production |
copy-webpack-plugin |
Asset management (manifests, icons, styles) |
html-webpack-plugin |
HTML generation for popup/settings pages |
web-ext |
Firefox testing and submission automation |
eslint |
Code quality and consistency |
chrome.runtime.*- Extension messaging and lifecyclechrome.storage.*- Persistent emoji preferencesbrowser.webRequest.*- Request handlingMutationObserver- DOM monitoringWebSocket- Real-time communicationfetch()- API requests (Tenor, Flowly servers)
flowly-extension/
├── src/
│ ├── content.ts # Main entry point (injected into BBB pages)
│ │
│ ├── modules/ # Feature modules
│ │ ├── mentions.ts # @mention detection & highlighting
│ │ ├── reactions.ts # Emoji reaction system
│ │ ├── mentions/
│ │ │ ├── mention.module.ts # Mention module class
│ │ │ └── event.handler.ts # Mention event handling
│ │ ├── moderators/
│ │ │ └── moderator.module.ts # Moderator badge detection
│ │ ├── question/
│ │ │ └── question.module.ts # Question highlighting
│ │ ├── users/
│ │ │ ├── activeUsers.module.ts # Active user tracking
│ │ │ └── user.module.ts # User info management
│ │ ├── warning/
│ │ │ └── warning.module.ts # Warning alert system
│ │ ├── pause/
│ │ │ └── pause.module.ts # Break announcement system
│ │ ├── gif/
│ │ │ ├── gif.module.ts # GIF search and insertion
│ │ │ └── gif-selector.element.ts # GIF picker UI
│ │ ├── detachable/
│ │ │ └── detachable.module.ts # Pop-out chat window
│ │ └── suggestion/
│ │ └── suggestionBox.module.ts # Suggestion system
│ │
│ ├── managers/
│ │ └── websocket.manager.ts # WebSocket singleton with pub/sub
│ │
│ ├── services/ # Business logic services
│ │ └── ... # Service implementations
│ │
│ ├── pages/ # Extension UI pages
│ │ ├── popup/
│ │ │ ├── popup.html # Quick access popup
│ │ │ └── popup.ts # Popup script (version display)
│ │ └── settings/
│ │ ├── settings.html # Settings page
│ │ └── settings.ts # Emoji configuration UI
│ │
│ ├── utils/
│ │ ├── observer.ts # DOM change observation system
│ │ ├── chat.ts # Chat message utilities
│ │ └── ... # Helper functions
│ │
│ ├── styles/
│ │ └── styles.css # All extension styling (1,626 lines)
│ │ - Reaction system styles
│ │ - Modal & notification styles
│ │ - Animation keyframes
│ │ - Emoji picker integration
│ │ - Warning & pause styles
│ │ - Message highlighting
│ │
│ └── assets/
│ ├── flowly-48.png # 48x48 icon
│ ├── flowly-96.png # 96x96 icon
│ ├── discord.png # Discord link
│ └── buy-me-a-coffee.png # Support link
│
├── types/ # TypeScript type definitions
│ ├── activeUsers.d.ts # Active user types
│ ├── detachable.d.ts # Detachable chat types
│ ├── pause.d.ts # Pause/break types
│ ├── popup.d.ts # Popup types
│ ├── reactions.d.ts # Reaction types
│ ├── user.d.ts # User types
│ ├── warning.d.ts # Warning types
│ └── gif.d.ts # GIF picker types
│
├── icons/ # Icons (various sizes)
│ ├── flowly-48.png
│ ├── flowly-96.png
│ └── ...
│
├── manifests/ # Browser-specific manifests
│ ├── chrome/manifest.json # Manifest V3 (Chrome)
│ ├── firefox/manifest.json # Manifest V2 (Firefox)
│ └── manifest.json # Fallback Manifest V2
│
├── scripts/
│ ├── release.ts # Release automation script
│ └── tsconfig.json # TypeScript config for scripts
│
├── dist/ # Build output (generated)
│ ├── chrome/ # Chrome-specific build
│ └── firefox/ # Firefox-specific build
│
├── webpack.config.js # Webpack configuration
├── tsconfig.json # TypeScript compiler options
├── eslint.config.js # Code quality rules
├── package.json # Dependencies & scripts
├── .env.example # Environment variables template
│
├── CONTRIBUTING.md # Contribution guidelines
├── CONTRIBUTORS.md # List of contributors
├── LICENSE # CC BY-NC-SA 4.0 License
└── README.md # This file
Purpose: Emoji reaction system on messages
Key Features:
class ReactionManager extends SingletonModule {
// Inject reaction buttons on messages
injectReactionButtons(messageContainer: HTMLElement)
// Handle emoji selection
handleReactionClick(messageId: string, emoji: string)
// Update reactions in real-time
updateReactions(reactions: MessageReactions)
// Debounced DOM observation
observeNewMessages()
}Configuration:
const config = {
debounceDelay: 100, // ms
maxVisibleReactions: 5, // Per message
enableReactionCounts: true,
defaultEmojis: ['👍', '❤️', '😂', '😮', '😢', '😡', '🎉', '🤔', '👀', '🔥', '✨', '👎']
}Storage: WebExtension API storage.sync for custom emojis
Purpose: Track and display active participants with GitHub integration
API Integration:
// WebSocket messages
const register = { type: 'register', username, sessionId }
const heartbeat = { type: 'heartbeat', username, sessionId }
// Responses
const activeUsers = {
type: 'activeUsers',
users: ['john', 'jane'],
githubContributors: [
{ login: 'thevillain', contributions: 45, avatar: 'url' }
]
}Features:
- 10-second update interval
- Automatic name normalization (accents, case-insensitive)
- GitHub contributor highlighting
- User status levels: 'active', 'contributor', 'none'
Purpose: Technical issue reporting with moderator alerts
Warning Types:
enum ProblemType {
AUDIO = 'audio',
VIDEO = 'video',
SCREENSHARE = 'screenshare',
CONNECTION = 'connection'
}Features:
- Sound alerts (synthesized chords)
- User count per problem type
- 120-second cooldown per type
- Toast notifications
- Moderator-only visibility
Cooldown System:
if (lastWarning + COOLDOWN_TIME > now) {
// Skip duplicate warning
return;
}Purpose: Break/pause announcements to all users
Presets:
const PRESETS = {
SHORT: 5 * 60 * 1000, // 5 minutes
MEDIUM: 10 * 60 * 1000, // 10 minutes
LONG: 15 * 60 * 1000, // 15 minutes
VERY_LONG: 30 * 60 * 1000, // 30 minutes
CUSTOM: null // User input
}Features:
- Real-time countdown display
- Moderator controls (stop, extend)
- Pause reason tracking
- Formatted end time display
- Easter egg: Coffee emoji rain for coffee breaks
Singleton Pattern:
class WebSocketManager {
private static instance: WebSocketManager
static getInstance(): WebSocketManager {
if (!WebSocketManager.instance) {
WebSocketManager.instance = new WebSocketManager()
}
return WebSocketManager.instance
}
}Pub/Sub System:
// Subscribe to message types
manager.subscribe('activeUsers', (data) => {
updateUserList(data.users)
})
// Send messages
manager.send({
type: 'reaction_update',
data: { messageId, emoji, action }
})Message Queue:
- Queues messages during offline
- Resends on reconnection
- Preserves message order
Heartbeat:
setInterval(() => {
ws.send({ type: 'heartbeat', username, sessionId })
}, 5000)Server: wss://ws.flowlyweb.com/ (configurable)
Connection Flow:
Extension Loads
↓
WebSocket Manager: new WebSocket(serverUrl)
↓
Await Connection Ready
↓
Send register { username, sessionId }
↓
Receive activeUsers response
↓
Subscribe modules to message types
↓
Send periodic heartbeats (5s)
| Type | Direction | Purpose |
|---|---|---|
register |
Client→Server | Register user in session |
unregister |
Client→Server | Leave session |
heartbeat |
Client→Server | Keep-alive (5s interval) |
reaction_update |
Client→Server | Send emoji reaction |
warning |
Client→Server | Report technical issue |
pause |
Client→Server | Announce break |
update_reactions |
Server→Client | Broadcast reaction updates |
activeUsers |
Server→Client | Active participant list |
Reconnection Strategy:
class ReconnectionStrategy {
private attempts = 0
private maxAttempts = 5
private backoffDelay = 1000
async reconnect() {
while (attempts < maxAttempts) {
await delay(backoffDelay)
try {
return await connect()
} catch (e) {
backoffDelay *= 2 // Exponential backoff
attempts++
}
}
}
}Fallback: Messages queued if WebSocket unavailable
Create .env file for development:
# WebSocket Server
WS_SERVER=wss://ws.flowlyweb.com/
# APIs
TENOR_API_KEY=your_tenor_key # Free tier (no key needed)
# Browser Store Credentials
AMO_JWT_ISSUER=firefox@addons.mozilla.org
AMO_JWT_SECRET=your_secret
CHROME_CLIENT_ID=your_client_id
CHROME_CLIENT_SECRET=your_secret
CHROME_REFRESH_TOKEN=your_token
CHROME_EXTENSION_ID=onphhlbmjailmffempahbcnocelnlcmn
# Update Server
UPDATE_SERVER=https://updates.flowlyweb.com
UPLOAD_TOKEN=your_tokenMulti-target Build:
// webpack.config.js
const targets = {
chrome: { manifest: 'chrome/manifest.json' },
firefox: { manifest: 'manifest.json' },
'node-scripts': { entry: 'scripts/release.ts' }
}
export default targets.map(target => ({
entry: getEntryPoints(target),
output: { path: `dist/${target}/` },
plugins: [new CopyPlugin({ patterns: getPatterns(target) })]
}))Build Environment Variables:
--env target=chrome # Chrome build
--env target=firefox # Firefox build
--env target=both # Both browsers (default)- Node.js 18.0.0+
- npm 8.0.0+
- Git
- Code editor (VSCode recommended)
-
Clone repository
git clone https://github.com/FlowlyWeb/flowly-extension.git cd flowly-extension -
Install dependencies
npm install
-
Create environment file
cp .env.example .env # Edit .env with your configuration -
Build for development
npm run build # Output: dist/chrome/ and dist/firefox/ -
Start watch mode
npm run dev # Rebuilds automatically on file changes
- Build:
npm run build:chrome - Open
chrome://extensions/ - Enable "Developer mode" (top right)
- Click "Load unpacked"
- Select
dist/chrome/directory - Extension loads and auto-updates on file changes
- Build:
npm run build:firefox - Open
about:debugging#/runtime/this-firefox - Click "Load Temporary Add-on"
- Select
dist/firefox/manifest.json - For persistent dev: Use
npm start
Linting:
npm run lint # Check for issues
npm run lint:fix # Auto-fix issuesCode Standards:
- TypeScript strict mode
- 4-space indentation
- Single quotes
- Semicolons required
- camelCase identifiers
- Meaningful variable names
Create New Module:
-
Create module file:
src/modules/myfeature/myfeature.module.ts -
Extend base class:
import { SingletonModule } from '../base.module'
export class MyFeatureModule extends SingletonModule {
async setup(): Promise<void> {
// Initialize module
this.subscribe('messageType', this.handleMessage.bind(this))
}
private handleMessage(data: any): void {
// Process message
}
async cleanup(isRefresh?: boolean): Promise<void> {
// Cleanup on unload
}
}- Register in
src/content.ts:
import { MyFeatureModule } from './modules/myfeature/myfeature.module'
const myFeatureModule = new MyFeatureModule()
await myFeatureModule.setup()Test in Development:
- Build extension
- Load in browser (Chrome/Firefox)
- Open test BigBlueButton meeting
- Test feature functionality
- Check browser console for errors
- Monitor WebSocket connections (DevTools)
npm run build
# Creates dist/chrome/ and dist/firefox/ with unminified codenpm run build:prod
# Creates minified, optimized builds
# Output: dist/chrome/ and dist/firefox/Manual Upload:
- Build:
npm run build:chrome:prod - Visit Chrome Developer Dashboard
- Upload
dist/chrome/as ZIP - Review and publish
Automated Release:
npm run release:chrome
# Requires: CHROME_CLIENT_ID, CHROME_CLIENT_SECRET, etc.Manual Submission:
- Build:
npm run build:firefox:prod - Visit Firefox Developer Hub
- Upload
dist/firefox/as ZIP - Complete review process
Automated Release:
npm run release:firefox
# Requires: AMO_JWT_ISSUER, AMO_JWT_SECRETSemantic Versioning:
npm run release:major # 1.0.0 → 2.0.0
npm run release:minor # 1.0.0 → 1.1.0
npm run release:patch # 1.0.0 → 1.0.1Automated Steps:
- Update version in manifests
- Create Git commit with version tag
- Build for all browsers
- Upload to stores
-
Fork & Clone
git clone https://github.com/YOUR_USERNAME/flowly-extension.git cd flowly-extension -
Create Feature Branch
git checkout -b feature/awesome-feature
-
Make Changes
- Follow code standards
- Write clear comments
- Test thoroughly
- Keep commits atomic
-
Commit with Conventional Commits
git commit -m "feat: add awesome feature" git commit -m "fix: resolve issue with reactions" git commit -m "docs: update README"
-
Push & Create Pull Request
git push origin feature/awesome-feature # Create PR on GitHub with clear description
feat:- New featurefix:- Bug fixdocs:- Documentationstyle:- Code style (no logic change)refactor:- Code restructuringperf:- Performance improvementtest:- Testschore:- Tooling/configuration
- Language: English for variables, functions, comments
- Format: 4 spaces, LF line endings
- Quotes: Single quotes
- Types: TypeScript strict mode (no
any) - Comments: JSDoc for public APIs
- Naming: camelCase for variables, PascalCase for classes
- Clear description of changes
- Screenshots for UI changes
- Link to related issues
- Update CONTRIBUTORS.md if applicable
- All tests passing
See CONTRIBUTING.md for detailed guidelines.
Issue: Features (reactions, warnings, etc.) don't appear in BBB
Solutions:
- Verify BigBlueButton version 2.4+
- Check extension is enabled:
- Chrome:
chrome://extensions/→ Enable "Flowly" - Firefox:
about:addons→ Enable "Flowly"
- Chrome:
- Reload BBB page:
Ctrl+R(Cmd+R on Mac) - Clear browser cache:
Ctrl+Shift+Delete - Check console for errors:
F12→ Console tab
Issue: "WebSocket connection failed" or reactions not syncing
Solutions:
// Check WebSocket status
// Open console (F12) and type:
console.log(window.flowlyDebug?.websocket?.connected)
// Check server connectivity
fetch('https://ws.flowlyweb.com/health')
.then(r => r.json())
.then(console.log)
.catch(console.error)- Verify internet connection
- Check if
wss://ws.flowlyweb.com/is accessible - Disable VPN/proxy temporarily
- Check firewall settings
Issue: Custom emoji selection doesn't persist
Solutions:
- Check storage permissions:
- Chrome: Settings → Privacy → Site settings → Cookies
- Firefox: Preferences → Privacy → Cookies and Site Data
- Clear storage and re-configure:
- Settings page → Customize emojis
- Check browser console for errors
Issue: Chat is laggy, reactions slow to appear
Solutions:
- Disable detachable chat (if not needed)
- Reduce custom emoji count
- Close other browser tabs
- Update browser to latest version
- Disable other extensions
Enable detailed logging:
// In browser console
localStorage.setItem('flowly:debug', 'true')
// Reload page
// Check console for debug logs// Verify extension is loaded
if (window.flowly) {
console.log('Flowly loaded successfully')
console.log('Version:', window.flowly.version)
} else {
console.error('Flowly extension not detected')
}- GitHub Issues: https://github.com/FlowlyWeb/flowly-extension/issues
- Discord: Join community for support
- Email: Support available for enterprise users
Flowly Extension is released under the CC BY-NC-SA 4.0 (Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International) License.
Key Terms:
- ✅ Allowed: Free educational use, personal projects, modifications
- ✅ Required: Attribution to original creators
- ❌ Not Allowed: Commercial use without permission
- 📋 Derivatives: Must use same license (share-alike)
For commercial use or licensing exceptions, contact: Théo Vilain
Project Creator: Théo Vilain (Teyk0o)
Lead Developer: Théo Vilain
Contributors:
- Matthieu Le Priol (Mimouss56) - Client-side development
- Community members - Bug reports, feature requests, translations
See CONTRIBUTORS.md for complete list.
- GitHub Discussions: https://github.com/FlowlyWeb/flowly-extension/discussions
- Issue Tracker: https://github.com/FlowlyWeb/flowly-extension/issues
- Discord Server: Join for support and announcements
- Website: https://flowly.theovilain.com
Love Flowly? Consider supporting the project:
- ⭐ Star on GitHub: https://github.com/FlowlyWeb/flowly-extension
- 🐛 Report bugs: GitHub Issues
- 💡 Suggest features: GitHub Discussions
- 📢 Share: Tell friends and colleagues
Data Collection:
- ✅ No user data collected beyond WebSocket session messages
- ✅ No analytics tracking
- ✅ No advertisement
- ✅ Open source code - Audit welcome
WebSocket Communication:
- Uses WSS (WebSocket Secure) with TLS encryption
- Session-based only (no persistent server storage)
- Messages expire with session
Storage:
- Only emoji preferences stored locally
- Sync across devices with browser account (optional)
- No personal data associated with storage
Q: Does Flowly work with any BigBlueButton server? A: Flowly is optimized for oclock.school and lutice.online but works with any BBB instance (some features may vary).
Q: Is Flowly free? A: Yes! Flowly is completely free. Educational use only (CC BY-NC-SA 4.0 license).
Q: How does Flowly handle privacy? A: Flowly collects no user data. Only WebSocket session messages are sent (for reactions, warnings, etc.). No analytics, no tracking.
Q: Can I contribute? A: Absolutely! See CONTRIBUTING.md for guidelines.
Q: How do I report bugs? A: GitHub Issues: https://github.com/FlowlyWeb/flowly-extension/issues
Q: Can I modify Flowly for commercial use? A: No, the CC BY-NC-SA 4.0 license prohibits commercial use. Contact creator for licensing.
Flowly has been used in educational institutions including:
- oclock.school (France)
- Lutice Learning Management System (France)
Teachers report:
- Improved student engagement in video conferences
- Better issue reporting and classroom management
- Enhanced real-time interaction capabilities
Built with ❤️ to enhance educational video conferencing.
"Where every word matters" - Flowly Team
