v0.2.3 release notes
Patch release on top of v0.2.2. No breaking changes. One consistent theme: autoInstall() alone gives you the complete mascot experience — no host wiring, no CSS overrides, no bodyHtml to write.
TL;DR
- HERO greeting body defaults ship in the SDK — every install shows a coherent bilingual first-visit greeting without the host writing any HTML. Override title / rows / kbdHint per-field, override the whole HTML via
bodyHtml, or disable viaheroGreeting: false. - Sprite URL runtime resolver — SDK reads its own JS location via
import.meta.urlat construction time + inline-sets--dddk-*-urlon:rootwith reachable absolute URLs. Fixes the "Dwell swim / cursor / palette footer icon are all missing on subdirectory hosts / non-Vite setups" bug that only dddk-frontend had worked around by hand-overriding paths. autoInstall()auto-attaches MobileTrigger — withfab.alwaysVisible: true(desktop shows the FAB too) + the new heroGreeting default. Passmobile: falseto opt out.- New
DwellconfigshowCornerMascots: boolean— enterprise / business-app hosts (accounting, ERP, medical) can render just the Dwell frame outline without the playful side-view swim duck + sunglasses "chill" duck corners. Defaulttrue(existing behaviour preserved). - New
spritesoption onautoInstall(...)— swap any bundled sprite for your brand character by passing an override map.avatar/swim/hero/chill/swimCycle/brandMark/cursor— each optional, unspecified keys fall back to the SDK bundle.
What changed
HERO greeting body defaults
Before v0.2.3 the greeting body was 100% the host's responsibility — mobile.showHeroGreeting('Hi!') showed just a bare text line, or the host had to hand-write 60+ lines of bodyHtml (title + action rows + keyboard hint) themselves. Every host looked different; dddk-frontend's rich greeting was custom code that other installs didn't inherit.
v0.2.3 ships a bilingual template inside the SDK. New config on MobileTriggerConfig:
export interface HeroGreetingConfig {
autoShow?: boolean; // default true; auto-fires on first mount
autoDismissMs?: number; // default 20000
storageKey?: string; // default 'dddk_hero_greeting_seen_v1'
delayMs?: number; // default 1200
title?: string | Partial<Record<string, string>>; // bilingual
rows?: HeroGreetingRow[]; // action list
kbdHint?: string | Partial<Record<string, string>> | false;
ariaLabel?: string | Partial<Record<string, string>>;
bodyHtml?: string | ((locale: string) => string); // full escape hatch
}
Three overrides you'll actually use:
// 1. Just tweak the title, keep everything else default
new MobileTrigger({
heroGreeting: {
title: { en: "Hi! I'm Rex", 'zh-TW': '嗨!我是 Rex' },
},
});
// 2. Full replacement — pass raw HTML
new MobileTrigger({
heroGreeting: {
bodyHtml: (locale) => locale === 'zh-TW'
? '<div>你好</div>'
: '<div>Hello</div>',
},
});
// 3. Disable it entirely
new MobileTrigger({ heroGreeting: false });
Every visual axis of the template is a CSS variable declared in tokens.css:
--dddk-fab-hero-title-size/-title-weight--dddk-fab-hero-row-size/-row-gap/-row-margin/-icon-size--dddk-fab-hero-kbd-size/-kbd-margin/-kbd-opacity
Override on :root for site-wide tuning without touching the config.
Sprite URL runtime resolver
The SDK ships seven duck sprites in dist/duck/. tokens.css declares --dddk-avatar-url: url('./duck/neutral.png') etc. as defaults.
The catch: three SDK subsystems (Dwell, palette footer, WebAgent cursor) inject their own <style> blocks at runtime. Chrome resolves url() inside runtime-injected styles against the document URL — not the source CSS file. So the SDK's relative ./duck/… breaks on any host served from a subdirectory, or on setups that aren't standard Vite production.
initSpriteDefaults() runs at autoInstall() time — computes each sprite URL via new URL('./duck/x.png', import.meta.url) and inline-sets on :root.style:
- Vite / Webpack / esbuild recognise this pattern as an asset reference — process the PNG at build time + rewrite the string.
- Non-bundler setups (esm.sh, raw
<script type="module">) resolve the URL against the actual JS location, which is where the sprites also live.
Either way, sprite URLs point at something reachable. Host overrides still win — pass autoInstall({ sprites: { avatar: '/my-brand/mascot.png' } }) and the resolver honours it.
autoInstall() auto-attaches MobileTrigger
Before v0.2.3, calling autoInstall() gave you a palette + subtitle bar but no FAB. You had to also call new MobileTrigger({ ... }).attachTo(dddk) separately. That mismatched the "just install and it works" promise.
v0.2.3 has autoInstall() mount a MobileTrigger by default with fab.alwaysVisible: true (desktop shows the FAB too), plus the new HERO greeting on first visit. New top-level options:
autoInstall({
mobile: false, // disable FAB entirely
// or:
mobile: { fab: { position: 'bottom-left' } }, // override any MobileTriggerConfig field
sprites: { // swap sprites
avatar: '/my-brand/mascot.png',
swim: '/my-brand/swim.png',
},
heroGreeting: { // convenience alias for mobile.heroGreeting
title: { en: "Hi! I'm Rex", 'zh-TW': '嗨!我是 Rex' },
},
});
Dwell showCornerMascots opt-out
The two decorative Dwell corner mascots (side-view swim duck riding the top edge + sunglasses "chill" duck at the frame corner) were reported as out-of-context on serious business UIs (accounting, ERP, medical). New config:
new Dwell({
llm: myLLM,
showCornerMascots: false, // frame outline only; no mascots
});
Long-press-to-activate + Escape-to-clear + the frame outline itself work identically. Only the mascots are suppressed.
Bug fixes
showHeroGreeting()documentation clarified — the greeting body is now SDK-provided when nobodyHtmlis passed, matching the auto-fire default.- HERO greeting session-storage key renamed from host-specific
dddk:palette_hint_shownto SDK-owneddddk_hero_greeting_seen_v1. Hosts that previously wired the greeting via layout code no longer need to manage session-storage themselves.
Migrating from v0.2.2
Purely additive — every field, function, and CSS variable that existed in v0.2.2 still works. Two optional adoptions:
- Drop your hand-written HERO greeting body — pass a per-field override on
MobileTriggerConfig.heroGreetinginstead. Frontend just dropped 60 lines this way. - Delete
--dddk-*-urloverrides in yourapp.cssif you were using them to work around the "sprites don't render on subdirectory hosts" bug — the runtime resolver now handles it.
Full guide: migrating.md.
What v0.2.3 does NOT change
- All existing hosts using
new DotDotDuck({...})+ manualnew MobileTrigger({...})continue to work unchanged. - No CSS variable names or renderer contracts changed.
- The
showHeroGreeting(text, opts)public API signature is unchanged. - No new peer dependencies.