Giter Club home page Giter Club logo

pixelmanipulator's Introduction

PixelManipulator logo PixelManipulator View the Demo

js-standard-style View the Docs pixelmanipulator snyk score npm bundle size npm type definitions Coveralls CircleCI npm GitHub Repo stars License: GPL v3 or later

PixelManipulator is a TypeScript library that can run any two-dimensional cellular automata, such as "Conway's Game of Life," and "Rule 90." Inspired by the The Powder Toy.

About the demo View the Demo

The demo includes a full-view pixel array, with configurable size, along with a movable viewfinder - also with configurable size. Targeter lines - synced between the viewfinder and the full-view pixel array - are also equipped so you can line up your complicated large-scale builds. You can even disable the targeter lines, the "focus box;" a box indicating the location of the viewfinder, and the pixelCounter, a tool that lets you see how many of what pixel are present. Don't forget that the pixel placer menu lets you not only set a different element for alt, normal and control clicking, but lets you fill the full-view pixel array with a specified random percent of that element with only a button click. All this, and a newly added element customizer, allowing one to edit the color, name and loop attributes of an element.

Pre-programmed cellular automata include:

Getting Started with the library

NPM Package

In your project run one of these:

  • For yarn, yarn add pixelmanipulator
  • For npm, npm i pixelmanipulator

If you are using esmodules, you now can import it like this:

import { PixelManipulator, rules, Ctx2dRenderer } from 'pixelmanipulator'

A great starting point is this console-only demo.

To run the node demo

  1. Clone this repo.
  2. npm i
  3. npm run node-demo

For documentation, View the Docs

Old-school

Start with this html:

<!doctype html>
<html>
  <head>
    <script src="https://unpkg.com/pixelmanipulator@^5.5.5"></script>
  </head>
  <body>
    <canvas id="myCanvas"></canvas>
    <script>
      var canvas = document.getElementById("myCanvas")

      // Create a renderer that renders on that canvas
      var renderer = new pixelmanipulator.Ctx2dRenderer(canvas)

      // Create a PixelManipulator, setting the size to 400 by 400
      var p = new pixelmanipulator.PixelManipulator(renderer, 400, 400)

      // An example element to get you started.
      var gol = p.addElement( {
        name: "Conway's Game Of Life",

        // born on 3, survives on 2 or 3
        ...pixelmanipulator.rules.lifelike(p, 'B3/S23'),

        // the rgb color
        renderAs: [0, 255, 0]
      })

      // If your browser doesn't support spread syntax
      // (that's the `...`), then this works too!
      var rule_ninety = p.addElement({
        name: "Rule 90",
        renderAs: [147, 112, 219]
      })
      p.modifyElement(rule_ninety, pixelmanipulator.rules.wolfram(p, 'Rule 90'))

      // Randomly fill 15% of the canvas with "Conway's Game of Life"
      p.randomlyFill(gol, 15)

      // Watch it go!
      p.play()
    </script>
  </body>
</html>

Pixelmanipulator supports various browser-side module loaders, such as

  • CommonJS (CJS)
  • Asynchronus Module Definition (AMD)
  • And also supports a fallback to the namespaced global variable pixelmanipulator

For documentation, View the Docs

What is Conway's game of Life

Conway's game of life is a cellular automata with a few simple rules. All of these rules use a distance formula where it counts the both the pixels that are immidately touching the edges and the pixels that are immidately touching the corners. For example (givin that O is the cell, and X is one that is checked in the moore distance fourmula):

XXX
XOX
XXX

On an empty cell, if there are exactly three(3) living cells around it, then it is born. A cell will remain alive if there are exactly two(2) or three(3) living cells nearby. Elsewise, the cell either remains dead, or becomes dead.

Adding a basic life-type cellular automata

