npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

toosoon-lsystem

v3.0.0

Published

Library providing functionalities for creating and manipulating Lindenmayer systems (L-Systems) using various parameters

Downloads

53

Readme

TOOSOON L-SYSTEM

Library providing functionalities for creating and manipulating Lindenmayer systems (L-Systems) using various parameters.

Credits: lindenmayer

Installation

Yarn:

$ yarn add toosoon-lsystem

NPM:

$ npm install toosoon-lsystem

Usage

Basic

import LSystem from 'toosoon-lsystem';

const system = new LSystem({
  axiom: 'F++F++F',
  productions: { F: 'F-F++F-F' },
  iterations: 2
});

system.iterate();

console.log(system.getAxiomString());
// 'F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F'

Custom Alphabet

Using custom alphabets allows you to use custom strings as symbols.

const ALPHABET = ['Block', 'Line'] as const;
type A = Alphabet<(typeof ALPHABET)[number]>;

new LSystem<A>({
  alphabet: [...ALPHABET],
  axiom: 'Block',
  productions: {
    Block: 'Block-Line',
    Line: 'Line++Block--Line'
  }
});

Defines

Defines are especially usefull when coupled with parametric syntax.

new LSystem({
  defines: {
    [key]: [value]
  }
});

Productions

You can set productions in two ways.

Multiple productions via constructor:

new LSystem({
  productions: {
    [symbol]: [production],
    [symbol]: [production]
  }
});

Or via the setter-methods:

// Set single production
system.setProduction([symbol], [production]);
// Set multiple productions
system.setProductions({
  [symbol]: [production],
  [symbol]: [production]
});

String-Based Productions

The most basic production consists of a single string, representing the result of a production.

// Each 'F' will be replacd with 'FF'
system.setProduction('F', 'FF');

Object-based Productions

To allow even more flexibility than String-based productions, you can choose to use a wrapper Object in the following way to allow for stochastic, context-sensitive and conditional L-Systems. This object basically wraps around a regular Array, String or Function Production, which are now defined in the successor field.

String-based successor

Equivalent to String-based productions for Object-based ones.

LSystem.setProduction('F', { successor: 'FF' });
Array-based successor

If you are reading about L-System in the classic ABOP, you may have stumbled upon parametric L-Systems. Those have optional parameters inside each symbol. To make this possible you can use Arrays of successors besides basic Strings as production results (and axioms).

LSystem.setProduction('F', {
  successor: [
    { symbol: 'F', params: [1, 2] },
    { symbol: 'F', params: [3, 4] }
  ]
});
Context-sensitive production

To add a context-sensitive check you can add before and after contexts properties.

// Replace 'F' with 'FF' only if precceded by 'FA' and followed by 'A'
system.setProduction('F', {
  successor: 'FF',
  context: { before: 'FA', after: 'A' }
});

See also the chapter on classic syntax to learn how to write more concise context sensitive productions.

Parametrical production

See the chapter on classic syntax to learn how to write concise parametrical productions.

Conditional production

You may also define a condition which has to return a boolean.

// Replace 'F' with 'FF' only if condition is `true`
myLsystem.setProduction('F', {
  successor: 'FF',
  condition: () => {
    return condition === true;
  }
});
Stochastic production

Instead of a single successor, a stochastic L-System defines an Array which includes multiple Objects with their own successor. The weight property defines the probability of each successor to be choosen. If all successors have the same weight they have an equal chance to get choosen. If one successor has a higher weight than another, it is more likely to get choosen.

LSystem.setProduction('F', {
  stochastic: [
    { successor: 'A', weight: 50 }, // 50% probability
    { successor: 'AB', weight: 25 }, // 25% probability
    { successor: 'A+B', weight: 25 } // 25% probability
  ]
});

In order to create pseudo-randomness, toosoon-utils/prng functions are used to determine stochastic outputs.

Function-based successor

Besides Strings and Arrays, you can also define functions as successors for complete flexibilty. Each successor function has also access to an info object:

  • axiom: Reference to the current axiom. Useful in combination with index.
  • index: The current index of the symbol inside the whole axiom.
  • part: The current symbol part. Not very useful for String based L-Systems. But for Array based ones, this lets you access the whole symbol object, including any custom parameters you added.
  • params: Shorthand for part.params.

A successor function returns a valid production result. If nothing or false is returned, the symbol will not replaced.

Usages examples:

// Replace 'F' with 'A' if it is at least at index 3 (4th position) inside the current axiom, otherwise return 'B'
system.setAxiom('FFFFFFF');
system.setProduction('F', {
  successor: ({ index }) => (index >= 3 ? 'A' : 'B')
});
system.iterate(); // 'FFFFFF' results in -> 'BBBAAAA'

// Replace any occurrence of 'F' with a random amount (but max. 5) of 'F'
system.setProduction('F', {
  successor: () => {
    let result = '';
    let n = Math.ceil(Math.random() * 5);
    for (let i = 0; i < n; i++) result += 'F';
    return result;
  }
});

// Replace 'F' with 'FM' on mondays and with 'FT' on tuesdays. Otherwise nothing is returned, therefore 'F' stays 'F'
system.setProduction('F', {
  successor: () => {
    const day = new Date().getDay();
    if (day === 1) return 'FM';
    if (day === 2) return 'FT';
  }
});

Apply Productions

To apply your productions onto the axiom you call iterate() on your L-System instance.

In each iteration step, all symbols of the axiom are replaced with new symbols based on your defined productions.

When you call iterate(), the resulted axiom of your L-System is returned. You can also get the resulted axiom via getAxiomString().

Commands

To visualize or post-process your L-System you can define commands functions for each symbol. These functions are similar to productions, but instead of replacing the existing axiom, commands are used to draw for example different lines for different symbols. All commands are executed by calling run().

A very common application for commands would be the creation of turtle graphics.

Classic Syntax

Context-sensitive syntax

// Instead of:
system.setProduction('F', {
  successor: 'G',
  context: { before: 'AB', after: 'C' }
});

// You can write:
system.setProduction('AB<F>C', 'G');

Parametric syntax

// Instead of:
system.setProduction('F', {
  successor: [
    { symbol: 'A', params: [1] },
    { symbol: 'B', params: [2, 1] }
  ]
});

// You can write:
system.setProduction('F', 'A(1) B(2, 1)');

// Then use parametrical productions:
system.setProduction('A(t)', 'B(t, t + 1)');
system.setProduction('B(t, d)', 'A(t * d)');

API

See full documentation here.

License

MIT License, see LICENSE for details.