@flighthq/shading 0.2.1-next.410.a23f189
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/dist/createAnimatedNormalModifier.d.ts +10 -0
- package/dist/createAnimatedNormalModifier.d.ts.map +1 -0
- package/dist/createAnimatedNormalModifier.js +22 -0
- package/dist/createAnimatedNormalModifier.js.map +1 -0
- package/dist/createDissolveModifier.d.ts +10 -0
- package/dist/createDissolveModifier.d.ts.map +1 -0
- package/dist/createDissolveModifier.js +21 -0
- package/dist/createDissolveModifier.js.map +1 -0
- package/dist/createEmissiveModifier.d.ts +11 -0
- package/dist/createEmissiveModifier.d.ts.map +1 -0
- package/dist/createEmissiveModifier.js +21 -0
- package/dist/createEmissiveModifier.js.map +1 -0
- package/dist/createEnvReflectModifier.d.ts +9 -0
- package/dist/createEnvReflectModifier.d.ts.map +1 -0
- package/dist/createEnvReflectModifier.js +18 -0
- package/dist/createEnvReflectModifier.js.map +1 -0
- package/dist/createFogModifier.d.ts +11 -0
- package/dist/createFogModifier.d.ts.map +1 -0
- package/dist/createFogModifier.js +18 -0
- package/dist/createFogModifier.js.map +1 -0
- package/dist/createRimModifier.d.ts +9 -0
- package/dist/createRimModifier.d.ts.map +1 -0
- package/dist/createRimModifier.js +17 -0
- package/dist/createRimModifier.js.map +1 -0
- package/dist/createShadedMaterial.d.ts +13 -0
- package/dist/createShadedMaterial.d.ts.map +1 -0
- package/dist/createShadedMaterial.js +28 -0
- package/dist/createShadedMaterial.js.map +1 -0
- package/dist/createToonModifier.d.ts +7 -0
- package/dist/createToonModifier.d.ts.map +1 -0
- package/dist/createToonModifier.js +15 -0
- package/dist/createToonModifier.js.map +1 -0
- package/dist/createVertexDisplaceModifier.d.ts +13 -0
- package/dist/createVertexDisplaceModifier.d.ts.map +1 -0
- package/dist/createVertexDisplaceModifier.js +24 -0
- package/dist/createVertexDisplaceModifier.js.map +1 -0
- package/dist/getModifierDefineKey.d.ts +4 -0
- package/dist/getModifierDefineKey.d.ts.map +1 -0
- package/dist/getModifierDefineKey.js +36 -0
- package/dist/getModifierDefineKey.js.map +1 -0
- package/dist/getUnregisteredModifierKinds.d.ts +4 -0
- package/dist/getUnregisteredModifierKinds.d.ts.map +1 -0
- package/dist/getUnregisteredModifierKinds.js +17 -0
- package/dist/getUnregisteredModifierKinds.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/isBuiltInModifierSlot.d.ts +2 -0
- package/dist/isBuiltInModifierSlot.d.ts.map +1 -0
- package/dist/isBuiltInModifierSlot.js +18 -0
- package/dist/isBuiltInModifierSlot.js.map +1 -0
- package/dist/isModifierStackValid.d.ts +4 -0
- package/dist/isModifierStackValid.d.ts.map +1 -0
- package/dist/isModifierStackValid.js +8 -0
- package/dist/isModifierStackValid.js.map +1 -0
- package/dist/modifierRegistry.d.ts +13 -0
- package/dist/modifierRegistry.d.ts.map +1 -0
- package/dist/modifierRegistry.js +18 -0
- package/dist/modifierRegistry.js.map +1 -0
- package/dist/orderModifierStack.d.ts +3 -0
- package/dist/orderModifierStack.d.ts.map +1 -0
- package/dist/orderModifierStack.js +36 -0
- package/dist/orderModifierStack.js.map +1 -0
- package/dist/registerBuiltInModifiers.d.ts +11 -0
- package/dist/registerBuiltInModifiers.d.ts.map +1 -0
- package/dist/registerBuiltInModifiers.js +108 -0
- package/dist/registerBuiltInModifiers.js.map +1 -0
- package/package.json +43 -0
- package/src/createAnimatedNormalModifier.test.ts +49 -0
- package/src/createDissolveModifier.test.ts +30 -0
- package/src/createEmissiveModifier.test.ts +44 -0
- package/src/createEnvReflectModifier.test.ts +28 -0
- package/src/createFogModifier.test.ts +31 -0
- package/src/createRimModifier.test.ts +31 -0
- package/src/createShadedMaterial.test.ts +45 -0
- package/src/createToonModifier.test.ts +23 -0
- package/src/createVertexDisplaceModifier.test.ts +36 -0
- package/src/getModifierDefineKey.test.ts +74 -0
- package/src/getUnregisteredModifierKinds.test.ts +40 -0
- package/src/isBuiltInModifierSlot.test.ts +25 -0
- package/src/isModifierStackValid.test.ts +27 -0
- package/src/modifierRegistry.test.ts +59 -0
- package/src/orderModifierStack.test.ts +48 -0
- package/src/registerBuiltInModifiers.test.ts +118 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Modifier } from '@flighthq/types';
|
|
2
|
+
import { EmissiveModifierKind } from '@flighthq/types';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { createEmissiveModifier } from './createEmissiveModifier';
|
|
6
|
+
import { getUnregisteredModifierKinds } from './getUnregisteredModifierKinds';
|
|
7
|
+
import { createModifierRegistry } from './modifierRegistry';
|
|
8
|
+
import { registerBuiltInModifiers } from './registerBuiltInModifiers';
|
|
9
|
+
|
|
10
|
+
describe('getUnregisteredModifierKinds', () => {
|
|
11
|
+
it('returns an empty array when every kind is registered', () => {
|
|
12
|
+
const registry = createModifierRegistry();
|
|
13
|
+
registerBuiltInModifiers(registry);
|
|
14
|
+
const stack = [createEmissiveModifier({ color: 0xffffffff })];
|
|
15
|
+
expect(getUnregisteredModifierKinds(registry, stack)).toEqual([]);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('returns an empty array for an empty stack', () => {
|
|
19
|
+
const registry = createModifierRegistry();
|
|
20
|
+
expect(getUnregisteredModifierKinds(registry, [])).toEqual([]);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('names each unregistered kind once in first-seen order', () => {
|
|
24
|
+
const registry = createModifierRegistry();
|
|
25
|
+
registerBuiltInModifiers(registry);
|
|
26
|
+
const stack: Modifier[] = [
|
|
27
|
+
{ kind: 'acme.Missing', slot: 'Effect' },
|
|
28
|
+
createEmissiveModifier({ color: 0xffffffff }),
|
|
29
|
+
{ kind: 'acme.Other', slot: 'Normal' },
|
|
30
|
+
{ kind: 'acme.Missing', slot: 'Effect' },
|
|
31
|
+
];
|
|
32
|
+
expect(getUnregisteredModifierKinds(registry, stack)).toEqual(['acme.Missing', 'acme.Other']);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('reports a built-in kind as unregistered when built-ins were not installed', () => {
|
|
36
|
+
const registry = createModifierRegistry();
|
|
37
|
+
const stack = [createEmissiveModifier({ color: 0xffffffff })];
|
|
38
|
+
expect(getUnregisteredModifierKinds(registry, stack)).toEqual([EmissiveModifierKind]);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ModifierSlot } from '@flighthq/types';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { isBuiltInModifierSlot } from './isBuiltInModifierSlot';
|
|
5
|
+
|
|
6
|
+
describe('isBuiltInModifierSlot', () => {
|
|
7
|
+
it('accepts every built-in slot name', () => {
|
|
8
|
+
expect(isBuiltInModifierSlot(ModifierSlot.Diffuse)).toBe(true);
|
|
9
|
+
expect(isBuiltInModifierSlot(ModifierSlot.Specular)).toBe(true);
|
|
10
|
+
expect(isBuiltInModifierSlot(ModifierSlot.Normal)).toBe(true);
|
|
11
|
+
expect(isBuiltInModifierSlot(ModifierSlot.Emissive)).toBe(true);
|
|
12
|
+
expect(isBuiltInModifierSlot(ModifierSlot.Effect)).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('rejects reserved and vendor-prefixed slots', () => {
|
|
16
|
+
expect(isBuiltInModifierSlot('Ambient')).toBe(false);
|
|
17
|
+
expect(isBuiltInModifierSlot('Shadow')).toBe(false);
|
|
18
|
+
expect(isBuiltInModifierSlot('acme.Weird')).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('rejects arbitrary strings', () => {
|
|
22
|
+
expect(isBuiltInModifierSlot('')).toBe(false);
|
|
23
|
+
expect(isBuiltInModifierSlot('diffuse')).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Modifier } from '@flighthq/types';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { createEmissiveModifier } from './createEmissiveModifier';
|
|
5
|
+
import { isModifierStackValid } from './isModifierStackValid';
|
|
6
|
+
import { createModifierRegistry } from './modifierRegistry';
|
|
7
|
+
import { registerBuiltInModifiers } from './registerBuiltInModifiers';
|
|
8
|
+
|
|
9
|
+
describe('isModifierStackValid', () => {
|
|
10
|
+
it('is true when every kind is registered', () => {
|
|
11
|
+
const registry = createModifierRegistry();
|
|
12
|
+
registerBuiltInModifiers(registry);
|
|
13
|
+
expect(isModifierStackValid(registry, [createEmissiveModifier({ color: 0xffffffff })])).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('is true for an empty stack', () => {
|
|
17
|
+
const registry = createModifierRegistry();
|
|
18
|
+
expect(isModifierStackValid(registry, [])).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('is false when any kind is unregistered', () => {
|
|
22
|
+
const registry = createModifierRegistry();
|
|
23
|
+
registerBuiltInModifiers(registry);
|
|
24
|
+
const stack: Modifier[] = [createEmissiveModifier({ color: 0xffffffff }), { kind: 'acme.Missing', slot: 'Effect' }];
|
|
25
|
+
expect(isModifierStackValid(registry, stack)).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Modifier } from '@flighthq/types';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { createModifierRegistry, registerModifier, resolveModifier } from './modifierRegistry';
|
|
5
|
+
|
|
6
|
+
describe('createModifierRegistry', () => {
|
|
7
|
+
it('allocates an empty registry', () => {
|
|
8
|
+
const registry = createModifierRegistry();
|
|
9
|
+
expect(registry.definitions.size).toBe(0);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('allocates a fresh registry each call', () => {
|
|
13
|
+
const a = createModifierRegistry();
|
|
14
|
+
const b = createModifierRegistry();
|
|
15
|
+
registerModifier(a, { kind: 'acme.Foo', slot: 'Effect' });
|
|
16
|
+
expect(resolveModifier(b, 'acme.Foo')).toBeNull();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('registerModifier', () => {
|
|
21
|
+
it('stores a definition retrievable by kind', () => {
|
|
22
|
+
const registry = createModifierRegistry();
|
|
23
|
+
registerModifier(registry, { kind: 'acme.Foo', slot: 'Emissive' });
|
|
24
|
+
expect(resolveModifier(registry, 'acme.Foo')?.slot).toBe('Emissive');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('is last-write-wins for the same kind', () => {
|
|
28
|
+
const registry = createModifierRegistry();
|
|
29
|
+
registerModifier(registry, { kind: 'acme.Foo', slot: 'Emissive' });
|
|
30
|
+
registerModifier(registry, { kind: 'acme.Foo', slot: 'Normal' });
|
|
31
|
+
expect(resolveModifier(registry, 'acme.Foo')?.slot).toBe('Normal');
|
|
32
|
+
expect(registry.definitions.size).toBe(1);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('retains a getDefineSignature callback', () => {
|
|
36
|
+
const registry = createModifierRegistry();
|
|
37
|
+
registerModifier(registry, {
|
|
38
|
+
kind: 'acme.Foo',
|
|
39
|
+
slot: 'Effect',
|
|
40
|
+
getDefineSignature: (modifier: Readonly<Modifier>) => modifier.slot,
|
|
41
|
+
});
|
|
42
|
+
const definition = resolveModifier(registry, 'acme.Foo');
|
|
43
|
+
expect(definition?.getDefineSignature?.({ kind: 'acme.Foo', slot: 'Effect' })).toBe('Effect');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('resolveModifier', () => {
|
|
48
|
+
it('returns null for an unregistered kind', () => {
|
|
49
|
+
const registry = createModifierRegistry();
|
|
50
|
+
expect(resolveModifier(registry, 'acme.Missing')).toBeNull();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('returns the registered definition', () => {
|
|
54
|
+
const registry = createModifierRegistry();
|
|
55
|
+
const definition = { kind: 'acme.Foo', slot: 'Normal' };
|
|
56
|
+
registerModifier(registry, definition);
|
|
57
|
+
expect(resolveModifier(registry, 'acme.Foo')).toBe(definition);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Modifier } from '@flighthq/types';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { createAnimatedNormalModifier } from './createAnimatedNormalModifier';
|
|
5
|
+
import { createEmissiveModifier } from './createEmissiveModifier';
|
|
6
|
+
import { createRimModifier } from './createRimModifier';
|
|
7
|
+
import { orderModifierStack } from './orderModifierStack';
|
|
8
|
+
|
|
9
|
+
describe('orderModifierStack', () => {
|
|
10
|
+
const normal = createAnimatedNormalModifier({ map: null, scroll: { x: 0, y: 0 } });
|
|
11
|
+
const emissive = createEmissiveModifier({ color: 0xffffffff });
|
|
12
|
+
const rim = createRimModifier({ color: 0xffffffff });
|
|
13
|
+
|
|
14
|
+
it('groups modifiers into the canonical Normal -> Emissive -> Effect pipeline order', () => {
|
|
15
|
+
const ordered = orderModifierStack([rim, emissive, normal]);
|
|
16
|
+
expect(ordered.map((modifier) => modifier.slot)).toEqual(['Normal', 'Emissive', 'Effect']);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('is independent of cross-slot authoring order', () => {
|
|
20
|
+
const a = orderModifierStack([normal, emissive, rim]);
|
|
21
|
+
const b = orderModifierStack([rim, normal, emissive]);
|
|
22
|
+
expect(a).toEqual(b);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('preserves authoring order within one slot', () => {
|
|
26
|
+
const rimA = createRimModifier({ color: 0x111111ff });
|
|
27
|
+
const rimB = createRimModifier({ color: 0x222222ff });
|
|
28
|
+
const ordered = orderModifierStack([rimB, rimA]);
|
|
29
|
+
expect(ordered).toEqual([rimB, rimA]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('sorts unknown and reserved slots after every built-in slot, stably', () => {
|
|
33
|
+
const ambient: Modifier = { kind: 'acme.Ambient', slot: 'Ambient' };
|
|
34
|
+
const vendor: Modifier = { kind: 'acme.Custom', slot: 'acme.Weird' };
|
|
35
|
+
const ordered = orderModifierStack([ambient, rim, vendor, normal]);
|
|
36
|
+
expect(ordered).toEqual([normal, rim, ambient, vendor]);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('does not mutate the input stack', () => {
|
|
40
|
+
const input = [rim, normal];
|
|
41
|
+
orderModifierStack(input);
|
|
42
|
+
expect(input).toEqual([rim, normal]);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('returns an empty array for an empty stack', () => {
|
|
46
|
+
expect(orderModifierStack([])).toEqual([]);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { Texture } from '@flighthq/types';
|
|
2
|
+
import {
|
|
3
|
+
AnimatedNormalModifierKind,
|
|
4
|
+
DissolveModifierKind,
|
|
5
|
+
EmissiveModifierFacing,
|
|
6
|
+
EmissiveModifierKind,
|
|
7
|
+
EnvReflectModifierKind,
|
|
8
|
+
FogModifierKind,
|
|
9
|
+
FogModifierMode,
|
|
10
|
+
ModifierSlot,
|
|
11
|
+
RimModifierKind,
|
|
12
|
+
ToonModifierKind,
|
|
13
|
+
VertexDisplaceModifierKind,
|
|
14
|
+
VertexDisplaceModifierSource,
|
|
15
|
+
} from '@flighthq/types';
|
|
16
|
+
import { describe, expect, it } from 'vitest';
|
|
17
|
+
|
|
18
|
+
import { createAnimatedNormalModifier } from './createAnimatedNormalModifier';
|
|
19
|
+
import { createDissolveModifier } from './createDissolveModifier';
|
|
20
|
+
import { createEmissiveModifier } from './createEmissiveModifier';
|
|
21
|
+
import { createFogModifier } from './createFogModifier';
|
|
22
|
+
import { createVertexDisplaceModifier } from './createVertexDisplaceModifier';
|
|
23
|
+
import { createModifierRegistry, resolveModifier } from './modifierRegistry';
|
|
24
|
+
import { registerBuiltInModifiers } from './registerBuiltInModifiers';
|
|
25
|
+
|
|
26
|
+
describe('registerBuiltInModifiers', () => {
|
|
27
|
+
it('registers all eight built-in kinds against their slots', () => {
|
|
28
|
+
const registry = createModifierRegistry();
|
|
29
|
+
registerBuiltInModifiers(registry);
|
|
30
|
+
expect(resolveModifier(registry, EmissiveModifierKind)?.slot).toBe(ModifierSlot.Emissive);
|
|
31
|
+
expect(resolveModifier(registry, RimModifierKind)?.slot).toBe(ModifierSlot.Effect);
|
|
32
|
+
expect(resolveModifier(registry, AnimatedNormalModifierKind)?.slot).toBe(ModifierSlot.Normal);
|
|
33
|
+
expect(resolveModifier(registry, EnvReflectModifierKind)?.slot).toBe(ModifierSlot.Effect);
|
|
34
|
+
expect(resolveModifier(registry, FogModifierKind)?.slot).toBe(ModifierSlot.Effect);
|
|
35
|
+
expect(resolveModifier(registry, DissolveModifierKind)?.slot).toBe(ModifierSlot.Effect);
|
|
36
|
+
expect(resolveModifier(registry, ToonModifierKind)?.slot).toBe(ModifierSlot.Effect);
|
|
37
|
+
expect(resolveModifier(registry, VertexDisplaceModifierKind)?.slot).toBe(ModifierSlot.Vertex);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('gives EnvReflect and Toon no signature (single program shapes)', () => {
|
|
41
|
+
const registry = createModifierRegistry();
|
|
42
|
+
registerBuiltInModifiers(registry);
|
|
43
|
+
expect(resolveModifier(registry, EnvReflectModifierKind)?.getDefineSignature).toBeUndefined();
|
|
44
|
+
expect(resolveModifier(registry, ToonModifierKind)?.getDefineSignature).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('signals fog mode structurally', () => {
|
|
48
|
+
const registry = createModifierRegistry();
|
|
49
|
+
registerBuiltInModifiers(registry);
|
|
50
|
+
const sign = resolveModifier(registry, FogModifierKind)?.getDefineSignature;
|
|
51
|
+
expect(sign?.(createFogModifier({ color: 0xffffffff }))).toBe('l');
|
|
52
|
+
expect(sign?.(createFogModifier({ color: 0xffffffff, mode: FogModifierMode.Exponential }))).toBe('e');
|
|
53
|
+
expect(sign?.(createFogModifier({ color: 0xffffffff, mode: FogModifierMode.Exponential2 }))).toBe('x');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('signals dissolve mask presence structurally', () => {
|
|
57
|
+
const registry = createModifierRegistry();
|
|
58
|
+
registerBuiltInModifiers(registry);
|
|
59
|
+
const sign = resolveModifier(registry, DissolveModifierKind)?.getDefineSignature;
|
|
60
|
+
expect(sign?.(createDissolveModifier({ threshold: 0.5 }))).toBe('');
|
|
61
|
+
expect(sign?.(createDissolveModifier({ threshold: 0.5, map: {} as Texture }))).toBe('m');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('signals vertex-displace source and fixed axis structurally', () => {
|
|
65
|
+
const registry = createModifierRegistry();
|
|
66
|
+
registerBuiltInModifiers(registry);
|
|
67
|
+
const sign = resolveModifier(registry, VertexDisplaceModifierKind)?.getDefineSignature;
|
|
68
|
+
expect(sign?.(createVertexDisplaceModifier({ source: VertexDisplaceModifierSource.Sine, amplitude: 1 }))).toBe('s');
|
|
69
|
+
expect(sign?.(createVertexDisplaceModifier({ source: VertexDisplaceModifierSource.HeightMap, amplitude: 1 }))).toBe(
|
|
70
|
+
'h',
|
|
71
|
+
);
|
|
72
|
+
expect(
|
|
73
|
+
sign?.(
|
|
74
|
+
createVertexDisplaceModifier({
|
|
75
|
+
source: VertexDisplaceModifierSource.Sine,
|
|
76
|
+
amplitude: 1,
|
|
77
|
+
axis: { x: 0, y: 1, z: 0 },
|
|
78
|
+
}),
|
|
79
|
+
),
|
|
80
|
+
).toBe('sa');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('gives Rim no signature (a single program shape)', () => {
|
|
84
|
+
const registry = createModifierRegistry();
|
|
85
|
+
registerBuiltInModifiers(registry);
|
|
86
|
+
expect(resolveModifier(registry, RimModifierKind)?.getDefineSignature).toBeUndefined();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('signals emissive mask and facing gate structurally', () => {
|
|
90
|
+
const registry = createModifierRegistry();
|
|
91
|
+
registerBuiltInModifiers(registry);
|
|
92
|
+
const sign = resolveModifier(registry, EmissiveModifierKind)?.getDefineSignature;
|
|
93
|
+
expect(sign?.(createEmissiveModifier({ color: 0xffffffff }))).toBe('');
|
|
94
|
+
expect(sign?.(createEmissiveModifier({ color: 0xffffffff, mask: {} as Texture }))).toBe('m');
|
|
95
|
+
expect(sign?.(createEmissiveModifier({ color: 0xffffffff, facing: EmissiveModifierFacing.AwayFromLight }))).toBe(
|
|
96
|
+
'g',
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('signals animated-normal layer count structurally', () => {
|
|
101
|
+
const registry = createModifierRegistry();
|
|
102
|
+
registerBuiltInModifiers(registry);
|
|
103
|
+
const sign = resolveModifier(registry, AnimatedNormalModifierKind)?.getDefineSignature;
|
|
104
|
+
expect(sign?.(createAnimatedNormalModifier({ map: null, scroll: { x: 0, y: 0 } }))).toBe('0');
|
|
105
|
+
expect(sign?.(createAnimatedNormalModifier({ map: {} as Texture, scroll: { x: 0, y: 0 } }))).toBe('1');
|
|
106
|
+
expect(
|
|
107
|
+
sign?.(createAnimatedNormalModifier({ map: {} as Texture, scroll: { x: 0, y: 0 }, secondaryMap: {} as Texture })),
|
|
108
|
+
).toBe('2');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('is last-write-wins, reinstalling built-ins over an override', () => {
|
|
112
|
+
const registry = createModifierRegistry();
|
|
113
|
+
registerBuiltInModifiers(registry);
|
|
114
|
+
registry.definitions.set(RimModifierKind, { kind: RimModifierKind, slot: 'Normal' });
|
|
115
|
+
registerBuiltInModifiers(registry);
|
|
116
|
+
expect(resolveModifier(registry, RimModifierKind)?.slot).toBe(ModifierSlot.Effect);
|
|
117
|
+
});
|
|
118
|
+
});
|