PHPackages                             owlycode/interlacing - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. owlycode/interlacing

AbandonedArchivedLibrary[Utility &amp; Helpers](/categories/utility)

owlycode/interlacing
====================

v1.0.0(6y ago)10MITPHP

Since Nov 9Pushed 6y ago1 watchersCompare

[ Source](https://github.com/OwlyCode/interlacing)[ Packagist](https://packagist.org/packages/owlycode/interlacing)[ RSS](/packages/owlycode-interlacing/feed)WikiDiscussions master Synced 5d ago

READMEChangelog (1)Dependencies (2)Versions (2)Used By (0)

What is it?
-----------

[](#what-is-it)

It's a php alternative to [Tracery](https://tracery.io/) by [GalaxyKate](http://www.galaxykate.com/), from which it was heavily inspired. It is used to generate procedural texts based on a grammar.

How to use it?
--------------

[](#how-to-use-it)

Grab the phar at  or install it as a dependency of your project with composer: `composer req owlycode/interlacing`.

Firt declare a grammar:

```
# grammar.yaml
content:
    root: "the {{ adjective }} {{ animal }}"
    animal: ["warthog", "hedgehog", "ocelot"]
    adjective: ["warty", "hoary", "oneiric"]
```

And then use it by running `interlacing.phar grammar.yaml` or inside your own code:

```
use OwlyCode\Interlacing\Interlacing;

// index.php
$i = Interlacing::fromFile(__DIR__.'/grammar.yaml');

echo $i->resolve('root'); // Will output things like "the hoary ocelot".
```

The grammar file is composed of a list of placeholders and their possible associated values. You can put placeholders inside content using the `{{ }}` delimiters. Each time interlacing encounters a placeholder, it lookups for possible values from the grammar and picks one randomly.

Usually the `root` placeholder is used as an entrypoint.

Using alterations and resolvers
-------------------------------

[](#using-alterations-and-resolvers)

You can apply alterations to your placeholders by appending them with a leading `|`. Alterations can be chained.

Resolvers are not manually applied, they just affect the way a placeholder is replaced by a value. Everytime a placeholder is used, Interlacing runs every known resolvers and returns the value of the first one that gives a non-null result. Otherwise, it lookups into the grammar for the possible values and picks one.

Builtin alterations and resolvers
---------------------------------

[](#builtin-alterations-and-resolvers)

### Pluralize

[](#pluralize)

Pluralize a word. You can change the locale inside the grammar (english by default):

```
content:
    root: "{{ animal|s }}"
    name: ["cat", "dog", "mouse"] # cats, dogs, mice
```

```
locale: fr
content:
    root: "{{ animal|s }}"
    name: ["chat", "chien", "cheval"] # chats, chiens, chevaux
```

### Capitalize

[](#capitalize)

Capitalizes the first letter.

```
content:
    proverb: "{{ animal|capitalize }} can eat {{ animal }}, as they say."
    name: ["the lion", "the mouse", "the cat", "the cow"]
```

Could produce: `The mouse can eat the cow, as they say.`

### Memory

[](#memory)

Allows to dynamically build placeholders during the execution.

- store: stores the displayed placeholder value.
- storeAll: stores all possibles values of the placeholder.
- storeOthers: stores all possibles values of the placeholder except the one displayed.
- push: adds the displayed placeholder value to the already stored values.
- pop: removes the displayed memorized value from the memory.

Examples:

```
content:
    root: ["We pick {{ value|store(selected_value) }} and we can show it later: {{ selected_value }}"]
    value: ['A', 'B', 'C']
```

```
content:
    root: ["To make a cake you need {{ ingredient|storeOthers(i) }}, {{ i|pop }} and {{ i }}"]
    ingredient: ['eggs', 'flour', 'water']
```

```
content:
    root: ["{{ duo }} went on an adventure. {{ adventurer|pop }} survived, but not {{ adventurer }}."]
    duo: ['{{ name|storeOthers(c)|push(adventurer) }} and {{ c|push(adventurer) }}']
    name: ['Alice', 'Peter', 'John', 'Frantz', 'Albert', 'Mark']
```

Beware: If you override a grammar based placeholder by a memory value, it will replace it entirely.

### Silence

[](#silence)

Prevents a placeholder from rendering, often used with memory alterations: it allows to pair some results.

```
content:
    root: ["Fishes are {{ level }} at {{ skill }}."]
    skill: [ "swimming{{ good|store(level)|silence }}", "flying{{ bad|store(level)|silence }}"]
    good: ["good", "skilled"]
    bad: ["bad", "unskilled"]
```

Will produce `Fishes are good at swimming.` or `Fishes are bad at flying.` but never `Fishes are good at flying.`.

Creating your own alterations and resolvers
-------------------------------------------

[](#creating-your-own-alterations-and-resolvers)

You can create your own alterations by implementing the `OwlyCode\Interlacing\Plugin\AlterationInterface` interface:

```
namespace Custom\Plugin;

class Prepend implements AlterationInterface
{
    // An alteration always receive the placeholder name, the actual resolved value and the args provided to the alteration
    public function prepend(string $placeholder, string $input, array $args): string
    {
        return $args[0] . $input;
    }

    // Returns the list of alterations by name.
    public function getAlterations(): array
    {
        return [
            'prepend' => [$this, 'prepend'], // Usage: {{ placeholder|prepend("prefix") }}
        ];
    }
}
```

And you can create a resolver by implementing the `OwlyCode\Interlacing\Plugin\ResolverInterface` interface:

```
namespace Custom\Plugin;

class Now implements ResolverInterface
{
    public function resolve($name): ?string
    {
        if ($name === 'now') {
            return (new \Datetime())->format('Y-m-d H:i:s');
        }

        return null;
    }
}
```

Now let's use our previously declared alteration and resolver:

```
plugins:
    - Custom\Plugin\Now
    - Custom\Plugin\Prepend
content:
    root: "{{ now|prepend("time: ") }}"
```

This would display: `time: 2019-11-08 22:44:00`, where the date and time are set to now.

###  Health Score

24

—

LowBetter than 32% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity2

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

2380d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/95352e0b7023eef954a0902948970e3d5824f7637f544582e99f7bf381f66fac?d=identicon)[tmaindron](/maintainers/tmaindron)

---

Top Contributors

[![OwlyCode](https://avatars.githubusercontent.com/u/1631270?v=4)](https://github.com/OwlyCode "OwlyCode (2 commits)")

### Embed Badge

![Health badge](/badges/owlycode-interlacing/health.svg)

```
[![Health](https://phpackages.com/badges/owlycode-interlacing/health.svg)](https://phpackages.com/packages/owlycode-interlacing)
```

###  Alternatives

[orchestra/canvas

Code Generators for Laravel Applications and Packages

21017.2M158](/packages/orchestra-canvas)[netgen/content-browser

Netgen Content Browser is a Symfony bundle that provides an interface which selects items from any kind of backend and returns the IDs of selected items back to the calling code.

14112.1k8](/packages/netgen-content-browser)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
