Merge pull request 'scene: Phacelle bound says measured-not-proved; neutral creature draws nothing' (#8) from nibu/phacelle-7-neutral-creature into ratatoskr/estate-navigator
This commit is contained in:
commit
95e24aadb5
3 changed files with 26 additions and 21 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { BUCKET_SCALE, creatureScale, NEUTRAL_SCALE, SizeBucket } from './creatures';
|
||||
import { BUCKET_SCALE, creatureScale, SizeBucket } from './creatures';
|
||||
|
||||
const buckets: SizeBucket[] = ['small', 'medium', 'large'];
|
||||
|
||||
|
|
@ -10,14 +10,18 @@ describe('creature scale', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('is one fixed size for every neutral creature, whatever its sizeBucket', () => {
|
||||
buckets.forEach((sizeBucket) =>
|
||||
expect(creatureScale({ sizeBucket, neutral: true })).toBe(NEUTRAL_SCALE)
|
||||
);
|
||||
it('draws nothing for a neutral creature, whatever sizeBucket it was sent', () => {
|
||||
expect(creatureScale({ neutral: true })).toBeNull();
|
||||
buckets.forEach((sizeBucket) => expect(creatureScale({ sizeBucket, neutral: true })).toBeNull());
|
||||
});
|
||||
|
||||
it('is only visible as an override where the bucket would have said something else', () => {
|
||||
expect(BUCKET_SCALE.small).not.toBe(NEUTRAL_SCALE);
|
||||
expect(BUCKET_SCALE.large).not.toBe(NEUTRAL_SCALE);
|
||||
it('does not crash or default to medium when a non-neutral creature has no sizeBucket', () => {
|
||||
expect(creatureScale({ neutral: false })).toBeNull();
|
||||
expect(creatureScale({ sizeBucket: undefined, neutral: false })).toBeNull();
|
||||
});
|
||||
|
||||
it('draws nothing for an unknown bucket, including inherited property names', () => {
|
||||
expect(creatureScale({ sizeBucket: 'huge' as SizeBucket, neutral: false })).toBeNull();
|
||||
expect(creatureScale({ sizeBucket: 'toString' as SizeBucket, neutral: false })).toBeNull();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@
|
|||
// Props contract: heimdall-body:follow_up:ratatoskr-creature-projection-v2 (against GameCult/Bifrost; supersedes heimdall-body/ratatoskr-creature-projection).
|
||||
// Nothing here is binding until Bifrost's steward cuts that contract.
|
||||
//
|
||||
// Shape: {id, estate, sizeBucket, neutral, activity}.
|
||||
// Shape: {id, estate, neutral, activity} plus sizeBucket when neutral is false.
|
||||
// Invariants:
|
||||
// - Exact vote weights stay in Bifrost; Ratatoskr only ever sees a bucket.
|
||||
// - neutral=true overrides any bucket, and no size is drawn.
|
||||
// - neutral=true means Bifrost publishes no sizeBucket, no kind and no energy. A received value is
|
||||
// ignored, and a neutral creature is not drawn.
|
||||
// - A missing or unknown sizeBucket is not drawn either; no size is ever defaulted.
|
||||
// - activity comes from the Heimdall session.
|
||||
// Consent: humans get a coarse bucket by default plus a typed opt-out; Minds and Personas may show finer buckets.
|
||||
// Humans have three coarse buckets. The scales below (0.7 / 1 / 1.4) are placeholders, not fixed.
|
||||
|
|
@ -16,8 +18,8 @@ export type SizeBucket = 'small' | 'medium' | 'large';
|
|||
export interface Creature {
|
||||
id: string;
|
||||
estate: string;
|
||||
sizeBucket: SizeBucket;
|
||||
/** A neutral creature (no estate allegiance) is drawn at one fixed size whatever its bucket. */
|
||||
/** Absent when neutral. Read it only through creatureScale. */
|
||||
sizeBucket?: SizeBucket;
|
||||
neutral: boolean;
|
||||
activity: 'idle' | 'active';
|
||||
}
|
||||
|
|
@ -28,10 +30,8 @@ export const BUCKET_SCALE: Readonly<Record<SizeBucket, number>> = {
|
|||
large: 1.4,
|
||||
};
|
||||
|
||||
/** Neutral creatures are medium sized, not necessarily their bucket's size. */
|
||||
export const NEUTRAL_SCALE = BUCKET_SCALE.medium;
|
||||
|
||||
/** Neutral overrides sizeBucket. */
|
||||
export function creatureScale(c: Pick<Creature, 'sizeBucket' | 'neutral'>): number {
|
||||
return c.neutral ? NEUTRAL_SCALE : BUCKET_SCALE[c.sizeBucket];
|
||||
/** The draw scale, or null when nothing is drawn: a neutral creature, or a bucket that is absent or unknown. */
|
||||
export function creatureScale(c: Pick<Creature, 'sizeBucket' | 'neutral'>): number | null {
|
||||
if (c.neutral || c.sizeBucket === undefined) return null;
|
||||
return Object.prototype.hasOwnProperty.call(BUCKET_SCALE, c.sizeBucket) ? BUCKET_SCALE[c.sizeBucket] : null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,10 @@ export const WORLD = {
|
|||
erodeSide: [1.7, 0, 1] as const,
|
||||
erodeNorm: 0.5,
|
||||
// Bound on |grad| of the phasor's cos component for the side and norm above. Libby measured a
|
||||
// sup of 6.63 at |side| = 1.5, n = 0 (CultLib PR #1 head 990521b3); 7.0 adds margin. The
|
||||
// shader passes roughness n = 0 as a literal, so the doc envelope max(10, 1.25|side|)/(1-n)
|
||||
// needs no 1/(1-n) factor here; if n ever becomes nonzero, divide this bound by (1 - n).
|
||||
// sup of 6.63 at |side| = 1.5, n = 0 (CultLib PR #1 head 990521b3); 7.0 adds margin.
|
||||
// The sup was measured, not proved. The shader passes roughness n = 0 as a literal, so the doc
|
||||
// envelope max(10, 1.25|side|)/(1-n) needs no 1/(1-n) factor here; if n ever becomes nonzero,
|
||||
// divide this bound by (1 - n).
|
||||
// |value| <= 1 holds by construction (the output is a normalized phasor).
|
||||
// Typed number, not the literal 7, so callers can build variants such as { ...WORLD, phacelleGradBound: 0 }.
|
||||
phacelleGradBound: 7.0 as number,
|
||||
|
|
|
|||
Loading…
Reference in a new issue