Initial commit

This commit is contained in:
Hugo Mårdbrink 2025-11-30 15:44:22 +01:00
commit a6272848f9
379 changed files with 74829 additions and 0 deletions

View file

@ -0,0 +1 @@
export * from "../prelude.mjs";

View file

@ -0,0 +1,271 @@
import { Ok, Error } from "./gleam.mjs";
class PaintCanvas extends HTMLElement {
// Open an issue if you are in need of any other attributes :)
static observedAttributes = ["width", "height", "style", "picture"];
constructor() {
super();
// Create a canvas
this.canvas = document.createElement("canvas");
const style = document.createElement("style");
style.textContent = `
:host {
display: inline-block;
}
`;
this.shadow = this.attachShadow({ mode: "open" });
this.shadow.appendChild(style);
this.shadow.appendChild(this.canvas);
this.ctx = this.canvas.getContext("2d");
}
attributeChangedCallback(name, _oldValue, newValue) {
if (name === "picture") {
this.picture = newValue;
return;
} else if (name === "width") {
this.width = newValue;
} else if (name === "height") {
this.height = newValue;
}
}
drawPicture() {
if (!this.pictureString) {
return;
}
this.ctx.reset();
const display =
window.PAINT_STATE[
"display_on_rendering_context_with_default_drawing_state"
];
display(this.pictureString, this.ctx);
}
set picture(value) {
this.pictureString = value;
this.drawPicture();
}
set width(value) {
this.canvas.width = value;
this.drawPicture();
}
set height(value) {
this.canvas.height = value;
this.drawPicture();
}
get width() {
return this.canvas.width;
}
get height() {
return this.canvas.height;
}
}
export function define_web_component() {
window.customElements.define("paint-canvas", PaintCanvas);
}
export function get_rendering_context(selector) {
// TODO: Handle the case where the canvas element is not found.
return document.querySelector(selector).getContext("2d");
}
export function setup_request_animation_frame(callback) {
window.requestAnimationFrame((time) => {
callback(time);
});
}
export function setup_input_handler(event_name, callback) {
window.addEventListener(event_name, callback);
}
export function get_key_code(event) {
return event.keyCode;
}
export function set_global(state, id) {
if (typeof window.PAINT_STATE == "undefined") {
window.PAINT_STATE = {};
}
window.PAINT_STATE[id] = state;
}
export function get_global(id) {
if (!window.PAINT_STATE) {
return new Error(undefined);
}
if (!(id in window.PAINT_STATE)) {
return new Error(undefined);
}
return new Ok(window.PAINT_STATE[id]);
}
export function get_width(ctx) {
return ctx.canvas.clientWidth;
}
export function get_height(ctx) {
return ctx.canvas.clientHeight;
}
// Based on https://stackoverflow.com/questions/17130395/real-mouse-position-in-canvas
export function mouse_pos(ctx, event) {
// Calculate the scaling of the canvas vs its content
const rect = ctx.canvas.getBoundingClientRect();
const scaleX = ctx.canvas.width / rect.width;
const scaleY = ctx.canvas.height / rect.height;
return [
(event.clientX - rect.left) * scaleX,
(event.clientY - rect.top) * scaleY,
];
}
// if check_pressed is true, the function will return true if the button was pressed
// if check_pressed is false, the function will return true if the button was released
export function check_mouse_button(
event,
previous_event,
button_index,
check_pressed,
) {
let previous_buttons = previous_event?.buttons ?? 0;
let current_buttons = event.buttons;
// ~001 &&
// 011
// -----
// 010 found the newly pressed!
//
// 011 &&
// ~001
// -----
// 010 found the newly released!
if (check_pressed) {
previous_buttons = ~previous_buttons;
} else {
current_buttons = ~current_buttons;
}
let button = previous_buttons & current_buttons & (1 << button_index);
return !!button;
}
export function reset(ctx) {
ctx.reset();
}
export function arc(ctx, radius, start, end, fill, stroke) {
ctx.beginPath();
ctx.arc(0, 0, radius, start, end);
if (fill) {
ctx.fill();
}
if (stroke) {
ctx.stroke();
}
}
export function polygon(ctx, points, closed, fill, stroke) {
ctx.beginPath();
ctx.moveTo(0, 0);
let started = false;
for (const point of points) {
let x = point[0];
let y = point[1];
if (started) {
ctx.lineTo(x, y);
} else {
ctx.moveTo(x, y);
started = true;
}
}
if (closed) {
ctx.closePath();
}
if (fill && closed) {
ctx.fill();
}
if (stroke) {
ctx.stroke();
}
}
export function text(ctx, text, style) {
ctx.font = style;
ctx.fillText(text, 0, 0);
}
export function save(ctx) {
ctx.save();
}
export function restore(ctx) {
ctx.restore();
}
export function set_fill_colour(ctx, css_colour) {
ctx.fillStyle = css_colour;
}
export function set_stroke_color(ctx, css_color) {
ctx.strokeStyle = css_color;
}
export function set_line_width(ctx, width) {
ctx.lineWidth = width;
}
export function translate(ctx, x, y) {
ctx.translate(x, y);
}
export function scale(ctx, x, y) {
ctx.scale(x, y);
}
export function rotate(ctx, radians) {
ctx.rotate(radians);
}
export function reset_transform(ctx) {
ctx.resetTransform();
}
export function draw_image(ctx, image, width_px, height_px) {
ctx.drawImage(image, 0, 0, width_px, height_px);
}
export function image_from_query(selector) {
return document.querySelector(selector);
}
export function image_from_src(src) {
const image = new Image();
image.src = src;
return image;
}
export function on_image_load(image, callback) {
if (image.complete) {
callback();
} else {
image.addEventListener("load", callback);
}
}
export function set_image_smoothing_enabled(ctx, value) {
ctx.imageSmoothingEnabled = value;
}

View file

@ -0,0 +1,3 @@
export function pi() {
return Math.PI;
}

View file

