Skip to content

Live2D / Spine Model

Firefly supports displaying Live2D or Spine mascot models on the page. Choose one of the two.

Config File

src/config/pioConfig.ts

Spine Model

Basic

PropertyTypeDefaultDescription
enablebooleanfalseEnable Spine mascot

Model

PropertyTypeDefaultDescription
model.pathstring-Spine model file path (.json)
model.scalenumber1.0Scale
model.xnumber0X offset
model.ynumber0Y offset

Position

PropertyTypeDefaultDescription
position.cornerstring"bottom-left"Position: "bottom-left" "bottom-right" "top-left" "top-right"
position.offsetXnumber0Horizontal offset
position.offsetYnumber0Vertical offset

Size

PropertyTypeDefaultDescription
size.widthnumber135Container width
size.heightnumber165Container height

Interaction

PropertyTypeDefaultDescription
interactive.enabledbooleantrueEnable interaction
interactive.clickAnimationsstring[]-Click animations
interactive.clickMessagesstring[]-Click messages
interactive.messageDisplayTimenumber3000Message display time (ms)
interactive.idleAnimationsstring[]-Idle animations
interactive.idleIntervalnumber8000Idle animation interval (ms)

Responsive

PropertyTypeDefaultDescription
responsive.hideOnMobilebooleantrueHide on mobile
responsive.mobileBreakpointnumber768Mobile breakpoint (px)

Other

PropertyTypeDefaultDescription
zIndexnumber1000Z-index
opacitynumber1.0Opacity (0-1)

Live2D Model

Live2D is implemented using l2d-widget, supporting both Cubism 2 and Cubism 6 formats.

Basic

PropertyTypeDefaultDescription
enablebooleanfalseEnable Live2D mascot

Model

PropertyTypeDefaultDescription
model.pathstring-Live2D model file path (model.json or model3.json), supports external URLs
model.volumenumber0Action sound volume (0-1), default 0 (muted)
model.scalenumber1Model scale ratio
model.xnumber0X axis offset, range -2~2, positive = right
model.ynumber0Y axis offset, range -2~2, positive = up

Supports passing an array for multiple models with automatic switch button in menu:

ts
model: [
  { path: "/models/cat-black/model.json" },
  { path: "/models/cat-white/model.json" },
]

Position

PropertyTypeDefaultDescription
positionstring"bottom-left"Position: "bottom-left" "bottom-right"

Size

PropertyTypeDefaultDescription
sizenumber | { width, height }300Canvas size (px), number or object

Theme Color

PropertyTypeDefaultDescription
primaryColorstring"rgba(96,165,250,0.9)"Theme color for menu, status bar, etc. Supports CSS variables like "var(--primary)"

Animation

PropertyTypeDefaultDescription
transitionDurationnumber1500Enter/exit animation duration (ms)
transitionType"slide" | "fade""slide"Enter/exit animation type
PropertyTypeDescription
menus.itemsMenuItem[]Completely replace default menu items
menus.extraItemsMenuItem[]Append to default menu
menus.align"left" | "right"Menu alignment

MenuItem structure:

PropertyTypeDescription
iconstringIconify icon name, e.g. "mdi:home"
labelstringMenu item text
actionstringAction identifier: "home" "scrollToTop" "sleep" "switchModel" "github"

Tips

PropertyTypeDefaultDescription
tips.enablebooleantrueEnable tips, set false to completely disable
tips.welcomeMessagestring[]-Welcome messages, shown randomly on first load
tips.messagesstring[]-Loop tip messages
tips.durationnumber3000Tip display duration (ms)
tips.intervalnumber5000Tip loop interval (ms)
tips.offset.xnumber0Horizontal offset (px), positive = right
tips.offset.ynumber0Vertical offset (px), positive = down

Responsive

PropertyTypeDefaultDescription
responsive.hideOnMobilebooleantrueHide on mobile
responsive.mobileBreakpointnumber768Mobile breakpoint (px)

Spine Full Example

ts
export const spineModelConfig: SpineModelConfig = {
  enable: true,
  model: {
    path: "/pio/models/spine/firefly/1310.json",
    scale: 1.0,
    x: 0,
    y: 0,
  },
  position: { corner: "bottom-left", offsetX: 0, offsetY: 0 },
  size: { width: 135, height: 165 },
  interactive: {
    enabled: true,
    clickAnimations: ["emoji_0", "emoji_1", "emoji_2"],
    clickMessages: ["Hello!", "Have a nice day!"],
    messageDisplayTime: 3000,
    idleAnimations: ["idle", "emoji_0"],
    idleInterval: 8000,
  },
  responsive: { hideOnMobile: true, mobileBreakpoint: 768 },
  zIndex: 1000,
  opacity: 1.0,
};

Live2D Full Example

ts
export const live2dWidgetConfig = {
  enable: true,
  model: {
    path: "/pio/models/live2d/snow_miku/model.json",
  },
  position: "bottom-left",
  size: { width: 200, height: 200 },
  primaryColor: "var(--primary)",
  transitionDuration: 1500,
  transitionType: "slide",
  menus: {
    items: [
      { icon: "mdi:home", label: "Home", action: "home" },
      { icon: "mdi:arrow-up", label: "Top", action: "scrollToTop" },
      { icon: "mdi:sleep", label: "Sleep", action: "sleep" },
      { icon: "mdi:github", label: "GitHub", action: "github" },
    ],
    align: "right",
  },
  tips: {
    welcomeMessage: ["Hello! I'm Miku~", "Welcome to my world!"],
    messages: ["Need help?", "Nice weather today!", "Want to play a game?"],
    duration: 3000,
    interval: 6000,
  },
  responsive: { hideOnMobile: true, mobileBreakpoint: 768 },
};

WARNING

Placing the model in the bottom-right corner may block the back-to-top button. Consider using "bottom-left".