Skip to content

Commit

Permalink
Merge branch 'dev' into stable
Browse files Browse the repository at this point in the history
  • Loading branch information
funwithtriangles committed Sep 17, 2018
2 parents 596d98f + 08bc5fc commit ace822c
Show file tree
Hide file tree
Showing 147 changed files with 5,914 additions and 1,155 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"key-spacing" : 0,
"jsx-quotes" : [2, "prefer-single"],
"max-len" : [2, 120, 2],
"object-curly-spacing" : [2, "always"]
"object-curly-spacing" : [2, "always"],
"no-var" : 2
}
}
255 changes: 255 additions & 0 deletions docs/dev/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
# Creating Sketches for Hedron

## Starting a project
It is best practice to create a project folder outside of Hedron. This is advantageous, because:

1. The project can exist as it's own repository
2. You can install dependencies from NPM without polluting Hedron's own dependencies

Inside the project folder, you'll want to have a "sketches" folder, this is what you'll point Hedron to.

## Sketch
Sketches together in the sketches directory. A sketch is itself directory with two required files:

- config.js
- index.js

## config.js

This is where the params and shots are defined.

```javascript
module.exports = {
// Default title when sketch is loaded in (can be changed by user)
defaultTitle: 'Solid',
// Params are values between 0 and 1 that can be manipulated by the user
// these values are sent to the sketch every frame
// e.g. Speed, scale, colour
params: [
{
key: 'rotSpeedX', // needs to be unique
title: 'Rotation Speed X', // should be human
defaultValue: 0 // must be between 0 and 1
},
],
// Shots are single functions that can fire, as opposed to values that change
// e.g. Explosions, Pre-defined animations
shots: [
{
method: 'shapeShift', // needs to be unique
title: 'Shape Shift' // should be human
}
]
}
```

## index.js

This is where the actual sketch is held. You can `require` other modules from here, so don't feel restricted to a single file.

### Very basic example
This is the minimum you need to do in order to use Hedron.

```javascript
const THREE = require('three')

class MyFirstSketch {
constructor () {
// Create a cube, add it to the root of the scene
const mat = new THREE.MeshNormalMaterial()
const geom = new THREE.BoxGeometry(300, 300, 300)
this.cube = new THREE.Mesh(geom, mat)
this.root.add(this.cube)
}

update (params) {
// params.rotSpeedX is a value that is controlled by the user,
// in order to change the rotation speed of the cube
this.cube.rotation.x += params.rotSpeedX
}
}

module.exports = MyFirstSketch
```

### Advanced example
This example shows many more features of Hedron, with lots more comments