@ -0,0 +1,246 @@
import * as $colour from "../gleam_community_colour/gleam_community/colour.mjs";
import * as $result from "../gleam_stdlib/gleam/result.mjs";
import { toList, makeError } from "./gleam.mjs";
import { pi } from "./numbers_ffi.mjs";
import * as $internal_implementation from "./paint/internal/types.mjs";
const FILEPATH = "src/paint.gleam";
/**
* Create an angle expressed in radians
*/
export function angle_rad(radians) {
return new $internal_implementation.Radians(radians);
}
/**
* A utility around [colour.from_rgb_hex_string](https://hexdocs.pm/gleam_community_colour/gleam_community/colour.html#from_rgb_hex_string)
* (from `gleam_community/colour`) that **panics** on an invalid hex code.
*/
export function colour_hex(string) {
return $result.lazy_unwrap(
$colour.from_rgb_hex_string(string),
() => {
throw makeError(
"panic",
FILEPATH,
"paint",
47,
"colour_hex",
"Failed to parse hex code",
{}
)
},
);
}
/**
* A utility around [colour.from_rgb255](https://hexdocs.pm/gleam_community_colour/gleam_community/colour.html#from_rgb255)
* (from `gleam_community/colour`) that **panics** if the values are outside of the allowed range.
*/
export function colour_rgb(red, green, blue) {
return $result.lazy_unwrap(
$colour.from_rgb255(red, green, blue),
() => {
throw makeError(
"panic",
FILEPATH,
"paint",
55,
"colour_rgb",
"The value was not inside of the valid range [0-255]",
{}
)
},
);
}
/**
* A blank picture
*/
export function blank() {
return new $internal_implementation.Blank();
}
/**
* An arc with some radius going from some
* starting angle to some other angle in clock-wise direction
*/
export function arc(radius, start, end) {
return new $internal_implementation.Arc(radius, start, end);
}
/**
* A polygon consisting of a list of 2d points
*/
export function polygon(points) {
return new $internal_implementation.Polygon(points, true);
}
/**
* Lines (same as a polygon but not a closed shape)
*/
export function lines(points) {
return new $internal_implementation.Polygon(points, false);
}
/**
* A rectangle with some given width and height
*/
export function rectangle(width, height) {
return polygon(
toList([[0.0, 0.0], [width, 0.0], [width, height], [0.0, height]]),
);
}
/**
* A square
*/
export function square(length) {
return rectangle(length, length);
}
/**
* Draw an image such as a PNG, JPEG or an SVG. See the `canvas` back-end for more details on how to load images.
*/
export function image(image, width_px, height_px) {
return new $internal_implementation.ImageRef(image, width_px, height_px);
}
/**
* Set image scaling to be smooth (this is the default behaviour)
*/
export function image_scaling_smooth(picture) {
return new $internal_implementation.ImageScalingBehaviour(
picture,
new $internal_implementation.ScalingSmooth(),
);
}
/**
* Disable smooth image scaling, suitable for pixel art.
*/
export function image_scaling_pixelated(picture) {
return new $internal_implementation.ImageScalingBehaviour(
picture,
new $internal_implementation.ScalingPixelated(),
);
}
/**
* Text with some given font size
*/
export function text(text, font_size) {
return new $internal_implementation.Text(
text,
new $internal_implementation.FontProperties(font_size, "sans-serif"),
);
}
/**
* Translate a picture in horizontal and vertical direction
*/
export function translate_xy(picture, x, y) {
return new $internal_implementation.Translate(picture, [x, y]);
}
/**
* Translate a picture in the horizontal direction
*/
export function translate_x(picture, x) {
return translate_xy(picture, x, 0.0);
}
/**
* Translate a picture in the vertical direction
*/
export function translate_y(picture, y) {
return translate_xy(picture, 0.0, y);
}
/**
* Scale the picture in the horizontal direction
*/
export function scale_x(picture, factor) {
return new $internal_implementation.Scale(picture, [factor, 1.0]);
}
/**
* Scale the picture in the vertical direction
*/
export function scale_y(picture, factor) {
return new $internal_implementation.Scale(picture, [1.0, factor]);
}
/**
* Scale the picture uniformly in horizontal and vertical direction
*/
export function scale_uniform(picture, factor) {
return new $internal_implementation.Scale(picture, [factor, factor]);
}
/**
* Rotate the picture in a clock-wise direction
*/
export function rotate(picture, angle) {
return new $internal_implementation.Rotate(picture, angle);
}
/**
* Fill a picture with some given colour, see `Colour`.
*/
export function fill(picture, colour) {
return new $internal_implementation.Fill(picture, colour);
}
/**
* Set a solid stroke with some given colour and width
*/
export function stroke(picture, colour, width) {
return new $internal_implementation.Stroke(
picture,
new $internal_implementation.SolidStroke(colour, width),
);
}
/**
* Remove the stroke of the given picture
*/
export function stroke_none(picture) {
return new $internal_implementation.Stroke(
picture,
new $internal_implementation.NoStroke(),
);
}
/**
* Combine multiple pictures into one
*/
export function combine(pictures) {
return new $internal_implementation.Combine(pictures);
}
/**
* Concatenate two pictures
*/
export function concat(picture, another_picture) {
return combine(toList([picture, another_picture]));
}
/**
* Create an angle expressed in degrees
*/
export function angle_deg(degrees) {
return new $internal_implementation.Radians(((degrees * pi())) / 180.0);
}
/**
* A circle with some given radius
*/
export function circle(radius) {
return new $internal_implementation.Arc(
radius,
new $internal_implementation.Radians(0.0),
new $internal_implementation.Radians(2.0 * pi()),
);
}

View file

