Building a Camera App in TypeScriptHow to build a simple photo app in HTML5, CSS3, and TypeScriptKenneth ReillyBlockedUnblockFollowFollowingMay 16Screenshot of Visual Studio Code with simple browser-based camera appIntroductionIn this article, we’ll look at how to build a simple camera web app in HTML5, CSS3, and TypeScript.
The full source code for the project is available here.
Modern, standards-compliant browsers provide incredibly powerful and flexible APIs for working with the browser engine in various ways, which includes accessing various hardware devices (such as the camera).
Project ConfigurationLet’s take a look at the package.
json file generated with npm init, along with a clean tsconfig.
json to define compiler options:Project structure with package.
json and tsconfig.
json filesThis project uses no external dependencies aside from node and a TypeScript compiler.
The file tsconfig.
json instructs the TypeScript compiler to generate ES6 modules and output them to the .
That wraps up the project configuration, meaning the rest will have to be implemented by hand.
While challenging, this is made much easier with type checking and other language features, along with powerful code completion and refactoring tools available in modern development environments such as Visual Studio Code.
Application HTML StructureThe page structure for this simple app is defined in index.
html with metadata and file importsThis short and sweet HTML file includes the bare minimum required for a decent example app: some Open Graph and other metadata, imports for css/style.
css and the module .
js, and the app structure, which is a main container with video, and a footer with two buttons — one for taking a photo, and the other for switching between device cameras.
Note the inline SVG used for the button icons.
By setting the viewBox property on the svg elements to “-1 -1 2 2”, the point coordinate system for the entire box becomes centered between -1 and 1 on each axis.
This makes it fairly simple to draw things like circles and chevrons as in the example above, using values such as r=0.
6 to indicate 60% of the total span from center to edge.
Application CSS DefinitionsThe layout and styles for this app are defined in css/style.
css definitions (minus the button:hover effects)This file is also short, with most of it fitting into the screenshot aside from the button:hover selectors.
For simplicity, a root unit of 16px has been defined for the footer metric, with a footer height of (16px * 7) and a button height of (16px * 5), which results in a 7:5 ratio of footer to button height.
The html, body, and svg icons are set to 100% width and height with zero margin or padding.
The video width is set to 100vw, and the height to a value of 100vh minus the footer height.
The buttons are centered horizontally and spaced evenly across the footer using CSS3 Flexbox properties.
TypeScript ImplementationNext up are the TypeScript files that contain the actual implementation of the main features of this application, which are:Preview the live camera outputSwitch between forward and rear facing camerasTake a picture and save it to the local device filesystemFirst we’ll look at the file src/types.
ts, in which there are a few useful types exported for both convenience and type safety:The contents of src/types.
ts with definitions for various typesWithin the file src/types.
ts, there is an enum for CameraMode which will be used to select the forward and rear facing cameras, an IButtons interface defining the app buttons, and a Defaults class defining width=640.
Next up is the main application file, src/photobooth.
ts:The PhotoBooth abstract class with static properties and initializersThe PhotoBooth class contains static properties for holding references to these four important components used within the application:mode: the currently selected CameraModebuttons: the HTMLButtonElement buttonscanvas: an off-screen canvas used to extract the photo from a live streamvideo: an HTMLVideoElement that displays the live camera streamAlso defined is a static init() method, which retrieves DOM references to the buttons to attach click handlers to them and then calls the static method on_enumerate_devices() which in turn begins the camera initialization.
The PhotoBooth class with initialization and feature methodsThe method init_camera() initializes the camera by calling the get_media() method to retrieve a Promise<MediaStream> from the browser which matches the criteria defined in constraints, and then passing that Promise to the on_get_media() handler, which in turn sets up the canvas and video objects and sets the stream as the video source.
The final initialization tasks of setting the height and width of the canvas and video are placed within the on_video_ready() handler, which is fired by the video element once the browser has finished loading it into the DOM and rendering it on-screen.
The PhotoBooth class showing handlers and feature methodsThe last event handler defined in the PhotoBooth class is on_error(), which is used as a generic error handler for Promise objects in the app by attaching them to promise chains via the .
Also, we have the actual features of the photo app.
The first is take_photo() which retrieves a .
jpeg image by proxying the video through the off-screen canvas object and then triggering a download via an anchor .
The second is the method switch_cam(), which swaps the CameraMode and re-initializes the camera.
ConclusionThis example project demonstrates how to prototype a simple application concept with just a few lines of HTML5, CSS3, and TypeScript, by leveraging the modern features of these languages and the environments designed to support them.
One of the powerful features of TypeScript is the ability to define an application in a very structural way, in which it resembles a well-designed server rack, versus a huge mess of random wires everywhere.
The full source for this application is available here, with a live demo here.
I hope you enjoyed this article and found it useful.
If you have any corrections or suggestions, or any other ideas in mind, feel free to leave me a comment.
Thanks for reading!.. More details