Written by Emmanuel Odioko✏️
Before the introduction of generative graphics tools, creating detailed designs was a time-consuming and manually intensive process. This was especially true for designs involving complex patterns. Generative graphics tools introduced automation and algorithmic techniques into the creative process, empowering artists and developers to push their creative boundaries.
In this tutorial, we’ll introduce Alma, a new generative graphic platform, and discuss its features and capabilities. We’ll also demonstrate how easy it is to use Alma’s interactive playground to create generative graphics.
Prerequisites
To get the most value from this tutorial, you should have the following:
- Familiarity with the concept of generative graphics
- Basic knowledge of node-based programming
- Basic knowledge of interactive design
What are generative graphics?
The concept of generative art and graphics has roots in the early days of computer programming and digital art. Artists and programmers have been experimenting with algorithmic and generative techniques since the mid-20th century.
One of the pioneering figures in generative art is Georg Nees, a German artist who, in the 1960s, used algorithms to create artwork. Subsequently, other artists and researchers, such as Frieder Nake and Vera Molnár, contributed to the development of generative art and graphics.
What are generative graphic tools?
Generative graphics tools are software applications or programming frameworks that enable visual content creation through algorithms. These algorithms are used to generate digital art, interactive installations, data visualization, and creative coding.
Here’s an analogy that may help explain this concept further: imagine that generative graphic tools are automated, self-playing instruments. Composers create the algorithms that define the rules and patterns. The instruments, guided by the algorithms and instructions, can produce relaxing melodies, harmonies, and rhythms without direct human input for each note.
Developers are like the composers in this analogy, defining the algorithms and instructions. The generative tool interprets these algorithms to create visual compositions, just as the self-playing instruments interpret musical scores to produce music.
Getting to know Alma
Alma is a unique platform that harnesses the power of generative graphics, allowing users to create beautiful visual effects and graphics through a node-based system. Alma is comparable to Blender's node editor, a popular tool for 3D artists and designers. Similar to Blender, Alma's approach is centered around nodes, connections, and code nodes, offering a versatile toolset for crafting dynamic visual experiences.
Alma finds utility across various creative domains. Whether you're an artist, a designer, or a developer, Alma can serve your needs in different ways. Here are some potential use cases for Alma:
- Website graphics: Designers and developers can leverage Alma to create captivating graphics for websites, enhancing user engagement and visual appeal
- Artistic expression: Artists can use Alma to experiment with generative graphics, bringing their visions to life through code and creative node-based interactions
- Interactive installations: Developers can use Alma to create interactive installations for events, or digital experiences, adding a dynamic and engaging element to their projects
- Educational purposes: Educational institutions may find Alma valuable for teaching students about generative graphics, creative coding, and visual effects.
N.B., as of this writing, Alma is still in the alpha stage, so there may still be some challenges associated with implementations
Introducing Alma’s playground
Alma's playground is where our creative journey begins. Let’s take a look to better understand how we can use this tool to create our own generative graphics. The playground comprises several essential components, each serving a distinct role in the generative graphics creation process.
Nodes
Nodes are the fundamental building blocks within Alma's circuit. They represent various operations, such as trigonometry logic, texture sampling, color manipulation, and lighting calculations: These nodes have input and output ports, allowing users to create complex networks of operations: In the above example, we can see two nodes with their inputs and outputs. First, there’s a VECTOR
4
node that takes in four float inputs (the F
stands for float) and outputs a four-component vector (VEC4
).
We connect the VEC4
output to the VEC4 COLOR
input of the second node, WEBGL CONTEXT
, which is the root node of the graph that injects its color into the renderer.
Connections
Connections serve as the pathways for logic and data flow throughout our circuit. They ensure that data moves seamlessly between nodes, enforcing a strict type system to maintain consistency.
Here’s the connection from our previous example:
Code nodes
The GLSL (OpenGL Shading Language) node is an option for those who want to implement complex logic quickly. Users can input a GLSL function, which Alma automatically converts into a node that’s compatible with other nodes in the circuit.
This is a really handy feature. A couple of Code nodes, like CREATION
, are already available from the Alma playground: In order to see the code, we can click the <> icon in the GLSL function node:
Toolbar
The toolbar provides convenient utilities to enhance user experience. It includes options for viewing the final GLSL code, accessing examples for inspiration, adding new nodes to our circuit, importing and exporting serialized circuits, and enabling a fullscreen mode for an immersive experience:
Effects
Alma offers a collection of prebuilt graphic effects in its playground that we can modify and experiment with. Some examples include GRADIENT
, NOISE
, REPETITION
, and CREATION
. These serve as starting points for our creative projects:
Creating a basic noise effect graphic
Let’s use Alma’s playground to create a simple noise effect graphic. In this step-by-step guide, we’ll introduce the interface, demonstrate how to manipulate nodes and connections, and provide insights for creating visually appealing generative graphics.
Enter the playground
First, let’s visit Alma’s playground. There’s a short tutorial there that serves as a basic introduction the playground: Now, let’s click Next to enter the playground. This opens up an example playground that we can play around with to get a feel for the components and how they work: For the purposes of this tutorial, we’ll create a new playground interface.
Import the WebGL Context node
The WebGL Context node is required to render graphics. It’s currently a bit tricky to add this node using the toolbar, so instead we’ll just import a circuit containing the node.
A circuit is basically a JSON file that generates the nodes and connections of a playground. To import a circuit, we click the IMPORT/EXPORT button, represented by a save icon (the fourth icon from the left in the below toolbar: Once the text field is open, we’ll enter the following code:
{
"id": "946cbf0c-555c-4a23-8871-153033dcb299",
"name": "Alma WebGL Starter",
"nodes": [
[
"dfb2ecbb-0845-471d-b910-2fdaf575c26b",
{
"id": "dfb2ecbb-0845-471d-b910-2fdaf575c26b",
"name": "WebGL Context",
"type": "WEBGL_CONTEXT",
"data": {
"position": {
"x": -388,
"y": 263
}
},
"inputs": {
"color": {
"id": "22370f15-7e0d-4529-9444-f6763afff4a5",
"name": "Color",
"type": "vec4",
"defaultValue": {
"tag": "lit",
"type": "vec4",
"val": [
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 1
}
]
},
"value": {
"tag": "lit",
"type": "vec4",
"val": [
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
}
]
}
}
},
"outputs": {}
}
]
],
"connections": []
}
Now, we should have something like this in the playground:
Creating a static noise effect
To create a static noise effect, we’ll need three additional nodes:
- UV node
- Random node (a custom GLSL Code node)
- Vector 4 node
Create the UV node
To add the UV node, we click the + button in the toolbar, or right-click anywhere on the circuit canvas, and then select NEW NODE > ACCESSORS > UV: The UV Node has three Vector 2 (V2
) outputs; we’re interested in the ASPECT CORRECTED
output. This is where the random node comes into play.
Create a random GLSL Code node
Next, let’s click the +NEW NODE, or right-click on the canvas, to create a new node. Then, we’ll select NEW NODE > COMMON > GLSL: Now, we’ll enter the following code:
float random(vec2 p) {
vec2 K1 = vec2(
23.14069263277926, // e^pi (Gelfond's constant)
2.665144142690225 // 2^sqrt(2) (Gelfond–Schneider constant)
);
return fract( cos( dot(p,K1) ) * 12345.6789 );
}
At this point, the playground should look like this: This node takes a Vector 2 (VEC2
) input and outputs a float (F
).
Add a Vector 4 node
In order to display graphics, we’ll need to provide a Vector 4 input for the WebGL Context node. Let’s click the + button in the toolbar, or right-click on the canvas. Then, we’ll select NEW NODE > VECTOR > VECTOR 4: Once the node has been created, we can enter the random float (F
) output from the RANDOM
node into the VECTOR 4
node, like so: This will produce the noise effect: Here’s the generated code for the Static Noise effect
graphic:
{
"id": "946cbf0c-555c-4a23-8871-153033dcb299",
"name": "Static Noise effect",
"nodes": [
[
"dfb2ecbb-0845-471d-b910-2fdaf575c26b",
{
"id": "dfb2ecbb-0845-471d-b910-2fdaf575c26b",
"name": "WebGL Context",
"type": "WEBGL_CONTEXT",
"data": {
"position": {
"x": -197,
"y": 422
}
},
"inputs": {
"color": {
"id": "22370f15-7e0d-4529-9444-f6763afff4a5",
"name": "Color",
"type": "vec4",
"defaultValue": {
"tag": "lit",
"type": "vec4",
"val": [
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 1
}
]
}
}
},
"outputs": {}
}
],
[
"d0b1e7a5-c0d9-4665-9a7f-177b4a926bd4",
{
"id": "d0b1e7a5-c0d9-4665-9a7f-177b4a926bd4",
"name": "UV",
"type": "UV",
"data": {
"position": {
"x": -1055,
"y": 532
}
},
"inputs": {},
"outputs": {
"aspectCorrected": {
"id": "1876fc2e-5876-4739-8d4d-065588e7344e",
"name": "Aspect Corrected",
"type": "vec2"
},
"uv": {
"id": "4aa3fb2c-cef1-4cf0-848c-dce738555fea",
"name": "UV",
"type": "vec2"
},
"fragCoord": {
"id": "8412d3a3-c97e-403a-b845-287342a274d7",
"name": "Frag Coord",
"type": "vec4"
}
}
}
],
[
"a6b8018e-00b9-4ea0-acbb-f497b21806a9",
{
"id": "a6b8018e-00b9-4ea0-acbb-f497b21806a9",
"name": "Random",
"type": "GLSL",
"data": {
"glsl": "float random(vec2 p) {n vec2 K1 = vec2(n 23.14069263277926, // e^pi (Gelfond's constant)n 2.665144142690225 // 2^sqrt(2) (Gelfond–Schneider constant)n );nn return fract( cos( dot(p,K1) ) * 12345.6789 );n}",
"position": {
"x": -773,
"y": 689
}
},
"inputs": {
"p": {
"id": "c38394cc-3175-4e27-b3f9-f5c5ac24b202",
"name": "p",
"type": "vec2",
"defaultValue": {
"tag": "lit",
"type": "vec2",
"val": [
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
}
]
}
}
},
"outputs": {
"output": {
"id": "420b0fa1-3edd-4892-a1b7-dc0dec3467ed",
"name": "Output",
"type": "float"
}
}
}
],
[
"76d22e0f-f9b4-48db-831b-c084bad5129a",
{
"id": "76d22e0f-f9b4-48db-831b-c084bad5129a",
"name": "Vector 4",
"type": "VECTOR_4",
"data": {
"position": {
"x": -483,
"y": 651
}
},
"inputs": {
"x": {
"id": "ebb5d644-5865-4f47-9334-c67fae2aea61",
"name": "X",
"type": "float",
"defaultValue": {
"tag": "lit",
"type": "float",
"val": 0
}
},
"y": {
"id": "605b83ac-83d0-4256-b1cf-d3c2ed9e6d6f",
"name": "Y",
"type": "float",
"defaultValue": {
"tag": "lit",
"type": "float",
"val": 0
}
},
"z": {
"id": "93ccd2d6-fb68-47ff-8e6e-c3591426df54",
"name": "Z",
"type": "float",
"defaultValue": {
"tag": "lit",
"type": "float",
"val": 0
}
},
"w": {
"id": "8ab84ce4-0373-4dfa-9afb-040debd5f198",
"name": "W",
"type": "float",
"defaultValue": {
"tag": "lit",
"type": "float",
"val": 1
}
}
},
"outputs": {
"vector4": {
"id": "0808e28c-f00f-43d7-becb-bc72dc5b03b9",
"name": "Vector 4",
"type": "vec4"
}
}
}
]
],
"connections": [
[
"01078152-6cf7-4c6f-8b28-3ea800462c18",
{
"id": "01078152-6cf7-4c6f-8b28-3ea800462c18",
"from": "1876fc2e-5876-4739-8d4d-065588e7344e",
"to": "c38394cc-3175-4e27-b3f9-f5c5ac24b202"
}
],
[
"5e230d0d-ec71-481b-9c73-3fb90b199ff1",
{
"id": "5e230d0d-ec71-481b-9c73-3fb90b199ff1",
"from": "420b0fa1-3edd-4892-a1b7-dc0dec3467ed",
"to": "ebb5d644-5865-4f47-9334-c67fae2aea61"
}
],
[
"06fbd536-8aad-457c-a77e-75b9e166582c",
{
"id": "06fbd536-8aad-457c-a77e-75b9e166582c",
"from": "420b0fa1-3edd-4892-a1b7-dc0dec3467ed",
"to": "605b83ac-83d0-4256-b1cf-d3c2ed9e6d6f"
}
],
[
"9d4cc697-8807-4478-9f7d-d721d6073401",
{
"id": "9d4cc697-8807-4478-9f7d-d721d6073401",
"from": "420b0fa1-3edd-4892-a1b7-dc0dec3467ed",
"to": "93ccd2d6-fb68-47ff-8e6e-c3591426df54"
}
],
[
"3b1bd33c-bd6c-4d6d-bb2f-c03e19915467",
{
"id": "3b1bd33c-bd6c-4d6d-bb2f-c03e19915467",
"from": "420b0fa1-3edd-4892-a1b7-dc0dec3467ed",
"to": "8ab84ce4-0373-4dfa-9afb-040debd5f198"
}
],
[
"402faf84-44b2-45d7-bcbf-b83cd845168d",
{
"id": "402faf84-44b2-45d7-bcbf-b83cd845168d",
"from": "0808e28c-f00f-43d7-becb-bc72dc5b03b9",
"to": "22370f15-7e0d-4529-9444-f6763afff4a5"
}
]
]
}
Creating a gradient effect
Let’s demonstrate how to use Alma’s playground to create a gradient effect. To start, we’ll set up a blank playground by removing existing nodes or by importing a circuit.
To create the gradient effect, we’ll need four nodes:
- WebGL Context node
- UV node
- Swizzle node
- Vector 4 node
Import the WebGL Context node
The WebGL Context node is required to render the graphics. We’ll import the circuit as we did earlier in this tutorial by clicking the IMPORT/EXPORT button, represented by a save icon: Once the text field is open, we’ll enter the following code:
{
"id": "946cbf0c-555c-4a23-8871-153033dcb299",
"name": "Alma WebGL Starter",
"nodes": [
[
"dfb2ecbb-0845-471d-b910-2fdaf575c26b",
{
"id": "dfb2ecbb-0845-471d-b910-2fdaf575c26b",
"name": "WebGL Context",
"type": "WEBGL_CONTEXT",
"data": {
"position": {
"x": -388,
"y": 263
}
},
"inputs": {
"color": {
"id": "22370f15-7e0d-4529-9444-f6763afff4a5",
"name": "Color",
"type": "vec4",
"defaultValue": {
"tag": "lit",
"type": "vec4",
"val": [
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 1
}
]
},
"value": {
"tag": "lit",
"type": "vec4",
"val": [
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
}
]
}
}
},
"outputs": {}
}
]
],
"connections": []
}
The playground should look like this: Next, we’ll add a couple of nodes to create a gradient effect.
Add the UV node
To add the UV node, let’s click the + button in the toolbar, or right-click anywhere on the circuit canvas, and select NEW NODE > ACCESSORS > UV:
Add a Swizzle node
Next, we’ll add a Swizzle node that destructs a vector and returns its individual components. Then, we’ll click the + button in the toolbar, or right-click anywhere on the circuit canvas, and select NEW NODE > VECTOR > SWIZZLE:
Add a Vector 4 node
Now, we’ll add a Vector 4 node that takes in four float values and outputs a four-component vector. We’ll click the + button in the toolbar, or right-click anywhere on the circuit canvas, and select NEW NODE > VECTOR > VECTOR 4:
Connecting the nodes
Now, let’s connect our nodes by following these steps:
- Connect the
UV
output of theUV
node to theSWIZZLE
vector input - Connect the
X
andY
float output of theSWIZZLE
node to theX
andY
input of theVECTOR
4
node - Connect the
VECTOR
4
output to theCOLOR
input of theWEBGL CONTEXT
node
We should have something like this:
Animating the gradient
We can animate the gradient by adding a TIME
node. Let’s click the + button in the toolbar, or right-click anywhere on the circuit canvas, and select NEW NODE > ACCESSORS > TIME: Next, we’ll add a SINE
node which returns the sine of the given input. Click the + button in the toolbar, or right-click anywhere on the circuit canvas, and select NEW NODE > TRIGONOMETRY > SINE: Now, we simply connect the TIME
output to the SINE
input and the SINE
output to one of the VECTOR
4
inputs like so: Here’s the resulting gradient: Here’s the output code:
{
"id": "946cbf0c-555c-4a23-8871-153033dcb299",
"name": "Alma Gradient",
"nodes": [
[
"dfb2ecbb-0845-471d-b910-2fdaf575c26b",
{
"id": "dfb2ecbb-0845-471d-b910-2fdaf575c26b",
"name": "WebGL Context",
"type": "WEBGL_CONTEXT",
"data": {
"position": {
"x": 345,
"y": 243
}
},
"inputs": {
"color": {
"id": "22370f15-7e0d-4529-9444-f6763afff4a5",
"name": "Color",
"type": "vec4",
"defaultValue": {
"tag": "lit",
"type": "vec4",
"val": [
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 1
}
]
}
}
},
"outputs": {}
}
],
[
"17394fd6-1018-4b26-877e-31b03e1d97db",
{
"id": "17394fd6-1018-4b26-877e-31b03e1d97db",
"name": "UV",
"type": "UV",
"data": {
"position": {
"x": -556.875,
"y": 270.375
}
},
"inputs": {},
"outputs": {
"aspectCorrected": {
"id": "8b41dade-d1bc-4673-874b-b24f33351a91",
"name": "Aspect Corrected",
"type": "vec2"
},
"uv": {
"id": "d91659e2-7c05-4997-9dbf-e0b9d62e2d20",
"name": "UV",
"type": "vec2"
},
"fragCoord": {
"id": "7b6a3eb5-eb34-42ec-9a23-90eb04fca837",
"name": "Frag Coord",
"type": "vec4"
}
}
}
],
[
"41e47893-dc50-441f-b657-c2ee326fbf87",
{
"id": "41e47893-dc50-441f-b657-c2ee326fbf87",
"name": "Swizzle",
"type": "SWIZZLE",
"data": {
"position": {
"x": -266.5,
"y": 311.75
},
"type": {
"selected": "vec2",
"options": [
"vec2",
"vec3",
"vec4"
]
}
},
"inputs": {
"vector": {
"id": "367c3cd3-291d-4738-bd75-c18f7033a90b",
"name": "Vector",
"type": "vec2",
"defaultValue": {
"tag": "lit",
"type": "vec2",
"val": [
{
"tag": "lit",
"type": "float",
"val": 0
},
{
"tag": "lit",
"type": "float",
"val": 0
}
]
}
}
},
"outputs": {
"x": {
"id": "528b5162-993c-48e5-b4e9-7928e66bd40c",
"name": "X",
"type": "float"
},
"y": {
"id": "ae87ed86-f192-413b-8789-c9c585b411c9",
"name": "Y",
"type": "float"
}
}
}
],
[
"b84da403-ca3d-4870-a959-4f115c8c1b5e",
{
"id": "b84da403-ca3d-4870-a959-4f115c8c1b5e",
"name": "Vector 4",
"type": "VECTOR_4",
"data": {
"position": {
"x": 35.5,
"y": 220.75
}
},
"inputs": {
"x": {
"id": "5896372f-e794-46f4-a291-90ceac5a47d9",
"name": "X",
"type": "float",
"defaultValue": {
"tag": "lit",
"type": "float",
"val": 0
}
},
"y": {
"id": "5b9d42fe-a6c4-4b24-a1aa-b3735517a875",
"name": "Y",
"type": "float",
"defaultValue": {
"tag": "lit",
"type": "float",
"val": 0
}
},
"z": {
"id": "068e80ed-14b6-4d95-963d-c21ff1e7c752",
"name": "Z",
"type": "float",
"defaultValue": {
"tag": "lit",
"type": "float",
"val": 0
}
},
"w": {
"id": "53199eef-7046-4d1e-b344-6229b96e86cf",
"name": "W",
"type": "float",
"defaultValue": {
"tag": "lit",
"type": "float",
"val": 1
},
"value": {
"tag": "lit",
"type": "float",
"val": 1
}
}
},
"outputs": {
"vector4": {
"id": "587fac1d-8b8f-4fb6-856c-5cb26c2eb9aa",
"name": "Vector 4",
"type": "vec4"
}
}
}
],
[
"be523300-a5bb-4887-b5d4-117b4aac4aa6",
{
"id": "be523300-a5bb-4887-b5d4-117b4aac4aa6",
"name": "Time",
"type": "TIME",
"data": {
"position": {
"x": -621.25,
"y": 75.375
}
},
"inputs": {},
"outputs": {
"time": {
"id": "912f8e39-973d-408c-96e8-0aa4feaa5d10",
"name": "Time",
"type": "float"
}
}
}
],
[
"da05fa64-73fe-4e8a-b24e-614e5c1319b0",
{
"id": "da05fa64-73fe-4e8a-b24e-614e5c1319b0",
"name": "Sine",
"type": "SINE",
"data": {
"position": {
"x": -293.36376953125,
"y": 37.45458984375
},
"type": {
"selected": "float",
"options": [
"float",
"vec2",
"vec3",
"vec4"
]
}
},
"inputs": {
"input": {
"id": "55203142-60ef-44f7-b536-1fbd882da361",
"name": "Input",
"type": "float",
"defaultValue": {
"tag": "lit",
"type": "float",
"val": 0
}
}
},
"outputs": {
"output": {
"id": "83e99f93-871f-49be-9d64-0e3e9e2a2b51",
"name": "Output",
"type": "float"
}
}
}
]
],
"connections": [
[
"09352645-3ce4-4959-aa8a-ec0f2bb0fbaf",
{
"id": "09352645-3ce4-4959-aa8a-ec0f2bb0fbaf",
"from": "d91659e2-7c05-4997-9dbf-e0b9d62e2d20",
"to": "367c3cd3-291d-4738-bd75-c18f7033a90b"
}
],
[
"23aa3199-e044-420d-849e-956724db0cc5",
{
"id": "23aa3199-e044-420d-849e-956724db0cc5",
"from": "528b5162-993c-48e5-b4e9-7928e66bd40c",
"to": "5896372f-e794-46f4-a291-90ceac5a47d9"
}
],
[
"5f5b361d-2a32-482c-94ee-4b31e2a65ed4",
{
"id": "5f5b361d-2a32-482c-94ee-4b31e2a65ed4",
"from": "ae87ed86-f192-413b-8789-c9c585b411c9",
"to": "5b9d42fe-a6c4-4b24-a1aa-b3735517a875"
}
],
[
"d5593a33-796d-41c5-97ff-0c63b4b4a707",
{
"id": "d5593a33-796d-41c5-97ff-0c63b4b4a707",
"from": "587fac1d-8b8f-4fb6-856c-5cb26c2eb9aa",
"to": "22370f15-7e0d-4529-9444-f6763afff4a5"
}
],
[
"52046d4b-9ab7-448e-9a5f-f2b2c9885d32",
{
"id": "52046d4b-9ab7-448e-9a5f-f2b2c9885d32",
"from": "912f8e39-973d-408c-96e8-0aa4feaa5d10",
"to": "55203142-60ef-44f7-b536-1fbd882da361"
}
],
[
"80579b46-e4f0-42c0-a7ba-103740d90111",
{
"id": "80579b46-e4f0-42c0-a7ba-103740d90111",
"from": "83e99f93-871f-49be-9d64-0e3e9e2a2b51",
"to": "068e80ed-14b6-4d95-963d-c21ff1e7c752"
}
]
]
}
Conclusion
Alma is a creative platform that encourages exploration and experimentation with generative graphics. Its intuitive interface enables artists, designers, and developers to easily bring their visions to life.
This generative graphics tool has an extensive array of nodes, connections, and code nodes, offering endless possibilities for creating dynamic visual experiences. Since Alma is still in alpha stage, we can expect even more extensive and enhanced functionality to come!
Get set up with LogRocket's modern error tracking in minutes:
- Visit https://logrocket.com/signup/ to get an app ID.
- Install LogRocket via NPM or script tag.
LogRocket.init()
must be called client-side, not server-side.
NPM:
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
Script Tag:
Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
3.(Optional) Install plugins for deeper integrations with your stack:
- Redux middleware
- ngrx middleware
- Vuex plugin
Top comments (0)