@ -0,0 +1,655 @@
import * as $colour from "../../gleam_community_colour/gleam_community/colour.mjs";
import * as $int from "../../gleam_stdlib/gleam/int.mjs";
import * as $option from "../../gleam_stdlib/gleam/option.mjs";
import { None, Some } from "../../gleam_stdlib/gleam/option.mjs";
import { Ok, Empty as $Empty, CustomType as $CustomType, makeError } from "../gleam.mjs";
import * as $paint from "../paint.mjs";
import { translate_xy } from "../paint.mjs";
import * as $encode from "../paint/encode.mjs";
import * as $event from "../paint/event.mjs";
import * as $impl_canvas from "../paint/internal/impl_canvas.mjs";
import * as $types from "../paint/internal/types.mjs";
import {
Arc,
Blank,
Combine,
Fill,
FontProperties,
Image,
NoStroke,
Polygon,
Radians,
Rotate,
Scale,
SolidStroke,
Stroke,
Text,
Translate,
} from "../paint/internal/types.mjs";
const FILEPATH = "src/paint/canvas.gleam";
export class Config extends $CustomType {
constructor(width, height) {
super();
this.width = width;
this.height = height;
}
}
export const Config$Config = (width, height) => new Config(width, height);
export const Config$isConfig = (value) => value instanceof Config;
export const Config$Config$width = (value) => value.width;
export const Config$Config$0 = (value) => value.width;
export const Config$Config$height = (value) => value.height;
export const Config$Config$1 = (value) => value.height;
class DrawingState extends $CustomType {
constructor(fill, stroke) {
super();
this.fill = fill;
this.stroke = stroke;
}
}
/**
* Create a reference to an image using a CSS query selector. For example:
* ```
* fn kitten() {
* canvas.image_from_query("#kitten")
* }
* // In the HTML file:
* // <img
* // style="display: none"
* // src="https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_November_2010-1a.jpg"
* // id="kitten"
* // />
* ```
*
* > [!WARNING]
* > **Important**: Make sure the image has loaded before trying to draw a pictures referencing it.
* > You can do this using `canvas.wait_until_loaded` function.
*/
export function image_from_query(selector) {
let id = "image-selector-" + selector;
let $ = $impl_canvas.get_global(id);
if ($ instanceof Ok) {
undefined
} else {
let image = $impl_canvas.image_from_query(selector);
$impl_canvas.set_global(image, id)
}
return new Image(id);
}
/**
* Create a reference to an image using a source path.
* ```
* fn my_logo_image() {
* canvas.image_from_src("./priv/static/logo.svg")
* }
* ```
*
* > [!WARNING]
* > **Important**: Make sure the image has loaded before trying to draw a pictures referencing it.
* > You can do this using `canvas.wait_until_loaded` function.
*/
export function image_from_src(src) {
let id = "image-src-" + src;
let $ = $impl_canvas.get_global(id);
if ($ instanceof Ok) {
undefined
} else {
let image = $impl_canvas.image_from_src(src);
$impl_canvas.set_global(image, id)
}
return new Image(id);
}
/**
* Wait until a list of images have all been loaded, for example:
* ```
* fn lucy() {
* canvas.image_from_query("#lucy")
* }
*
* fn cat() {
* canvas.image_from_src("./path/to/kitten.png")
* }
*
* pub fn main() {
* use <- canvas.wait_until_loaded([lucy(), kitten()])
* // It is now safe to draw Pictures containing the images lucy and kitten :)
* }
* ```
*/
export function wait_until_loaded(images, on_loaded) {
if (images instanceof $Empty) {
return on_loaded();
} else {
let image = images.head;
let rest = images.tail;
let id;
id = image.id;
let $ = $impl_canvas.get_global(id);
let js_image;
if ($ instanceof Ok) {
js_image = $[0];
} else {
throw makeError(
"let_assert",
FILEPATH,
"paint/canvas",
101,
"wait_until_loaded",
"Pattern match failed, no pattern matched the value.",
{
value: $,
start: 3025,
end: 3077,
pattern_start: 3036,
pattern_end: 3048
}
)
}
return $impl_canvas.on_image_load(
js_image,
() => { return wait_until_loaded(rest, on_loaded); },
);
}
}
function display_on_rendering_context(loop$picture, loop$ctx, loop$state) {
while (true) {
let picture = loop$picture;
let ctx = loop$ctx;
let state = loop$state;
if (picture instanceof Blank) {
return undefined;
} else if (picture instanceof Polygon) {
let points = picture[0];
let closed = picture.closed;
return $impl_canvas.polygon(ctx, points, closed, state.fill, state.stroke);
} else if (picture instanceof Arc) {
let radius = picture.radius;
let start = picture.start;
let end = picture.end;
let start_radians;
start_radians = start[0];
let end_radians;
end_radians = end[0];
return $impl_canvas.arc(
ctx,
radius,
start_radians,
end_radians,
state.fill,
state.stroke,
);
} else if (picture instanceof Text) {
let text = picture.text;
let properties = picture.style;
let size_px;
let font_family;
size_px = properties.size_px;
font_family = properties.font_family;
$impl_canvas.save(ctx);
$impl_canvas.text(
ctx,
text,
($int.to_string(size_px) + "px ") + font_family,
);
return $impl_canvas.restore(ctx);
} else if (picture instanceof $types.ImageRef) {
let width_px = picture.width_px;
let height_px = picture.height_px;
let id = picture[0].id;
let $ = $impl_canvas.get_global(id);
let image;
if ($ instanceof Ok) {
image = $[0];
} else {
throw makeError(
"let_assert",
FILEPATH,
"paint/canvas",
231,
"display_on_rendering_context",
"Pattern match failed, no pattern matched the value.",
{
value: $,
start: 6608,
end: 6657,
pattern_start: 6619,
pattern_end: 6628
}
)
}
return $impl_canvas.draw_image(ctx, image, width_px, height_px);
} else if (picture instanceof Fill) {
let p = picture[0];
let colour = picture[1];
$impl_canvas.save(ctx);
$impl_canvas.set_fill_colour(ctx, $colour.to_css_rgba_string(colour));
display_on_rendering_context(p, ctx, new DrawingState(true, state.stroke));
return $impl_canvas.restore(ctx);
} else if (picture instanceof Stroke) {
let p = picture[0];
let stroke = picture[1];
if (stroke instanceof NoStroke) {
loop$picture = p;
loop$ctx = ctx;
loop$state = new DrawingState(state.fill, false);
} else {
let color = stroke[0];
let width = stroke[1];
$impl_canvas.save(ctx);
$impl_canvas.set_stroke_color(ctx, $colour.to_css_rgba_string(color));
$impl_canvas.set_line_width(ctx, width);
display_on_rendering_context(p, ctx, new DrawingState(state.fill, true));
return $impl_canvas.restore(ctx);
}
} else if (picture instanceof $types.ImageScalingBehaviour) {
let p = picture[0];
let behaviour = picture[1];
$impl_canvas.save(ctx);
$impl_canvas.set_image_smoothing_enabled(
ctx,
(() => {
if (behaviour instanceof $types.ScalingSmooth) {
return true;
} else {
return false;
}
})(),
);
display_on_rendering_context(p, ctx, state);
return $impl_canvas.restore(ctx);
} else if (picture instanceof Translate) {
let p = picture[0];
let vec = picture[1];
let x;
let y;
x = vec[0];
y = vec[1];
$impl_canvas.save(ctx);
$impl_canvas.translate(ctx, x, y);
display_on_rendering_context(p, ctx, state);
return $impl_canvas.restore(ctx);
} else if (picture instanceof Scale) {
let p = picture[0];
let vec = picture[1];
let x;
let y;
x = vec[0];
y = vec[1];
$impl_canvas.save(ctx);
$impl_canvas.scale(ctx, x, y);
display_on_rendering_context(p, ctx, state);
return $impl_canvas.restore(ctx);
} else if (picture instanceof Rotate) {
let p = picture[0];
let angle = picture[1];
let rad;
rad = angle[0];
$impl_canvas.save(ctx);
$impl_canvas.rotate(ctx, rad);
display_on_rendering_context(p, ctx, state);
return $impl_canvas.restore(ctx);
} else {
let pictures = picture[0];
if (pictures instanceof $Empty) {
return undefined;
} else {
let p = pictures.head;
let ps = pictures.tail;
display_on_rendering_context(p, ctx, state);
loop$picture = new Combine(ps);
loop$ctx = ctx;
loop$state = state;
}
}
}
}
function parse_key_code(key_code) {
if (key_code === 32) {
return new Some(new $event.KeySpace());
} else if (key_code === 37) {
return new Some(new $event.KeyLeftArrow());
} else if (key_code === 38) {
return new Some(new $event.KeyUpArrow());
} else if (key_code === 39) {
return new Some(new $event.KeyRightArrow());
} else if (key_code === 40) {
return new Some(new $event.KeyDownArrow());
} else if (key_code === 87) {
return new Some(new $event.KeyW());
} else if (key_code === 65) {
return new Some(new $event.KeyA());
} else if (key_code === 83) {
return new Some(new $event.KeyS());
} else if (key_code === 68) {
return new Some(new $event.KeyD());
} else if (key_code === 90) {
return new Some(new $event.KeyZ());
} else if (key_code === 88) {
return new Some(new $event.KeyX());
} else if (key_code === 67) {
return new Some(new $event.KeyC());
} else if (key_code === 18) {
return new Some(new $event.KeyEnter());
} else if (key_code === 27) {
return new Some(new $event.KeyEscape());
} else if (key_code === 8) {
return new Some(new $event.KeyBackspace());
} else {
return new None();
}
}
/**
* Utility to set the origin in the center of the canvas
*/
export function center(picture) {
return (config) => {
let width;
let height;
width = config.width;
height = config.height;
let _pipe = picture;
return translate_xy(_pipe, width * 0.5, height * 0.5);
};
}
const default_drawing_state = /* @__PURE__ */ new DrawingState(false, true);
/**
* Display a picture on a HTML canvas element
* (specified by some [CSS Selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors)).
* ```
* canvas.display(fn (_: canvas.Config) { circle(50.0) }, "#mycanvas")
* ```
*/
export function display(init, selector) {
let ctx = $impl_canvas.get_rendering_context(selector);
$impl_canvas.reset(ctx);
let picture = init(
new Config($impl_canvas.get_width(ctx), $impl_canvas.get_height(ctx)),
);
return display_on_rendering_context(picture, ctx, default_drawing_state);
}
function get_tick_func(ctx, view, update, selector) {
return (time) => {
let $ = $impl_canvas.get_global(selector);
let current_state;
if ($ instanceof Ok) {
current_state = $[0];
} else {
throw makeError(
"let_assert",
FILEPATH,
"paint/canvas",
399,
"get_tick_func",
"Pattern match failed, no pattern matched the value.",
{
value: $,
start: 11581,
end: 11644,
pattern_start: 11592,
pattern_end: 11609
}
)
}
let new_state = update(current_state, new $event.Tick(time));
$impl_canvas.set_global(new_state, selector);
let picture = view(new_state);
$impl_canvas.reset(ctx);
display_on_rendering_context(picture, ctx, default_drawing_state);
return $impl_canvas.setup_request_animation_frame(
get_tick_func(ctx, view, update, selector),
);
};
}
/**
* Animations, interactive applications and tiny games can be built using the
* `interact` function. It roughly follows the [Elm architecture](https://guide.elm-lang.org/architecture/).
* Here is a short example:
* ```
* type State =
* Int
*
* fn init(_: canvas.Config) -> State {
* 0
* }
*
* fn update(state: State, event: event.Event) -> State {
* case event {
* event.Tick(_) -> state + 1
* _ -> state
* }
* }
*
* fn view(state: State) -> Picture {
* paint.circle(int.to_float(state))
* }
*
* fn main() {
* interact(init, update, view, "#mycanvas")
* }
* ```
*/
export function interact(init, update, view, selector) {
let ctx = $impl_canvas.get_rendering_context(selector);
let initial_state = init(
new Config($impl_canvas.get_width(ctx), $impl_canvas.get_height(ctx)),
);
$impl_canvas.set_global(initial_state, selector);
let create_key_handler = (event_name, constructor) => {
return $impl_canvas.setup_input_handler(
event_name,
(event) => {
let key = parse_key_code($impl_canvas.get_key_code(event));
if (key instanceof Some) {
let key$1 = key[0];
let $ = $impl_canvas.get_global(selector);
let old_state;
if ($ instanceof Ok) {
old_state = $[0];
} else {
throw makeError(
"let_assert",
FILEPATH,
"paint/canvas",
292,
"interact",
"Pattern match failed, no pattern matched the value.",
{
value: $,
start: 8332,
end: 8391,
pattern_start: 8343,
pattern_end: 8356
}
)
}
let new_state = update(old_state, constructor(key$1));
return $impl_canvas.set_global(new_state, selector);
} else {
return undefined;
}
},
);
};
create_key_handler(
"keydown",
(var0) => { return new $event.KeyboardPressed(var0); },
);
create_key_handler(
"keyup",
(var0) => { return new $event.KeyboardRelased(var0); },
);
$impl_canvas.setup_input_handler(
"mousemove",
(event) => {
let $ = $impl_canvas.mouse_pos(ctx, event);
let x;
let y;
x = $[0];
y = $[1];
let $1 = $impl_canvas.get_global(selector);
let old_state;
if ($1 instanceof Ok) {
old_state = $1[0];
} else {
throw makeError(
"let_assert",
FILEPATH,
"paint/canvas",
309,
"interact",
"Pattern match failed, no pattern matched the value.",
{
value: $1,
start: 8863,
end: 8922,
pattern_start: 8874,
pattern_end: 8887
}
)
}
let new_state = update(old_state, new $event.MouseMoved(x, y));
$impl_canvas.set_global(new_state, selector);
return undefined;
},
);
let create_mouse_button_handler = (event_name, constructor, check_pressed) => {
return $impl_canvas.setup_input_handler(
event_name,
(event) => {
let previous_event_id = "PAINT_PREVIOUS_MOUSE_INPUT_FOR_" + selector;
let previous_event = $impl_canvas.get_global(previous_event_id);
$impl_canvas.set_global(event, previous_event_id);
let check_button = (i) => {
return $impl_canvas.check_mouse_button(
event,
previous_event,
i,
check_pressed,
);
};
let trigger_update = (button) => {
let $ = $impl_canvas.get_global(selector);
let old_state;
if ($ instanceof Ok) {
old_state = $[0];
} else {
throw makeError(
"let_assert",
FILEPATH,
"paint/canvas",
338,
"interact",
"Pattern match failed, no pattern matched the value.",
{
value: $,
start: 9856,
end: 9915,
pattern_start: 9867,
pattern_end: 9880
}
)
}
let new_state = update(old_state, constructor(button));
return $impl_canvas.set_global(new_state, selector);
};
let $ = check_button(0);
if ($) {
trigger_update(new $event.MouseButtonLeft())
} else {
undefined
}
let $1 = check_button(1);
if ($1) {
trigger_update(new $event.MouseButtonRight())
} else {
undefined
}
let $2 = check_button(2);
if ($2) {
trigger_update(new $event.MouseButtonMiddle())
} else {
undefined
}
return undefined;
},
);
};
create_mouse_button_handler(
"mousedown",
(var0) => { return new $event.MousePressed(var0); },
true,
);
create_mouse_button_handler(
"mouseup",
(var0) => { return new $event.MouseReleased(var0); },
false,
);
return $impl_canvas.setup_request_animation_frame(
get_tick_func(ctx, view, update, selector),
);
}
/**
* If you are using [Lustre](https://github.com/lustre-labs/lustre) or some other framework to build
* your web application you may prefer to use the [web components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components) API
* and the `define_web_component` function.
* ```
* // Call this function once to register a custom HTML element <paint-canvas>
* canvas.define_web_component()
* // You can then display your picture by setting the "picture"
* // property or attribute on the element.
*
* // In Lustre it would look something like this:
* fn canvas(picture: paint.Picture, attributes: List(attribute.Attribute(a))) {
* element.element(
* "paint-canvas",
* [attribute.attribute("picture", encode.to_string(picture)), ..attributes],
* [],
* )
*}
* ```
* A more detailed example for using this API can be found in the `demos/with_lustre` directory.
*/
export function define_web_component() {
$impl_canvas.define_web_component();
return $impl_canvas.set_global(
(encoded_picture, ctx) => {
let $ = $encode.from_string(encoded_picture);
let picture;
if ($ instanceof Ok) {
picture = $[0];
} else {
throw makeError(
"let_assert",
FILEPATH,
"paint/canvas",
447,
"define_web_component",
"Invalid picture provided to web component",
{
value: $,
start: 13602,
end: 13662,
pattern_start: 13613,
pattern_end: 13624
}
)
}
return display_on_rendering_context(picture, ctx, default_drawing_state);
},
"display_on_rendering_context_with_default_drawing_state",
);
}

