Initial commit! 🎉
This commit is contained in:
commit
bb1b543721
|
@ -0,0 +1,107 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Image & data output directory
|
||||
output/
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "driftingnebula",
|
||||
"description": "Generative art with GIMP, GEGL and ImageMagick.",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"start": "node --loader=ts-node/esm --no-warnings source/driftingnebula.ts",
|
||||
"test": "xo"
|
||||
},
|
||||
"dependencies": {
|
||||
"execa": "^6.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.21",
|
||||
"ts-node": "^10.6.0",
|
||||
"typescript": "^4.6.2",
|
||||
"xo": "^0.48.0"
|
||||
},
|
||||
"type": "module",
|
||||
"xo": {
|
||||
"prettier": true,
|
||||
"rules": {
|
||||
"no-await-in-loop": "off"
|
||||
},
|
||||
"space": true
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,53 @@
|
|||
import fsp from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import {performance} from 'node:perf_hooks';
|
||||
|
||||
import {execa} from 'execa';
|
||||
|
||||
import {Crop} from './gegl/exports.js';
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const projects: Project[] = [];
|
||||
|
||||
for (const {name, operations, resolution} of projects) {
|
||||
const dataStart = performance.now();
|
||||
const {width, height} = resolution;
|
||||
|
||||
const baseDir = path.resolve(`./output/${name}`);
|
||||
await fsp.mkdir(baseDir, {recursive: true});
|
||||
|
||||
console.log(`# ${name}`);
|
||||
console.log(`* ${width}x${height}`);
|
||||
console.log(`* ${operations.length} operations`);
|
||||
|
||||
const graph = operations.flatMap((operation) => {
|
||||
const graph = operation.graph();
|
||||
if (operation.appendCrop) {
|
||||
graph.push(...new Crop({height, width}).graph());
|
||||
}
|
||||
|
||||
return graph;
|
||||
});
|
||||
|
||||
const prettyGraph = graph.map((operation) =>
|
||||
operation.startsWith('gegl:') ? `\n${operation}\n` : ` ${operation}\n`,
|
||||
);
|
||||
|
||||
const graphFile = `${name}.txt`;
|
||||
const outputFile = `${name}.png`;
|
||||
|
||||
console.log(`* Writing ${graphFile}`);
|
||||
await fsp.writeFile(
|
||||
path.join(baseDir, graphFile),
|
||||
prettyGraph.join('').trimStart(),
|
||||
);
|
||||
|
||||
console.log(`* Writing ${outputFile}`);
|
||||
await execa('gegl', ['-o', path.join(baseDir, outputFile), '--', ...graph]);
|
||||
|
||||
const time = (performance.now() - dataStart).toFixed(2);
|
||||
console.log(`* Generated in ${time}ms`);
|
||||
}
|
||||
}
|
||||
|
||||
void main();
|
|
@ -0,0 +1,28 @@
|
|||
export abstract class BaseOperation<P> {
|
||||
public parameters: P;
|
||||
|
||||
/**
|
||||
* Some GEGL operations will run infinitely unless you limit the buffer in
|
||||
* some way, so all operations must indicate whether or not they should be
|
||||
* followed by a crop operation.
|
||||
*/
|
||||
public abstract appendCrop: boolean;
|
||||
|
||||
/** The GEGL operation name, starting with `gegl:`. */
|
||||
public abstract name: string;
|
||||
|
||||
constructor(parameters: P) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public graph(): string[] {
|
||||
const graph: string[] = [this.name];
|
||||
|
||||
for (const [key, value] of Object.entries(this.parameters)) {
|
||||
const kebabCasedKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||
graph.push(`${kebabCasedKey}=${value as string}`);
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import {BaseOperation} from './base.js';
|
||||
|
||||
export interface CropParameters {
|
||||
height: number;
|
||||
resetOrigin: boolean;
|
||||
width: number;
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export class Crop extends BaseOperation<CropParameters> {
|
||||
public static default: CropParameters = {
|
||||
height: 0,
|
||||
resetOrigin: false,
|
||||
width: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
|
||||
public appendCrop = false;
|
||||
public name = 'gegl:crop';
|
||||
|
||||
constructor(parameters?: Partial<CropParameters>) {
|
||||
super({...Crop.default, ...parameters});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export * from './base.js';
|
||||
export * from './crop.js';
|
||||
export * from './generic.js';
|
||||
export * from './simplex-noise.js';
|
|
@ -0,0 +1,18 @@
|
|||
import {BaseOperation} from './base.js';
|
||||
|
||||
export type GenericParameters = Record<string, number | string>;
|
||||
|
||||
export class Generic extends BaseOperation<GenericParameters> {
|
||||
public appendCrop: boolean;
|
||||
public name: string;
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
parameters?: GenericParameters,
|
||||
appendCrop?: boolean,
|
||||
) {
|
||||
super(parameters ?? {});
|
||||
this.name = name;
|
||||
this.appendCrop = appendCrop ?? false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import {BaseOperation} from './base.js';
|
||||
|
||||
export interface SimplexNoiseParameters {
|
||||
iterations: number;
|
||||
scale: number;
|
||||
seed: number;
|
||||
}
|
||||
|
||||
export class SimplexNoise extends BaseOperation<SimplexNoiseParameters> {
|
||||
public static default: SimplexNoiseParameters = {
|
||||
iterations: 1,
|
||||
scale: 1,
|
||||
seed: 1,
|
||||
};
|
||||
|
||||
public appendCrop = true;
|
||||
public name = 'gegl:simplex-noise';
|
||||
|
||||
constructor(parameters?: Partial<SimplexNoiseParameters>) {
|
||||
super({...SimplexNoise.default, ...parameters});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import {BaseOperation} from './gegl/exports.js';
|
||||
|
||||
declare global {
|
||||
interface Project {
|
||||
name: string;
|
||||
operations: Array<InstanceType<typeof BaseOperation>>;
|
||||
resolution: {
|
||||
height: number;
|
||||
width: number;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"outDir": "build",
|
||||
"strict": true,
|
||||
"target": "ESNext"
|
||||
},
|
||||
"include": [
|
||||
"source/**/*.ts"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue