angular-avatar-player 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/fesm2022/angular-avatar-player.mjs +1664 -0
- package/fesm2022/angular-avatar-player.mjs.map +1 -0
- package/index.d.ts +20 -0
- package/lib/avatar-player.module.d.ts +9 -0
- package/lib/components/avatar-player/avatar-player.component.d.ts +28 -0
- package/lib/components/svg-avatar/svg-avatar.component.d.ts +52 -0
- package/lib/geometry/avatar-animator.d.ts +36 -0
- package/lib/geometry/avatar-renderer.d.ts +64 -0
- package/lib/geometry/avatar.model.d.ts +24 -0
- package/lib/geometry/eye-colors.d.ts +2 -0
- package/lib/geometry/hair-colors.d.ts +2 -0
- package/lib/geometry/index.d.ts +46 -0
- package/lib/geometry/lip-sync-player.d.ts +16 -0
- package/lib/geometry/skin-tones.d.ts +21 -0
- package/lib/geometry/svg-parts/beard-path.d.ts +16 -0
- package/lib/geometry/svg-parts/beard-shapes.d.ts +2 -0
- package/lib/geometry/svg-parts/eye-shapes.d.ts +7 -0
- package/lib/geometry/svg-parts/glasses-shapes.d.ts +2 -0
- package/lib/geometry/svg-parts/hair-shapes.d.ts +7 -0
- package/lib/geometry/svg-parts/mouth-shapes.d.ts +1 -0
- package/lib/geometry/svg-parts/mustache-shapes.d.ts +2 -0
- package/lib/geometry/svg-parts/profession-layers.d.ts +7 -0
- package/lib/geometry/trait-previews.d.ts +2 -0
- package/lib/geometry/visemes.d.ts +19 -0
- package/lib/services/avatar-animation.service.d.ts +14 -0
- package/lib/services/lip-sync.service.d.ts +13 -0
- package/package.json +48 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public entry point of the avatar geometry.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS LIVES INSIDE THE ANGULAR LIBRARY
|
|
5
|
+
*
|
|
6
|
+
* The code below is plain TypeScript with no framework imports — it could sit in
|
|
7
|
+
* a package of its own, and that is where it used to live. It lives here
|
|
8
|
+
* because of a hard limit in ng-packagr:
|
|
9
|
+
*
|
|
10
|
+
* - ng-packagr treats EVERY bare specifier as external
|
|
11
|
+
* (`isExternalDependency`, ng-packagr/lib/flatten/rollup.js), so a
|
|
12
|
+
* `from 'avatar-core'` import ships unresolved and breaks the tarball.
|
|
13
|
+
* - a relative import into another package does not work either: ng-packagr
|
|
14
|
+
* compiles src/ -> dist/avatar-player/esm2022/ first and only then bundles,
|
|
15
|
+
* so a path valid from src/ points at nothing from the intermediate dir.
|
|
16
|
+
*
|
|
17
|
+
* Living inside the library means ng-packagr compiles it as first-party source
|
|
18
|
+
* and inlines it into the published bundle. The React package imports these
|
|
19
|
+
* same files with a relative specifier at build time, so there is still exactly
|
|
20
|
+
* ONE copy of the geometry in the repository and in CI.
|
|
21
|
+
*
|
|
22
|
+
* Consequence: consumers of angular-avatar-player and react-avatar-player get
|
|
23
|
+
* their own copy of the renderer inside the tarball. That is deliberate — it
|
|
24
|
+
* means `npm i angular-avatar-player` is a single, self-contained install.
|
|
25
|
+
*/
|
|
26
|
+
export type { AvatarConfig, Gender, SkinTone, HaircutStyle, HairColor, EyeColor, MustacheStyle, BeardStyle, EyeStyle, GlassesStyle, ProfessionType, } from './avatar.model';
|
|
27
|
+
export { SKIN_TONES } from './skin-tones';
|
|
28
|
+
export { HAIR_COLORS } from './hair-colors';
|
|
29
|
+
export { EYE_COLORS } from './eye-colors';
|
|
30
|
+
export { buildTraitPreview } from './trait-previews';
|
|
31
|
+
export type { PreviewKind } from './trait-previews';
|
|
32
|
+
export { textToVisemes, MS_PER_VISEME } from './visemes';
|
|
33
|
+
export { VISEME_SILENCE, VISEME_WIDE, VISEME_ROUND, VISEME_SPREAD, VISEME_PRESSED, VISEME_TEETH, } from './visemes';
|
|
34
|
+
export { buildAvatarSvg, buildAvatarSvgInner, avatarCssVars, hairClipUrl, helmetClipUrl, isAstronaut, hasHat, HAT_PROFESSIONS, HELMET_PROFESSIONS, CANVAS, } from './avatar-renderer';
|
|
35
|
+
export type { BuildAvatarOptions } from './avatar-renderer';
|
|
36
|
+
export { MOUTH_SHAPES } from './svg-parts/mouth-shapes';
|
|
37
|
+
export { EYE_SHAPES } from './svg-parts/eye-shapes';
|
|
38
|
+
export { HAIR_SHAPES } from './svg-parts/hair-shapes';
|
|
39
|
+
export { GLASSES_SHAPES } from './svg-parts/glasses-shapes';
|
|
40
|
+
export { MUSTACHE_SHAPES } from './svg-parts/mustache-shapes';
|
|
41
|
+
export { BEARD_SHAPES } from './svg-parts/beard-shapes';
|
|
42
|
+
export { faceFor, faceHalfWidthAt, fitToFace, buildBeardSvg, MAN_FACE, WOMAN_FACE, } from './svg-parts/beard-path';
|
|
43
|
+
export type { FaceGeometry } from './svg-parts/beard-path';
|
|
44
|
+
export { PROFESSION_LAYERS } from './svg-parts/profession-layers';
|
|
45
|
+
export { AvatarAnimator } from './avatar-animator';
|
|
46
|
+
export { LipSyncPlayer } from './lip-sync-player';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare class LipSyncPlayer {
|
|
2
|
+
private readonly MS_PER_VISEME;
|
|
3
|
+
/** @see textToVisemes */
|
|
4
|
+
textToVisemes(text: string): number[];
|
|
5
|
+
/**
|
|
6
|
+
* Play a viseme sequence, calling onViseme(id) each frame.
|
|
7
|
+
*
|
|
8
|
+
* `onEnd` fires exactly once when the sequence finishes or is cancelled, so
|
|
9
|
+
* callers can clear a "speaking" flag reliably. Do NOT infer the end from
|
|
10
|
+
* onViseme(0): viseme 0 is silence and occurs at every space, so it would
|
|
11
|
+
* end the utterance at the first word gap.
|
|
12
|
+
*
|
|
13
|
+
* Returns a cancel function. Always resets to 0 (silence) on end or cancel.
|
|
14
|
+
*/
|
|
15
|
+
play(visemes: number[], onViseme: (v: number) => void, onEnd?: () => void): () => void;
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SkinTone } from './avatar.model';
|
|
2
|
+
/**
|
|
3
|
+
* - `base` — main face fill
|
|
4
|
+
* - `ear` — secondary tone for ears
|
|
5
|
+
* - `lip` — lips
|
|
6
|
+
* - `shadow` — a THIRD tone reserved for small linework (nose stroke).
|
|
7
|
+
*
|
|
8
|
+
* `shadow` used to be conflated with `ear`, which made the nose vanish
|
|
9
|
+
* on the two darkest tones: `deep` ear is #3C200E against a #4A2912 face,
|
|
10
|
+
* far too close to read as a line. `shadow` is always a clear step darker
|
|
11
|
+
* than `ear` so it stays legible at the 2px stroke width we use.
|
|
12
|
+
*
|
|
13
|
+
* The style guide allows at most two tones per *region*. The nose is its
|
|
14
|
+
* own region, so a dedicated third value is compliant.
|
|
15
|
+
*/
|
|
16
|
+
export declare const SKIN_TONES: Record<SkinTone, {
|
|
17
|
+
base: string;
|
|
18
|
+
ear: string;
|
|
19
|
+
lip: string;
|
|
20
|
+
shadow: string;
|
|
21
|
+
}>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { BeardStyle, Gender } from '../avatar.model';
|
|
2
|
+
export interface FaceGeometry {
|
|
3
|
+
cx: number;
|
|
4
|
+
cy: number;
|
|
5
|
+
rx: number;
|
|
6
|
+
ry: number;
|
|
7
|
+
}
|
|
8
|
+
/** The two head shapes the renderer supports. */
|
|
9
|
+
export declare const MAN_FACE: FaceGeometry;
|
|
10
|
+
export declare const WOMAN_FACE: FaceGeometry;
|
|
11
|
+
export declare function faceFor(gender: Gender): FaceGeometry;
|
|
12
|
+
/** Half-width of the head at a given y. Returns 0 at or past the chin. */
|
|
13
|
+
export declare function faceHalfWidthAt(face: FaceGeometry, y: number): number;
|
|
14
|
+
/** Fit every `d` and every ellipse in a piece of SVG markup to a head. */
|
|
15
|
+
export declare function fitToFace(markup: string, face: FaceGeometry): string;
|
|
16
|
+
export declare function buildBeardSvg(style: BeardStyle, face: FaceGeometry, fill: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const MOUTH_SHAPES: Record<number, string>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Silence. */
|
|
2
|
+
export declare const VISEME_SILENCE = 0;
|
|
3
|
+
/** A / I — wide open */
|
|
4
|
+
export declare const VISEME_WIDE = 1;
|
|
5
|
+
/** O / U — rounded */
|
|
6
|
+
export declare const VISEME_ROUND = 2;
|
|
7
|
+
/** E — spread */
|
|
8
|
+
export declare const VISEME_SPREAD = 3;
|
|
9
|
+
/** M / B / P — pressed */
|
|
10
|
+
export declare const VISEME_PRESSED = 4;
|
|
11
|
+
/** F / V — teeth on lip */
|
|
12
|
+
export declare const VISEME_TEETH = 5;
|
|
13
|
+
/** How long each viseme is held, in ms. */
|
|
14
|
+
export declare const MS_PER_VISEME = 80;
|
|
15
|
+
/**
|
|
16
|
+
* Map text characters to viseme ids 0–5.
|
|
17
|
+
* 0=silence, 1=A/I wide, 2=O/U round, 3=E spread, 4=M/B/P pressed, 5=F/V teeth
|
|
18
|
+
*/
|
|
19
|
+
export declare function textToVisemes(text: string): number[];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AvatarAnimator } from '../geometry';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
/**
|
|
4
|
+
* Angular-facing wrapper around the framework-free {@link AvatarAnimator}.
|
|
5
|
+
*
|
|
6
|
+
* The timers live in ../geometry so the React player can drive the same blink
|
|
7
|
+
* and pupil logic. This class exists only so Angular apps can inject it and so
|
|
8
|
+
* DI scopes one animator per component — a shared instance would mean one avatar
|
|
9
|
+
* leaving the DOM stops blinking for every other avatar on the page.
|
|
10
|
+
*/
|
|
11
|
+
export declare class AvatarAnimationService extends AvatarAnimator {
|
|
12
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<AvatarAnimationService, never>;
|
|
13
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<AvatarAnimationService>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { LipSyncPlayer } from '../geometry';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
/**
|
|
4
|
+
* Angular-facing wrapper around the framework-free {@link LipSyncPlayer}.
|
|
5
|
+
*
|
|
6
|
+
* The logic lives in ../geometry so the React player and any non-Angular
|
|
7
|
+
* renderer use the exact same mapping. This class exists only so Angular apps
|
|
8
|
+
* can inject it and so DI gives each player component its own instance.
|
|
9
|
+
*/
|
|
10
|
+
export declare class LipSyncService extends LipSyncPlayer {
|
|
11
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<LipSyncService, never>;
|
|
12
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<LipSyncService>;
|
|
13
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "angular-avatar-player",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Animated SVG avatar component for Angular. Blinking, eye movement, head idle motion and lip sync, rendered as pure vector SVG with no images or runtime assets.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"angular",
|
|
7
|
+
"avatar",
|
|
8
|
+
"svg",
|
|
9
|
+
"avatar-generator",
|
|
10
|
+
"lipsync",
|
|
11
|
+
"lip-sync",
|
|
12
|
+
"chat",
|
|
13
|
+
"assistant",
|
|
14
|
+
"animation",
|
|
15
|
+
"component"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://mateuszpsuja.github.io/AvatarCreator/",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/MateuszPsuja/AvatarCreator.git",
|
|
21
|
+
"directory": "src/libs/avatar-player"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/MateuszPsuja/AvatarCreator/issues"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"author": "Mateusz Psuja",
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@angular/common": "^19.2.0",
|
|
31
|
+
"@angular/core": "^19.2.0",
|
|
32
|
+
"@angular/platform-browser": "^19.2.0"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"tslib": "^2.3.0"
|
|
36
|
+
},
|
|
37
|
+
"module": "fesm2022/angular-avatar-player.mjs",
|
|
38
|
+
"typings": "index.d.ts",
|
|
39
|
+
"exports": {
|
|
40
|
+
"./package.json": {
|
|
41
|
+
"default": "./package.json"
|
|
42
|
+
},
|
|
43
|
+
".": {
|
|
44
|
+
"types": "./index.d.ts",
|
|
45
|
+
"default": "./fesm2022/angular-avatar-player.mjs"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|