Want to start painting now? Head to https://aframe.io/a-painter!
Make sure you have a WebVR-enabled browser. In Chromium, enable the flags for chrome://flags/#enable-webvr
and chrome://flags/#enable-gamepad-extensions
. Firefox support is coming soon.
(Don’t have a headset? No problem – you can still view paintings from any device!)
The Mozilla VR team are big fans of Tilt Brush. It’s a wonderful example of the power of VR as an expressive medium. In the last few weeks, we've been experimenting with our own Web-based interpretation of Tilt Brush. We wanted to show how easy it is to produce and share your creations on the Web across platforms, with no software installations required.
To browse paintings, you just need a browser with WebGL, but to unleash your inner artist, you'll need a system with hand-tracked controllers, which currently means using an HTC Vive on Windows (though we hope this changes soon!).
What can I do with A-Painter today?
- Paint in 3D using hand-tracked motion controllers. Use both hands to paint!
- Share drawings with the world simply by copying and pasting a URL.
- View 3D drawings anywhere both with and without a headset.
- Paint on top of other people’s drawings and make them your own.
- Drag and drop images and
OBJ
models from your desktop to the browser, for a template or starting point to paint over. - Save and load local binary files of your drawings.
- Over 30 brushes with a custom A-Painter Brush API to easily create new ones.
How to play with it
It’s easy! Go to the A-Painter web site with a WebVR-enabled browser (with Gamepad Extensions enabled in about:config
), and put on your HTC Vive headset. Grab your controllers, hold the trigger button, and start painting!
If you don't have a headset, you can still view other people's creations using mouse and keyboard or mobile.
Controls
- Trigger: Hold down to paint (it’s pressure sensitive).
- Thumbpad: Slide up and down to change the brush size.
- Grip: Squeeze to undo the latest stroke.
- Menu Button: Press to toggle the main menu.
Once you open the main menu, you can modify the color, size, and brush type by pointing the other controller to the desired option and clicking the trigger. The controller used to point and click is the one that will receive the new settings.
- Color history: The latest seven colors used will be saved in these swatches.
- Clear: Clears the painting. Use with care!
- Save: The whole painting will be saved and uploaded to a server in a binary format. Outside of VR (but still in your browser), you'll get a URL to share your painting and resume your work later.
- Copy: The current brush settings (type, color, and size) of the controller holding the menu will be transferred to the pointing controller.
A-Painter is extensible
To create a new brush, implement the following interface, and register it by calling AFRAME.registerBrush(brushName, definition, options)
.
And, from within your AFRAME.registerBrush
call, define the following:
BrushInterface.prototype = {
addPoint: function (position, orientation, pointerPosition, pressure, timestamp) {},
tick: function (timeOffset, delta) {}
};
The only required method to implement is addPoint. With addPoint, you'll use the point, orientation, and pressure data from the controller to create or modify a geometry. Return true
if you've added something to the scene and false
otherwise. If you want to add dynamic behavior, implement the tick method, which will be called on every frame.
Here is the code for a custom spheres
brush:
/* globals AFRAME, THREE */
AFRAME.registerBrush(
// Name of brush.
'spheres',
// Methods for brush definition.
{
init: function (color, width) {
// Initialize the material based on the stroke color.
this.material = new THREE.MeshStandardMaterial({
color: this.data.color,
roughness: 0.5,
metalness: 0.5,
side: THREE.DoubleSide,
shading: THREE.FlatShading
});
this.geometry = new THREE.IcosahedronGeometry(1, 0);
},
// This method is called every time we need to add a point
// to our stroke. It should return `true` if the point is
// added correctly and `false` otherwise.
addPoint: function (position, orientation, pointerPosition,
pressure, timestamp) {
// Create a new sphere mesh to insert at the given position.
var sphere = new THREE.Mesh(this.geometry, this.material);
// The scale is determined by the trigger pressure.
var scale = this.data.size / 2 * pressure;
sphere.scale.set(scale, scale, scale);
sphere.initialScale = sphere.scale.clone();
// Generate a random phase to be used in the tick animation.
sphere.phase = Math.random() * Math.PI * 2;
// Set the position and orientation of the sphere to match
// the controller’s.
sphere.position.copy(pointerPosition);
sphere.rotation.copy(orientation);
// Add the sphere to the `object3D`.
this.object3D.add(sphere);
// Return `true`, since we’ve correctly added a new point (sphere).
return true;
},
// This method is called on every frame.
tick: function (timeOffset, delta) {
for (var i = 0; i < this.object3D.children.length; i++) {
var sphere = this.object3D.children[i];
// Calculate the sine value based on the time and the phase for
// this sphere, and use it to scale the geometry.
var sin = (Math.sin(sphere.phase + timeOffset / 500.0) + 1) / 2 + 0.1;
sphere.scale.copy(sphere.initialScale).multiplyScalar(sin);
}
},
},
// Additional options for this brush.
{
thumbnail: 'brushes/thumb_spheres.gif',
spacing: 0.01
}
);
Read more about creating custom brushes.
Perhaps we could…
While developing this tool, we've come up with many interesting ideas. The future of A-Painter depends on your feedback and adoption, but here are some features we'd like to add:
- More and better tools, such as a color picker and eraser
- More and better brushes
- Save screenshots and
GIF
animations - Audio-reactive brushes
- Multi-user painters and spectators
- Import
glTF
models - Export to standard 3D file formats, such as
OBJ
andglTF
- Dedicated web site with gallery of users' submissions
- Post-processing filters
- Performance optimizations to existing brushes
If you have an idea, find an issue, or want to contribute to the codebase, please join us at https://github.com/aframevr/a-painter.