View file

@ -0,0 +1,506 @@
import * as $colour from "../../gleam_community_colour/gleam_community/colour.mjs";
import * as $json from "../../gleam_json/gleam/json.mjs";
import * as $decode from "../../gleam_stdlib/gleam/dynamic/decode.mjs";
import { toList } from "../gleam.mjs";
import * as $paint from "../paint.mjs";
import * as $types from "../paint/internal/types.mjs";
import { FontProperties, NoStroke, Radians, SolidStroke } from "../paint/internal/types.mjs";
function decode_angle() {
return $decode.field(
"radians",
$decode.float,
(radians) => { return $decode.success(new Radians(radians)); },
);
}
function decode_font() {
return $decode.field(
"sizePx",
$decode.int,
(size_px) => {
return $decode.field(
"fontFamily",
$decode.string,
(font_family) => {
return $decode.success(new FontProperties(size_px, font_family));
},
);
},
);
}
function decode_stroke() {
return $decode.field(
"type",
$decode.string,
(stroke_type) => {
if (stroke_type === "noStroke") {
return $decode.success(new NoStroke());
} else if (stroke_type === "solidStroke") {
return $decode.field(
"colour",
$colour.decoder(),
(colour) => {
return $decode.field(
"thickness",
$decode.float,
(thickness) => {
return $decode.success(new SolidStroke(colour, thickness));
},
);
},
);
} else {
return $decode.failure(new NoStroke(), "StrokeProperties");
}
},
);
}
function decode_vec2() {
return $decode.field(
"x",
$decode.float,
(x) => {
return $decode.field(
"y",
$decode.float,
(y) => { return $decode.success([x, y]); },
);
},
);
}
function decode_picture() {
return $decode.recursive(
() => {
return $decode.field(
"type",
$decode.string,
(ty) => {
if (ty === "arc") {
return $decode.field(
"radius",
$decode.float,
(radius) => {
return $decode.field(
"start",
decode_angle(),
(start) => {
return $decode.field(
"end",
decode_angle(),
(end) => {
return $decode.success(
new $types.Arc(radius, start, end),
);
},
);
},
);
},
);
} else if (ty === "blank") {
return $decode.success(new $types.Blank());
} else if (ty === "combine") {
return $decode.field(
"pictures",
$decode.list(decode_picture()),
(pictures) => {
return $decode.success(new $types.Combine(pictures));
},
);
} else if (ty === "fill") {
return $decode.field(
"picture",
decode_picture(),
(picture) => {
return $decode.field(
"colour",
$colour.decoder(),
(colour) => {
return $decode.success(new $types.Fill(picture, colour));
},
);
},
);
} else if (ty === "polygon") {
return $decode.field(
"points",
$decode.list(decode_vec2()),
(points) => {
return $decode.field(
"closed",
$decode.bool,
(closed) => {
return $decode.success(new $types.Polygon(points, closed));
},
);
},
);
} else if (ty === "rotate") {
return $decode.field(
"angle",
decode_angle(),
(angle) => {
return $decode.field(
"picture",
decode_picture(),
(picture) => {
return $decode.success(new $types.Rotate(picture, angle));
},
);
},
);
} else if (ty === "scale") {
return $decode.field(
"x",
$decode.float,
(x) => {
return $decode.field(
"y",
$decode.float,
(y) => {
return $decode.field(
"picture",
decode_picture(),
(picture) => {
return $decode.success(
new $types.Scale(picture, [x, y]),
);
},
);
},
);
},
);
} else if (ty === "stroke") {
return $decode.field(
"stroke",
decode_stroke(),
(stroke) => {
return $decode.field(
"picture",
decode_picture(),
(picture) => {
return $decode.success(new $types.Stroke(picture, stroke));
},
);
},
);
} else if (ty === "text") {
return $decode.field(
"text",
$decode.string,
(text) => {
return $decode.field(
"style",
decode_font(),
(style) => {
return $decode.success(new $types.Text(text, style));
},
);
},
);
} else if (ty === "translate") {
return $decode.field(
"x",
$decode.float,
(x) => {
return $decode.field(
"y",
$decode.float,
(y) => {
return $decode.field(
"picture",
decode_picture(),
(picture) => {
return $decode.success(
new $types.Translate(picture, [x, y]),
);
},
);
},
);
},
);
} else if (ty === "image") {
return $decode.field(
"id",
$decode.string,
(id) => {
return $decode.field(
"width_px",
$decode.int,
(width_px) => {
return $decode.field(
"height_px",
$decode.int,
(height_px) => {
return $decode.success(
new $types.ImageRef(
new $types.Image(id),
width_px,
height_px,
),
);
},
);
},
);
},
);
} else if (ty === "image_scaling_behaviour") {
return $decode.field(
"behaviour",
$decode.string,
(behaviour) => {
return $decode.field(
"picture",
decode_picture(),
(picture) => {
if (behaviour === "smooth") {
return $decode.success(
new $types.ImageScalingBehaviour(
picture,
new $types.ScalingSmooth(),
),
);
} else if (behaviour === "pixelated") {
return $decode.success(
new $types.ImageScalingBehaviour(
picture,
new $types.ScalingPixelated(),
),
);
} else {
return $decode.failure(new $types.Blank(), "Picture");
}
},
);
},
);
} else {
return $decode.failure(new $types.Blank(), "Picture");
}
},
);
},
);
}
/**
* Attempt to deserialize a `Picture`
*/
export function from_string(string) {
let decoder = $decode.field(
"picture",
decode_picture(),
(picture) => { return $decode.success(picture); },
);
return $json.parse(string, decoder);
}
function font_to_json(font) {
let size_px;
let font_family;
size_px = font.size_px;
font_family = font.font_family;
return $json.object(
toList([
["sizePx", $json.int(size_px)],
["fontFamily", $json.string(font_family)],
]),
);
}
function stroke_to_json(stroke) {
if (stroke instanceof NoStroke) {
return $json.object(toList([["type", $json.string("noStroke")]]));
} else {
let colour = stroke[0];
let thickness = stroke[1];
return $json.object(
toList([
["type", $json.string("solidStroke")],
["colour", $colour.encode(colour)],
["thickness", $json.float(thickness)],
]),
);
}
}
function angle_to_json(angle) {
let rad;
rad = angle[0];
return $json.object(toList([["radians", $json.float(rad)]]));
}
function picture_to_json(picture) {
if (picture instanceof $types.Blank) {
return $json.object(toList([["type", $json.string("blank")]]));
} else if (picture instanceof $types.Polygon) {
let points = picture[0];
let closed = picture.closed;
return $json.object(
toList([
["type", $json.string("polygon")],
[
"points",
$json.array(
points,
(point) => {
let x;
let y;
x = point[0];
y = point[1];
return $json.object(
toList([["x", $json.float(x)], ["y", $json.float(y)]]),
);
},
),
],
["closed", $json.bool(closed)],
]),
);
} else if (picture instanceof $types.Arc) {
let radius = picture.radius;
let start = picture.start;
let end = picture.end;
return $json.object(
toList([
["type", $json.string("arc")],
["radius", $json.float(radius)],
["start", angle_to_json(start)],
["end", angle_to_json(end)],
]),
);
} else if (picture instanceof $types.Text) {
let text = picture.text;
let style = picture.style;
return $json.object(
toList([
["type", $json.string("text")],
["text", $json.string(text)],
["style", font_to_json(style)],
]),
);
} else if (picture instanceof $types.ImageRef) {
let width_px = picture.width_px;
let height_px = picture.height_px;
let id = picture[0].id;
return $json.object(
toList([
["type", $json.string("image")],
["id", $json.string(id)],
["width_px", $json.int(width_px)],
["height_px", $json.int(height_px)],
]),
);
} else if (picture instanceof $types.Fill) {
let picture$1 = picture[0];
let colour = picture[1];
return $json.object(
toList([
["type", $json.string("fill")],
["colour", $colour.encode(colour)],
["picture", picture_to_json(picture$1)],
]),
);
} else if (picture instanceof $types.Stroke) {
let picture$1 = picture[0];
let stroke = picture[1];
return $json.object(
toList([
["type", $json.string("stroke")],
["stroke", stroke_to_json(stroke)],
["picture", picture_to_json(picture$1)],
]),
);
} else if (picture instanceof $types.ImageScalingBehaviour) {
let picture$1 = picture[0];
let behaviour = picture[1];
return $json.object(
toList([
["type", $json.string("image_scaling_behaviour")],
[
"behaviour",
$json.string(
(() => {
if (behaviour instanceof $types.ScalingSmooth) {
return "smooth";
} else {
return "pixelated";
}
})(),
),
],
["picture", picture_to_json(picture$1)],
]),
);
} else if (picture instanceof $types.Translate) {
let picture$1 = picture[0];
let x = picture[1][0];
let y = picture[1][1];
return $json.object(
toList([
["type", $json.string("translate")],
["x", $json.float(x)],
["y", $json.float(y)],
["picture", picture_to_json(picture$1)],
]),
);
} else if (picture instanceof $types.Scale) {
let picture$1 = picture[0];
let x = picture[1][0];
let y = picture[1][1];
return $json.object(
toList([
["type", $json.string("scale")],
["x", $json.float(x)],
["y", $json.float(y)],
["picture", picture_to_json(picture$1)],
]),
);
} else if (picture instanceof $types.Rotate) {
let picture$1 = picture[0];
let angle = picture[1];
return $json.object(
toList([
["type", $json.string("rotate")],
["angle", angle_to_json(angle)],
["picture", picture_to_json(picture$1)],
]),
);
} else {
let from = picture[0];
return $json.object(
toList([
["type", $json.string("combine")],
["pictures", $json.array(from, picture_to_json)],
]),
);
}
}
/**
* Serialize a `Picture` to a string.
*
* Note, serializing an `Image` texture will only store an ID referencing the image. This means that if you deserialize a Picture containing
* references to images, you are responsible for making sure all images are loaded before drawing the picture.
* More advanced APIs to support use cases such as these are planned for a future release.
*
* Also, if you wish to store the serialized data, remember that the library currently makes no stability guarantee that
* the data can be deserialized by *future* versions of the library.
*/
export function to_string(picture) {
let version = "paint:unstable";
let _pipe = $json.object(
toList([
["version", $json.string(version)],
["picture", picture_to_json(picture)],
]),
);
return $json.to_string(_pipe);
}

