nn (netnet-standard-library.js) is a browser-based JavaScript library designed to aid creative coders working on internet art and web design projects. It serves as the core utility library for netnet.studio, functioning both as a tool-kit for creating interactive and generative work within the platform and as a tool for building netnet.studio itself. The library is intentionally approachable for beginners, featuring helpful error messages and friendly documentation, yet expressive enough to support complex creative work.
| introduction page | documentation page | demo gallery |
Add a single <script> tag to your HTML, there's no build step, no package manager, no dependencies. The global nn object is then available everywhere on the page. Pin to a specific version so your project won't change unexpectedly if the library updates:
<!-- 1.0.1 (most recent stable version) -->
<script src="https://cdn.jsdelivr.net/gh/netizenorg/netnet-standard-library@1.0.1/build/nn.min.js"></script>
<!-- 0.9.0 (the original pre-release version) -->
<script src="https://cdn.jsdelivr.net/gh/netizenorg/netnet-standard-library@0.9.0/build/nn.min.js"></script>Here's a "hello world" GIF-drawing tool, you can also remix this on netnet.studio.
<script src="https://cdn.jsdelivr.net/gh/netizenorg/netnet-standard-library/build/nn.min.js"></script>
<script>
function drawGifs () {
// if mouse is not (!) pressed down exit function
if (!nn.mouseDown) return
// otherwise, create a new gif
nn.create('img')
.set('src', 'https://netnet.studio/cd.gif')
.positionOrigin('center')
.position(nn.mouseX, nn.mouseY)
.css('pointer-events', 'none')
.addTo('body')
}
// click and drag mouse across the screen
// to draw new gif img elements
nn.on('mousemove', drawGifs)
</script>To learn more visit our introduction page, there you'll find intros to the library's core concepts/patterns including:
- How to render HTML elements dynamically
- How to use callback functions
- How to setup event listeners for interaction
- How to work with async/await functions
- How to render vector graphics with
<svg>and raster graphics with<canvas> - How to setup a generative animation loop
There are many amazing creative coding libraries that extend the capabilities of the Web's creative APIs, often providing frameworks for expressing higher-level concepts, like how A-Frame's Entity-Component-System adds game design principles to WebGL and WebXR, or how Tone.js brings music synthesis and DAW (Digital Audio Workstation) concepts to the Web Audio API. While the nn library can be used on its own, it's really designed to work alongside these other frameworks. For example, you could use D3.js to generate data visualizations, then apply nn's color theory methods to ensure the chart colors follow harmonious color schemes and meet WCAG AA accessibility standards. Similarly, you could use nn's music theory utilities to generate scales and chords, then pass them to Tone.js for playback. You can see this in action in our demos gallery.
If you'd like to contribute to this repository, below are the steps you should take to setup a local project as well as contribute any bug fixes, additions or other changes.
- start by fork our repo this repo
- then clone your fork
git clone https://github.com/[YOUR_USER_NAME]/netnet.studio.git - then install the dev dependencies
npm install - lastly, setup a remote "upstream" to our repo:
git remote add upstream https://github.com/netizenorg/netnet-standard-library.git
-
before starting on a new feature it's always a good idea to run
git pull upstream mainto pull updates from our repo. -
create a "feature" branch
git checkout -b [FEATURE-NAME]for your contribution. -
All the source code can be found in
/src, there you'll find sub-folders for the different categories, within those sub-folders you'll find the source code files and their accompanying documentation files.
- If you edit or add a new function/method, make sure to add/edit it's documentation entry as well.
- If your contribution also requires updating the API Index (in this README below) make sure to do that as well
- as you work locally you can
- use the
npm run buildcommand to create new builds of the library - serve the repo locally to use the
/examplespage to write examples and test your changes - use the
npm run lintcommand to ensure you're conforming to our coding style before making any commits. - use the
npm run docsto make sure thesourceproperty of your doc entry has the right start/end lines
-
when you're ready, create a PR from your
featurebranch and into ourmainbranch. -
Once your PR has been merged, clean things up before starting on another feature
git checkout main
git pull upstream main
git push origin --delete [FEATURE-NAME]
git branch --delete [FEATURE-NAME]
Below is an index of all of nn internal methods with hyperlinks to their documentation. You can also find the
full documentation page here: https://netizenorg.github.io/netnet-standard-library/docs/
- nn.width
// browser's current width - nn.height
// browser's current height - nn.mouseX
// mouse's current x position - nn.mouseY
// mouse's current y position - nn.mouseDown
// is mouse currently pressed - nn.pointer
// first active pointer contact { x, y, id, type } or null - nn.pointers
// array of all active pointer contacts
- nn.sleep(ms)
// pause code for a specified time - nn.times(n, fn)
// call a function n times - nn.range(start, end, step)
// generate a range of numbers - nn.on(evt, fn)
// register an event listener on the window - nn.off(evt, fn)
// remove an event listener from the window
- nn.get(selector)
// select an element and return it "overloaded"(same chainable methods ascreate) - nn.getAll(selector)
// select all matching elements "overloaded"(same chainable methods ascreate) - nn.create(tag)
// create an "overloaded" HTMLElement- .on(evt, fn)
// attach an event listener - .off(evt, fn)
// remove an event listener - .content(str)
// set the element's innerHTML - .set(attr, val)
// set an attribute or object of attributes; also .set('.class') or .set('#id') - .get(selector)
// select a child element - .getAll(selector)
// select all matching child elements - .css(prop, val)
// set a CSS property or object of properties - .transition(prop, ms)
// set a CSS transition - .addTo(parent)
// append element to a parent - .size(w, h)
// set width (and optionally height); omit h for a square - .position(x, y)
// position element absolutely - .positionOrigin(type)
// 'center' makes x/y refer to element's center - .rotate(deg)
// rotate element in degrees - .scale(x, y)
// scale element - .skew(xDeg, yDeg)
// skew element - .blur(px)
// apply CSS blur filter - .brightness(val)
// apply CSS brightness filter - .contrast(val)
// apply CSS contrast filter - .dropShadow(x, y, blur, color)
// apply CSS drop shadow - .grayscale(val)
// apply CSS grayscale filter - .hueRotate(deg)
// apply CSS hue rotation - .invert(val)
// apply CSS invert filter - .opacity(val)
// apply CSS opacity filter - .saturate(val)
// apply CSS saturation filter - .sepia(val)
// apply CSS sepia filter - .data
// proxy for reading/writing data-* attributes - .value
// auto-coerced to number for number/range inputs
- .on(evt, fn)
- nn.loadImage(src)
// Promise-based image loading - nn.filterImage(image, fn, opts?)
// filter image pixels; fn receives { r,g,b,a } (default), or raw array - nn.filterVideo(video, fn, opts?)
// live filter video pixels; fn receives { r,g,b,a } (default), or raw array - nn.popup(url, x, y, w, h)
// open a new browser window - nn.hyper(media)
// attach time-based cues to audio/video with .at(seconds, fn)
- nn.askFor(type)
// request camera, mic, gps, etc. ('video','audio','capture','gps','notifications','clipboard','bluetooth','usb','serial','motion','orientation') - nn.askForStream(constraints)
// full getUserMedia with constraints object - nn.askForCapture()
// screen/window/tab capture - nn.askForNotifications()
// request notification permission - nn.askForClipboard()
// read the clipboard - nn.askForBluetooth(filters?)
// show Bluetooth device picker - nn.askForUSB(filters?)
// show USB device picker - nn.askForSerial(filters?)
// show serial port picker - nn.askForMotion()
// request device motion permission (iOS 13+) - nn.askForOrientation()
// request device orientation permission (iOS 13+) - nn.askForGPS()
// request geolocation - nn.MIDI
// access plugged-in MIDI devices
- nn.parse(str)
// parse a JSON or CSV string; auto-detects format - nn.serialize(data, format?)
// convert data to a JSON or CSV string - nn.download(data, filename?)
// trigger a browser file download; auto-detects type - nn.upload(options?)
// open file picker; returns Promise with { name, size, type, data }
- nn.isBrowser()
// is the code running in a browser - nn.isMobile()
// is the visitor on a mobile device - nn.browserInfo()
// browser name and version - nn.platformInfo()
// OS and platform info - nn.gpuInfo()
// graphics card info - nn.screen()
// screen dimensions and properties - nn.orientation()
// device orientation - nn.language()
// user's language preference - nn.timeZone()
// user's time zone - nn.audioSupport()
// browser audio format support - nn.videoSupport()
// browser video format support - nn.storageSupport()
// localStorage / sessionStorage support - nn.fontSupport()
// font feature support - nn.hasTouch()
// touch screen support - nn.hasWebGL()
// WebGL / 3D graphics support - nn.hasWebVR()
// WebVR support - nn.hasWebXR()
// WebXR (VR/AR) support - nn.hasWebAudio()
// Web Audio API support - nn.hasMIDI()
// Web MIDI API support - nn.hasMediaDevices()
// getUserMedia support - nn.hasDeviceMotion()
// device motion events support - nn.hasDeviceOrientation()
// device orientation events support - nn.hasPointerLock()
// Pointer Lock API support - nn.hasGamepad()
// Gamepad API support - nn.hasWebSerial()
// Web Serial API support - nn.hasWebUSB()
// WebUSB API support - nn.hasBluetooth()
// Web Bluetooth API support - nn.hasSpeechRecognition()
// Speech Recognition API support - nn.hasSpeechSynthesis()
// Speech Synthesis API support - nn.hasWebAssembly()
// WebAssembly support - nn.hasFullscreen()
// Fullscreen API support
- nn.norm(val, min, max)
// normalize a value to 0–1 - nn.clamp(val, min, max)
// constrain a value to a range - nn.lerp(a, b, t)
// linear interpolation - nn.map(val, inMin, inMax, outMin, outMax)
// map a value from one range to another - nn.dist(x1, y1, x2, y2)
// distance between two points - nn.angleBtw(x1, y1, x2, y2)
// angle between two points - nn.radToDeg(rad)
// radians to degrees - nn.degToRad(deg)
// degrees to radians - nn.cartesianToPolar(x, y)
// cartesian to polar coordinates - nn.polarToCartesian(dist, angle)
// polar to cartesian coordinates - nn.shuffle(arr)
// randomize the items in an array - nn.randomInt(min, max)
// random integer - nn.randomFloat(min, max)
// random float - nn.random(min, max)
// random number, or random item from an array - nn.perlin(x, y, z)
// Perlin noise - nn.ease(type, t)
// easing / tweening functions
- nn.randomColor()
// generate a random color string - nn.colorGradient(colors, steps)
// multi-stop gradient as a color array or CSS string - nn.colorScheme(color, type)
// generate a color scheme array - nn.lerpColor(a, b, t)
// interpolate between two colors - nn.closestColor(color, palette)
// find the nearest color in a palette - nn.rgb(r, g, b, a)
// build an rgb/rgba CSS color string - nn.hsl(h, s, l, a)
// build an hsl/hsla CSS color string - nn.toRGB(color)
// normalize any color to { r, g, b } - nn.toHSL(color)
// normalize any color to { h, s, l } - nn.toHex(color)
// normalize any color to a hex string - nn.isLight(color)
// check if a color is light or dark - nn.colorContrast(a, b)
// WCAG contrast ratio between two colors - nn.colorMatch(a, b)
// find color strings within larger strings - nn.alpha2hex(alpha)
// alpha float to hex byte string - nn.hex2alpha(hex)
// hex byte string to alpha float
- nn.notes
// array of note names for each semitone index - nn.modes
// map of mode names to their interval patterns - nn.chords
// predefined chord shapes as scale-degree arrays - nn.noteToMidi(note)
// note name like 'C4' → MIDI number - nn.midiToNote(midi)
// MIDI number → note name like 'C4' - nn.noteToFrequency(note)
// note name like 'A4' → frequency in Hz - nn.frequencyToNote(freq)
// frequency in Hz → nearest note name - nn.midiToFrequency(midi)
// MIDI number → frequency in Hz - nn.frequencyToMidi(freq)
// frequency in Hz → nearest MIDI number - nn.stripOctave(note)
// remove octave number from a note name - nn.randomMode()
// generate a random set of scale step intervals - nn.createScale(root, mode)
// build a scale from a root note and mode - nn.rotateScale(scale, k)
// rotate a scale to start from a different degree - nn.transposeScale(scale, semitones)
// transpose all notes in a scale - nn.createChord(scale, type)
// extract a chord from a scale - nn.voiceChord(chord, oct)
// add octave numbers for strictly ascending pitches
nn.create('canvas') returns a canvas element with additional drawing methods:
- .fillColor
// get/set fill color - .strokeColor
// get/set stroke color - .lineWidth
// get/set stroke width - .lineCap
// get/set line cap style ('butt', 'round', 'square') - .lineJoin
// get/set line join style ('miter', 'round', 'bevel') - .font
// get/set font string - .textAlign
// get/set text alignment - .textBaseline
// get/set text baseline - .globalAlpha
// get/set global opacity - .blendMode
// get/set blend mode - .shadowBlur
// get/set shadow blur radius - .shadowColor
// get/set shadow color - .shadowOffsetX
// get/set shadow X offset - .shadowOffsetY
// get/set shadow Y offset
- .circle(x, y, r)
// draw a filled/stroked circle - .ellipse(x, y, rx, ry, rotation)
// draw a filled/stroked ellipse - .rect(x, y, w, h)
// draw a filled/stroked rectangle - .line(x1, y1, x2, y2)
// draw a stroked line - .triangle(x1, y1, x2, y2, x3, y3)
// draw a filled/stroked triangle - .text(str, x, y)
// draw a text string - .drawImage(src, x, y, w, h)
// draw an image or video
- .beginPath()
// start a new path - .moveTo(x, y)
// move pen to a point - .lineTo(x, y)
// draw a line to a point - .arc(x, y, r, start, end)
// add an arc to the path - .bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
// add a cubic Bézier curve - .closePath()
// close the current path - .fill()
// fill the current path - .stroke()
// stroke the current path
- .save()
// push drawing state onto the stack - .restore()
// pop drawing state from the stack - .translate(x, y)
// shift the coordinate origin - .rotate(radians)
// rotate the coordinate system - .scale(x, y)
// scale the coordinate system
- .clear()
// erase the entire canvas - .resize(w, h)
// resize the canvas drawing buffer - .getPixels(opts?)
// get pixel data as { r,g,b,a } objects (default) or raw array - .setPixels(arr)
// write pixel data back; accepts { r,g,b,a } objects or a flat Uint8ClampedArray - .createLinearGradient(x0, y0, x1, y1)
// create a linear gradient
nn.create('svg') returns an SVG element with shape factory methods. Shapes returned by those factories are themselves chainable.
- .circle(cx, cy, r)
// create and append a circle - .ellipse(cx, cy, rx, ry)
// create and append an ellipse - .rect(x, y, w, h)
// create and append a rectangle - .line(x1, y1, x2, y2)
// create and append a line - .path(d)
// create and append a path - .polygon(points)
// create and append a polygon - .polyline(points)
// create and append a polyline - .text(str, x, y)
// create and append a text element - .group()
// create and append a group element - .image(href, x, y, w, h)
// create and append an image element
- .position(x, y)
// move element; meaning depends on type (cx/cy, x/y, or translate) - .positionOrigin(type)
// 'center' makes .position() center rects and text on the given point - .size(...)
// resize: circle→r, ellipse→rx,ry, rect/svg→width,height
- .fill(color)
// set fill color - .stroke(color)
// set stroke color - .strokeWidth(n)
// set stroke width - .strokeDash(val)
// set stroke dash pattern - .strokeOffset(n)
// set stroke-dashoffset; animate to draw lines - .opacity(n)
// set opacity - .textAlign(val)
// set text alignment (text/tspan only) - .textBaseline(val)
// set text baseline (text/tspan only) - .borderRadius(rx, ry?)
// set rounded corners (rect only)
- .translate(x, y)
// translate via SVG transform - .rotate(deg, cx, cy)
// rotate via SVG transform - .scale(x, y)
// scale via SVG transform
( ◕ ◞ ◕ )