An entirely on-chain generative art project by Hideki Tsukamoto — The first in a series of four NFT collections in the ‘Apex’ series.
Cypher’s generation was conducted via auction on the Ethereum Network on 15th August 2021. The collection is now comprised of 1024 unique NFTs with different visual properties and characteristics. The following is a breakdown of the project concept, some simple technical details and an explanation of the properties that make each Cypher unique.
With Cypher, we didn’t want to render anything or rely the IPFS or off-chain resources for storage of our tokens’ image data. So over the course of the project (unknown to us, this was a path that had already been trodden by others) we developed a system where in my seeded generative artwork was retrieved directly from the blockchain deterministically on demand.
The idea being, that if Generative Art is desired to be exactly the same every time the generate(seed) function is called, then why store anything? Why not just call the function on the blockchain again with the correct seed (stored in the token) and have the artwork recalculated and returned on request?
Each Cypher has a base value n. This valued is weighted using a pre-baked distribution curve, (a lookup table) to produce the collections distribution, with fewer of the Level 1, 4 and 5 Cyphers, and comparatively more Level 2 and 3 Cyphers. This weighted number with added noise, provides also Chaos and Decay thresholds and also sets the Intricacy level.
A Cypher has 5 main properties:
Level, Intricacy, Decay, Chaos and Channels.
All Cyphers belong to a Generation, and tokens minted very early (#0–3) carry the additional properties Genesis, Primary, Secondary and Tertiary respectively.
Cyphers also have potential properties that are tracked but not yet visible in the metadata.
As the Apex project progresses, the significance of these properties will be explained. They will often be linked to side projects and experimental mechanisms for which a Cypher can be considered a key.
Note: This article outlines how the above properties define the visual appearance of the Cypher - it does not detail the mechanisms mentioned above.
A simple property, in the Rarity section above I mentioned n. Before n is weighted and has noise added to create a value from which Properties are derived, it’s used directly to decide which gradient a Cypher will use for it’s colour. At generation, noise is applied to a Cypher’s properties, (this has the effect of increasing or decreasing the property values slightly).
The Level represents the raw “score” of the Cypher, as a colour gradient, before any noise is applied to the properties.
At the atomic level, a Cypher is composed entirely of Segments.
A Segment has an angle that defines its span, and is composed of five features:
Inner and Outer Spans, a pair of matching Edges, one or more Fill types and a Padding value.
In the above Segment:
- Edges : TRUE
- Inner Span : DOTTED
- Outer Span : DOTTED
- Padding : TRUE
- Fill : INCREMENT
While Edge and Padding are either on or off, there are multiple styles of Span, these range from completely absent to a basic line to more detailed brackets and dotted variants. Fill has a similar number of variants, from Increment (above) to Text, Solid or Hollow and (unlike Spans) these can be stacked so you can often find Segments with both a Fill of both Solid and Text for example. Padding merely controls if the the Segment and its Fill has a border or meets the edges of the adjacent Segment.
These features are made available to the Cyphers drawing algorithm based on it’s Intricacy level.
Edge Types : NONE, SIMPLE, ENDS, BRACKETS, DOTTED
Fill Types : NONE, SOLID, HOLLOW, INCREMENTS, TEXT
The actual features chosen for a Segment are derived ‘randomly’ (from the transaction hash), but the Intricacy governs from which features types that random choice will be able to select.
Higher Intricacy allows the drawing algorithm to select from a larger palette of components from which to draw Segments.
When a number of Segments are arranged in a sequence they form an Arc. These Arcs are the building blocks of the full Rings that make a Cypher.
One or more Arcs are used as templates in the construction of a Ring. In the image above a single Arc of 125 degrees, comprised of two smaller Segments is generated as a template Segment.
This template is only entered into the Ring of the Cypher if the random value generated by the transaction has falls below the Decay threshold for this Cypher — If the threshold is exceeded then the Arc is then duplicated to form the repeating patterns familiar high-level Cyphers, if not the instance of the template Arc is discarded and the result is an incomplete Ring in that Channel. (Yes, Cypher is heavy on abstractions).
Above: With high Decay only the template Arc exists (left). A low Decay value results in three new instance Arcs are created to make a full Ring.
Another property derived from the token hash is designed to erode the organisation of the Arcs at the point they’re entered into a Ring.
In a similar way to the way Decay is calculated above, a Chaos threshold and ‘random’ number is derived from the hash - if the number is greater than the Chaos threshold then an extra rotation value is added to the Arc causing it’s appearance to be less cleanly aligned.
As you can see above the central portion of the Cypher on the left has no Chaos applied, it’s layout is perfectly aligned. On the right, the exact same set of Rings appears with overlapping, chaotically organised Arcs.
Channels represent a portion of the radius of a Cypher. There are always 8 per cypher, and they are sized by the properties of the transaction hash. The outer radius of each Channel does actually appear in the tokens but they’re very faint, so I’ve exaggerated in the example below with a thicker yellow line to demonstrate.
These Channels can contain multiple Rings but if the Channel isn’t successfully entered into the Cypher, then those Rings are bypassed at the point of generation and don’t feature — So basically, Channels define the density of the Cypher. This isn’t simply ‘ring_count’ of similar — I wanted bands of rings to appear (or not) in larger groups to give a less scrappy and more readable visual result.
Channels are useful as a measure of opportunity, and they aid transformation when a Cypher was generated outside of of the initial octal sequence of a Generation.
Which roughly equates, to: ‘More to come from Cypher - stay tuned’, (sorry).
The secondary market for Cypher can be found on OpenSea here