Current section

Files

Jump to
mascarpone src mascarpone.erl
Raw

src/mascarpone.erl

-module(mascarpone).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/mascarpone.gleam").
-export([main/0]).
-export_type([step/0, template/0, model/0, msg/0]).
-type step() :: welcome |
lustre_choice |
template_choice |
complete |
{failed, binary()}.
-type template() :: two_d_game | three_d_game | physics_demo.
-type model() :: {model,
step(),
binary(),
boolean(),
boolean(),
gleam@option:option(template())}.
-type msg() :: next_step |
{set_lustre, boolean()} |
{set_template, template()} |
generate.
-file("src/mascarpone.gleam", 75).
-spec init(binary()) -> {model(), list(fun(() -> msg()))}.
init(Project_name) ->
{{model, welcome, Project_name, true, false, none}, []}.
-file("src/mascarpone.gleam", 143).
-spec view_welcome() -> shore@internal:node_(msg()).
view_welcome() ->
shore@ui:col(
[shore@ui:text_styled(
<<"╔═══════════════════════════════════╗"/utf8>>,
{some, cyan},
none
),
shore@ui:text_styled(
<<"║ 🎮 Tiramisu Project Creator 🎮 ║"/utf8>>,
{some, cyan},
none
),
shore@ui:text_styled(
<<"║ Gleam 3D Game Engine ║"/utf8>>,
{some, cyan},
none
),
shore@ui:text_styled(
<<"╚═══════════════════════════════════╝"/utf8>>,
{some, cyan},
none
),
shore@ui:text(<<""/utf8>>),
shore@ui:text(<<"Welcome to Tiramisu! 🍰"/utf8>>),
shore@ui:text(<<""/utf8>>),
shore@ui:text(
<<"This wizard will help you set up Tiramisu for your game project."/utf8>>
),
shore@ui:text(<<""/utf8>>),
shore@ui:hr(),
shore@ui:text(<<""/utf8>>),
shore@ui:button(<<"Continue"/utf8>>, enter, next_step)]
).
-file("src/mascarpone.gleam", 176).
-spec view_lustre_choice() -> shore@internal:node_(msg()).
view_lustre_choice() ->
shore@ui:col(
[shore@ui:text_styled(<<"Lustre Integration"/utf8>>, {some, cyan}, none),
shore@ui:text(<<""/utf8>>),
shore@ui:text(
<<"Lustre allows you to create UI overlays for your game"/utf8>>
),
shore@ui:text(
<<"(menus, HUDs, dialogs, etc.) using a reactive framework."/utf8>>
),
shore@ui:text(<<""/utf8>>),
shore@ui:hr(),
shore@ui:text(<<""/utf8>>),
shore@ui:text(<<"Include Lustre?"/utf8>>),
shore@ui:text(<<""/utf8>>),
shore@ui:button(
<<"[Y] Yes (recommended)"/utf8>>,
{char, <<"y"/utf8>>},
{set_lustre, true}
),
shore@ui:button(
<<"[N] No"/utf8>>,
{char, <<"n"/utf8>>},
{set_lustre, false}
)]
).
-file("src/mascarpone.gleam", 192).
-spec view_template_choice() -> shore@internal:node_(msg()).
view_template_choice() ->
shore@ui:col(
[shore@ui:text_styled(<<"Project Template"/utf8>>, {some, cyan}, none),
shore@ui:text(<<""/utf8>>),
shore@ui:button(
<<"[1] 2D Game - Orthographic camera and sprite setup"/utf8>>,
{char, <<"1"/utf8>>},
{set_template, two_d_game}
),
shore@ui:button(
<<"[2] 3D Game - Perspective camera with lighting"/utf8>>,
{char, <<"2"/utf8>>},
{set_template, three_d_game}
),
shore@ui:button(
<<"[3] Physics Demo - Physics-enabled objects"/utf8>>,
{char, <<"3"/utf8>>},
{set_template, physics_demo}
)]
).
-file("src/mascarpone.gleam", 252).
-spec view_error(binary()) -> shore@internal:node_(msg()).
view_error(Msg) ->
shore@ui:col(
[shore@ui:text_styled(<<"❌ Error occurred"/utf8>>, {some, red}, none),
shore@ui:text(<<""/utf8>>),
shore@ui:text(Msg)]
).
-file("src/mascarpone.gleam", 260).
-spec template_name(template()) -> binary().
template_name(Template) ->
case Template of
two_d_game ->
<<"2D Game"/utf8>>;
three_d_game ->
<<"3D Game"/utf8>>;
physics_demo ->
<<"Physics Demo"/utf8>>
end.
-file("src/mascarpone.gleam", 214).
-spec view_complete(model()) -> shore@internal:node_(msg()).
view_complete(Model) ->
shore@ui:col(
[shore@ui:text_styled(
<<"✅ Project setup complete!"/utf8>>,
{some, green},
none
),
shore@ui:text(<<""/utf8>>),
shore@ui:text(
<<"Project: "/utf8, (erlang:element(3, Model))/binary>>
),
shore@ui:text(
<<"Template: "/utf8,
(template_name(
gleam@option:unwrap(
erlang:element(6, Model),
three_d_game
)
))/binary>>
),
shore@ui:text(<<"Lustre: "/utf8, (case erlang:element(4, Model) of
true ->
<<"Yes"/utf8>>;
false ->
<<"No"/utf8>>
end)/binary>>),
shore@ui:text(<<"Physics: "/utf8, (case erlang:element(5, Model) of
true ->
<<"Yes"/utf8>>;
false ->
<<"No"/utf8>>
end)/binary>>),
shore@ui:text(<<""/utf8>>),
shore@ui:hr(),
shore@ui:text(<<""/utf8>>),
shore@ui:text(<<"Next steps:"/utf8>>),
shore@ui:text(<<""/utf8>>),
shore@ui:text(<<"1. Start the dev server:"/utf8>>),
shore@ui:text_styled(
<<" gleam run -m lustre/dev start"/utf8>>,
{some, cyan},
none
),
shore@ui:text(<<""/utf8>>),
shore@ui:text(
<<"2. Open http://localhost:1234 in your browser"/utf8>>
),
shore@ui:text(<<""/utf8>>),
shore@ui:text(<<"Happy game development! 🎮"/utf8>>),
shore@ui:text(<<""/utf8>>),
shore@ui:text(<<"Press Ctrl + X to leave"/utf8>>)]
).
-file("src/mascarpone.gleam", 131).
-spec view(model()) -> shore@internal:node_(msg()).
view(Model) ->
case erlang:element(2, Model) of
welcome ->
view_welcome();
lustre_choice ->
view_lustre_choice();
template_choice ->
view_template_choice();
complete ->
view_complete(Model);
{failed, Msg} ->
view_error(Msg)
end.
-file("src/mascarpone.gleam", 310).
-spec find_root(binary()) -> binary().
find_root(Path) ->
Toml = filepath:join(Path, <<"gleam.toml"/utf8>>),
case simplifile_erl:is_file(Toml) of
{ok, false} ->
find_root(filepath:join(Path, <<".."/utf8>>));
{error, _} ->
find_root(filepath:join(Path, <<".."/utf8>>));
{ok, true} ->
Path
end.
-file("src/mascarpone.gleam", 288).
-spec get_project_name() -> {ok, binary()} | {error, snag:snag()}.
get_project_name() ->
Root = find_root(<<"."/utf8>>),
Toml_path = filepath:join(Root, <<"gleam.toml"/utf8>>),
gleam@result:'try'(
begin
_pipe = simplifile:read(Toml_path),
snag:map_error(
_pipe,
fun(_) -> <<"Could not read gleam.toml"/utf8>> end
)
end,
fun(Content) ->
gleam@result:'try'(
begin
_pipe@1 = tom:parse(Content),
snag:map_error(
_pipe@1,
fun(_) -> <<"Could not parse gleam.toml"/utf8>> end
)
end,
fun(Toml) ->
gleam@result:'try'(
begin
_pipe@2 = tom:get_string(Toml, [<<"name"/utf8>>]),
snag:map_error(
_pipe@2,
fun(_) ->
<<"Could not find project name in gleam.toml"/utf8>>
end
)
end,
fun(Name) -> {ok, Name} end
)
end
)
end
).
-file("src/mascarpone.gleam", 319).
-spec update_gleam_toml(binary(), boolean()) -> {ok, nil} | {error, snag:snag()}.
update_gleam_toml(Project_name, Include_lustre) ->
Root = find_root(<<"."/utf8>>),
Toml_path = filepath:join(Root, <<"gleam.toml"/utf8>>),
gleam@result:'try'(
begin
_pipe = simplifile:read(Toml_path),
snag:map_error(
_pipe,
fun(_) -> <<"Could not read gleam.toml"/utf8>> end
)
end,
fun(Content) ->
Content@1 = case gleam_stdlib:contains_string(
Content,
<<"target ="/utf8>>
) of
true ->
Content;
false ->
gleam@string:replace(
Content,
<<<<"name = \""/utf8, Project_name/binary>>/binary,
"\""/utf8>>,
<<<<"name = \""/utf8, Project_name/binary>>/binary,
"\"\ntarget = \"javascript\""/utf8>>
)
end,
Deps = [<<"tiramisu = \">= 2.0.0 and < 3.0.0\""/utf8>>,
<<"vec = \">= 3.0.1 and < 4.0.0\""/utf8>>],
Dev_deps = [<<"lustre_dev_tools = \">= 2.0.2 and <= 3.0.0\""/utf8>>],
Deps@1 = case Include_lustre of
true ->
lists:append(
Deps,
[<<"lustre = \">= 5.0.0 and < 6.0.0\""/utf8>>]
);
false ->
Deps
end,
Content_with_deps = case gleam_stdlib:contains_string(
Content@1,
<<"[dependencies]"/utf8>>
) of
true ->
gleam@list:fold(
Deps@1,
Content@1,
fun(Acc, Dep) ->
gleam@string:replace(
Acc,
<<"[dependencies]"/utf8>>,
<<"[dependencies]\n"/utf8, Dep/binary>>
)
end
);
false ->
<<<<Content@1/binary, "\n\n[dependencies]\n"/utf8>>/binary,
(gleam@string:join(Deps@1, <<"\n"/utf8>>))/binary>>
end,
Content_with_dev_deps = case gleam_stdlib:contains_string(
Content_with_deps,
<<"[dev-dependencies]"/utf8>>
) of
true ->
gleam@list:fold(
Dev_deps,
Content_with_deps,
fun(Acc@1, Dep@1) ->
gleam@string:replace(
Acc@1,
<<"[dev-dependencies]"/utf8>>,
<<"[dev-dependencies]\n"/utf8, Dep@1/binary>>
)
end
);
false ->
<<<<Content_with_deps/binary,
"\n\n[dev-dependencies]\n"/utf8>>/binary,
(gleam@string:join(Dev_deps, <<"\n"/utf8>>))/binary>>
end,
Lustre_config = <<"\n\n[tools.lustre.html]
scripts = [
{ type = \"importmap\", content = \"{ \\\"imports\\\": { \\\"three\\\": \\\"https://cdn.jsdelivr.net/npm/three@0.180.0/build/three.module.js\\\", \\\"three/addons/\\\": \\\"https://cdn.jsdelivr.net/npm/three@0.180.0/examples/jsm/\\\", \\\"@dimforge/rapier3d-compat\\\": \\\"https://cdn.jsdelivr.net/npm/@dimforge/rapier3d-compat@0.11.2/+esm\\\" } }\" }
]
stylesheets = [
{ content = \"body { margin: 0; padding: 0; overflow: hidden; }\" }
]
"/utf8>>,
Final_content = case gleam_stdlib:contains_string(
Content_with_dev_deps,
<<"[tools.lustre.html]"/utf8>>
) of
true ->
Content_with_dev_deps;
false ->
<<Content_with_dev_deps/binary, Lustre_config/binary>>
end,
_pipe@1 = simplifile:write(Toml_path, Final_content),
snag:map_error(
_pipe@1,
fun(_) -> <<"Could not write gleam.toml"/utf8>> end
)
end
).
-file("src/mascarpone.gleam", 406).
-spec create_gitignore() -> {ok, nil} | {error, snag:snag()}.
create_gitignore() ->
Root = find_root(<<"."/utf8>>),
Gitignore_path = filepath:join(Root, <<".gitignore"/utf8>>),
Content = <<"*.beam
*.ez
/build
erl_crash.dump
/priv
.DS_Store
node_modules/
dist/
.lustre/"/utf8>>,
_pipe = simplifile:write(Gitignore_path, Content),
snag:map_error(_pipe, fun(_) -> <<"Could not write .gitignore"/utf8>> end).
-file("src/mascarpone.gleam", 442).
-spec generate_2d_template() -> binary().
generate_2d_template() ->
<<"/// 2D Game Example - Orthographic Camera
import gleam/float
import gleam/option
import tiramisu
import tiramisu/background
import tiramisu/camera
import tiramisu/effect.{type Effect}
import tiramisu/geometry
import tiramisu/light
import tiramisu/material
import tiramisu/scene
import tiramisu/transform
import vec/vec3
pub type Model {
Model(time: Float)
}
pub type Msg {
Tick
}
pub fn main() -> Nil {
tiramisu.run(
dimensions: option.None,
background: background.Color(0x1a1a2e),
init: init,
update: update,
view: view,
)
}
fn init(_ctx: tiramisu.Context(String)) -> #(Model, Effect(Msg), option.Option(_)) {
#(Model(time: 0.0), effect.tick(Tick), option.None)
}
fn update(
model: Model,
msg: Msg,
ctx: tiramisu.Context(String),
) -> #(Model, Effect(Msg), option.Option(_)) {
case msg {
Tick -> {
let new_time = model.time +. ctx.delta_time
#(Model(time: new_time), effect.tick(Tick), option.None)
}
}
}
fn view(model: Model, ctx: tiramisu.Context(String)) -> List(scene.Node(String)) {
let cam = camera.camera_2d(
width: float.round(ctx.canvas_width),
height: float.round(ctx.canvas_height),
)
let assert Ok(sprite_geom) = geometry.plane(width: 50.0, height: 50.0)
let assert Ok(sprite_mat) = material.basic(color: 0xff0066, transparent: False, opacity: 1.0, map: option.None)
[
scene.Camera(
id: \"camera\",
camera: cam,
transform: transform.at(position: vec3.Vec3(0.0, 0.0, 20.0)),
look_at: option.None,
active: True,
viewport: option.None,
),
scene.Light(
id: \"ambient\",
light: {
let assert Ok(light) = light.ambient(color: 0xffffff, intensity: 1.0)
light
},
transform: transform.identity,
),
scene.Mesh(
id: \"sprite\",
geometry: sprite_geom,
material: sprite_mat,
transform: transform.Transform(
position: vec3.Vec3(0.0, 0.0, 0.0),
rotation: vec3.Vec3(0.0, 0.0, model.time),
scale: vec3.Vec3(1.0, 1.0, 1.0),
),
physics: option.None,
),
]
}
"/utf8>>.
-file("src/mascarpone.gleam", 533).
-spec generate_3d_template() -> binary().
generate_3d_template() ->
<<"/// 3D Game Example - Perspective Camera with Lighting
import gleam/option
import tiramisu
import tiramisu/background
import tiramisu/camera
import tiramisu/effect.{type Effect}
import tiramisu/geometry
import tiramisu/light
import tiramisu/material
import tiramisu/scene
import tiramisu/transform
import vec/vec3
pub type Model {
Model(time: Float)
}
pub type Msg {
Tick
}
pub fn main() -> Nil {
tiramisu.run(
dimensions: option.None,
background: background.Color(0x1a1a2e),
init: init,
update: update,
view: view,
)
}
fn init(_ctx: tiramisu.Context(String)) -> #(Model, Effect(Msg), option.Option(_)) {
#(Model(time: 0.0), effect.tick(Tick), option.None)
}
fn update(
model: Model,
msg: Msg,
ctx: tiramisu.Context(String),
) -> #(Model, Effect(Msg), option.Option(_)) {
case msg {
Tick -> {
let new_time = model.time +. ctx.delta_time
#(Model(time: new_time), effect.tick(Tick), option.None)
}
}
}
fn view(model: Model, _ctx: tiramisu.Context(String)) -> List(scene.Node(String)) {
let assert Ok(cam) = camera.perspective(field_of_view: 75.0, near: 0.1, far: 1000.0)
let assert Ok(sphere_geom) = geometry.sphere(radius: 1.0, width_segments: 32, height_segments: 32)
let assert Ok(sphere_mat) = material.new() |> material.with_color(0x0066ff) |> material.build
let assert Ok(ground_geom) = geometry.plane(width: 20.0, height: 20.0)
let assert Ok(ground_mat) = material.new() |> material.with_color(0x808080) |> material.build
[
scene.Camera(
id: \"camera\",
camera: cam,
transform: transform.at(position: vec3.Vec3(0.0, 5.0, 10.0)),
look_at: option.Some(vec3.Vec3(0.0, 0.0, 0.0)),
active: True,
viewport: option.None,
),
scene.Light(
id: \"ambient\",
light: {
let assert Ok(light) = light.ambient(color: 0xffffff, intensity: 0.5)
light
},
transform: transform.identity,
),
scene.Light(
id: \"directional\",
light: {
let assert Ok(light) = light.directional(color: 0xffffff, intensity: 0.8)
light
},
transform: transform.at(position: vec3.Vec3(10.0, 10.0, 10.0)),
),
scene.Mesh(
id: \"sphere\",
geometry: sphere_geom,
material: sphere_mat,
transform: transform.at(position: vec3.Vec3(0.0, 0.0, 0.0)),
physics: option.None,
),
scene.Mesh(
id: \"ground\",
geometry: ground_geom,
material: ground_mat,
transform: transform.Transform(
position: vec3.Vec3(0.0, -2.0, 0.0),
rotation: vec3.Vec3(-1.57, 0.0, 0.0),
scale: vec3.Vec3(1.0, 1.0, 1.0),
),
physics: option.None,
),
]
}
"/utf8>>.
-file("src/mascarpone.gleam", 637).
-spec generate_physics_template() -> binary().
generate_physics_template() ->
<<"/// Physics Demo - Falling Cubes
/// Demonstrates physics simulation with Rapier3D
import gleam/option
import tiramisu
import tiramisu/background
import tiramisu/camera
import tiramisu/effect.{type Effect}
import tiramisu/geometry
import tiramisu/light
import tiramisu/material
import tiramisu/physics
import tiramisu/scene
import tiramisu/transform
import vec/vec3
pub type Id {
Camera
Ambient
Directional
Ground
Cube1
Cube2
}
pub type Model {
Model
}
pub type Msg {
Tick
}
pub fn main() -> Nil {
tiramisu.run(
dimensions: option.None,
background: background.Color(0x1a1a2e),
init: init,
update: update,
view: view,
)
}
fn init(_ctx: tiramisu.Context(Id)) -> #(Model, Effect(Msg), option.Option(_)) {
// Initialize physics world with gravity
let physics_world =
physics.new_world(
physics.WorldConfig(gravity: vec3.Vec3(0.0, -9.81, 0.0), correspondances: [
#(Cube1, \"cube-1\"),
#(Cube2, \"cube-2\"),
#(Ground, \"ground\"),
]),
)
#(Model, effect.tick(Tick), option.Some(physics_world))
}
fn update(
model: Model,
msg: Msg,
ctx: tiramisu.Context(Id),
) -> #(Model, Effect(Msg), option.Option(_)) {
let assert option.Some(physics_world) = ctx.physics_world
case msg {
Tick -> {
let new_physics_world = physics.step(physics_world)
#(model, effect.tick(Tick), option.Some(new_physics_world))
}
}
}
fn view(_model: Model, ctx: tiramisu.Context(Id)) -> List(scene.Node(Id)) {
let assert option.Some(physics_world) = ctx.physics_world
let assert Ok(cam) = camera.perspective(field_of_view: 75.0, near: 0.1, far: 1000.0)
let assert Ok(cube_geom) = geometry.box(width: 1.0, height: 1.0, depth: 1.0)
let assert Ok(cube1_mat) = material.new() |> material.with_color(0xff4444) |> material.build
let assert Ok(cube2_mat) = material.new() |> material.with_color(0x44ff44) |> material.build
let assert Ok(ground_geom) = geometry.box(width: 20.0, height: 0.2, depth: 20.0)
let assert Ok(ground_mat) = material.new() |> material.with_color(0x808080) |> material.build
[
scene.Camera(
id: Camera,
camera: cam,
transform: transform.at(position: vec3.Vec3(0.0, 10.0, 15.0)),
look_at: option.Some(vec3.Vec3(0.0, 0.0, 0.0)),
active: True,
viewport: option.None,
),
scene.Light(
id: Ambient,
light: {
let assert Ok(light) = light.ambient(color: 0xffffff, intensity: 0.5)
light
},
transform: transform.identity,
),
scene.Light(
id: Directional,
light: {
let assert Ok(light) = light.directional(color: 0xffffff, intensity: 2.0)
light
},
transform: transform.at(position: vec3.Vec3(5.0, 10.0, 7.5)),
),
// Ground (static physics body)
scene.Mesh(
id: Ground,
geometry: ground_geom,
material: ground_mat,
transform: transform.at(position: vec3.Vec3(0.0, 0.0, 0.0)),
physics: option.Some(
physics.new_rigid_body(physics.Fixed)
|> physics.with_collider(physics.Box(20.0, 0.2, 20.0))
|> physics.with_restitution(0.0)
|> physics.build(),
),
),
// Falling cube 1 (dynamic physics body)
scene.Mesh(
id: Cube1,
geometry: cube_geom,
material: cube1_mat,
transform: case physics.get_transform(physics_world, Cube1) {
Ok(t) -> t
Error(Nil) -> transform.at(position: vec3.Vec3(-2.0, 5.0, 0.0))
},
physics: option.Some(
physics.new_rigid_body(physics.Dynamic)
|> physics.with_collider(physics.Box(1.0, 1.0, 1.0))
|> physics.with_mass(1.0)
|> physics.with_restitution(0.5)
|> physics.with_friction(0.5)
|> physics.build(),
),
),
// Falling cube 2 (dynamic physics body)
scene.Mesh(
id: Cube2,
geometry: cube_geom,
material: cube2_mat,
transform: case physics.get_transform(physics_world, Cube2) {
Ok(t) -> t
Error(Nil) -> transform.at(position: vec3.Vec3(2.0, 7.0, 0.0))
},
physics: option.Some(
physics.new_rigid_body(physics.Dynamic)
|> physics.with_collider(physics.Box(1.0, 1.0, 1.0))
|> physics.with_mass(1.0)
|> physics.with_restitution(0.6)
|> physics.with_friction(0.3)
|> physics.build(),
),
),
]
}
"/utf8>>.
-file("src/mascarpone.gleam", 425).
-spec create_main_file(binary(), template()) -> {ok, nil} | {error, snag:snag()}.
create_main_file(Project_name, Template) ->
Root = find_root(<<"."/utf8>>),
Src_dir = filepath:join(Root, <<"src"/utf8>>),
Main_path = filepath:join(Src_dir, <<Project_name/binary, ".gleam"/utf8>>),
Content = case Template of
two_d_game ->
generate_2d_template();
three_d_game ->
generate_3d_template();
physics_demo ->
generate_physics_template()
end,
_pipe = simplifile:write(Main_path, Content),
snag:map_error(_pipe, fun(_) -> <<"Could not write main file"/utf8>> end).
-file("src/mascarpone.gleam", 270).
-spec generate_project(model()) -> {ok, nil} | {error, snag:snag()}.
generate_project(Model) ->
gleam@result:'try'(
update_gleam_toml(erlang:element(3, Model), erlang:element(4, Model)),
fun(_) ->
gleam@result:'try'(
create_gitignore(),
fun(_) ->
gleam@result:'try'(
create_main_file(
erlang:element(3, Model),
gleam@option:unwrap(
erlang:element(6, Model),
three_d_game
)
),
fun(_) -> {ok, nil} end
)
end
)
end
).
-file("src/mascarpone.gleam", 88).
-spec update(model(), msg()) -> {model(), list(fun(() -> msg()))}.
update(Model, Msg) ->
case Msg of
next_step ->
Next_step = case erlang:element(2, Model) of
welcome ->
lustre_choice;
lustre_choice ->
template_choice;
template_choice ->
complete;
complete ->
complete;
{failed, _} ->
complete
end,
{{model,
Next_step,
erlang:element(3, Model),
erlang:element(4, Model),
erlang:element(5, Model),
erlang:element(6, Model)},
[]};
{set_lustre, Value} ->
{{model,
template_choice,
erlang:element(3, Model),
Value,
erlang:element(5, Model),
erlang:element(6, Model)},
[]};
{set_template, Template} ->
Updated_model = {model,
erlang:element(2, Model),
erlang:element(3, Model),
erlang:element(4, Model),
erlang:element(5, Model),
{some, Template}},
Result = generate_project(Updated_model),
case Result of
{ok, _} ->
{{model,
complete,
erlang:element(3, Updated_model),
erlang:element(4, Updated_model),
erlang:element(5, Updated_model),
erlang:element(6, Updated_model)},
[]};
{error, Err} ->
{{model,
{failed, snag:pretty_print(Err)},
erlang:element(3, Updated_model),
erlang:element(4, Updated_model),
erlang:element(5, Updated_model),
erlang:element(6, Updated_model)},
[]}
end;
generate ->
Result@1 = generate_project(Model),
case Result@1 of
{ok, _} ->
{{model,
complete,
erlang:element(3, Model),
erlang:element(4, Model),
erlang:element(5, Model),
erlang:element(6, Model)},
[]};
{error, Err@1} ->
{{model,
{failed, snag:pretty_print(Err@1)},
erlang:element(3, Model),
erlang:element(4, Model),
erlang:element(5, Model),
erlang:element(6, Model)},
[]}
end
end.
-file("src/mascarpone.gleam", 16).
-spec main() -> nil.
main() ->
Exit = gleam@erlang@process:new_subject(),
case get_project_name() of
{ok, Project_name} ->
case begin
_pipe = shore:spec(
fun() -> init(Project_name) end,
fun view/1,
fun update/2,
Exit,
shore:default_keybinds(),
shore:on_update()
),
shore:start(_pipe)
end of
{ok, _} -> nil;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"mascarpone"/utf8>>,
function => <<"main"/utf8>>,
line => 21,
value => _assert_fail,
start => 398,
'end' => 672,
pattern_start => 409,
pattern_end => 419})
end,
_pipe@1 = Exit,
gleam_erlang_ffi:'receive'(_pipe@1);
{error, Err} ->
gleam_stdlib:println_error(
<<"\n❌ Error: "/utf8, (snag:pretty_print(Err))/binary>>
)
end.