A MagicMirror² module that displays animated portrait videos with support for multiple portraits, rotation, smooth transitions, and customizable frame styles.
Perfect for creating a Hogwarts-style moving portrait gallery on your MagicMirror!
- 📹 Multiple Portrait Support - Display and rotate between multiple videos
- 🔄 Smooth Transitions - Crossfade between portraits with configurable duration
- 🖼️ Frame Styles - Choose from Hogwarts Gold, Vintage Wood, Modern, or No Frame
- 📝 Name Overlay - Show character names with stylish overlay
- 🔔 Notification Support - Control playback and visibility via notifications
- ⚙️ Fully Configurable - Customize size, opacity, timing, and more
- 🎨 CSS Customizable - Easy to extend with your own frame styles
- Navigate to your MagicMirror's
modulesfolder:
cd ~/MagicMirror/modules- Clone this repository:
git clone https://github.com/fischi87/MMM-MovingPortrait.git- Add your portrait videos to the
videosfolder:
# Copy your video files
cp /path/to/your/portrait.mp4 ~/MagicMirror/modules/MMM-MovingPortrait/videos/Add the module to your config/config.js file:
{
module: "MMM-MovingPortrait",
position: "middle_center",
config: {
portraits: [
{ file: "wizard.mp4", name: "Albus Dumbledore" }
]
}
}{
module: "MMM-MovingPortrait",
position: "middle_center",
config: {
// Array of portraits
portraits: [
{ file: "dumbledore.mp4", name: "Albus Dumbledore" },
{ file: "mcgonagall.mp4", name: "Minerva McGonagall" },
{ file: "snape.mp4", name: "Severus Snape" }
],
// Display settings
width: "400px",
height: "600px",
opacity: 0.85,
// Frame style: "hogwarts", "vintage", "modern", "none"
frameStyle: "hogwarts",
// Rotation settings
rotationInterval: 30000, // 30 seconds (0 = no rotation)
fadeTransitionDuration: 2000, // 2 seconds
// Name display
showName: false, // Show portrait name
namePosition: "bottom", // "top" or "bottom"
// Video settings
autoplay: true,
loop: true,
muted: true
// --- Erweiterungen für Exklusiv-Trigger ---
activeDuration: 15000, // Zeit in ms, wie lange das Modul nach Trigger sichtbar ist
exclusiveMode: true // Wenn true, werden alle anderen Module ausgeblendet
}
}| Option | Type | Default | Description |
|---|---|---|---|
portraits |
Array | [{file: "portrait.mp4", name: "Portrait 1"}] |
Array of portrait objects with file and optional name |
width |
String | "400px" |
Width of the portrait display |
height |
String | "600px" |
Height of the portrait display |
opacity |
Number | 0.85 |
Opacity of the entire portrait (0.0 to 1.0) |
frameStyle |
String | "hogwarts" |
Frame style: "hogwarts", "vintage", "modern", "none" |
rotationInterval |
Number | 30000 |
Time in milliseconds between portrait changes (0 = no rotation) |
fadeTransitionDuration |
Number | 2000 |
Duration of crossfade transition in milliseconds |
showName |
Boolean | false |
Display portrait name as overlay |
namePosition |
String | "bottom" |
Position of name overlay: "top" or "bottom" |
autoplay |
Boolean | true |
Autoplay videos |
loop |
Boolean | true |
Loop videos |
muted |
Boolean | true |
Mute video audio |
randomOnShow |
Boolean | true |
Start with random portrait when module is shown |
activeDuration |
Number | 10000 |
Zeit in Millisekunden, wie lange das Modul nach Exklusiv-Trigger sichtbar ist |
exclusiveMode |
Boolean | false |
Wenn true, werden alle anderen Module für die Dauer ausgeblendet |
Ornate golden frame with magical glow effect, perfect for wizard portraits.
Classic wooden frame with aged appearance.
Sleek minimal frame with dark tones.
No frame, just soft shadow and rounded corners.
- Runway Gen-3 (runwayml.com) - Best quality animated portraits
- Kling AI (klingai.com) - Excellent for longer videos
- Pika Labs (pika.art) - Quick and easy
- Format: MP4 (H.264 codec recommended)
- Resolution: 1080x1920 (9:16 portrait) or 768x1152 (2:3)
- Duration: 5-10 seconds (will loop automatically)
- Frame Rate: 24-30 fps
- File Size: Keep under 10MB for best performance
- Generate Base Image (Leonardo.ai, Midjourney, or Runway):
Renaissance oil painting portrait, elderly wizard with long white beard,
burgundy velvet robes, white ruff collar, holding wooden wand,
Tudor era clothing, dark background, aged oil painting texture,
craquelure cracks, museum quality, candlelight
- Animate in Runway:
Historical oil painting portrait coming to life, subtle head turn,
slow blinking, slight expression change, candlelight flickering,
aged canvas texture visible, dignified movement
- Download as MP4 and copy to
videos/folder
The module uses absolute positioning by default (centered). You can change this in the CSS or use MagicMirror's standard positions:
top_left,top_center,top_rightupper_thirdmiddle_centerlower_thirdbottom_left,bottom_center,bottom_right
Note: For centered display, use middle_center and the module will handle positioning.
Add your own frame style in MMM-MovingPortrait.css:
.portrait-container.frame-custom {
border: 10px solid #YOUR_COLOR;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.8);
/* Add your custom styling */
}Then use in config:
frameStyle: "custom"The module supports the following notifications for controlling playback and visibility:
Um das Modul für eine definierte Zeit exklusiv anzuzeigen und ein zufälliges Video abzuspielen, sende die Notification:
this.sendNotification("PORTRAIT_EXKLUSIV");Ablauf:
- Bei Empfang der Notification wird ein zufälliges Video gewählt und das Modul angezeigt.
- Nach Ablauf der Zeit (activeDuration) wird das Modul (und ggf. andere Module) wieder ausgeblendet.
Du kannst z.B. mit dem Modul MMM-MQTTbridge oder aus einem eigenen Modul diese Notification senden.
// Show the module
this.sendNotification("PORTRAIT_SHOW");
// Hide the module
this.sendNotification("PORTRAIT_HIDE");
// Toggle between show/hide
this.sendNotification("PORTRAIT_TOGGLE");// Show next portrait
this.sendNotification("PORTRAIT_NEXT");
// Show previous portrait
this.sendNotification("PORTRAIT_PREVIOUS");
// Select specific portrait by index (0-based)
this.sendNotification("PORTRAIT_SELECT", { index: 2 });
// Select specific portrait by name
this.sendNotification("PORTRAIT_SELECT", { name: "Albus Dumbledore" });// Pause automatic rotation
this.sendNotification("PORTRAIT_PAUSE");
// Resume automatic rotation
this.sendNotification("PORTRAIT_RESUME");
// Stop rotation (same as pause, but with different intent)
this.sendNotification("PORTRAIT_STOP_ROTATION");// In another module's script
Module.register("MyControlModule", {
notificationReceived: function(notification, payload, sender) {
if (notification === "BUTTON_PRESSED") {
if (payload.button === "next") {
this.sendNotification("PORTRAIT_NEXT");
}
}
}
});- Check video path:
ls ~/MagicMirror/modules/MMM-MovingPortrait/videos/- Verify video format:
file ~/MagicMirror/modules/MMM-MovingPortrait/videos/your-video.mp4Should show: ISO Media, MP4 Base Media v1
- Check browser console:
Press
Ctrl+Shift+Ion your MagicMirror and look for errors
- Reduce video resolution
- Reduce file size (compress videos)
- Use H.264 codec
- Reduce
rotationIntervalif rotating multiple videos
- Check MagicMirror logs:
pm2 logs mm- Verify config.js syntax:
cd ~/MagicMirror
npm run config:check- Restart MagicMirror:
pm2 restart mm{
module: "MMM-MovingPortrait",
position: "top_left",
config: {
portraits: [
{ file: "dumbledore.mp4", name: "Headmaster" }
],
width: "300px",
height: "450px",
frameStyle: "hogwarts",
showName: true
}
}{
module: "MMM-MovingPortrait",
position: "middle_center",
config: {
portraits: [
{ file: "wizard1.mp4", name: "Albus Dumbledore" },
{ file: "wizard2.mp4", name: "Minerva McGonagall" },
{ file: "wizard3.mp4", name: "Severus Snape" },
{ file: "wizard4.mp4", name: "Pomona Sprout" }
],
width: "500px",
height: "750px",
frameStyle: "hogwarts",
rotationInterval: 20000, // 20 seconds
fadeTransitionDuration: 3000, // 3 second fade
showName: true,
namePosition: "bottom"
}
}{
module: "MMM-MovingPortrait",
position: "top_right",
config: {
portraits: [
{ file: "portrait.mp4" }
],
width: "350px",
height: "500px",
opacity: 0.9,
frameStyle: "modern"
}
}Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - see LICENSE file for details
Created by Axel
Inspired by the moving portraits from Harry Potter and the Hogwarts castle.
- NEW: Added
PORTRAIT_EXKLUSIVnotification for exclusive portrait display - NEW: Added
activeDurationconfig option - control how long portrait is visible after trigger - NEW: Added
exclusiveModeconfig option - hide all other modules during portrait display - NEW: Random video selection on each trigger
- REMOVED: Soft edges feature (softEdges option removed)
- Improved MQTT integration documentation
- Enhanced notification system for external triggers
- Added Notification Support for external module control
- Added module visibility control (show/hide/toggle)
- Enhanced rotation pause/resume capabilities
- Improved code structure with helper methods
- Better logging for notifications
- Initial release
- Multiple portrait support with rotation
- Four frame styles (Hogwarts, Vintage, Modern, None)
- Smooth crossfade transitions
- Name overlay support
- Fully configurable
If you encounter any issues or have feature requests, please open an issue on GitHub.
Made with ❤️ for MagicMirror²
