Repository navigation
Add cheeks and hat options to the skin - #4
Merged
Merged
Conversation
**What changed** - Pulled the `PerspectiveCamera` in `src/render/createJax.ts` back a little and re-centred its look-at point, so there is more room above his head. **Why** - The party hat already reached the top edge of the canvas, and the new hats stand as tall. Without the extra headroom they are clipped. **Details** - The camera moves from `z = 8.6` to `z = 9.2` and looks at `y = -0.3`. The figure is about 7% smaller in the frame. **Validation** - Checked in a software-rendered headless browser with every hat and the party mood. Not looked at on real hardware.
**What changed** - Added `cheeks?: boolean` (default `false`) and `hat?: Hat` (default `'none'`) to `Skin`, with the `Hat` type and the `HATS` const (`'none'`, `'peakCap'`, `'topHat'`). - Added optional `colours.hat` and `colours.hatBand` to the skin colours. - `defaultSkin` sets cheeks off, no hat, a slate `hat` colour and a crimson `hatBand`. **Why** - The rosy cheeks were always on, and there was no way to dress him in a hat of the app's choosing. **Details** - The new colours are optional, so skins written against the earlier contract still type-check. The renderers fall back to a charcoal-purple hat and the skin's `accent` for the band. - `colours.blush` stays, and now colours the cheeks and a few small props. **Validation** - `src/types.test.ts` covers `HATS`.
**What changed** - `buildOtter` adds the cheek slabs only when `skin.cheeks` is `true`. - `buildOtter` builds a peak cap or a top hat from flat slabs on the head pivot when `skin.hat` asks for one, exposed as `OtterRig.hat` (a group named `hat-peakCap` or `hat-topHat`). - The chosen hat scales and fades out while `propHat` is up and returns after, using the same presence tween as the other props. No new pose channel is needed. **Why** - Cheeks become an opt-in look, and apps can dress him in a hat without touching the party mood's own paper hat, which keeps priority. **Details** - The head slab's bevelled front face stands proud of its nominal depth, so the cheeks moved forward to `z = 0.43`; they were previously buried in the fur and effectively invisible. - The cap and the top hat are deep enough in `z` to wrap the front of the head, and sit between the ears without touching them. **Validation** - `src/model/otter.test.ts` covers the defaults, cheeks on and off, each hat's group, the hand-over with `propHat` and disposal of the new geometries. - Looked at in a software-rendered headless browser. Not looked at on real hardware.
**What changed** - `createFallbackJax` draws the cheeks (`lq-jax-cheek`) only when `options.skin.cheeks` is `true`. - It draws the chosen hat as a flat SVG group (`lq-jax-worn-hat` with `lq-jax-hat-peakCap` or `lq-jax-hat-topHat`) using `colours.hat` and `colours.hatBand`. - `FALLBACK_CSS` hides the worn hat for the party mood, with the same opacity transition as the props. **Why** - The fallback should match the 3D otter when the app passes the same `skin`. **Details** - Without a `skin` the output has no cheeks and no hat. The API is unchanged and there are no inline styles. **Validation** - `src/fallback/fallback.test.ts` checks the elements appear only when requested and that no `style` attributes are written.
**What changed** - The demo has a `Cheeks` toggle and a `Hat` select (none, peak cap, top hat) that rebuild the running companions, in both the 3D and fallback paths. - The README describes `cheeks`, `hat`, `colours.hat` and `colours.hatBand`. **Why** - The options are a matter of look, so they need to be judged by eye. **Validation** - Built the demo and drove it in a headless browser through each option.
**What changed** - `HATS` and `Hat` now include `'party'`, and the `Skin.hat` and `colours.hat` doc comments say how it behaves. This changes the shared contract in `src/types.ts` deliberately. - `buildOtter` builds a `hat-party` group on the head for `hat: 'party'`, from the same `buildPartyHat` geometry as the party mood's `propHat` prop. - With the party hat chosen, the mood prop is left empty and hidden, and the chosen hat ignores `propHat`, so it stays on with no fade and there is never a second one. **Why** - The party hat could only be seen in the party mood, so it was not available as a look. **Validation** - Tests cover the `HATS` values, the `hat-party` group, exactly one visible party hat at `propHat` 0, 0.5 and 1, and unchanged behaviour for the other hats.
**What changed** - `hat: 'party'` draws one `lq-jax-party-hat` group on the head in every mood. - With it chosen, the mood's own `lq-jax-prop-hat` is not drawn, so the party mood adds no second hat. It carries no `lq-jax-worn-hat` class, so the CSS that hides worn hats does not touch it. - The other hats keep hiding in the party mood. **Validation** - A test checks one party hat element in every mood and no inline `style` attributes.
**What changed** - The demo's Hat select lists "party hat". - The README paragraph on cheeks and hats names `'party'` and says it stays on in every mood.
ScottMorris
force-pushed
the
feat/cheeks-and-hats
branch
from
October 15, 2026 15:39
4a96fc1 to
df526e3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
skin.cheeks(boolean, defaultfalse) draws the rosy cheeks in the 3D model and the SVG fallback. The old cheek slabs sat inside the head's bevel and were effectively invisible; they now sit in front of the face and are clearly visible when switched on.skin.hatis'none'(default),'peakCap','topHat'or'party', with theHattype andHATSarray exported and optionalcolours.hatandcolours.hatBand. The hat sits on the head between the ears and moves with it. While the party mood shows its own hat, a chosen peak cap or top hat scales and fades out, and returns afterwards. No new pose channel.hat: 'party'he wears the same party hat the party mood uses, all the time; in the party mood there is exactly one party hat, with no fade or flicker.options.skin, and the demo has a Cheeks toggle and a Hat select with all four choices.z8.6 to 9.2, look-aty-0.45 to -0.3) so the party hat and the top hat are not clipped at the top of the canvas; the otter is about 7% smaller in the frame. This is a separate commit (fix(render)) that can be dropped on its own.Known limitations
Test plan
bun run test(176 tests),bun run lint,bun run format:check,bun run buildnode scripts/check-package.mjsandbunx vite build demo