Steamworks Documentation
Steam Timelines

Overview

Steam Timeline is a feature that exists within the Game Recording framework designed to make it easy for players to find, save and share gameplay moments.

https://youtu.be/YwBD0E4-EsI

Requirements

Your game does not need to do anything special for the Game Recording to work, however the experience can be enhanced by adding some simple API calls to your game.

The calls are primarily used to pass information to the Steam Timeline UI
NOTE: The overlay is automatically disabled for 'Software' app types. If you need the overlay enabled, you can do so by:
  1. Making sure your Steam account has the Edit App Metadata permission
  2. Navigate from the App's landing page to > Edit Steamworks Settings > Installation tab > General Installation
  3. Check box for Enable Steam Overlay for Application
  4. Publish

Integrating Steam Timeline functionality in your app


The Steam Timeline API calls can be found here: ISteamTimeline

Timeline Icons

Steam Timelines includes a set of icons ready to use for your game. You can reference them in AddTimelineEvent using the prefix "steam_". Additionally, you can generate number icons from 0-99 using the format "steam_[number]", e.g. "steam_0", "steam_1", etc.

You can also upload custom icons for your product on the Steamworks site.

Default set of icons:

IconNameDescription
steam_markerMarker
steam_achievementAchievement
steam_attackAttack
steam_boltBolt
steam_bookmarkBookmark
steam_bugBug
steam_cartCart
steam_cautionCaution
steam_chatChat
steam_checkmarkCheckmark
steam_chestChest
steam_circleCircle
steam_combatCombat
steam_completedCompleted
steam_crownCrown
steam_deathDeath
steam_defendDefend
steam_diamondDiamond
steam_editEdit
steam_effectEffect
steam_explosionExplosion
steam_fixFix
steam_flagFlag
steam_gemGem
steam_groupGroup
steam_heartHeart
steam_infoInfo
steam_invalidInvalid
steam_minusMinus
steam_pairPair
steam_personPerson
steam_plusPlus
steam_purchasePurchase
steam_questionQuestion
steam_ribbonRibbon
steam_screenshotScreenshot
steam_scrollScroll
steam_squareSquare
steam_starStar
steam_starburstStarburst
steam_timerTimer
steam_transferTransfer
steam_triangleTriangle
steam_trophyTrophy
steam_viewView
steam_xX

Example Code

Below is a code sample for integrating Steam Timeline with Left 4 Dead. This code was used in the Steamworks video introduction linked above.

//=========== Copyright (c) Valve Corporation, All rights reserved. =========== #include "cbase.h" #include "igamesystem.h" #include "gameeventlistener.h" #include "steam/steam_api.h" #include "steam/isteamtimeline.h" #include "clientterrorplayer.h" #include "fmtstr.h" //----------------------------------------------------------------------------- class L4DSteamVideo : public CAutoGameSystem, public CGameEventListener { public: // CAutoGameSystem virtual bool Init(); virtual void Shutdown(); // CGameEventListener virtual void FireGameEvent( IGameEvent* pEvent ); private: bool m_bEnabled; }; //----------------------------------------------------------------------------- bool L4DSteamVideo::Init() { ISteamTimeline *pSteamTimeline = SteamTimeline(); if ( pSteamTimeline ) { pSteamTimeline->SetTimelineGameMode( k_ETimelineGameMode_Staging ); // Create the event listeners ListenForGameEvent( "survival_round_start" ); ListenForGameEvent( "round_end" ); ListenForGameEvent( "heal_success" ); ListenForGameEvent( "player_incapacitated_start" ); } // if pSteamVideo is null then the client's steam API is not recent enough // in this case, we still init the system it just doesn't do anything m_bEnabled = pSteamTimeline != nullptr; return true; } //----------------------------------------------------------------------------- void L4DSteamVideo::Shutdown() { StopListeningForAllEvents(); m_bEnabled = false; } //----------------------------------------------------------------------------- void L4DSteamVideo::FireGameEvent( IGameEvent *pEvent ) { if ( !m_bEnabled ) return; int userid = pEvent->GetInt( "userid", 0 ); if ( userid != 0 && userid != C_BasePlayer::GetLocalPlayer()->GetUserID() ) return; const char* eventname = pEvent->GetName(); if ( V_strcmp( "survival_round_start", eventname ) == 0 ) { SteamTimeline()->SetTimelineGameMode( k_ETimelineGameMode_Playing ); } else if ( V_strcmp( "round_end", eventname ) == 0 ) { SteamTimeline()->SetTimelineGameMode( k_ETimelineGameMode_Staging ); } else if ( V_strcmp( "heal_success", eventname ) == 0 ) { SteamTimeline()->AddTimelineEvent( "medkit32", "Healed", CFmtStr( "Restored %d Health", pEvent->GetInt( "health_restored" ) ), 0, -5.f, 5.f, k_ETimelineEventClipPriority_Standard ); } else if ( V_strcmp( "player_incapacitated_start", eventname ) == 0 ) { C_TerrorPlayer* pAttacker = (C_TerrorPlayer*)UTIL_PlayerByUserId( pEvent->GetInt( "userid" ) ); const char* pszAttacker = pAttacker ? pAttacker->GetCharacterDisplayName() : "the world"; SteamTimeline()->AddTimelineEvent( "foo", "Incapacitated", CFmtStr( "INCAPACITATED by %s", pszAttacker ), 0, 0.f, 0.f, k_ETimelineEventClipPriority_Featured ); } } static L4DSteamVideo s_steamVideo;