After Effects, but layers are code
Aether is a creative coding playground that lets you build visual compositions using JavaScript. Think of it as After Effects where every layer is programmable code. Create animations, effects, and visual experiments by stacking and blending different types of layers.
# Clone the repository
git clone <repository-url>
cd Aether
# Install dependencies
npm install
# Start development server
npm run devCreate a new file in the examples/ directory:
import { createPlayer } from '../src/player.js'
import { Layer } from '../src/layer.js'
import { gradient } from '../layers/generators/gradient.js'
import { rgbOffset } from '../layers/pixel/rgbOffset.js'
const layers = [
new Layer({ size: [320, 240] }, gradient, {
startColor: '#ff6b6b',
endColor: '#4ecdc4',
direction: 'horizontal'
}),
new Layer({ size: [320, 240] }, rgbOffset, {
offset: 0.02,
mode: 0
})
]
const player = createPlayer({
size: [320, 240],
animated: true,
duration: 5,
targetFPS: 30,
layers
})
await player.loadAndStart()The main orchestrator that manages your composition:
- size: Final output dimensions
[width, height] - animated: Whether the composition should animate
- duration: Length in seconds
- targetFPS: Target frame rate
- layers: Array of Layer objects
Each layer has:
- size: Layer dimensions
[width, height] - blendMode: How it blends with layers below
- opacity: Layer transparency (0-1)
- renderer: The actual rendering logic
- params: Configuration for the renderer
Available blend modes: normal, multiply, screen, overlay, darken, lighten, color-dodge, color-burn, hard-light, soft-light, difference, exclusion, hue, saturation, color, luminosity
Create content from scratch:
- Fragment Shader - Loadable GLSL pixel shaders
- Gradient - Linear and radial gradients
- Particles - Particle system with physics
- Pixel Pattern - Array-defined repeating patterns
- Perlin Noise - Random noise field (greyscale)
- Simple 3D Layer - Three.js procedural meshes
- Text - Text rendering with custom fonts
Load external content:
- Image Layer - Load and display static images
Modify pixel data:
- Adjustments - Brightness, contrast, saturation
- Blur - Canvas API-based blur
- Invert - Color inversion
- Pixelate - Pixelation effect
- Posterize - Uniform quantization with bucketing
- RGB Offset - Channel separation effects
- Threshold - Chroma-based black/white snapping
- Vignette - Edge darkening
Final output effects:
- CGA Dither - 4-color palette Bayer dithering
- Feedback - Frame blending for trails
- Receipt - Simplified low-resolution output
- Waves - Rutt-Etra style wave rendering
Browse the examples/ directory for working compositions:
- RGB Offset - Basic image with RGB channel separation
- Blob Animation - Animated blob with WebGL shaders
- CGA Sphere - 3D sphere with CGA-style dithering
- Plato Solids - 3D geometric shapes with rotation
- Dot Matrix - Dot matrix pattern generation
- Spherical Particles - Particles moving on sphere surface
- Maths Texture - Mathematical texture generation
- Start the development server:
npm run dev - Open
http://localhost:5173 - Click on any example to view it
- Use the viewer controls to play/pause and export
new Layer(controls, renderer, params)controls:
size: [width, height]- Layer dimensionsblendMode: string- Blend mode (optional, defaults to 'normal')opacity: number- Layer opacity (optional, defaults to 1.0)
renderer: Object with a render(ctx, params) method
params: Configuration object passed to the renderer
Parameters can be functions that receive animation progress:
{
offset: (pct) => 0.01 + 0.1 * Math.sin(pct * Math.PI * 2),
rotation: (pct) => pct * Math.PI * 2
}pct: Animation progress [0, 1]t: Current time in seconds
{
// Required: Main rendering function
render(ctx, params) {
// ctx: Canvas 2D context
// params: Evaluated parameters + {width, height, inputCtx, t, pct, frame}
},
// Optional: Default parameters
defaultParams: {
// Default values
},
// Optional: Initialization
async init(params) {
// Called once before rendering starts
},
// Optional: Reset function
reset(params) {
// Called when animation loops
}
}The viewer includes export functionality:
- Individual Frames (PNG) - Export each frame as PNG
- WebM VP9 (Lossless) - High-quality video export
- WebM VP8 (High Quality) - Compressed video export
Click the πΉ button in the viewer to export your composition.
Aether/
βββ src/ # Core library
β βββ player.js # Main player logic
β βββ layer.js # Layer management
β βββ webgl/ # WebGL utilities
βββ layers/ # Layer implementations
β βββ generators/ # Content generators
β βββ media/ # Media loaders
β βββ pixel/ # Pixel effects
β βββ postproc/ # Post-processing
βββ examples/ # Example compositions
βββ assets/ # Images, models, shaders
βββ index.html # Main viewer
- Create a new file in the appropriate
layers/subdirectory - Export an object with a
rendermethod - Optionally include
defaultParams,init, andresetmethods - Import and use in your compositions
# Build for production
npm run build
# Preview production build
npm run preview- Creative Coding - Visual experiments and generative art
- Prototyping - Quick visual effect prototypes
- Education - Learning graphics programming concepts
- Art Projects - Digital art and installations
- Video Effects - Custom video processing pipelines
- Fork the repository
- Create a feature branch
- Add your layer or improvement
- Include an example if applicable
- Submit a pull request
MIT License - see LICENSE file for details.
Built with β€οΈ for the creative coding community