SVG Assembly Process
Relevant source files
The following files were used as context for generating this wiki page:- packages/avatar/src/core/utils/svg.ts
- packages/avatar/src/core/index.ts
- packages/avatar/src/open-peeps/index.ts
- packages/avatar/src/open-peeps/components/face.ts
- packages/avatar/src/open-peeps/components/facialHair.ts
- packages/avatar/src/open-peeps/components/accessories.ts
- packages/avatar/test/unit/index.test.ts
- packages/avatar/src/core/utils/escape.ts
The SVG assembly process is a core feature of the @nextorders/avatar package, responsible for generating a complete SVG avatar as a string. This process is orchestrated by the createAvatar function, which takes a style definition and a set of options to produce a deterministic or randomized avatar. It involves selecting various SVG components (like face, hair, and accessories), applying colors, assembling them, and applying a series of post-processing transformations such as scaling, rotation, and masking.
The process is highly modular, separating the core assembly logic from the specific style implementation (e.g., open-peeps). The core logic handles the application of generic SVG effects, while the style implementation is responsible for providing the actual SVG body content and component selection logic. The final output is a complete <svg> element string, which can also be returned as a JSON object with metadata or a Data URI.
High-Level Assembly Flow
The createAvatar function is the entry point for generating an avatar. It follows a sequential process to build the final SVG string.
This diagram illustrates the main steps executed within the createAvatar function.
Detailed Sections
1. Core Avatar Creation (createAvatar)
The createAvatar function in packages/avatar/src/core/index.ts is the central orchestrator.
- Options Merging: It first merges the default style options with any user-provided options.
- PRNG Initialization: A pseudo-random number generator (PRNG) is created using the provided
seed. This ensures that for the same seed, the avatar generation is deterministic. - Style-Specific Creation: It calls the
createmethod of the providedstyleobject (e.g., theopen-peepsstyle). This method returns aStyleCreateResultobject containing the initial SVGbodyandattributes. - Background Application: It determines the background color and type (
solidorgradientLinear) and prepends the corresponding<rect>element to the SVG body. - Transformations: It sequentially applies transformations to the SVG body by wrapping it in
<g>tags withtransformattributes. The order of application is:scale,flip,rotate,translate. - Masking: If a
radiusorclipoption is provided, it adds a<mask>to the SVG to create rounded corners or clip the viewbox. - Final Assembly: It generates the attribute string for the
<svg>tag and combines it with the fully-processed SVG body to create the final SVG string. - Result Object: It returns an object with methods to get the SVG as a string (
toString()), a JSON object with metadata (toJson()), or a Data URI (toDataUri()).
Sources: packages/avatar/src/core/index.ts:10-79
2. Open Peeps Style Implementation
The open-peeps style castomizes the avatar generation by providing the specific SVG components.
Component and Color Selection
The create function within packages/avatar/src/open-peeps/index.ts is responsible for creating the avatar's core content.
This diagram shows the style.create function's interaction with utility functions to select avatar parts and colors.
SVG Body Assembly
The body of the SVG is constructed by assembling 여러 SVG components. Each component (e.g., head, face, facialHair, accessories) is a function that returns an SVG path string. These are placed inside <g> (group) elements with transform attributes to position them correctly.
// packages/avatar/src/open-peeps/index.ts:16-25
export const create: StyleCreate<OpenPeepsOptions> = ({ prng, options }) => {
const components = getComponents({ prng, options })
const colors = getColors({ prng, options })
return {
// ...
body: `<g fill-rule="evenodd" clip-rule="evenodd">...</g><g transform="matrix(.99789 0 0 1 156 62)">${components.head?.value(colors) ?? ''}</g><g transform="translate(315 248)">${components.face?.value(colors) ?? ''}</g><g transform="translate(279 400)">${components.facialHair?.value(colors) ?? ''}</g><g transform="translate(203 303)">${components.accessories?.value(colors) ?? ''}</g>`,
// ...
}
}
The individual components are simple functions returning SVG path data.
// packages/avatar/src/open-peeps/components/face.ts:4
export const face: ComponentGroup = {
angryWithFang: () =>
`<path fill-rule="evenodd" clip-rule="evenodd" d="M196.5 186c1.5-2 5.1 6.4 5.9 7.4 3.2 4 5.8 9.9 6.2 14.9v.4l15.4-2.2c2-1.5 4.8-1 7.5.3 6 3 3 12.7-3.4 12.5-17.5-.4-35.3 1.8-52.7 3.9-8.9 1-17.8 2-26.6 3.5-8.3 1.3-16.8 3.2-25.2 3.5-.4 0-.6-.6-.2-.8 7.4-3.8 15.8-6.1 23.8-8.4a344.1 344.1 0 0 1 49.8-10.7l-.2-.4c-1-3.4-1-7.3-1.2-10.8l-.1-2c-.2-3.2-.4-9.3 1-11.2Zm-25.7-41.6c7.6 4.6 19 15.3 11 26.6-9.6 10-23.4-1.4-30.2-6.6-6.3-4-13.3 6.3-7.5 11 49 36.3 69-29.8 30.5-36.4-4.2-.8-5.8 4-3.8 5.4ZM49.4 104c12.6-2 25.4-2.2 38.1-1.5a404.7 404.7 0 0 1 30 2.6c2.5.3 6.3 1.7 8.7 1 7.1-1.9 13.9 4.9 12 12-2 7-10.4 9-15.8 4.7-2.5-1-5-1.8-7.7-2.5-.2.8-.5 1.6-.9 2.3l-1.3 2.7-.6 1.5-.6 1.5c-1 2.5-2 4.8-4.6 6.1-3.6 1.8-9.2.8-10.7-3.4-2.3-4.5-.8-10.7.5-15.3l.1-.3C81 111.6 65 108.8 49.4 105c-.5-.2-.6-1 0-1.1ZM236 87.2c.8-1.6 2.7-1.6 3.8 0 2.4 3.3-3 8.2-5.4 10.5l-.2.2a91.4 91.4 0 0 1-21.6 15.5l.7 1.6c1 2.6 1 5.8 0 8.5-1.7 5.6-6.4 10-12.5 10-3.2 0-7-3-6.6-6.5l.5-4c-4.3 1.4-9.5-.2-12.3-3.8-3.7-4.9-2.7-13 3.1-16 4.3-2.2 9-2.8 13.6-4 4.6-1.1 9.2-2.5 13.6-4l13.3-4.6 6.5-2.2c1-.3 2.4-1 3.5-1.2Z" fill="#000"/>`,
// ... more face components
};
Sources: packages/avatar/src/open-peeps/index.ts:15-25, packages/avatar/src/open-peeps/components/face.ts:4-6, packages/avatar/src/openpeeps/components/facialHair.ts, packages/avatar/src/open-peeps/components/accessories.ts
3. SVG Transformations and Effects
A set of utility functions in packages/avatar/src/core/utils/svg.ts is used to apply post-processing effects to the generated SVG body. Each function takes the current StyleCreateResult and returns a new SVG body string with the effect applied.
| Function | Description | Source File |
|---|---|---|
addBackground | Prepends a background <rect> to the SVG body. It can be a solid color or a linear gradient. | svg.ts:27-70 |
addScale | Wraps the body in a <g> tag to scale the avatar. It calculates the necessary translation to keep it centered. | svg.ts:72-82 |
addTranslate | Wraps the body in a <g> tag to translate (move) the avatar horizontally or vertically. | svg.ts:84-95 |
addRotate | Wraps the body in a <g> tag to rotate the avatar around its center. | svgts:97-103 |
addFlip | Wraps the body in a <g> tag to flip the avatar horizontally. | svg.ts:105-111 |
addViewboxMask | Adds a <mask> with a <rect> to create rounded corners. The main body is then wrapped in a <g> that references this mask. | svg.ts:113-123 |
createAttrString | Converts the attributes acessórios into a single string for the main <svg> tag, escaping special XML characters. | svg.ts:125-135 |
Sources: packages/avatar/src/core/utils/svg.ts, packages/avatar/src/core/utils/escape.ts
The order of these transformations is explicitly defined in createAvatar.
// packages/avatar/src/core/index.ts:35-57
if (options.scale !== undefined && options.scale !== 100) {
result.body = svgUtils.addScale(result, options.scale)
}
if (options.flip) {
result.body = svgUtils.addFlip(result)
}
if (options.rotate) {
result.body = svgUtils.addRotate(result, options.rotate)
}
if (options.translateX || options.translateY) {
result.body = svgUtils.addTranslate(
result,
options.translateX,
options.translateY,
)
}
result.body = svgUtils.addBackground(...)
if (options.radius || options.clip) {
result.body = svgUtils.addViewboxMask(result, options.radius ?? 0)
}
Sources: packages/avatar/src/core/index.ts:35-57
4. Final Output
The process culminates in the creation of a result object. The toString() method returns the final, complete SVG string. Unit tests confirm that this process generates a valid SVG string of a reasonable size.
// packages/avatar/test/unit/index.test.ts:28-37
it('should return correct result with full options and normal size', () => {
const result = createAvatar({
seed: 'random2',
gender: 'male',
clothing: 'amber',
emotion: 7,
})
// in kilobytes
const resultSize = result.length / 1024
expect(resultSize).toBeGreaterThan(0)
expect(resultSize).toBeLessThan(20)
})
Sources: packages/avatar/test/unit/index.test.ts:28-37, packages/avatar/src/core/index.ts:63-79
Summary
The SVG assembly process is a well-defined pipeline that transforms a set of options and a style definition into a complete SVG image. It begins with style-specific component selection, followed by a series of generic transformations and effects managed by the core system. This layered architecture allows for easy creation of new avatar styles while reusing the powerful SVG manipulation toolkit. The final output is a portable and ready-to-use SVG string.