```javascript
/** HEDRON TIP **
This is a nice and simple sketch to get you going!
A polyhedron that can spin on all axes. The user can change the speed of the rotation.
The user can change the scale. The user can also click on "shapeshift" and the geometry changes.
**/

/** HEDRON TIP **
Hedron uses three.js, so you'll need that :)
**/
const THREE = require('three')

/** HEDRON TIP **
Hedron sketches must be a class
**/
class Solid {
/** HEDRON TIP **
The constructor method has three arguments:
scene - This is the THREE object for the scene. You can also access the THREE renderer
using scene.renderer
meta - This is an object with meta data that might be useful. It has the following properties:
sketchesFolder - The path to the sketches folder on your computer. Useful if you need to link to a resource such as an image.
params - The sketch params when the sketch first initialises
**/
constructor (scene, meta, params) {
/** HEDRON TIP **
Must define a "root" property as a THREE.Group or THREE.Object3D
Hedron looks for this and will add it to the scene.
**/
this.root = new THREE.Group()

/** HEDRON TIP **
It's good practice to not manipulate the root object
so we create another group and add it to the root.
This isn't required and the name isn't important.
**/
this.group = new THREE.Group()
this.root.add(this.group)

// Empty array to be populated with meshes
this.meshes = []

// Defining a single material for all the polyhedra
const mat = new THREE.MeshBasicMaterial(
{ wireframe: true, color: 0xffffff }
)
const size = 300

// Array geometries (the platonic solids!)
const geoms = [
new THREE.IcosahedronGeometry(size),
new THREE.BoxGeometry(size, size, size),
new THREE.OctahedronGeometry(size),
new THREE.TetrahedronGeometry(size),
new THREE.DodecahedronGeometry(size)
]

// Loop through meshes
geoms.forEach(geom => {
// Create a mesh for each solid
const mesh = new THREE.Mesh(geom, mat)
// Add to array
this.meshes.push(mesh)
// Add to scene
this.group.add(mesh)
})

// Update the shape based on params
this._updateShape(params.meshIndex)
}

/** HEDRON TIP **
The update method is called every frame by Hedron.
You have the following arguments to make use of...
ownParams: An object containing params defined in config.js.
These are values between 0 and 1 that can be manipulated in many ways by the user.
time: Elapsed time in ms (not used below)
frameDiff: Number of frames that should have passed since last frame.
Useful for keeping speeds consistent.
If the framerate changes, this value changes too. At 60fps the value will be
exactly 1. Less than 60fps and the value goes above 1. More than 60fps and the value
goes below 1. See below on how it can be used.
allParams: An object containing all params from all sketches. (not used below)
**/
update (params, time, frameDiff, allParams) {
// Solids spin too fast at 1
const baseSpeed = 0.15

/** HEDRON TIP **
Making use of params.rotSpeedX to rotate the solid. When the user changes
the "Rotation Speed X" param (defined in config.js), it will change here and the
speed increases. We're multiplying the final increase by 'frameDiff'
so that the speed stays consistent across varying framerates.
**/
this.group.rotation.x += params.rotSpeedX * baseSpeed * frameDiff
this.group.rotation.y += params.rotSpeedY * baseSpeed * frameDiff
this.group.rotation.z += params.rotSpeedZ * baseSpeed * frameDiff

// Change scale using params.scale
params.scale = Math.max(params.scale * 4, 0.00001)
this.group.scale.set(params.scale, params.scale, params.scale)
}

/** HEDRON TIP **
All non-special methods of the class are exposed as "shots".
These are single functions that can fire rather than paramaters than slowly change.
See config.js to see how these are defined.
Current params are given as an argument
**/
shapeShift (params) {
let meshIndex = params.meshIndex

// Increase index to shapeshift
meshIndex++

// If at end of array, loop round
if (meshIndex > this.meshes.length - 1) meshIndex = 0

this._updateShape(meshIndex)

/** HEDRON TIP **
If you've updated some params inside the shot, you'll need to return these new values
**/
return { meshIndex }
}

_updateShape (meshIndex) {
// Loop through meshes and only show the mesh
// that matches with current index
this.meshes.forEach((mesh, index) => {
if (meshIndex !== index) {
mesh.visible = false
} else {
mesh.visible = true
}
})
}

/** HEDRON TIP **
Use the destructor method to do anything when the sketch is deleted
**/
destructor () {
console.log('Solid sketch deleted!')
}
}

/** HEDRON TIP **
Class must be exported as a default.
**/
module.exports = Solid
```

## Hedron dev config

You can get extra functionality by adding `dev.config.js` to `/config` (from the root directory of the Hedron repo).

```javascript
// config/dev.config.js
module.exports = {
defaultProject: false
}
```

Setting `defaultProject` to the path of a saved project (e.g. `/Users/alex/Desktop/foo.json`) can help improve your workflow when developing:
* The project will load automatically on load/restart
* The project sketches folder will be watched for changes, triggering a restart

## Reimporting

If you've already got a project going with some sketches and then make edits to a sketch, Hedron automatically loads in the new content. However, if you've made changes to `config.js`, you'll need to "reimport" to see the new params and shots. Do this by clicking the button at the bottom of the view for that sketch.
85 changes: 85 additions & 0 deletions docs/user-guide/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Hedron User Guide

Here is a quick overview of how to use Hedron.

