For any product manager or app developer, it is very easy to record the screen of your latest release. It is also very easy to record yourself as you walk through the application. It is however not easy to combine these two videos together let alone in a presentable manner.
In this tutorial, we demonstrate how to create a demo walkthrough generator for easy updates of your product walkthroughs.
The completed project is available on Codesandbox.
You can clone the full source code on my Github repository.
To be able to follow through with this tutorial, entry-level knowledge of HTML, CSS, and JavaScript is required. Knowledge of VueJs is recommended but not required.
NuxtJs is a VueJS framework that provides us with a modular, performant, and enjoyable experience.
To set up our project, run the following command in your preferred working directory:
yarn create nuxt-app nuxtjs-mobile-demo-walkthrough-generator
# OR
npx create-nuxt-app nuxtjs-mobile-demo-walkthrough-generator
# OR
npm init nuxt-app nuxtjs-mobile-demo-walkthrough-generator
Code language: PHP (php)
The commands above will trigger a set of questions required to help the utility set up the project. Here are our recommended defaults:
Project name: nuxtjs-mobile-demo-walkthrough-generator
Programming language: JavaScript
Package manager: Yarn
UI Framework: Tailwind CSS
Nuxt.js modules: N/A
Linting tools: N/A
Testing framework: None
Rendering mode: Universal (SSR/SSG)
Deployment target: Server (Node.js hosting)
Deployment tools: N/A
What is your Github
<your-github-username>
Version control system: Git
You may now navigate to the project and launch it
cd nuxtjs-mobile-demo-walkthrough-generator
yarn dev
# OR
npm run dev
Code language: PHP (php)
@nuxtjs/cloudinary is the recommended Cloudinary plugin for NuxtJs. Cloudinary is a media management platform that allows us to unleash the potential of our media assets by providing a powerful API service.
We first need to add @nuxtjs/cloudinary
as a dependency in our project
yarn add @nuxtjs/cloudinary
# OR
npm install @nuxtjs/cloudinary
Code language: CSS (css)
Add @nuxtjs/cloudinary
as a module in the modules
project of the nuxt.config.js
file:
// nuxt.config.js
export default {
...
modules: [
'@nuxtjs/cloudinary'
]
...
}
Code language: JavaScript (javascript)
We will finally add a cloudinary
section in the nuxt.config.js
to set configurations for the module:
// nuxt.config.js
export default {
...
cloudinary: {
cloudName: process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,
secure: true,
useComponent: true
}
...
}
Code language: JavaScript (javascript)
As visible in the codebase above, we are making use of environmental variables. These are sensitive details that we do not want in our codebase. To set up environmental variables locally, we will create a .env
file
touch .env
Code language: CSS (css)
We will add the Cloudinary cloud name here. If you do not have one, create an account on https://cloudinary.com/. The cloud name will be visible in the console section.
<!-- .env -->
NUXT_ENV_CLOUDINARY_CLOUD_NAME=<secret-cloudinary-cloud-name>
Code language: HTML, XML (xml)
To generate the final complete file, we are going to make use of a video template. This is a 30-minute video that has no audio and has the background and phone template we require. This will limit our application to generate videos of max 30 minutes. Grab this video here. We recommend creating a folder called nuxtjs-mobile-demo-walkthrough-generator
and saving this video with the name iphone_se_template.mp4
. This will lead to the video having the public_id nuxtjs-mobile-demo-walkthrough-generator/iphone_se_template.mp4
.
We are first going to create a simple form for selecting the two video files. One is the mobile app video, the other is an instructional video. We are going to place this form in a Form.vue
component file.
<!-- components/Form.vue -->
<form action="#" method="POST">
<div>
<div>
<div>
<div>
<label for="mobile_app_video">
Mobile app video
</label>
<div>
<input id="mobile_app_video" name="mobile_app_video" required="" type="file" />
</div>
</div>
</div>
<div>
<div>
<label for="instructor_video">
Instructor video
</label>
<div>
<input id="instructor_video" name="instructor_video" required="" type="file" />
</div>
</div>
</div>
</div>
<div>
<button type="submit">
Save
</button>
<p v-if="uploadingMobileAppVideo || uploadingInstructorVideo">
Upload in progress
</p>
</div>
</div>
</form>
Code language: HTML, XML (xml)
As indicated in the above code, the submission of the form will be handled by the submit
method. Let’s see what this method contains:
<script>
// components/Form.vue
export default {
data() {
return {
uploadingMobileAppVideo: false,
uploadingInstructorVideo: false,
};
},
methods: {
submit(e) {
this.uploadMobileAppVideo(e);
this.uploadInstructorVideo(e);
},
async uploadMobileAppVideo(e) {
this.uploadingMobileAppVideo = true;
// Mobile app video file
let file = e.target.mobile_app_video.files[0];
/* Read data */
const data = await this.readData(file);
/* upload the converted data */
const resp = await this.$cloudinary.upload(data, {
upload_preset: "default-preset",
folder: `nuxtjs-mobile-demo-walkthrough-generator`,
});
this.$emit("MobileAppVideoUploaded", resp.public_id);
this.uploadingMobileAppVideo = false;
},
async uploadInstructorVideo(e) {
this.uploadingInstructorVideo = true;
// Instructor video file
let file = e.target.instructor_video.files[0];
/* Read data */
const data = await this.readData(file);
/* upload the converted data */
const resp = await this.$cloudinary.upload(data, {
upload_preset: "default-preset",
folder: `nuxtjs-mobile-demo-walkthrough-generator`,
});
this.$emit("InstructorVideoUploaded", resp.public_id);
this.uploadingInstructorVideo = false;
},
readData(f) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(f);
});
},
},
};
</script>
Code language: HTML, XML (xml)
In the above code, we read the files submitted and upload them to the nuxtjs-mobile-demo-walkthrough-generator
folder. We also specify an upload preset. These are a set of rules to be used for all uploads. To create an upload reset, proceed to the settings
section in your Cloudinary account. Proceed to the upload
section. We recommend the following settings:
Unique filename: true
Delivery type: upload
Access mode: public
The above code will upload the files and emit two events. MobileAppVideoUploaded
and InstructorVideoUploaded
. In the next section, we receive these two events and generate the final video.
We will now inject the Form.vue
component in the pages/index.vue
file and listen for the events:
<!-- pages/index.vue -->
<template>
...
<Form
@InstructorVideoUploaded="instructorVideoUploaded"
@MobileAppVideoUploaded="mobileAppVideoUploaded"
/>
...
</template>
Code language: HTML, XML (xml)
We will receive the public_id
and assign it to local variables. When overlaying videos in subfolders, you need to replace all \
with :
as indicated here.
// pages/index.vue
<script>
export default {
data() {
return {
instructorVideo: null,
mobileAppVideo: null,
};
},
methods: {
instructorVideoUploaded(public_id) {
this.instructorVideo = public_id.replace("/", ":");
},
mobileAppVideoUploaded(public_id) {
this.mobileAppVideo = public_id.replace("/", ":");
},
},
};
</script>
Code language: HTML, XML (xml)
Once the public_id
s have been stored in the page state, we will proceed to overlay the two videos on top of the initial video template. To remove the sound from the mobile app video, we add the audioCodec="none"
setting.
<template>
...
<cld-video
public-id="nuxtjs-mobile-demo-walkthrough-generator/iphone_se_template"
width="1000"
crop="scale"
quality="auto"
controls="true"
autoplay="true"
class="m-auto"
v-if="mobileAppVideo && instructorVideo"
>
<cld-transformation
:overlay="`video:${mobileAppVideo}`"
width="405"
height="750"
gravity="center"
x="-385"
y="0"
audioCodec="none"
/>
<cld-transformation
:overlay="`video:${instructorVideo}`"
width="300"
height="300"
gravity="south_east"
radius="150"
x="100"
y="100"
crop="fill"
/>
</cld-video>
...
</template>
Code language: HTML, XML (xml)
With the above code, we have successfully created a mobile demo walkthrough generator. When the product changes, we simply upload the new videos and retrieve the newly compiled video. This just shows the potential of what is possible.