🥋 Book I - Matrix
Welcome to Book I
host = :inet.gethostname()
host = :erl_epmd.names()
input = Kino.Input.text("Your name")
name = Kino.Input.read(input)
{:ok, class} = Dojo.Class.join(self(), "book1", %Dojo.Disciple{name: name, action: "away"})
coordinate = [{3, 4}, {2, 5}, {2, 6}]
DojoKino.Animate.new(1..10, fn index ->
Kino.Markdown.new(Dojo.Conway.genesis("blinker", 10, index, coordinate))
end)
f = &Dojo.Conway.reduce_genesis("blinker", 7, &1, coordinate)
Dojo.PubSub.publish({name, f}, :animate, "class:book1")
defmodule ECM do
def run(start_str, rule, times) do
IO.puts("rule : #{rule}")
each(start_str, rule_pattern(rule), times)
end
defp rule_pattern(rule) do
list =
Integer.to_string(rule, 2)
|> String.pad_leading(8, "0")
|> String.codepoints()
|> Enum.reverse()
Enum.map(0..7, fn i -> Integer.to_string(i, 2) |> String.pad_leading(3, "0") end)
|> Enum.zip(list)
|> Map.new()
end
defp each(_, _, 0), do: :ok
defp each(str, patterns, times) do
IO.puts(String.replace(str, "0", "⬜") |> String.replace("1", "⬛"))
str2 = String.last(str) <> str <> String.first(str)
next_str =
Enum.map_join(0..(String.length(str) - 1), fn i ->
Map.get(patterns, String.slice(str2, i, 3))
end)
each(next_str, patterns, times - 1)
end
end
pad = String.duplicate("0", 14)
str = pad <> "1" <> pad
ECM.run(str, 90, 4)
DojoKino.Animate.new(1..10, fn index -> ECM.run(str, 90, index) end)
defmodule GOL do
# ...
def next_generation(grid) do
# Define the convolution kernel for the Game of Life rules
kernel = [
[1, 1, 1],
[1, 0, 1],
[1, 1, 1]
]
# Apply the convolution to the grid
convolution(grid, kernel)
end
defp convolution(grid, kernel) do
# Implement the convolution operation here
# This involves sliding the kernel over the grid and applying the rules
# For simplicity, we'll assume a basic implementation that counts neighbors
# and applies the Game of Life rules
Enum.map(grid, fn row, y ->
Enum.map(row, fn cell, x ->
# Calculate the sum of the kernel applied to the cell
sum =
Enum.sum(Enum.with_index(kernel), fn {row, ky}, i ->
Enum.sum(Enum.with_index(row), fn cell, kx ->
if kx + i < 0 or kx + i >= length(row) or ky + y < 0 or ky + y >= length(grid) do
0
else
Enum.at(Enum.at(grid, ky + y), kx + i)
end
end)
end)
# Apply the Game of Life rules
if cell == 1 and (sum == 2 or sum == 3) do
1
else
if cell == 0 and sum == 3 do
1
else
0
end
end
end)
end)
end
end
defmodule KinoGuide.ShellCell do
use Kino.JS
use Kino.JS.Live
use Kino.SmartCell, name: "Shell script"
@impl true
def init(_attrs, ctx) do
{:ok, ctx, editor: [attribute: "source"]}
end
@impl true
def handle_connect(ctx) do
{:ok, %{}, ctx}
end
@impl true
def to_attrs(_ctx) do
%{}
end
@impl true
def to_source(attrs) do
quote do
System.shell(
unquote(quoted_multiline(attrs["source"])),
into: IO.stream(),
stderr_to_stdout: true
)
|> elem(1)
end
|> Kino.SmartCell.quoted_to_string()
end
defp quoted_multiline(string) do
{:<<>>, [delimiter: ~s["""]], [string <> "\n"]}
end
asset "main.js" do
"""
export function init(ctx, payload) {
ctx.importCSS("main.css");
root.innerHTML = `
Shell script
`;
}
"""
end
asset "main.css" do
"""
.app {
padding: 8px 16px;
border: solid 1px #cad5e0;
border-radius: 0.5rem 0.5rem 0 0;
border-bottom: none;
}
"""
end
end
Kino.SmartCell.register(KinoGuide.ShellCell)
defmodule Kino.TailwindPlayground do
use Kino.JS
use Kino.JS.Live
use Kino.SmartCell, name: "Tailwind Playground"
require Logger
@impl true
def init(attrs, ctx) do
{:ok, assign(ctx, initial_html: attrs["html"] || ""),
editor: [attribute: "html", language: "html", placement: :top]}
end
@impl true
def handle_connect(ctx) do
{:ok, %{}, ctx}
end
@impl true
def handle_event("initial-render", %{}, ctx) do
Process.send_after(self(), {:display_html, ctx.assigns.initial_html}, 100)
{:noreply, ctx}
end
@impl true
def to_attrs(_ctx) do
%{}
end
@impl true
def to_source(attrs) do
# we can't encode ctx in attrs so we send ourselves a message in order to display the html.
send(self(), {:display_html, attrs["html"]})
"Kino.nothing()"
end
@impl true
def handle_info({:display_html, html}, ctx) do
broadcast_event(ctx, "display-html", %{"html" => html})
{:noreply, ctx}
end
asset "main.css" do
"""
.wrapper {
position: relative;
width: 100%;
height: 100%;
overflow-x: auto;
background-color: white;
}
svg {
pointer-events: none;
}
.size-btn {
color: white;
border-radius: 8px;
border-style: none;
background-color: #33394c;
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
padding: 4px;
}
.active {
background-color: #495e7c;
}
.button-header {
padding: 12px;
background-color: #0f182a;
display: flex;
gap: 8px;
}
#iframe {
background-color: white;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: none;
display: block;
margin-left: auto;
margin-right: auto;
overflow: auto;
}
#iframe-container {
max-width: 100%;
display: block;
background-color: #292c34;
height: 570px;
resize: vertical;
overflow: hidden;
position: relative;
padding: 0 5px 5px;
}
"""
end
asset "main.js" do
"""
export function init(ctx, payload) {
ctx.importCSS("main.css");
ctx.root.innerHTML = `
xs
sm
md
`
ctx
.importJS(
"https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"
)
.then(() => {
let iframe = ctx.root.querySelector("#iframe");
let buttons = document.querySelectorAll(".size-btn");
iframe.srcdoc = `
`
buttons.forEach((btn) => {
btn.addEventListener("click", (e) => {
iframe.style.maxWidth = e.target.dataset.width;
buttons.forEach((btn) => { btn.classList.remove("active") })
e.target.classList.add("active")
});
});
ctx.handleEvent("display-html", ({ html }) => {
let body = iframe.contentWindow.document.querySelector("#body");
body.innerHTML = html
});
ctx.pushEvent("initial-render", { });
ctx.handleSync(() => {
// Synchronously invokes change listeners
document.activeElement && document.activeElement.dispatchEvent(new Event("change"));
});
});
}
"""
end
end
Kino.SmartCell.register(Kino.TailwindPlayground)
Kino.nothing()
Dojo.PubSub.publish(
"class:book1",
{name,
"""
@keyframes bounce {
0%, 100% { transform: translateY(200px); }
50% { transform: translateY(500px); }
}
Hello from Acme!
Welcome to our magical world.
"""}
)
require Dojo.Module
# String.to_atom("Brit")
Dojo.Module.generate(name, "hellod")
# :erlang.binary_to_existing_atom("Elixir.Dojo.PubSub", :utf8)
# Module.con
Dojo.Mat.Brit.hello()