Last active
March 18, 2023 15:58
-
-
Save sterlingcrispin/ca508f444fc6ac525035a24c180b6e5a to your computer and use it in GitHub Desktop.
ArtBlocks helpful files for artists
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if you need to minifiy an HLSL shader | |
you can use this website | |
https://ctrl-alt-test.fr/minifier/?main | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// this compresses your script into a tiny blob of code | |
// helpful for uploading to test/mainnet | |
const { minify } = require('terser') | |
const fs = require('fs') | |
const config = { | |
compress: { | |
dead_code: true, | |
drop_console: true, | |
drop_debugger: true, | |
keep_classnames: false, | |
keep_fargs: false, | |
keep_fnames: false, | |
keep_infinity: false, | |
passes: 5, | |
}, | |
mangle: { | |
eval: true, | |
properties: { | |
// these are all words that shouldn't be mangled | |
// it's most of the p5js reserved words and some other things | |
// there might be some repeats, but it doesn't matter | |
// if you have special words that must not be mangled, add them here | |
reserved: [ | |
'stroke', 'strokeWeight', 'noStroke', 'length', 'fill', 'noFill', 'background', 'colorMode', 'color', 'random', 'randomGaussian', 'randomSeed', 'noise', 'noiseSeed', 'noiseDetail', 'noisePerlin', 'noiseSimplex', 'noiseOctaves', 'noiseFrequency', | |
'color','alpha','red','green','blue','hue','saturation','brightness','lerpColor','lerp','background','clear','colorMode','fill','noFill','noStroke','stroke','strokeWeight','blendMode','createCanvas','createGraphics','resizeCanvas','noCanvas','image','imageMode','tint','noTint','blend','copy','filter','get','loadImage','loadPixels','set','updatePixels','pixels','dither','noDither','pixelDensity','displayDensity','width','height','windowWidth','windowHeight','displayWidth','displayHeight','frameCount','frameRate','focused','cursor','noCursor','displayWidth','displayHeight','bezier','bezierDetail','bezierPoint','bezierTangent','curve','curveDetail','curvePoint','curveTangent','curveTightness','line','point','quad','triangle','arc','ellipse','ellipseMode','line','lineCap','lineJoin','lineWidth','point','pointLight','quad','rect','rectMode','square','triangle','beginContour','beginShape','bezierVertex','curveVertex','endContour','endShape','quadraticVertex','vertex','box','cone','cylinder','ellipsoid','noSmooth','plane','sphere','smooth','torus','noStroke','stroke','strokeCap','strokeJoin','strokeWeight','beginCamera','camera','endCamera','perspective','printCamera','ortho','frustum','rotate','rotateX','rotateY','rotateZ','scale','shearX','shearY','translate','applyMatrix','popMatrix','printMatrix','pushMatrix','resetMatrix','rotate','PI','HALF_PI','QUARTER_PI','TAU','TWO_PI','DEGREES','RADIANS','angleMode','angle','cos','degrees','radians','sin','tan','acos','asin','atan','atan2','exp','log','mag','map','max','min','norm','pow','round','sq','sqrt','abs','ceil','constrain','dist','exp','floor','lerp','log','circle','setUniform','substr','parseInt','min','max','floor','push','pop','createVector','random','filter','stroke','strokeWeight','sqrt','push','pow','reverse','concat','addPoints','color','filter','windowResized','setup','draw','mouseClicked','mouseDragged' | |
], | |
}, | |
keep_classnames: false, | |
keep_fnames: /^(window\.|setup|width|draw|height|pixelDensity|color|alpha|windowResized)$/, | |
toplevel: true, | |
}, | |
module: false, | |
sourceMap: false, | |
} | |
const code = fs.readFileSync('./YOUR_SCRIPT_NAME.js', 'utf8') | |
minify(code, config).then((minified) => { | |
fs.writeFileSync('./miniscript.js', minified.code) | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// this will output the hash of the token being generated when the page loads | |
// its equivalent to minting a new token each time you refresh the page | |
console.log("tokenData.hash", tokenData.hash); | |
// you can also set the hash manually | |
// so the image is static and you can focus on debugging one image | |
// like this | |
// tokenData.hash = "0x6ef5e336dd31d6bbd322a19687a9eb2d8e1d2bfd71dfb44f5a845117539a15d0" | |
// this random number generator is from somewhere in the documentation | |
class Random { | |
constructor() { | |
this._useA = 0; | |
let sfc32 = function (uint128Hex) { | |
let a = parseInt(uint128Hex.substr(0, 8), 16); | |
let b = parseInt(uint128Hex.substr(8, 8), 16); | |
let c = parseInt(uint128Hex.substr(16, 8), 16); | |
let d = parseInt(uint128Hex.substr(24, 8), 16); | |
return function () { | |
a |= 0; | |
b |= 0; | |
c |= 0; | |
d |= 0; | |
let t = (((a + b) | 0) + d) | 0; | |
d = (d + 1) | 0; | |
a = b ^ (b >>> 9); | |
b = (c + (c << 3)) | 0; | |
c = (c << 21) | (c >>> 11); | |
c = (c + t) | 0; | |
return (t >>> 0) / 4294967296; | |
}; | |
}; | |
// seed prngA with first half of tokenData.hash | |
this._prngA = new sfc32(tokenData.hash.substr(2, 32)); | |
// seed prngB with second half of tokenData.hash | |
this._prngB = new sfc32(tokenData.hash.substr(34, 32)); | |
for (let i = 0; i < 1e6; i += 2) { | |
this._prngA(); | |
this._prngB(); | |
} | |
} | |
// random number between 0 (inclusive) and 1 (exclusive) | |
_random_dec() { | |
this._useA = !this._useA; | |
return this._useA ? this._prngA() : this._prngB(); | |
} | |
// random number between a (inclusive) and b (exclusive) | |
_random_num(a, b) { | |
return a + (b - a) * this._random_dec(); | |
} | |
// random integer between a (inclusive) and b (inclusive) | |
// requires a < b for proper probability distribution | |
_random_int(a, b) { | |
return Math.floor(this._random_num(a, b + 1)); | |
} | |
// random boolean with p as percent liklihood of 1 | |
_random_bool(p) { | |
return this._random_dec() < p; | |
} | |
} | |
let R = new Random(); | |
// Grab the first 16 values of the hash to use as a noise seed. | |
const seed = parseInt(tokenData.hash.slice(0, 16), 16); | |
console.log("seed", seed); | |
// below are are my random functions | |
// rndPool is a pool of random numbers | |
// because if you use R._random_dec() directly, the order you call it matters a lot | |
// by that I mean, suppose you're calling it 3 times during your setup function | |
// to determine the color of your background, the color of your foreground, and the size of your shape | |
// then later on you decide to change the order of those calls | |
// the results will be different even if you're using the same tokenData.hash | |
// using a pool of numbers like this also makes your features script extremely simple | |
// because 99% of the features script will just be copy pasting this code | |
var rndPool = []; | |
const rndPoolSize = 100; | |
for (var i = 0; i < rndPoolSize; i++) { | |
rndPool.push(R._random_dec()); | |
} | |
let getRndStreaming = (range) => { | |
return R._random_dec() * range; | |
}; | |
let getRndIntPoolIdxMinMax = (idx, min, max) => { | |
var rng = Math.floor(rndPool[idx] * (max-min+1) + min); | |
return Math.min(Math.max(rng, min), max); | |
}; | |
// so you'd use this like | |
var featureGenerateTree = getRndIntPoolIdxMinMax(11, 0, 100) < 65; | |
var featureBigSphere = getRndIntPoolIdxMinMax(12, 0, 100) < 65; | |
var featureBigCube = getRndIntPoolIdxMinMax(13, 0, 100) < 22; | |
var featureWhatever = getRndIntPoolIdxMinMax(14, 0, 100) < 11; | |
// then your separate features.js script would be really simple like, | |
// all of the above code plus this | |
// var traits = {}; | |
// traits.generateTree = featureGenerateTree; | |
// traits.bigSphere = featureBigSphere; | |
// traits.bigCube = featureBigCube; | |
// traits.whatever = featureWhatever; | |
// you could use the variables later in your regular program like | |
if (traits.generateTree) { | |
// do something | |
} | |
// if you need another random number you can just call getRndIntPoolIdxMinMax again somewhere else in your code | |
// I really recommend calling things like this | |
// after calling any trig functions like sin, cos, tan, etc | |
// because they can create tiny floating point errors | |
// between browsers , generating different images on different browsers | |
// ie: | |
// var value = Math.sqrt(Math.sin(0.5) * Math.cos(0.5)); | |
// value = FloatLessDetailThousand(value); | |
let FloatLessDetailThousand =(f)=>{ | |
return Math.floor(f*1000)/1000; | |
} | |
let floatLessDetailHundred = (f) => { | |
return Math.floor(f * 100) / 100; | |
} | |
let floatLessDetailTen = (f) => { | |
return Math.floor(f * 10) / 10; | |
} | |
const tinyNumber = .000000001; | |
// also doing floating point comparison like | |
// if (a == b) { ... } | |
// is a bad idea because of floating point errors between browsers | |
// so instead do something like | |
// if (Math.abs(a - b) < tinyNumber) { ... } | |
// or floor it but that's not as good | |
// if (Math.floor(a) == Math.floor(b)) { ... } | |
// you'll probably want to do something here | |
// so your image responds to the size of the browser window | |
function windowResized() { | |
} | |
// if you're using p5.js | |
// I would | |
// - calculate the position of everything assuming that the width of the canvas is a fixed 1000 units wide, or 0 to 1, or pick your own coordinates, and do all your math at that fixed size, ideally you only need to do all this once when the page first loads | |
// - as the user resizes the window, windowResized() is called | |
// - then get the new window size | |
// - resize your canvas to the new size | |
// - redraw your image and scale your precalculated positions to the new canvas size |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------- | |
Make sure you use this starter template, it will make your life a lot easier. | |
Everything in your project needs to be in a single javascript file as shown in example.js | |
You can not load in external assets like .Obj files | |
https://github.com/ArtBlocks/artblocks-starter-template | |
------- |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// this generates thumbnails similar to the static images rendered by AB | |
const puppeteer = require('puppeteer'); | |
let date_ob = new Date(); | |
var start=Date.now() | |
var hours = date_ob.getHours(); | |
var minutes = date_ob.getMinutes(); | |
var seconds = date_ob.getSeconds(); | |
// you can change this to a higher number if you want to generate screenshots of multiple tokens at once, best to keep it below 10 at a time | |
var limit = 1; | |
var idx = 0; | |
for (var i = 0; i < limit; i++) { | |
(async () => { | |
const browser = await puppeteer.launch( | |
{ | |
dumpio: true, | |
headless: 'chrome', | |
defaultViewport: { | |
width: 2800, | |
height: 2800 | |
}, | |
// this works for my M1 macbook pro | |
args: ['--no-sandbox', '--disable-setuid-sandbox', '--use-angle=metal'] | |
// depending on your machine you might use this instead | |
// args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--use-gl=egl'] | |
} | |
); | |
const page = await browser.newPage(); | |
page | |
.on('console', message => | |
console.log(`${message.type().substr(0, 3).toUpperCase()} ${message.text()}`)) | |
.on('pageerror', ({ message }) => console.log(message)) | |
.on('response', response => | |
console.log(`${response.status()} ${response.url()}`)) | |
.on('requestfailed', request => | |
console.log(`${request.failure().errorText} ${request.url()}`)) | |
await page.goto('http://localhost:3000/YOUR_SCRIPT_NAME', { waitUntil: 'load', timeout: 0 }); | |
console.log(`SCREENSHOT START seconds elapsed = ${(Date.now() - start)}`); | |
idx +=1; | |
await page.screenshot({ | |
path: 'screenshot_' + hours + '_' + minutes + "_" + seconds + "_" + idx + '.png' | |
}); | |
await browser.close(); | |
console.log(`SCREENSHOT END MS elapsed = ${(Date.now() - start)}`); | |
})(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment