This custom macro will help you embed videos of various formats such as .mp4
, .webm
, .mov
, .ogg
, and .avi
in your Twine stories using the SugarCube story format.
Macro.add('video', {
handler: function () {
if (this.args.length < 1) {
return this.error("The video macro requires a path argument.");
}
const videoPath = this.args[0];
const videoWidth = this.args.length > 1 ? this.args[1] : '100%';
let videoType;
// Determine the video type based on the file extension
if (videoPath.endsWith('.mp4')) {
videoType = 'video/mp4';
} else if (videoPath.endsWith('.webm')) {
videoType = 'video/webm';
} else if (videoPath.endsWith('.mov')) {
videoType = 'video/mp4';
} else if (videoPath.endsWith('.ogg')) {
videoType = 'video/ogg';
} else if (videoPath.endsWith('.avi')) {
videoType = 'video/x-msvideo';
} else {
return this.error("Unsupported video format.");
}
const videoHTML = `<video width="${videoWidth}" autoplay loop muted>
<source src="${videoPath}" type="${videoType}">
Your browser does not support the video tag.
</video>`;
new Wikifier(this.output, videoHTML);
}
});
I use this macro to include videos that play automatically in a continuous loop while muted (just like GIFs do). You can easily create other versions of this macro that behave slightly differently by editing the “videoHTML” constant. For example, you can remove the “muted” attribute to play videos with sound and save the modified macro as “video-sound” or something similar.
Alternatively, you could modify it so that it behaves more like the HTML <video> tag by default and accepts the same attributes as additional parameters:
Macro.add('video', {
handler: function () {
if (this.args.length < 1) {
return this.error("The video macro requires a path argument.");
}
const videoPath = this.args[0];
let videoWidth = '100%';
let videoType;
let additionalAttributes = [];
// Check if the second argument is a width or a video attribute
if (this.args[1] && !this.args[1].includes('=')) {
if (!this.args[1].includes('autoplay') && !this.args[1].includes('loop') && !this.args[1].includes('muted') && !this.args[1].includes('controls')) {
videoWidth = this.args[1];
additionalAttributes = this.args.slice(2);
} else {
additionalAttributes = this.args.slice(1);
}
} else {
additionalAttributes = this.args.slice(1);
}
// Determine the video type based on the file extension
if (videoPath.endsWith('.mp4')) {
videoType = 'video/mp4';
} else if (videoPath.endsWith('.webm')) {
videoType = 'video/webm';
} else if (videoPath.endsWith('.mov')) {
videoType = 'video/mp4';
} else if (videoPath.endsWith('.ogg')) {
videoType = 'video/ogg';
} else if (videoPath.endsWith('.avi')) {
videoType = 'video/x-msvideo';
} else {
return this.error("Unsupported video format.");
}
const additionalAttributesStr = additionalAttributes.join(' ');
const videoHTML = `<video width="${videoWidth}" ${additionalAttributesStr}>
<source src="${videoPath}" type="${videoType}">
Your browser does not support the video tag.
</video>`;
new Wikifier(this.output, videoHTML);
}
});
First, add the Macro to your Story JavaScript passage. You can then use the macro in any passage like this:
:: Start
Welcome to my interactive story!
<<video "path/to/your/video.mp4">>
The width of the video is set to 100% by default, but you can manually overwrite the default setting by entering the width as an additional argument.
<<video "path/to/your/video.mp4" "50%">>
If you’ve decided to go with the second version of the macro, the one that works more like the HTML <video> tag, then you can do something like this:
<<video "videos/intro.mp4" autoplay loop muted controls>>
or this:
<<video "videos/intro.mp4" "75%" autoplay loop muted controls>>
This macro supports the following video formats:
.mp4
with MIME type video/mp4
.webm
with MIME type video/webm
.mov
with MIME type video/mp4
.ogg
with MIME type video/ogg
.avi
with MIME type video/x-msvideo