Jacky can wear hats that dynamically track his head position, tilt, and scale across every animation frame. You can cycle through available hats, adjust their placement in real time, and — if you are a skin creator — embed precise frame-by-frame head coordinates directly in your skin manifest so hats sit perfectly on your custom character.
Open the Manifest Builder
How Hats Work
A hat is a transparent overlay window that renders a PNG (or GIF) image directly above Jacky. On every animation tick, Jacky calculates the head position using tracking data and moves, rotates, and scales the hat to match.
Tracking Data Priority
Jacky resolves hat position in this order:
- Skin-defined tracking — If your skin's
manifest.jsonincludes ahatblock with per-frame coordinates, those are used first. - Fallback database — If the skin has no
hatconfig, Jacky uses the included database, which contains pre-computed head coordinates for the default companion (calibrated at 256×256). - Default placement — If no data is available for a state, the hat defaults to the sprite's top-center.
The fallback database works well for the default companion, but custom skins with different proportions or head shapes should always include their own hat tracking data in the manifest.
Tracking During Missing Frames
If a frame has no defined tracking data (intentionally left out), Jacky hides the hat for that frame. If a frame is simply missing but the animation state is defined, Jacky reuses the last valid pose to avoid flicker.
Including Hat Tracking in Your Skin Manifest
To provide custom hat placement for your skin, add a hat object inside your manifest.json. Reference the Skins & Animations guide for the full manifest structure.
Hat Block Structure
The hat object maps animation folder names to arrays of per-frame tracking entries:
{
"type": "skin",
"name": "MyCustomSkin",
"version": "1.0.0",
"author": "YourName",
"description": "A custom companion with hat support",
"skin": {
"sprite_size": 128,
"fps": 12,
"sprite_facing": "right",
"card": {
"title": "My Companion",
"description": "A custom friend for your desktop",
"author": "YourName",
"link": "https://yoursite.com"
}
},
"hat": {
"Idle": [
{ "frame": 0, "x": 64, "y": 28, "angulo": 0.0, "distancia": 100.0 },
{ "frame": 1, "x": 64, "y": 29, "angulo": 1.5, "distancia": 101.0 },
{ "frame": 2, "x": 63, "y": 27, "angulo": -0.8, "distancia": 99.0 }
],
"Walking": [
{ "frame": 0, "x": 62, "y": 26, "angulo": -3.0, "distancia": 95.0 },
{ "frame": 1, "x": 65, "y": 30, "angulo": 2.5, "distancia": 102.0 }
],
"Dance": [
{ "frame": 0, "x": 70, "y": 25, "angulo": 0.0, "distancia": 105.0 }
],
"Sleep": [
{ "x": 50, "y": 80, "angulo": 45.0, "distancia": 80.0 }
]
}
}Folder names in the hat object must match the folder names on disk (e.g., Idle, Walking, Dance), not the internal PetState enum names. See the Animation States Reference for the full folder name list.
Per-Frame Entry Fields
| Field | Type | Required | Description |
|---|---|---|---|
frame | int | No | Frame index to apply these coordinates to. If omitted, entries are assigned sequentially (entry 0 → frame 0, entry 1 → frame 1, etc.) |
x | float | Yes | Horizontal head position (pixels), relative to your sprite_size. |
y | float | Yes | Vertical head position (pixels), relative to your sprite_size. |
angulo | float | No | Head tilt angle in degrees. Use angle as an alias. Defaults to 0. |
distancia | float | No | Tracking distance factor (affects dynamic scaling). Use distance as an alias. Defaults to 1.0. Higher values = head moves more between frames. |
Coordinate System
- All
xandyvalues are relative to the sprite's top-left corner, in pixels at the skin's nativesprite_size. - Jacky automatically scales these coordinates to the current display size.
- If you specify explicit
framenumbers, only those frames will show the hat. Frames without entries will hide the hat.
Horizontal Mirroring
When Jacky faces left, the hat is automatically mirrored horizontally — the x coordinate is flipped relative to the sprite center, and the rotation angle is inverted. You do not need to provide separate coordinates for left-facing sprites.
Changing and Adjusting Hats
Hat Sources
Jacky looks for hat images in two locations:
- Bundled hats — Default hats shipped with Jacky in
assets/hats/. - User hats — Custom hats placed in the
~/.jacky/hats/directory.
If a user hat has the same filename as a bundled hat, the user version takes priority.
Supported formats: .png (static) and .gif (animated).
Context Menu
Right-click Jacky to open the context menu, then find the Hats submenu:
| Option | Description |
|---|---|
| Enable Hats | Toggle the hat overlay on/off. |
| Next Hat | Switch to the next available hat. |
| Previous Hat | Switch to the previous available hat. |
| Adjust Hat... | Open the floating Hat Adjuster panel. |
Hat Adjuster Panel
The Hat Adjuster is a frameless floating panel that lets you fine-tune hat placement in real time:
| Control | Range | Default | Description |
|---|---|---|---|
| Enable Hats | On/Off | Off | Toggle the hat overlay. |
| Fixed Position | On/Off | Off | Lock the hat to a fixed position on the sprite (ignores tracking data). |
| Size | 10% – 300% | 100% | Scale the hat relative to its original size. |
| Offset X | -100 – 100 px | 0 | Shift the hat horizontally. |
| Offset Y | -200 – 200 px | -40 | Shift the hat vertically (negative = up). |
| Angle | -180° – 180° | 0° | Rotate the hat by a fixed offset. |
All sliders update the hat position live. Click Reset to revert to defaults, or close the panel to save your adjustments.
Persistence
All hat settings are saved to Jacky's config.json and persist across restarts:
hat_enabled— Whether hats are active.hat_current— The currently selected hat filename.hat_scale— Custom scale percentage.hat_offset_x/hat_offset_y— Custom position offsets.hat_angle— Custom rotation offset.hat_fixed_position— Whether to use a fixed position instead of tracking data.
Tips for Skin Creators
- Capture tracking data externally — Use an optical flow or point-tracking tool (e.g., Lucas-Kanade) to record head coordinates frame by frame, then export them into your
manifest.json. - Provide data for common states — At minimum, include
IdleandWalkingentries. Other states will fall back to the bundled database or defaults. - Test with the Adjuster — Load your skin, enable hats, and use the Hat Adjuster to verify placement. If hats sit correctly without adjustments, your tracking data is accurate.
- Omit intentional gaps — If the head is not visible in certain frames (e.g., a spin animation where the head is hidden), omit those frame entries to hide the hat naturally.