diff --git a/lib/pages/creature-page.tsx b/lib/pages/creature-page.tsx
index f4e7f88..016cbf2 100644
--- a/lib/pages/creature-page.tsx
+++ b/lib/pages/creature-page.tsx
@@ -24,6 +24,19 @@ const SYMBOL_MAP = new Map(
SvgVocabulary.map((symbol) => [symbol.name, symbol])
);
+/** Symbols that can be the "root" (i.e., main body) of a creature. */
+const ROOT_SYMBOLS = SvgVocabulary.filter(
+ (data) => data.meta?.always_be_nested !== true
+);
+
+/** Symbols that can be attached to the main body of a creature. */
+const ATTACHMENT_SYMBOLS = ROOT_SYMBOLS;
+
+/** Symbols that can be nested within any part of a creature. */
+const NESTED_SYMBOLS = SvgVocabulary.filter(
+ (data) => data.meta?.always_nest !== true
+);
+
/**
* Returns the data for the given symbol, throwing an error
* if it doesn't exist.
@@ -36,6 +49,25 @@ function getSymbol(name: string): SvgSymbolData {
return symbol;
}
+/**
+ * Given a parent symbol, return an array of random children to be nested within
+ * it.
+ *
+ * Can return an empty array e.g. if the parent symbol doesn't have
+ * any nesting areas.
+ */
+function getNestingChildren(parent: SvgSymbolData, rng: Random): JSX.Element[] {
+ const { meta, specs } = parent;
+ if (meta?.always_nest && specs?.nesting) {
+ const indices = range(specs.nesting.length);
+ const child = rng.choice(NESTED_SYMBOLS);
+ return [
+ ,
+ ];
+ }
+ return [];
+}
+
/**
* Randomly creates a symbol with the given number of
* types of attachments. The symbol itself, and where the
@@ -46,7 +78,7 @@ function getSymbolWithAttachments(
rng: Random
): JSX.Element {
const children: JSX.Element[] = [];
- const root = rng.choice(SvgVocabulary);
+ const root = rng.choice(ROOT_SYMBOLS);
if (root.specs) {
const attachmentKinds = rng.uniqueChoices(
Array.from(iterAttachmentPoints(root.specs))
@@ -55,7 +87,7 @@ function getSymbolWithAttachments(
numAttachmentKinds
);
for (let kind of attachmentKinds) {
- const attachment = rng.choice(SvgVocabulary);
+ const attachment = rng.choice(ATTACHMENT_SYMBOLS);
const indices = range(root.specs[kind]?.length ?? 0);
children.push(
);
}
}
+ children.push(...getNestingChildren(root, rng));
return ;
}