Gallery System
The gallery system provides an in-game photo and video gallery where players can view media evidence. Gallery items are defined in JSON files and can be unlocked as the story progresses.
Overview
The gallery system allows you to:
- Display photos and videos as evidence or story elements
- Organize media content separate from conversations
- Control when items unlock - initially or during gameplay
- Add context with captions and timestamps
- Share items in conversations while also storing them in the gallery
- Create a visual timeline of events with dated media
Directory Structure
Gallery items are stored in stories/your-story/gallery/ as JSON files.
stories/
└── your-story/
├── assets/
│ ├── crime-scene.jpg
│ ├── security-footage.mp4
│ └── evidence-photo.png
└── gallery/
├── crime-scene-photo.json
├── security-footage.json
└── evidence-photo.jsonEach .json file defines one gallery item that references a media file in the assets/ directory.
Creating Gallery Items
Image Gallery Item
Example: stories/your-story/gallery/crime-scene-photo.json
{
"type": "image",
"asset": "crime-scene.jpg",
"caption": "Evidence found at the warehouse",
"takenAt": "2025-10-22T15:30:00Z",
"initial": false
}Video Gallery Item
Example: stories/your-story/gallery/security-footage.json
{
"type": "video",
"asset": "security-footage.mp4",
"caption": "Security camera footage from Club Neon",
"takenAt": "2025-10-21T23:15:00Z"
}Initial Gallery Item
Example: stories/your-story/gallery/found-phone.json
{
"type": "image",
"asset": "found-phone.png",
"caption": "How did this get on my phone?",
"takenAt": "2025-10-20T14:30:00Z",
"initial": true
}JSON Fields
type (Required)
Purpose: Specifies whether the item is an image or video.
Values:
"image"- For photos and images"video"- For video clips
Example:
{
"type": "image"
}asset (Required)
Purpose: The filename of the media file in the assets directory.
Format: Just the filename, not the full path.
Examples:
{
"asset": "crime-scene.jpg"
}{
"asset": "security-footage.mp4"
}Supported formats:
- Images:
.jpg,.jpeg,.png,.gif,.webp - Videos:
.mp4,.webm,.mov
Important: The file must exist in stories/your-story/assets/ directory.
caption (Optional)
Purpose: Descriptive text shown with the gallery item.
Best practices:
- Keep captions concise but informative
- Provide context about what the media shows
- Use captions to hint at significance
- Can include questions or observations
Examples:
{
"caption": "Evidence found at the warehouse"
}{
"caption": "Last known photo of Sarah - taken at Club Neon"
}{
"caption": "Who is this person in the background?"
}takenAt (Optional)
Purpose: Timestamp when the photo/video was taken (in-story time).
Format: ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ
Examples:
{
"takenAt": "2025-10-21T23:15:00Z"
}{
"takenAt": "2025-10-22T15:30:00Z"
}When to use:
- Creating a timeline of events
- Showing when evidence was captured
- Organizing gallery items chronologically
- Adding realism to photos and videos
Format breakdown:
YYYY- Four-digit yearMM- Two-digit month (01-12)DD- Two-digit day (01-31)T- Separator between date and timeHH- Two-digit hour (00-23)MM- Two-digit minute (00-59)SS- Two-digit second (00-59)Z- UTC timezone indicator
initial (Optional)
Purpose: Makes the gallery item available from the start of the story.
Values:
true- Item is unlocked immediately when story startsfalseor omitted - Item must be unlocked via Ink
Examples:
Initial item:
{
"type": "image",
"asset": "found-phone.png",
"caption": "The phone I found",
"initial": true
}Locked item (unlocked during gameplay):
{
"type": "image",
"asset": "crime-scene.jpg",
"caption": "Evidence from the warehouse",
"initial": false
}When to use initial: true:
- Tutorial or welcome images
- Photos that exist on the "found phone" at story start
- Background information available immediately
- Setting the scene
When to omit or use initial: false:
- Evidence discovered during investigation
- Photos unlocked as rewards
- Media revealed at specific story moments
- Content tied to player progression
Unlocking Gallery Items
Initial Items
Gallery items with "initial": true are automatically available when the story starts:
{
"type": "image",
"asset": "welcome-photo.jpg",
"caption": "Welcome to the gallery",
"initial": true
}Use initial items for:
- Photos already on the "found phone"
- Tutorial/welcome images
- Starting evidence
- Background context
Unlocking via Ink
Gallery items without initial: true must be unlocked using the #gallery: tag in your Ink scripts.
Important: The gallery item ID is the filename without the .json extension.
Example:
If your file is stories/your-story/gallery/crime-scene-photo.json, the ID is crime-scene-photo.
Unlock in conversation:
I found this on Sarah's cloud backup. #gallery:security-footage
Take a look at what I discovered. #gallery:crime-scene-photo
Here's the photo from that night. #gallery:club-photoWhen unlocked via #gallery::
- The media appears in the conversation message
- The item is added to the gallery app
- The player can view it anytime in the gallery
Checking Gallery State
Use external functions to check if a gallery item has been unlocked or viewed:
{IsGalleryItemUnlocked("crime-scene-photo"):
You've already got access to that photo.
- else:
Let me send you the crime scene photo. #gallery:crime-scene-photo
}
{IsGalleryItemSeen("security-footage"):
So you watched the security footage. What did you notice?
- else:
Make sure you check the security footage in your gallery.
}File Naming
Gallery JSON files should use descriptive, lowercase names with hyphens:
✅ Good:
crime-scene-photo.jsonsecurity-footage.jsonsarah-last-photo.jsonwarehouse-exterior.json
❌ Avoid:
photo1.jsonImage File.jsoncrime_scene_photo.json
Best practices:
- Use descriptive names that indicate content
- Match the naming style of your assets
- Keep names concise but clear
- Use hyphens, not underscores or spaces
Complete Examples
Crime Scene Photo
File: stories/your-story/gallery/warehouse-evidence.json
{
"type": "image",
"asset": "warehouse-crime-scene.jpg",
"caption": "Evidence found at 142 Riverside Drive - torn fabric and footprints",
"takenAt": "2025-10-22T15:30:00Z"
}Unlock in Ink:
The police just sent over the crime scene photos. #gallery:warehouse-evidence
Take a close look - there might be clues we missed. #typing:2sSecurity Camera Footage
File: stories/your-story/gallery/club-neon-footage.json
{
"type": "video",
"asset": "club-neon-security.mp4",
"caption": "Security footage from Club Neon - Friday 11:30 PM",
"takenAt": "2025-10-21T23:30:00Z"
}Unlock in Ink:
I managed to get the security footage from the club. #gallery:club-neon-footage
Watch carefully - there's someone suspicious in the background. #typing:3sInitial Photo (Already on Phone)
File: stories/your-story/gallery/sarah-selfie.json
{
"type": "image",
"asset": "sarah-selfie.jpg",
"caption": "Sarah's last selfie - taken at Club Neon",
"takenAt": "2025-10-21T22:45:00Z",
"initial": true
}This photo is available immediately when the story starts, as if it was already on the found phone.
Mysterious Photo
File: stories/your-story/gallery/unknown-person.json
{
"type": "image",
"asset": "mysterious-figure.jpg",
"caption": "Who is this person? Why is this photo on Sarah's phone?",
"takenAt": "2025-10-21T20:15:00Z"
}Unlock in Ink:
I found something strange in Sarah's deleted photos. #gallery:unknown-person
Do you recognize this person? #typing:2sTimeline of Photos
Create a visual timeline by using consistent takenAt timestamps:
1. Before the incident:
{
"type": "image",
"asset": "sarah-at-work.jpg",
"caption": "Sarah at work - Friday afternoon",
"takenAt": "2025-10-21T16:00:00Z"
}2. At the club:
{
"type": "image",
"asset": "sarah-club-neon.jpg",
"caption": "Sarah with friends at Club Neon",
"takenAt": "2025-10-21T22:45:00Z"
}3. Last known photo:
{
"type": "image",
"asset": "club-exterior.jpg",
"caption": "Club Neon exterior - last photo on Sarah's phone",
"takenAt": "2025-10-21T23:25:00Z"
}Integration with Story
Sharing Evidence in Conversations
== detective_shares_evidence ==
I've got some evidence to share with you. #typing:3s
Here's what we found at the warehouse. #gallery:warehouse-evidence #delay:2s
And this is the security footage from that night. #gallery:club-footage #delay:3s
{IsGalleryItemSeen("warehouse-evidence") && IsGalleryItemSeen("club-footage"):
Now that you've seen everything, what do you think?
-> player_analysis
- else:
Take your time reviewing the evidence in your gallery.
-> END
}Progressive Evidence Reveal
// Early game - first clue
Here's the last photo on Sarah's phone. #gallery:club-exterior
// Mid game - more evidence
I found this in her cloud backup. #gallery:deleted-photo #delay:5m
// Late game - breakthrough
This changes everything. Look at this. #gallery:crucial-evidence #delay:10mConditional Unlocking
{police_contacted and warehouse_discovered:
The police sent over the crime scene photos. #gallery:crime-scene
- else:
We need to contact the police first before we can get the evidence photos.
}Combining with Other Systems
Gallery + Notes:
Here's the photo evidence. #gallery:warehouse-photo
I've added details to your notes. #unlockNote:photo-analysis #delay:2sGallery + News:
The news just published this photo. #unlockNews:breaking-story
I've saved it to your gallery too. #gallery:news-photo #delay:1sBest Practices
Organization
- Group related items - Use consistent naming for related photos/videos
- Create a timeline - Use
takenAtto establish chronological order - Balance initial vs unlocked - Don't overwhelm with too many initial items
- Match story pacing - Unlock items at appropriate story moments
Captions
Be descriptive:
{
"caption": "Security footage from Club Neon - shows Sarah leaving alone at 11:30 PM"
}Create intrigue:
{
"caption": "Who is the person watching Sarah from across the street?"
}Provide context:
{
"caption": "Warehouse at 142 Riverside Drive - where Sarah's phone was found"
}Ask questions:
{
"caption": "Why would Sarah take a photo of this abandoned building?"
}Media Files
Images:
- Optimize file size (compress before adding)
- Use appropriate resolution (1920x1080 or smaller)
- Ensure images are clear and visible
- Consider mobile viewing
Videos:
- Keep videos short (under 2 minutes ideal)
- Compress for web delivery
- Test playback on different devices
- Provide clear visuals even on small screens
Timestamps
Be consistent:
- Use the same timezone throughout
- Maintain chronological order
- Match timestamps with story timeline
- Align with news article dates
Create realistic gaps:
// Morning
"takenAt": "2025-10-21T09:00:00Z"
// Evening (realistic 14-hour gap)
"takenAt": "2025-10-21T23:00:00Z"Testing Checklist
Before publishing, verify:
- ✅ All asset files exist in
stories/your-story/assets/ - ✅ JSON syntax is valid (no missing commas or brackets)
- ✅
typeis either"image"or"video" - ✅ Filenames match exactly (case-sensitive)
- ✅ Initial items appear immediately when story starts
- ✅ Gallery items unlock correctly via
#gallery:tag - ✅ Images display properly on different screen sizes
- ✅ Videos play correctly
- ✅ Captions are clear and helpful
- ✅ Timestamps are in correct ISO 8601 format
Troubleshooting
Gallery item not appearing:
- Check that JSON file exists in
stories/your-story/gallery/ - Verify the ID used in
#gallery:matches the filename (without .json) - Ensure
typefield is set correctly - Check that asset file exists in assets directory
Media not loading:
- Confirm asset filename matches exactly (case-sensitive)
- Verify file format is supported
- Check file isn't corrupted
- Ensure file size isn't too large (compress if needed)
Initial items not showing:
- Verify
"initial": trueis set in JSON - Check JSON syntax is valid
- Ensure no typos in field names
Timestamp errors:
- Use ISO 8601 format:
YYYY-MM-DDTHH:MM:SSZ - Include the
Tseparator andZtimezone - Use 24-hour time format
- Ensure valid date values
Common Patterns
Evidence Collection
// As player discovers evidence, unlock gallery items
You found Sarah's phone! #typing:2s
Let me check what's on it... #typing:3s #delay:2s
There are some photos here. #gallery:phone-photo-1 #delay:1s
And a video from that night. #gallery:phone-video #delay:2sWitness Sharing Media
== witness_shares_photo ==
I took this photo that night. #typing:2s
You can see Sarah in the background. #gallery:witness-photo
Do you recognize the person she's talking to? #typing:2s
-> ENDPolice Evidence
== police_evidence ==
{police_contacted:
The detective sent over the case files. #typing:3s
Here are the crime scene photos. #gallery:crime-scene-1 #delay:2s
And the security camera footage. #gallery:security-footage #delay:2s
Review everything carefully. #typing:2s
-> END
- else:
We need to contact the police first.
-> END
}Progressive Discovery
// Initial photos on found phone
VAR photos_reviewed = false
== check_phone_photos ==
Let's see what's on this phone... #typing:3s
{not photos_reviewed:
There are several photos here. #typing:2s
This one looks recent. #gallery:recent-photo #delay:1s
And this one is from the club. #gallery:club-photo #delay:2s
Wait, what's this? #gallery:mysterious-photo #delay:3s #typing:2s
~ photos_reviewed = true
- else:
You've already seen all the photos.
}
-> ENDNext Steps
- Learn about News System for in-game news articles
- Explore Notes System for player clues and information
- See External Functions to check gallery state
- Understand Tag Reference for all available tags
- Review Project Structure for complete overview