Electronjs application example that I am using to make videos
This year I wanted to start looking into how to go about using electronjs, and so far I have a small collection of tech demos, and hello world type programs that make use of various features of electronjs to make desktop applications with html and javaScript. So far I all ready have wrote my getting started post on electronjs, and a few others on top of that. However over the long term though I am going to want to make at least one or two actual programs that I use to make some kind of content, such as a text editor, an art program of some kind, or maybe even something that can be used to make a video project of some kind. With that said I have a simple text editor program in the works, but for todays post I am going to be writing about the current state of something that I have been putting a whole lot more time into to make videos that I am calling VideoGround.
Over the years I have wrote a whole lot of posts on threejs which is a popular javaScript library that has to do with 3d modeling. I have learned, and continue to learn, a whole lot about threejs, and also while I am at it 3d modeling in general inside and outside of threejs when it comes to using blender for example. I also like vuejs when it comes to using a front end framework, and I have also logged a fair amount of time working with nodejs as well when it comes to working in a javaScript environment outside of a web browser. So then working on a project like this allows me to use, refresh, and refine knowledge of a wide range of skills that I developed over many years. That is always a good thing for what that is worth, but the real motivation with this is to also work on something that is fun, and even if it is a little buggy can still be used to make a final product.
What to know first
This is not a getting started type post on electronjs, threejs, vuejs, javaScript in general as well as any and all additional subjects that need to be covered first before making something like this. If you are still fairly new to javaScript in general it would be best to start out with some simple examples of javaScript alone in various environments for doing so. Also this might not be the best example of an electronjs application starting point, rather this is the first actual application that I have made that I am actually using to create some kind of content.
The full source code and additional assets are up on Github
The full source code for this electron js application is in my examples-electronjs repository on github.
1 - The root electronjs files
The core of the electron application that is video ground as of revision 3 consists of three files, a main javaScript file, a Menu file, and a preload file. There are of course a lot of additional files that have to do with the client system, and then even more files when it comes to making video projects. However in this first section I will be sticking to just the typical root level files of the electronjs application.
1.1 - The main javaScript file
When it comes to the web preferences of the main browser window I am explicitly setting contextIsolation to true. Even though I am using an older version of electron for this application this is the default for newer versions and I am thinking that I should get accustomed to working with it for the sake of any and all future electron projects I might make.
// I tried to disable webSecurity to see if that would fix the issue with CSP and vuejs (did not work)
webSecurity: true,
contextIsolation: true,
preload: path.resolve( __dirname, 'preload.js')
}
});
// load the html file for the main window
mainWindow.loadFile('html/window_main.html');
// Open the DevTools for debugging
mainWindow.webContents.openDevTools();
const menu = Menu.buildFromTemplate( require( path.join(__dirname, 'menu.js') ) );
mainWindow.setMenu(menu);
return mainWindow;
};
// the 'ready' event
app.whenReady().then(() => {
var mainWindow = createMainWindow();
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0){
createMainWindow()
}
})
});
// the 'window-all-closed' is also a kind of on quit event
app.on('window-all-closed', function () {
if (process.platform !== 'darwin')
app.quit()
});
1.2 - The Menu
I am going to want to have a custom menu for this application, and this will likely be the case for just about all future electron js applications as well. When it comes to the Menu of an application I could just make that part of the mainjavaScript file but I have found that I like to pull the object that I will be using with the Menu.buildFromTemplate method into a separate file and just require that in when creating the window.
This is the preload file that I am using to create an API that I can then used in the front end code of the application. This is then where I have a collection of methods that have to do with things like writing a frame png file when exporting a video to a folder in which I will be creating a video file. There is also directly exporting as a video from the browser, but I have found that doing so will often break as new versions of chromium come out. Even if I go that way in any future versions I am still going to want to have this feature as one of several export options.
So then I have the javaScript files that have to do with the main process, and also setting up features for the render process of this electronjs application project example. However now there is the question of that html file that I am loading in the main javaScript file, and everything that branches off from that.
2.1 - The main html file
The main html file that I load for the browser window in main.js also loads a whole bunch of additional javaScript files, and also provided some hard coded html that I work off of within those files. With that said on top of using electron I am also using threejs and vue.js when it comes to the client side code. Of course I need to use threejs because that is what I want to use when rendering each frame of a video, however I also want to use vuejs when it comes to working out user interface components as I have found that it just works out a lot better compared to what happens for me when I just go all out native with that.
I started a utils.js file where I intend to park a lot of typical methods that I will be using through the client system. I also have a file that is used to set up an object that is then changed by loading a main video javaScript file that overwrites what is set up in that file to define what the logic is for the video.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var utils = {};
// DAE tools
utils.DAE = {};
// get the first Mesh or Group type object to be found
When I first started this project I just wanted to have a single javaScript to just set up the core of what I wanted, so I just simply called it client.js . I am not sure if I should write to much about this file at this time if I am gong to make at least one or more additional.
fps_update = 30, // fps rate to update ( low fps for low CPU use, but choppy video )
fps_movement = 60, // fps rate to move camera
frame = 0,
frameMax = 600,
loopActive = false,
lt = newDate();
// update
let update = function(){
sm.per = Math.round(sm.frame) / sm.frameMax;
sm.bias = getBias(sm.per);
VIDEO.update(sm, scene, camera, sm.per, sm.bias);
};
// app loop
let loop = function () {
let now = newDate(),
secs = (now - lt) / 1000;
if(sm.loopActive){
requestAnimationFrame(loop);
if(secs > 1 / fps_update){
sm.setFrame();
sm.frameFrac += fps_movement * secs;
sm.frameFrac %= sm.frameMax;
sm.frame = Math.floor(sm.frameFrac)
lt = now;
}
}
};
// setup
sm.setup = function(){
sm.frame = 0;
sm.frameFrac = 0;
sm.loopActive = false;
scene.children = [];
scene.background = new THREE.Color('black');
VIDEO.init(sm, scene, camera);
sm.setFrame();
};
// set frame
sm.setFrame = function(){
// call update method
update(secs);
// render
renderer.render(scene, camera);
};
// start loop
sm.play = function(){
sm.loopActive = !sm.loopActive;
if(sm.loopActive){
lt = newDate();
loop();
}
};
sm.setup();
}
());
2.4 - ui playback
I am going to want to have at least one if not more features in the page that are used to interact with the state of the current video project that I am working on with this. One feature that I will want to have is a few buttons and various other input elements that have to do with just playing back the video, stopping the video, stepping the current frame forward and backward, and also to jump to a specific frame.
On top of having a user interface for playing back the video I am also going to want to have a user interface for mutating the state of the video itself.
This might prove to be a project that I might very well continue to work on, that should go without saying if I do end up using this every day to make videos. Future plains with it will involve not just adding every feature that I can think of, but rather be a little more reserved about making the program more complex. At this point I am a little more interested in making the application as it currently stands more solid as there are a fair number of bugs that I would like to work out with it, and I am just not complicate happy with the over all structurer as it currently stands as revision 3.
That is not to say that I do not have ideas for additional features, I do, many of them have to do with automating things that I am currently doing manually. For example making use of the child process module to call ffmpeg to create a final video from exported frame images rather than doing so mainly from the command line. I am currently using some bash aliases, but I should just be able to do that from within VideoGround.