///|
/// Metadata stored alongside a generated document.
pub(all) struct DocumentMetadata {
title : String
author : String
seed : UInt
purpose : String
tags : Array[String]
} derive(Eq, Debug, ToJson)
///|
pub fn DocumentMetadata::new(
title : String,
author : String,
seed : UInt,
purpose : String,
) -> DocumentMetadata {
{ title, author, seed, purpose, tags: [] }
}
///|
pub fn DocumentMetadata::tag(
self : DocumentMetadata,
value : String,
) -> DocumentMetadata {
self.tags.push(value)
self
}
///|
pub fn DocumentMetadata::to_comment(self : DocumentMetadata) -> String {
"\n"
}
///|
pub(all) struct DesignDocument {
composition : Composition
metadata : DocumentMetadata
} derive(Debug)
///|
pub fn DesignDocument::new(
composition : Composition,
metadata : DocumentMetadata,
) -> DesignDocument {
{ composition, metadata }
}
///|
pub fn DesignDocument::to_svg(self : DesignDocument) -> String {
self.metadata.to_comment() + self.composition.render().to_svg_string()
}
///|
pub fn DesignDocument::metrics(self : DesignDocument) -> LayoutMetrics {
let paths = []
for layer in self.composition.layers {
for motif in layer.motifs {
paths.push(motif.transformed_path())
}
}
measure_paths(
paths,
Rect::new(0.0, 0.0, self.composition.width, self.composition.height),
)
}
///|
pub fn DesignDocument::validate(self : DesignDocument) -> Array[String] {
let errors = []
if self.composition.width <= 0.0 {
errors.push("document width must be positive")
}
if self.composition.height <= 0.0 {
errors.push("document height must be positive")
}
if self.composition.layers.length() == 0 {
errors.push("document has no visible layers")
}
for layer in self.composition.layers {
if layer.name.length() == 0 {
errors.push("layer name cannot be empty")
}
}
errors
}
///|
pub fn make_design_document(
seed : UInt,
width : Double,
height : Double,
palette : Palette,
) -> DesignDocument {
let recipe = SceneRecipe::new(seed, width, height, 12, 12, palette)
let metadata = DocumentMetadata::new(
"Procedural Pattern", "MoonBit Generative Patterns", seed, "poster and packaging artwork",
)
.tag("procedural")
.tag("svg")
.tag("moonbit")
DesignDocument::new(recipe.build(), metadata)
}
///|
pub fn export_variants(
seed : UInt,
sizes : Array[(Double, Double)],
palette : Palette,
) -> Array[DesignDocument] {
let result = []
for size in sizes {
result.push(make_design_document(seed, size.0, size.1, palette))
}
result
}