├── .gitignore ├── README.md ├── config ├── ZipperPlugin.js ├── webpack.config.dev.js ├── webpack.config.js └── webpack.config.prod.js ├── package-lock.json ├── package.json ├── public ├── index.html └── style.css └── src └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | dist-zipped/ 4 | yarn.lock -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fx(hash), fx(stdio), and p5 boilerplate 2 | 3 | A boilerplate based on the [fxhash-webpack-boilerplate](https://github.com/fxhash/fxhash-webpack-boilerplate), but with [fx(stdio)](https://github.com/alt-escapism/stdio) and p5 installed. 4 | 5 | ## Getting started 6 | 7 | Ensure that you have [nodejs](https://nodejs.org/) installed. 8 | 9 | Clone the repository: 10 | 11 | ```sh 12 | git clone https://github.com/alt-escapism/fxhash-stdio-boilerplate.git your_folder && cd your_folder 13 | ``` 14 | 15 | Install: 16 | 17 | ```sh 18 | npm i 19 | ``` 20 | 21 | Start server: 22 | 23 | ```sh 24 | npm start 25 | ``` 26 | 27 | This last command will open up your project with fx(stdio) installed, and [live reloading](https://webpack.js.org/configuration/dev-server/#devserverlivereload) enabled, so that you can iterate faster on your projects. 28 | 29 | ## Developing with fx(stdio) 30 | 31 | The file `src/index.js` contains sample code for getting started with fx(stdio) 32 | and p5. This should show you how to integrate with fx(stdio). In short, import 33 | and use the randomization functions from `@altesc/stdio`, instead of the ones 34 | from p5. If you want a random variable to appear in the fx(stdio) UI, simply add 35 | a unique name as the first argument to the function. 36 | 37 | See the [fx(stdio) documentation](https://altesc.art/stdio) for more information. 38 | 39 | ## Publishing to fx(hash) 40 | 41 | ```sh 42 | $ npm run build 43 | ``` 44 | 45 | This will prepare your bundle for publishing to fx(hash). The fx(stdio) UI will be stripped from this version. 46 | 47 | A zip file can be found at `dist-zipped/project.zip`, which can be directly 48 | imported on fx(hash). 49 | -------------------------------------------------------------------------------- /config/ZipperPlugin.js: -------------------------------------------------------------------------------- 1 | const path = require("path") 2 | const AdmZip = require("adm-zip") 3 | 4 | 5 | const defaultOptions = { 6 | outputPath: path.resolve(__dirname, "../dist-zipped/project.zip") 7 | } 8 | 9 | /** 10 | * The zipper plugin hooks to the end of compilation event, and it creates a ZIP file of 11 | * all the files within the ./dist folder into the ./dist-zipped folder to create a file 12 | * ready to be deployed on fxhash. 13 | * https://webpack.js.org/contribute/writing-a-plugin/ 14 | */ 15 | class ZipperPlugin { 16 | constructor(options = {}) { 17 | this.options = { 18 | ...defaultOptions, 19 | ...options 20 | } 21 | } 22 | 23 | apply(compiler) { 24 | // Specify the event hook to attach to 25 | compiler.hooks.done.tapAsync( 26 | "ZipperPlugin", 27 | (stats, callback) => { 28 | const outputPath = stats.compilation.outputOptions.path 29 | const zip = new AdmZip() 30 | zip.addLocalFolder(outputPath) 31 | zip.toBuffer() 32 | zip.writeZip(this.options.outputPath) 33 | callback() 34 | } 35 | ) 36 | } 37 | } 38 | 39 | module.exports = ZipperPlugin -------------------------------------------------------------------------------- /config/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | const config = require("./webpack.config"); 2 | const StdioWebpackPlugin = require("@altesc/stdio/webpack-plugin"); 3 | 4 | module.exports = { 5 | ...config, 6 | mode: "development", 7 | devServer: { 8 | // disables the Hot Module Replacement feature because probably not ideal 9 | // in the context of generative art 10 | // https://webpack.js.org/concepts/hot-module-replacement/ 11 | hot: false, 12 | port: 8080, 13 | open: "/stdio", 14 | client: { 15 | overlay: { 16 | errors: true, 17 | warnings: false, 18 | }, 19 | webSocketURL: { 20 | hostname: "localhost", 21 | }, 22 | }, 23 | }, 24 | plugins: [...config.plugins, new StdioWebpackPlugin()], 25 | }; 26 | -------------------------------------------------------------------------------- /config/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 3 | 4 | module.exports = { 5 | entry: "./src/index.js", 6 | output: { 7 | path: path.resolve(__dirname, "../dist"), 8 | filename: "bundle.js", 9 | clean: true, 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.css$/i, 15 | use: ["style-loader", "css-loader"], 16 | }, 17 | ], 18 | }, 19 | plugins: [ 20 | new HtmlWebpackPlugin({ 21 | template: "./public/index.html", 22 | inject: "body", 23 | publicPath: "./", 24 | }), 25 | ], 26 | }; 27 | -------------------------------------------------------------------------------- /config/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | const CopyPlugin = require("copy-webpack-plugin"); 2 | const config = require("./webpack.config"); 3 | const ZipperPlugin = require("./ZipperPlugin"); 4 | const path = require("path"); 5 | 6 | module.exports = { 7 | ...config, 8 | mode: "production", 9 | // add the zipper plugin to the list of plugins 10 | plugins: [ 11 | ...config.plugins, 12 | new CopyPlugin({ 13 | patterns: [ 14 | { 15 | from: "public", 16 | // prevents the index.html from being copied to the the public folder, as it's going to be 17 | // generated by webpack 18 | filter: async (filePath) => { 19 | return path.basename(filePath) !== "index.html"; 20 | }, 21 | }, 22 | ], 23 | }), 24 | new ZipperPlugin(), 25 | ], 26 | }; 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fxhash-stdio-boilerplate", 3 | "private": true, 4 | "description": "An fxhash boilerplate with fx(stdio) and p5", 5 | "author": "alt-escapism", 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "webpack --config ./config/webpack.config.prod.js", 9 | "start": "webpack serve --config ./config/webpack.config.dev.js" 10 | }, 11 | "dependencies": { 12 | "@altesc/stdio": "^0.2.7", 13 | "p5": "^1.4.2" 14 | }, 15 | "devDependencies": { 16 | "adm-zip": "^0.5.9", 17 | "copy-webpack-plugin": "^9.0.1", 18 | "css-loader": "^6.4.0", 19 | "html-webpack-plugin": "^5.4.0", 20 | "style-loader": "^3.3.0", 21 | "webpack": "^5.59.0", 22 | "webpack-cli": "^4.9.1", 23 | "webpack-dev-server": "^4.3.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FXHASH project 5 | 6 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /public/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | /* hide scrollbars */ 3 | overflow: hidden; 4 | } 5 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import "p5"; 2 | // Use random functions from stdio and not from p5 3 | import { random, randomGaussian } from "@altesc/stdio"; 4 | 5 | window.setup = function () { 6 | createCanvas(400, 400); 7 | noLoop(); 8 | }; 9 | 10 | window.draw = function () { 11 | background(220); 12 | 13 | const count = randomGaussian("count", 20, 4, floor); 14 | const minSize = random("size/min", 10, 50, floor); 15 | const maxSize = random("size/max", 50, 100, floor); 16 | const drawShape = random("shape", { 17 | circle: (x, y, r) => circle(x, y, r), 18 | square: (x, y, len) => rect(x - len / 2, y - len / 2, len, len), 19 | }); 20 | 21 | for (let i = 0; i < count; i++) { 22 | const x = random(width); 23 | const y = random(height); 24 | const s = random(minSize, maxSize); 25 | drawShape(x, y, s); 26 | } 27 | 28 | fxpreview(); 29 | }; 30 | --------------------------------------------------------------------------------