View file

@ -0,0 +1,163 @@
import { CustomType as $CustomType } from "../gleam.mjs";
/**
* Triggered before drawing. Contains the number of milliseconds elapsed.
*/
export class Tick extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
export const Event$Tick = ($0) => new Tick($0);
export const Event$isTick = (value) => value instanceof Tick;
export const Event$Tick$0 = (value) => value[0];
/**
* Triggered when a key is pressed
*/
export class KeyboardPressed extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
export const Event$KeyboardPressed = ($0) => new KeyboardPressed($0);
export const Event$isKeyboardPressed = (value) =>
value instanceof KeyboardPressed;
export const Event$KeyboardPressed$0 = (value) => value[0];
/**
* Triggered when a key is released
*/
export class KeyboardRelased extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
export const Event$KeyboardRelased = ($0) => new KeyboardRelased($0);
export const Event$isKeyboardRelased = (value) =>
value instanceof KeyboardRelased;
export const Event$KeyboardRelased$0 = (value) => value[0];
/**
* Triggered when the mouse is moved. Contains
* the `x` and `y` value for the mouse position.
*/
export class MouseMoved extends $CustomType {
constructor($0, $1) {
super();
this[0] = $0;
this[1] = $1;
}
}
export const Event$MouseMoved = ($0, $1) => new MouseMoved($0, $1);
export const Event$isMouseMoved = (value) => value instanceof MouseMoved;
export const Event$MouseMoved$0 = (value) => value[0];
export const Event$MouseMoved$1 = (value) => value[1];
/**
* Triggered when a mouse button is pressed
*/
export class MousePressed extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
export const Event$MousePressed = ($0) => new MousePressed($0);
export const Event$isMousePressed = (value) => value instanceof MousePressed;
export const Event$MousePressed$0 = (value) => value[0];
/**
* Triggered when a mouse button is released.
*
* Note, on the web you might encounter issues where the
* release event for the right mouse button is not triggered
* because of the context menu.
*/
export class MouseReleased extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
export const Event$MouseReleased = ($0) => new MouseReleased($0);
export const Event$isMouseReleased = (value) => value instanceof MouseReleased;
export const Event$MouseReleased$0 = (value) => value[0];
export class KeyLeftArrow extends $CustomType {}
export const Key$KeyLeftArrow = () => new KeyLeftArrow();
export const Key$isKeyLeftArrow = (value) => value instanceof KeyLeftArrow;
export class KeyRightArrow extends $CustomType {}
export const Key$KeyRightArrow = () => new KeyRightArrow();
export const Key$isKeyRightArrow = (value) => value instanceof KeyRightArrow;
export class KeyUpArrow extends $CustomType {}
export const Key$KeyUpArrow = () => new KeyUpArrow();
export const Key$isKeyUpArrow = (value) => value instanceof KeyUpArrow;
export class KeyDownArrow extends $CustomType {}
export const Key$KeyDownArrow = () => new KeyDownArrow();
export const Key$isKeyDownArrow = (value) => value instanceof KeyDownArrow;
export class KeySpace extends $CustomType {}
export const Key$KeySpace = () => new KeySpace();
export const Key$isKeySpace = (value) => value instanceof KeySpace;
export class KeyW extends $CustomType {}
export const Key$KeyW = () => new KeyW();
export const Key$isKeyW = (value) => value instanceof KeyW;
export class KeyA extends $CustomType {}
export const Key$KeyA = () => new KeyA();
export const Key$isKeyA = (value) => value instanceof KeyA;
export class KeyS extends $CustomType {}
export const Key$KeyS = () => new KeyS();
export const Key$isKeyS = (value) => value instanceof KeyS;
export class KeyD extends $CustomType {}
export const Key$KeyD = () => new KeyD();
export const Key$isKeyD = (value) => value instanceof KeyD;
export class KeyZ extends $CustomType {}
export const Key$KeyZ = () => new KeyZ();
export const Key$isKeyZ = (value) => value instanceof KeyZ;
export class KeyX extends $CustomType {}
export const Key$KeyX = () => new KeyX();
export const Key$isKeyX = (value) => value instanceof KeyX;
export class KeyC extends $CustomType {}
export const Key$KeyC = () => new KeyC();
export const Key$isKeyC = (value) => value instanceof KeyC;
export class KeyEnter extends $CustomType {}
export const Key$KeyEnter = () => new KeyEnter();
export const Key$isKeyEnter = (value) => value instanceof KeyEnter;
export class KeyEscape extends $CustomType {}
export const Key$KeyEscape = () => new KeyEscape();
export const Key$isKeyEscape = (value) => value instanceof KeyEscape;
export class KeyBackspace extends $CustomType {}
export const Key$KeyBackspace = () => new KeyBackspace();
export const Key$isKeyBackspace = (value) => value instanceof KeyBackspace;
export class MouseButtonLeft extends $CustomType {}
export const MouseButton$MouseButtonLeft = () => new MouseButtonLeft();
export const MouseButton$isMouseButtonLeft = (value) =>
value instanceof MouseButtonLeft;
export class MouseButtonRight extends $CustomType {}
export const MouseButton$MouseButtonRight = () => new MouseButtonRight();
export const MouseButton$isMouseButtonRight = (value) =>
value instanceof MouseButtonRight;
export class MouseButtonMiddle extends $CustomType {}
export const MouseButton$MouseButtonMiddle = () => new MouseButtonMiddle();
export const MouseButton$isMouseButtonMiddle = (value) =>
value instanceof MouseButtonMiddle;