For life-type cellular automata (cellular automata that are like Conway's game of Life, but have different rules), there is a specific syntax for how to specify them: B3/S23. This syntax literally means "born on three(3), survive on two(2) or three(3)."

The example code above included B2/S23 (AKA "Conway's game of Life") as an example. Feel free to try out other patterns, like

  • Seeds B2/S
  • Highlife B36/S23
  • And more! (262144 combinations, 2^(9+9))

pixelmanipulator's People

Contributors

lazerbeak12345 avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

pixelmanipulator's Issues

fps limiter

add an fps limiter to make the frames smother (and so you can have a small canvas and still see what is happening)

Make a better user interface.

I would like developers to see that the default user interface I have made is by far not the only one that can be made with this library.

I would like to add a few more different user interfaces such as:

  • A jQuery UI example
  • A Bootstrap example
  • A Rust example
  • A dojo example
  • etc.

It may be a good idea for them to be their own repos, however.

Spawn in common things

Like gliders, etc.

  • File import for standard cellular patterns
  • A few builtin patterns?
  • Menu to use file import from other websites that have lots of these patterns.
  • Way to easily use already-imported patterns.

Customizer can change `loop`

  • Show only when pattern is set.
  • Update automatically when selector changed
  • Change actual value automatically.
    • Make user interface
    • Connect UI to library

Seperate .js file from .html

It would be wise to do this, as doing this would allow for people to use it in other things.
It's why it's on GitHub, and why it's advertised the way it is.

Memoization support

Is your feature request related to a problem? Please describe.
One thing that would speed up computation significantly is if there was some form of memoization.

Describe the solution you'd like
Something much like hashlife could work - but would require that all elements keep 100% of their state inside of the buffer.

In particular, none of the Wolfram rules do this, as they have a "row" value. It should be possible to remove this - but this will break backwards compatibility with the removal of that value.

Describe alternatives you've considered

  • It might also be possible - at the cost of performance - to not hash any areas containing a flagged rule, and all wolfram rules would be flagged.
  • #18

Additional context

  • Hashing is hard in a high level language - especially hashing when used for memoization.
  • This would be hard, also, due to a need for manual garbage collection.

Record into a gif

Is your feature request related to a problem? Please describe.
It'd be cool to make gifs using this.

Describe the solution you'd like
Use a library. I honestly don't really care about how the gif file format works under the hood.

Describe alternatives you've considered
shudders ๐Ÿ˜ฌ doing it manually

Additional context
This is actually one of the oldest feature requests.

Move to Typescript

Is your feature request related to a problem? Please describe.
There's a ton of bugs that would be fixed if strong typing were to be used. This would also decrease the amount of unit tests that will be needed by about 10-20%.

Describe the solution you'd like
In the v5-alpha branch gradually move to typescript. Have a dist folder to hold the output on the master branch, and have the npm include that, the .d.ts file and have the html source that javascript file. In addition, have a pre-bundled version as well with all runtime-deps (as there will be some in the future) bundled and the whole file minified. The html version will likely use that, unless it moves to requirejs.

Describe alternatives you've considered
JsDoc, or whatever it's called doesn't require compiling to run - but I think that while this is nice, it means that I'd be harder to use npm libraries as dependencies.

Additional context
I've used a similar approach for spud-slices - but I can do it better this time.

Steps

not looping correct off of right-side of canvas.

Describe the bug
GOL not looping correct off of right-side of canvas.

To Reproduce
on this w5h5 grid with GOL:

#@###
#@###
#@###
#####

it turns into

#####
#@###
#####
#####

Expected behavior

#####
@@@##
#####
#####

Additional context

This was reduced from shrinking the error-space of a bug where an glider at top-center of 100 by 100 canvas, pointing SE doesn't loop correctly.

Use the factory pattern instead of a single-instanced module

Is your feature request related to a problem? Please describe.
One cannot have more than one instance of pixelmanipulator

Describe the solution you'd like
Doing such a thing would allow a user of the library to have more than one instance of pixelmanipulator.

Describe alternatives you've considered
The constructor pattern might also be a viable solution.

Additional context
This is basically a singleton. Singletons are bad 99% percent of the time people think they are at first a good idea, and this is, according to modern accepted metrics, not one of these times, as having more than one instance of this object would not cause any problems.

Name is not logged correctly in console

Describe the bug
The element name is not logged correctly to the console anymore.

To Reproduce
Steps to reproduce the behavior:

  1. Open the demo
  2. Look at the console

Expected behavior
It should say the name, not a useless number.

Idea - Performance Improvement

You might want to reduced repeated calls to document.getElementById by making temporary local variables to store the document object you want. document.getElementById has to traverse to DOM to find the object, but once you have it - it might make it run faster if you used it from a pointer variable instead.
example:

instead of

document.getElementById('selectorBox').property1 =...
document.getElementById('selectorBox').property2 =...
document.getElementById('selectorBox').property3 =...

use

var sb = document.getElementById('selectorBox');  // one lookup
sb.property1 =...  // no lookup required.
sb.property2 =... // no lookup required.
sb.property3 =... // no lookup required.

The same approach could be done with object references in the js.

iterate doesn't use the correct pixbuff

The iterate function in the library uses the (potentially changed) pixel. This has caused bugs with the wolfram rule type in the past, and has decreased statelessness.

`p.canvas` should be made private

Is your feature request related to a problem? Please describe.
This has caused a great amount of needless dependency on the drawing implementation

Describe the solution you'd like
Rename it to p._canvas or something

Describe alternatives you've considered
Leaving it.

Additional context

startUsing= () => "Arrow functions";

Is your feature request related to a problem? Please describe.
The library not only could be faster, but it has a possibility of some code simplifications.

Describe the solution you'd like
Start using arrow = () => "functions"

These functions are often faster, and have simpler this contextualization.

Describe alternatives you've considered
Finding other ways to simplify the code.

Additional context
MDN arrow function documentation

There is one flaw I find with them, however: they are only supported on newer web-browsers,
but this is probably fine, considering the fact that it is probably too reliant upon huge arrays to work in
those browsers anyway.

issue with deadcells not getting called enough

Describe the bug
Adjacent empty cells to an occupied cell with a deadCell function will never be updated if the only attempted call to deadCell proves false, due to the singularity of flag-checking.

To Reproduce

Where C is "Conway's Game of Life" in the demo, and L is "No-Loop Conway's Game of Life" start with the pattern

  C
 C C
  C L
   LL

Hitting play will result in no change of state.

Expected behavior
The three L symbols should become a "block."

Additional context
When marking dead cells as "updated," instead of updating the cell, as a whole as "updated" regardless of type, keep a separate buffer for each element with a deadCell function and mark it in there.

In order to be performant, I may be forced to move where memory is allocated.

Add a way to cusomize the automata

Is your feature request related to a problem? Please describe.
Some of my users have expressed a desire for the ability to have some sort of custom automata setup.

Describe the solution you'd like

  • Have someplace (in-app, such as a slide-in/up dialog, or mobile) that lets the user modify a single element called "custom".
  • Have a similar dialog, but allow for users to add and remove as many of anything that they would like.

Describe alternatives you've considered
Leaving it as is to avoid further complexity.

Additional context
Other cellular automata tools seem to have this feature.

To make this possible, I'll need to do these:

Speed up rendering with fill rect.

See this SO question that I happened upon for more details, but, it basically comes down to some of my own testing. I will need to test which is faster, then make an API to choose what one they want, but have a default to what I tested to be faster.

So my question is this: Do I want to continue using ctx.putImageData to assign each pixel to the canvas(es), or do I want to change to (and make an API for) ctx.fillRect due to recent performance improvements that may show up here?

Use promises to increase performance.

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
Clever use of promises would allow for a single promise for every pixel on screen. This would use a lot more memory, but would also be a lot faster.

Describe alternatives you've considered
Leaving it as-is.

Additional context
Such a feature may be difficult because of race-conditions, and would be made easier if use of a promise library were an option.

Customizer can change `pattern`

  • Raw string mode (box always visible in edit mode)
    • Update automatically when selector changed
    • Change actual value automatically.
      • Make user interface
      • Connect UI to library
  • Radio box to change modes
    • Rule mode has raw number mode
      • Update automatically when selector changed
      • Change actual value automatically.
        • Make user interface
        • Connect UI to library
    • Or (with another radio box) it has binary input mode.
      • Update automatically when selector changed
      • Change actual value automatically.
        • Make user interface
        • Connect UI to library

Better npm usage documentation

Is your feature request related to a problem? Please describe.
It isn't very well documented in the readme how to use this package from npm. This is especially a problem since it's on npm

Describe the solution you'd like
Explain how to use it using AMD-style importing.

Describe alternatives you've considered
Give only brief mention?

Additional context

Width and height settings below a certain size throw an error.

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Width of 1, height of 2, hit reset. Throws error.

Expected behavior
Shouldn't throw error.

Additional context

Uncaught TypeError: Cannot read properties of undefined (reading 'liveCell')
    at Object.iterate (pixelmanipulator.js:579:21)
    at HTMLButtonElement.<anonymous> (pixelmanipulator.html:611:8)

Use index number array instead of raw colors to identify elements

Is your feature request related to a problem? Please describe.
This will make it easier to move to alternative drawing systems in the future.

Describe the solution you'd like
Some sort of static array that holds all of the pixel's type for both current and former pixel grids.

Describe alternatives you've considered

  • Chars instead of numbers (slower - chars are strings).
  • Static boolean array to use as a "dirty flag" field to trigger updates only when needed. (Actually might still not be needed)

Additional context
This would mean comparing one number instead of 3 - and would mean indexing one number, instead of 3. Speed is a nice side-effect of this.

Color redefinition causes odd bugs.

Describe the bug
Color collisions aren't caught even though they are easy.

To Reproduce
Create two different elements with the exact same color and different behavior. Both behaviors will be triggered on older versions, many other odd bugs

Expected behavior
Error needs to be raised when duplicate color is registered.

Additional context
Might be harder to recreate on 2.2 and later due to the way numbers are tracked.

When spawning cells randomly, it isn't using a good random algorithim.

When spawning cells randomly, it isn't using a good random algorithm.
This can cause some minor issues, such as higher density clumping on the right side, as is noticeable in the water cellular automata. (Said automata also uses math.random in other parts)

I plan on making two separate patches for this in the future.

  1. one for the frontend
  2. then for the lib

Separate demo into multiple files

Is your feature request related to a problem? Please describe.
This repo is marked as an html repo. That's not right at all.

Describe the solution you'd like
Move the CSS and javascript into their own files and import from them.

Describe alternatives you've considered
Use requirejs for the javascript

Additional context
Can help with discoverability

blank change

when changing the color of blank space it easily crashes

Separate Render and logic into their own functions

Is your feature request related to a problem? Please describe.
Should increase frame rates by removing the paint step.

Describe the solution you'd like
Put all of the rendering in one thread/loop and all of the logic in another.

Describe alternatives you've considered

  • #29 (not incompatible with this, actually)

Performance with `get_width` and associated functions.

Is your feature request related to a problem? Please describe.
Calling get_width has a higher-than expected performance cost.

Describe the solution you'd like
Save the width and height in a local variable not part of the canvas? Test thoroughly. Might require incompatibilities.

Describe alternatives you've considered
getters and setters might be faster

Move away from keeping track of present elements, and instead only update pixels in proper radius of oneanother.

Is your feature request related to a problem? Please describe.
This is one of the tightest bottlenecks, currently. This would improve performance for this greatly.

Describe the solution you'd like

  • Introduce a new datastructure to keep track of dead cells that need to be "updated," without allowing duplicates, preferably without much (or any) memory allocation.
  • In the definition of an element, identify what neighborhood type it uses.
  • When updating a live cell, flag all cells within it's own neighborhood that are dead that need an update.
  • Update all cells that were flagged.

Describe alternatives you've considered

  • It might also be possible - at the cost of performance - to not hash any areas containing a flagged rule, and all wolfram rules would be flagged.
  • #17

Additional context

  • Sets require memory allocation, Uint8Array's are either hard to use as a binary field (and use a lot of memory) or use too much (8 times more) memory, arrays require even more memory. Is there a different data structure that would do this better?

Steps

  • Introduce a way to get the list of distances for each neighborhood algorithm
  • Check for optional distances list during update
    • If absent, do current behavior (but only for cells that do not ever specify a distance)
    • If present, mark all cells indicated as needing an update (of that particular cell type)

Customizer can change name

  • Update automatically when selector changed
  • Change actual value automatically.
    • Make user interface
    • Connect UI to library

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.