## Sketches
Sketches are created with [three.js](https://github.com/mrdoob/three.js/). They are a Javascript module that exports a single [THREE.Group](https://threejs.org/docs/#api/objects/Group), to be placed in the main scene. The different aspects of a sketch can be controlled using "params" and "shots".

### Adding and removing sketches
Many sketches can be added to the same Hedron scene. These can be multiple instances of the same sketch, or different types of sketches.

In order to add sketches, click on the "+" in the right sidebar. If you're starting from scratch, you'll need to tell Hedron where your sketch folder is.

To remove a sketch, click the delete button at the bottom of the view for that sketch.

### Switching between sketches
You can switch between different sketches that are already added to Hedron using the right sidebar.

## Params
Params are the variables of a sketch. They are always a value between 0 and 1 (although more types of param are [planned](https://github.com/nudibranchrecords/hedron/issues/13)). The simplest way to control a param is to click and drag the value bar.

### Adding an input to a param
The real power of Hedron is the ability to link different inputs to a param. This can be audio, LFO or MIDI.

To add an input to a param:

1. Open the param by clicking on the area below the value bar
2. Choose an input using the "add new input" dropdown
3. Click the "activate" button to enable.

You can add more inputs and choose between them using the tabs inside that param. You'll note that each type of input has its own extra controls. Each of these can also be assigned to a MIDI control by clicking on the icon next to the value bar.

The activate/disable button can also be assigned a MIDI control by clicking on the icon next to the button (must send a "note on" midi message).

Some things to note:

- Adding a MIDI input will involve a "MIDI learn" step
- MIDI inputs are always active, they do not have an active/disabled state

## Shots
Shots are functions that the sketch has exposed for the user to have fun with. These could be things such as explosions, pre scripted animations, etc. The simplest way to control a shot is to click on the hit area for that shot.

### Adding an input to a shot
Shots have a very similar system to adding inputs as params, so please refer to the section above. However, there are a few things to note:

- When a shot has an audio input, the shot will display a value bar and a red "target line". If the value passes the target, the shot fires. It then needs to drop below this target to rearm. Adjusting the gain can give control over how often this fires
- MIDI should be a "note on" type control
- Instead of LFO, shots have a "sequencer". The rows of the sequencer are **one beat** (quarter note) split into 8. Click on each step for when you want the shot to fire.

## Reimporting shots and params
If you've already got a project going with some sketches and then make edits to a sketch, Hedron automatically loads in the new content. However, if you've made changes to config.js, you'll need to "reimport" to see the new params and shots. Do this by clicking the button at the bottom of the view for that sketch.

## Macros
Macros make it possible to control many params at once. To start using macros, click on "Macros" on the right sidebar.

### Adding a macro

1. Click "add macro" and give it a name
2. Click "start learning". Any changes to params you make will now be added to this macro.
3. Change some param values in a sketch
4. Click "stop learning"

### Macro gotchas

Currently, after creating a macro, it wont do much until you change the values of its target values. This is because when you are teaching the macro, you are moving the params to their target. You'll need to move these param values away from their target for the macro to work.

Improvements to macros are [planned](https://github.com/nudibranchrecords/hedron/issues/10).

## MIDI Devices
Midi devices display on the left hand side, underneath the preview.

### MIDI Banks
You can change the current bank you are using for each device using the list of numbers next to that device. When assigning MIDI anywhere, it will default to the current bank you are on for that device.

## MIDI Clock
By default, MIDI clock is generated by Hedron.

- Use the "Tap Tempo" button to match the tempo of the song you are performing to.
- Use the "reset" button at the beginning of the beat/bar/phrase to keep things in sync.
- You can manually edit the generated clock BPM, or disable it completely in the settings. (Project > Settings)
- If you have an external MIDI clock connected, Hedron will detect it automatically. You should disable the generated clock if you are using an external one.

## Other features

* Save or load using "Project > Save/Load/Save As..."
* Send to a connected display using "Displays > "Send to XXX"
Loading

0 comments on commit ace822c

Please sign in to comment.