View file

@ -0,0 +1,65 @@
import {
setup_input_handler,
get_width,
get_height,
set_global,
get_global,
reset,
save,
restore,
translate,
scale,
rotate,
reset_transform,
set_fill_colour,
set_stroke_color,
set_line_width,
set_image_smoothing_enabled,
arc,
polygon,
text,
draw_image,
image_from_query,
image_from_src,
on_image_load,
} from "../../impl_canvas_bindings.mjs";
import {
define_web_component,
setup_request_animation_frame,
get_rendering_context,
get_key_code,
mouse_pos,
check_mouse_button,
} from "./../../impl_canvas_bindings.mjs";
export {
arc,
check_mouse_button,
define_web_component,
draw_image,
get_global,
get_height,
get_key_code,
get_rendering_context,
get_width,
image_from_query,
image_from_src,
mouse_pos,
on_image_load,
polygon,
reset,
reset_transform,
restore,
rotate,
save,
scale,
set_fill_colour,
set_global,
set_image_smoothing_enabled,
set_line_width,
set_stroke_color,
setup_input_handler,
setup_request_animation_frame,
text,
translate,
};

View file

@ -0,0 +1,217 @@
import * as $colour from "../../../gleam_community_colour/gleam_community/colour.mjs";
import { CustomType as $CustomType } from "../../gleam.mjs";
export class Blank extends $CustomType {}
export const Picture$Blank = () => new Blank();
export const Picture$isBlank = (value) => value instanceof Blank;
export class Polygon extends $CustomType {
constructor($0, closed) {
super();
this[0] = $0;
this.closed = closed;
}
}
export const Picture$Polygon = ($0, closed) => new Polygon($0, closed);
export const Picture$isPolygon = (value) => value instanceof Polygon;
export const Picture$Polygon$0 = (value) => value[0];
export const Picture$Polygon$closed = (value) => value.closed;
export const Picture$Polygon$1 = (value) => value.closed;
export class Arc extends $CustomType {
constructor(radius, start, end) {
super();
this.radius = radius;
this.start = start;
this.end = end;
}
}
export const Picture$Arc = (radius, start, end) => new Arc(radius, start, end);
export const Picture$isArc = (value) => value instanceof Arc;
export const Picture$Arc$radius = (value) => value.radius;
export const Picture$Arc$0 = (value) => value.radius;
export const Picture$Arc$start = (value) => value.start;
export const Picture$Arc$1 = (value) => value.start;
export const Picture$Arc$end = (value) => value.end;
export const Picture$Arc$2 = (value) => value.end;
export class Text extends $CustomType {
constructor(text, style) {
super();
this.text = text;
this.style = style;
}
}
export const Picture$Text = (text, style) => new Text(text, style);
export const Picture$isText = (value) => value instanceof Text;
export const Picture$Text$text = (value) => value.text;
export const Picture$Text$0 = (value) => value.text;
export const Picture$Text$style = (value) => value.style;
export const Picture$Text$1 = (value) => value.style;
export class ImageRef extends $CustomType {
constructor($0, width_px, height_px) {
super();
this[0] = $0;
this.width_px = width_px;
this.height_px = height_px;
}
}
export const Picture$ImageRef = ($0, width_px, height_px) =>
new ImageRef($0, width_px, height_px);
export const Picture$isImageRef = (value) => value instanceof ImageRef;
export const Picture$ImageRef$0 = (value) => value[0];
export const Picture$ImageRef$width_px = (value) => value.width_px;
export const Picture$ImageRef$1 = (value) => value.width_px;
export const Picture$ImageRef$height_px = (value) => value.height_px;
export const Picture$ImageRef$2 = (value) => value.height_px;
export class Fill extends $CustomType {
constructor($0, $1) {
super();
this[0] = $0;
this[1] = $1;
}
}
export const Picture$Fill = ($0, $1) => new Fill($0, $1);
export const Picture$isFill = (value) => value instanceof Fill;
export const Picture$Fill$0 = (value) => value[0];
export const Picture$Fill$1 = (value) => value[1];
export class Stroke extends $CustomType {
constructor($0, $1) {
super();
this[0] = $0;
this[1] = $1;
}
}
export const Picture$Stroke = ($0, $1) => new Stroke($0, $1);
export const Picture$isStroke = (value) => value instanceof Stroke;
export const Picture$Stroke$0 = (value) => value[0];
export const Picture$Stroke$1 = (value) => value[1];
export class ImageScalingBehaviour extends $CustomType {
constructor($0, $1) {
super();
this[0] = $0;
this[1] = $1;
}
}
export const Picture$ImageScalingBehaviour = ($0, $1) =>
new ImageScalingBehaviour($0, $1);
export const Picture$isImageScalingBehaviour = (value) =>
value instanceof ImageScalingBehaviour;
export const Picture$ImageScalingBehaviour$0 = (value) => value[0];
export const Picture$ImageScalingBehaviour$1 = (value) => value[1];
export class Translate extends $CustomType {
constructor($0, $1) {
super();
this[0] = $0;
this[1] = $1;
}
}
export const Picture$Translate = ($0, $1) => new Translate($0, $1);
export const Picture$isTranslate = (value) => value instanceof Translate;
export const Picture$Translate$0 = (value) => value[0];
export const Picture$Translate$1 = (value) => value[1];
export class Scale extends $CustomType {
constructor($0, $1) {
super();
this[0] = $0;
this[1] = $1;
}
}
export const Picture$Scale = ($0, $1) => new Scale($0, $1);
export const Picture$isScale = (value) => value instanceof Scale;
export const Picture$Scale$0 = (value) => value[0];
export const Picture$Scale$1 = (value) => value[1];
export class Rotate extends $CustomType {
constructor($0, $1) {
super();
this[0] = $0;
this[1] = $1;
}
}
export const Picture$Rotate = ($0, $1) => new Rotate($0, $1);
export const Picture$isRotate = (value) => value instanceof Rotate;
export const Picture$Rotate$0 = (value) => value[0];
export const Picture$Rotate$1 = (value) => value[1];
export class Combine extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
export const Picture$Combine = ($0) => new Combine($0);
export const Picture$isCombine = (value) => value instanceof Combine;
export const Picture$Combine$0 = (value) => value[0];
export class Image extends $CustomType {
constructor(id) {
super();
this.id = id;
}
}
export const Image$Image = (id) => new Image(id);
export const Image$isImage = (value) => value instanceof Image;
export const Image$Image$id = (value) => value.id;
export const Image$Image$0 = (value) => value.id;
export class ScalingSmooth extends $CustomType {}
export const ImageScalingBehaviour$ScalingSmooth = () => new ScalingSmooth();
export const ImageScalingBehaviour$isScalingSmooth = (value) =>
value instanceof ScalingSmooth;
export class ScalingPixelated extends $CustomType {}
export const ImageScalingBehaviour$ScalingPixelated = () =>
new ScalingPixelated();
export const ImageScalingBehaviour$isScalingPixelated = (value) =>
value instanceof ScalingPixelated;
export class NoStroke extends $CustomType {}
export const StrokeProperties$NoStroke = () => new NoStroke();
export const StrokeProperties$isNoStroke = (value) => value instanceof NoStroke;
export class SolidStroke extends $CustomType {
constructor($0, $1) {
super();
this[0] = $0;
this[1] = $1;
}
}
export const StrokeProperties$SolidStroke = ($0, $1) => new SolidStroke($0, $1);
export const StrokeProperties$isSolidStroke = (value) =>
value instanceof SolidStroke;
export const StrokeProperties$SolidStroke$0 = (value) => value[0];
export const StrokeProperties$SolidStroke$1 = (value) => value[1];
export class FontProperties extends $CustomType {
constructor(size_px, font_family) {
super();
this.size_px = size_px;
this.font_family = font_family;
}
}
export const FontProperties$FontProperties = (size_px, font_family) =>
new FontProperties(size_px, font_family);
export const FontProperties$isFontProperties = (value) =>
value instanceof FontProperties;
export const FontProperties$FontProperties$size_px = (value) => value.size_px;
export const FontProperties$FontProperties$0 = (value) => value.size_px;
export const FontProperties$FontProperties$font_family = (value) =>
value.font_family;
export const FontProperties$FontProperties$1 = (value) => value.font_family;
export class Radians extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
export const Angle$Radians = ($0) => new Radians($0);
export const Angle$isRadians = (value) => value instanceof Radians;
export const Angle$Radians$0 = (value) => value[0];