VCD: Difference between revisions
mNo edit summary |
Le Glaconus (talk | contribs) m (maybe I should just reread myself) |
||
(26 intermediate revisions by 15 users not shown) | |||
Line 1: | Line 1: | ||
{{LanguageBar}} | |||
{{toc-right}} | |||
'''Valve Choreography Data''' ('''VCD''') is a proprietary file format used to store [[Choreography_Tool|choreography]] data. | |||
[[Category: | VCDs are authored in {{faceposer|4|nt=0}} and played in your map via the {{ent|logic_choreographed_scene}} entity. | ||
{{warning|The filename should contain only one period before the file extension; otherwise, the scene file cannot be found.}} | |||
{{note|VCD files must be compiled into {{ent|scenes.image}} before they can be used {{src07|since}} {{mapbase|not}}.}} | |||
== Format == | |||
VCD uses a plain-text format that superficially resembles a simplified version of {{wiki|JSON}} and can be edited with any text editor. Each file contains a nested list of objects that each have properties of their own. Properties can be strings, floats, or other objects and are denoted using a simple system of key-value pairs without separators. | |||
The basic notation is as follows: | |||
<source> | |||
// Very insightful comment | |||
object_type <object subtype> "name" <parameters> | |||
{ | |||
property "value" | |||
property value | |||
object_type <name> <parameters> | |||
{ | |||
property "value" | |||
} | |||
} | |||
</source> | |||
=== Objects === | |||
Each object is denoted using the syntax <code>type (subtype) "name" (parameters)</code>. Names, subtypes and paremeters may be optional depending on object type; the most simple declaration possible consists solely of an object type, such as with {{mono|event_ramp}}. Common objects are actors, channels, and events. | |||
==== Object types ==== | |||
{| class="wikitable" | |||
|- | |||
! Type !! Function !! Takes a name ? !! Parameters !! Example | |||
|- | |||
| {{mono|actor}} || A single actor, with channels as children || Yes || None || {{code|preset=1|actor "Alyx" { ... } }} | |||
|- | |||
| {{mono|channel}} || A single channel, with events as children || Yes || None || {{code|preset=1|channel "look at" { ... } }} | |||
|- | |||
| {{mono|event}} || A single event, possibly with an event ramp or tags as children || Yes || None || {{code|preset=1|event lookat "look at player" { ... } }} | |||
|- | |||
| {{mono|event_ramp}} || Used for storing ramp data for blending events || No || None || {{code|preset=1|event_ramp { ... } }} | |||
|- | |||
| {{mono|tags}} || Used for event timing tags || No || none || {{code|preset=1|tags { ... } }} | |||
|- | |||
| {{mono|absolutetags}} || Used for gestures || No || <code>playback_time</code> or <code>shifted_time</code> || {{code|preset=1|absolutetags shifted_time { ... } }} | |||
|- | |||
| {{mono|relativetags}} || Unimplemented, meant to be used for WAV events || No || Unknown || Unknown | |||
|- | |||
| {{mono|flexanimations}} || Used for flex animation data || No || See its dedicated section || {{code|preset=1|flexanimations <options> { ... } }} | |||
|- | |||
| {{mono|flextimingtags}} || Used for flex animation tags || No || None || {{code|preset=1|flextimingtags { ... } }} | |||
|- | |||
| {{mono|scalesettings}} || Obsolete way of saving UI data || No || None ||{{clr}} | |||
<source> | |||
scalesettings | |||
{ | |||
"CChoreoView" "25" | |||
"ExpressionTool" "100" | |||
"GestureTool" "100" | |||
"RampTool" "52" | |||
"SceneRampTool" "100" | |||
}</source> | |||
|} | |||
==== Object hierarchy/order ==== | |||
<small>{{todo|Make this pretty}}</small> | |||
* Actor(s) | |||
:* Channel(s) | |||
::* Event(s) | |||
:::* Event properties | |||
:::* Timing tags | |||
::* Channel properties | |||
:* Actor properties | |||
* Scene properties | |||
=== Properties === | |||
Properties of objects are denoted using their name (key) without parentheses, followed by a one or more values separated by spaces. Strings are enclosed in double quotes (" "), floats are not. Properties may be other objects, each with their own properties. The amount and type of available or required properties depend on the object type. | |||
A few properties are common across many object types, such as <code>time (float) (float)</code> and <code> param (string)</code>, indicating time codes and parameters that are to be passed to certain events. One such example is the <code>lookat</code> type event, which takes two time values for its position and duration or end point on the timeline and one param value to determine the entity an actor should look at: | |||
Properties not followed by any value are flags. For instance : <code>fixedlength</code>. Every flag is optional, but they might be forced to appear by {{faceposer|2|nt=0}}. | |||
<source> | |||
// From scenes/eli_lab/al_cmon.vcd | |||
... | |||
event lookat "look_player" | |||
{ | |||
time 0.053333 2.553333 | |||
param "!player" | |||
... | |||
} | |||
</source> | |||
=== Comments === | |||
Single-line comments may be created by prefacing a line with two slashes, for example: | |||
<source> | |||
// This is another insightful comment | |||
channel "look_at" | |||
{ | |||
... | |||
} | |||
</source> | |||
== Scene properties == | |||
=== Map name === | |||
;<code>mapname <[[string]]></code> : It is the name of the tied .bsp, which is used for loading entity names. It should be a relative path starting from the {{path|maps/}} folder. | |||
=== Window settings === | |||
<code>scalesettings</code>is an obsolete way of storing UI preferences, it doesn't have any effect on the UI as this data is stored in registry keys. It is however always written in VCD files by {{faceposer|2|nt=0}}. | |||
{{confirm|Does it work in {{SourceBranch|2004}} {{faceposer|1|nt=0}} ?}} | |||
'''Format''' : | |||
scalesettings | |||
{ | |||
"CChoreoView" "scale" | |||
<[[string]]> <[[string]]> | |||
} | |||
{{note|Window names are written in function of their names in the "View" tab.}} | |||
{{note|While every other window setting is optional, <code>CChoreoView</code> settings (the timeline window) are always written.}} | |||
=== Fps === | |||
;<code>fps <[[int]]></code> : It is the fps number used for snapping. Its default value is 60. In {{faceposer|2|nt=0}}, the minimum value acceptable is 1 and the maximum is the 32 bit signed integer limit (2'147'483'647). But when loaded, the values will be snapped to 10 and 240 respectively. | |||
=== Snap === | |||
;<code>snap <on/off></code> : It is used by {{faceposer|2|nt=0}} to save if the user wants snapping enabled, it is disabled by default. | |||
=== Ignore phonemes === | |||
{{todo}} | |||
{{confirm|{{SourceBranch|2007}} addition, doesn't seem to have any effect on {{faceposer|1|nt=0}} or the game. Cannot be toggled in {{faceposer|1|nt=0}}}} | |||
{{note|Off by default}} | |||
;<code>ignorePhonemes <on/off></code> | |||
== Actor properties == | |||
=== Model === | |||
;<code>faceposermodel <[[string]]></code> : It is the tied model name. | |||
{{note|It is stored as an absolute path, unlike <code>mapname</code>.}} | |||
=== Activity === | |||
;<code>active <[[bool]]></code> : It is used for the actor disabling feature. | |||
{{note|If it is 1, it will simply not be written.}} | |||
== Channel properties == | |||
=== Activity === | |||
;<code>active <[[bool]]></code> : It is used for the channel disabling feature. | |||
{{note|If it is 1, it will simply not be written.}} | |||
== Event subtypes == | |||
=== Subtype table === | |||
"1D events" are events with an end time of -1. | |||
{| class="wikitable" | |||
|- | |||
! Faceposer event type !! VCD subtype || Is 1D ? | |||
|- | |||
| Unspecified || {{mono|unspecified}} || --- | |||
|- | |||
| Expression || {{mono|expression}} || No | |||
|- | |||
| WAV File || {{mono|speak}} || No | |||
|- | |||
| Gesture || {{mono|gesture}} || No | |||
|- | |||
| Look at actor || {{mono|lookat}} || No | |||
|- | |||
| Move to actor || {{mono|moveto}} || No | |||
|- | |||
| Face actor || {{mono|face}} || No | |||
|- | |||
| Fire Trigger || {{mono|firetrigger}} || Yes | |||
|- | |||
| Generic(AI) || {{mono|generic}} || No | |||
|- | |||
| Sequence || {{mono|sequence}} || No | |||
|- | |||
| Flex animation || {{mono|flexanimation}} || No | |||
|- | |||
| Sub-scene || {{mono|subscene}} || No | |||
|- | |||
| Interrupt || {{mono|interrupt}} || No | |||
|- | |||
| Permit Responses || {{mono|permitresponses}} || No | |||
|- | |||
| Camera {{asw|since}} || {{mono|camera}} || No | |||
|- | |||
| Script {{asw|since}} || {{mono|script}} || Yes | |||
|- | |||
| The following subtypes are not treated as regular events by {{faceposer|1|nt=0}} || --- || --- | |||
|- | |||
| Section Pause || {{mono|section}} || Yes | |||
|- | |||
| Loop || {{mono|loop}} || Yes | |||
|- | |||
| Fire Completion || {{mono|stoppoint}} || Yes | |||
|- | |||
|} | |||
=== Common properties === | |||
Every event share these properties : | |||
;<code>time <[[float]]> <[[float]]></code> | |||
:{{note|If the second float is 0 (it is always written -1 by {{faceposer|2|nt=0}}) or lower, the event will act like a single point. It will disable the "End time" checkbox.}} | |||
;<code>param <[[string]]></code> | |||
;<code>[param2 <[[string]]>]</code> | |||
;<code>[param3 <[[string]]>]</code> | |||
;<code>fixedlength</code> : Makes resizing the event in {{faceposer|2|nt=0}} impossible. | |||
;<code>resumecondition</code> | |||
;<code>[active <[[bool]]>]</code> : <code>active</code> is simply nonexistent if set to 1. | |||
;<code>[tags { ... }]</code> | |||
:;<code><[[string]]> <[[float]]></code> | |||
:;<code>...</code> | |||
:The string represents a name, and the float a timestamp. | |||
:{{note|There can only be 128 tags for one event.}} | |||
;<code>[event_ramp { ... }]</code> | |||
:;<code><[[float]]> <[[float]]></code> | |||
:;<code>...</code> | |||
:The first float represents a timestamp, and the second a ratio. | |||
:{{note|There can only be 128 ramp values for one event.}} | |||
=== Unspecified and unhandled events === | |||
These events cannot be edited or exported, but can be moved and imported in {{faceposer|2|nt=0}}. The "Unspecified" event should never appear in {{faceposer|1|nt=0}} in normal circumstances. Every unhandled event (such as the "[[VCD#Script|Script]]" event) will acts in the same way in {{faceposer|1|nt=0}}, but they might function properly in-game. | |||
=== Expression === | |||
;<code>param <[[string]]></code> : Takes a phoneme class. | |||
:{{note|The most common phoneme classes to exist are <code>phonemes</code>, <code>phoneme_weak</code>, <code>phoneme_strong</code> because they are always precached.}} | |||
::{{note|The {{hl2series|4}} additionaly precaches <code>random</code> and <code>randomAlert</code>.}} | |||
;<code>param2 <[[string]]></code> : Takes a phoneme. | |||
'''Example :''' | |||
<source lang=js> | |||
expression "Expression event 1" | |||
{ | |||
time 0.000000 1.000000 | |||
param "phonemes" | |||
param2 "w" | |||
} | |||
</source> | |||
=== WAV File === | |||
;<code>param <[[string]]></code> : Takes a [[soundscript]] or a raw sound name. | |||
;<code>param2 <[[string]]></code> : Takes a float (in text form, between quotes) or <code>VOL_NORM</code>for its sound volume. | |||
:{{note|In {{SourceBranch|2004}}, <code>param2</code> has to take one of these following dB values : <br> | |||
:* <code>60dB</code> | |||
:* <code>65dB</code> | |||
:* <code>70dB</code> | |||
:* <code>75dB</code> | |||
:* <code>80dB</code> | |||
:* <code>85dB</code> | |||
:* <code>90dB</code> | |||
}} | |||
::{{confirm|Does it still work in games made after {{SourceBranch|2006}} ?}} | |||
;<code>fixedlength</code> : Is always set by {{faceposer|2|nt=0}} because sounds cannot be stretched. | |||
;<code>cctype <[[string]]></code> : Is used for closed captions, it can be <code>cc_master</code>, <code>cc_slave</code> or <code>cc_disabled</code>. | |||
:;<code>cc_slave <[[string]]></code> : Is related to combined audio files, it doesn't emit captions. | |||
::{{note|It can be changed in {{faceposer|1|nt=0}} with the "change selector" curved line pointing to one of the WAV events.}} | |||
:;<code>cc_disabled <[[string]]></code> : Is tied to the "Disable Captions" checkbox. | |||
;<code>cctoken <[[string]]></code> : Can be used to override caption tokens. It is most notably used for combined audio files. | |||
;<code>[cc_noattenuate]</code> : Is tied to the "Don't attenuate captions" checkbox. | |||
;<code>[cc_usingcombinedfile]</code> | |||
{{expand|title=Example :|{{clr}} | |||
<source lang=js> | |||
speak "Sound event 1" | |||
{ | |||
time 0.000000 3.407483 | |||
param "npc_citizen.question06" | |||
param2 "VOL_NORM" | |||
fixedlength | |||
cc_type "cc_master" | |||
cctoken "" | |||
cc_noattenuate | |||
} | |||
</source> | |||
}} | |||
=== Gesture === | |||
;<code>param <[[string]]></code> : Takes a sequence name. | |||
;<code>[synctofollowingestures]</code> | |||
;<code>absolutetags playback_time</code> : It is the data in the playback time section. | |||
:;<code>apex <[[float]]></code> | |||
:;<code>accent <[[float]]></code> | |||
:;<code>loop <[[float]]></code> | |||
:;<code>end <[[float]]></code> | |||
:;<code><[[string]]> <[[float]]></code> | |||
;<code>absolutetags shifted_time</code> : It is the data in the original time section. It shouldn't be modifiable in {{faceposer|2|nt=0}}. | |||
::{{note|It stores the data taken directly from the sequences' <code>[[$keyvalues]]</code> block. See [[Creating Faceposer gestures]] for more information.}} | |||
:;<code>apex <[[float]]></code> | |||
:;<code>accent <[[float]]></code> | |||
:;<code>loop <[[float]]></code> | |||
:;<code>end <[[float]]></code> | |||
:;<code><[[string]]> <[[float]]></code> | |||
:{{note|Tags have to be defined in both blocks.}} | |||
;<code>sequenceduration <[[float]]></code> : Defines the duration of the currently used sequence, it is read-only. | |||
{{expand|title=Example :|{{clr}} | |||
<source lang=js> | |||
event gesture "Gesture event 1" | |||
{ | |||
time 1.000000 4.502899 | |||
param "G_shrug" | |||
synctofollowinggesture | |||
absolutetags playback_time | |||
{ | |||
"apex" 0.077650 | |||
"accent" 0.116475 | |||
"loop" 0.155300 | |||
"end" 0.728225 | |||
"exampletag" 0.165000 | |||
} | |||
absolutetags shifted_time | |||
{ | |||
"apex" 0.160000 | |||
"accent" 0.240000 | |||
"loop" 0.320000 | |||
"end" 0.440000 | |||
"exampletag" 0.150000 | |||
} | |||
} | |||
</source> | |||
}} | |||
=== NULL gesture === | |||
Null gestures are simple gestures with <code>NULL</code> as their name. They can take every property regular gestures can take, but those will not be parsed. | |||
'''Example :''' | |||
<source lang=js> | |||
event gesture "NULL" | |||
{ | |||
time 0.000000 1.000000 | |||
param "" | |||
} | |||
</source> | |||
=== Look at actor === | |||
;<code>param <[[string]]></code> : Takes an actor name. | |||
;<code>[pitch <[[float]]>]</code> | |||
;<code>[yaw <[[float]]>]</code> | |||
{{modernConfirm|What is the lowest and highest accepted value for both ? Does it even do anything ? The [https://github.com/ValveSoftware/source-sdk-2013/blob/singleplayer/src/game/server/baseflex.cpp#L1513 code] doesn't seem to care about yaw and pitch.}} | |||
{{expand|title=Examples|{{clr}} | |||
'''Example 1 :''' | |||
<source lang=js> | |||
event lookat "Look at player" | |||
{ | |||
time 0.000000 1.0000000 | |||
param "!player" | |||
} | |||
</source> | |||
'''Example 2 :''' | |||
<source lang=js> | |||
event lookat "Look at desk" | |||
{ | |||
time 0.000000 1.000000 | |||
param "target_desk01" | |||
} | |||
</source> | |||
'''Example 3 :''' | |||
<source lang=js> | |||
event lookat "Look at marker" | |||
{ | |||
time 0.000000 1.000000 | |||
param "target_desk01" | |||
pitch 10 | |||
yaw -10 | |||
} | |||
</source> | |||
}} | |||
=== Move at actor === | |||
;<code>param <[[string]]></code> : Takes an actor name. | |||
;<code>param2 <[[string]]></code> : Takes a move type, it can be <code>Walk</code>, <code>Run</code> or <code>CrouchWalk</code>. | |||
:{{note|If a sequence name is specified, it will be used instead.}} | |||
;<code>[param3 <[[string]]>]</code> : Takes an actor name. | |||
{{todo|Find what <code>param3</code> really does}} | |||
;<code>distancetotarget <[[float]]></code> | |||
:{{note|The maximum stop distance in {{faceposer|2|nt=0}} is 200, higher values are still valid, however.}} | |||
;<code>[forceshortmovement]</code> | |||
{{expand|title=Examples :|{{clr}} | |||
'''Example 1 :''' | |||
<source lang=js> | |||
event moveto "Run to player" | |||
{ | |||
time 0.000000 1.0000000 | |||
param "!player" | |||
param2 "Run" | |||
} | |||
</source> | |||
'''Example 2 :''' | |||
<source lang=js> | |||
event moveto "Crouch-walk to desk" | |||
{ | |||
time 0.000000 1.0000000 | |||
param "target_desk02" | |||
param2 "CrouchWalk" | |||
distancetotarget 15.00 | |||
forceshortmovement | |||
} | |||
</source> | |||
}} | |||
=== Face actor === | |||
;<code>param <[[string]]></code> : Takes an actor name. | |||
;<code>[lockbodyfacing]</code> : Makes the actor's legs not move. | |||
'''Example :''' | |||
<source lang=js> | |||
event moveto "Face player" | |||
{ | |||
time 0.000000 1.0000000 | |||
param "!player" | |||
lockbodyfacing | |||
} | |||
</source> | |||
=== Fire Trigger === | |||
;<code>param <[[string]]></code> : Takes a number ranging from 1 to 16. It is meant to be used in conjunction with {{ent|logic_choreographed_scene}}'s ''OnTriggerX'' output. | |||
'''Example :''' | |||
<source lang=js> | |||
event firetrigger "Fire Trigger event" | |||
{ | |||
time 0.000000 -1.000000 | |||
param "5" | |||
} | |||
</source> | |||
=== Generic(AI) === | |||
;<code>param <[[string]]></code> : Takes an AI action. | |||
The AI actions can be : | |||
{| class="wikitable" | |||
|- | |||
! Action name !! Takes a target ? | |||
|- | |||
| {{mono|AI_BLINK}} || No | |||
|- | |||
| {{mono|AI_HOLSTER}} || No | |||
|- | |||
| {{mono|AI_UNHOLSTER}} || No | |||
|- | |||
| {{mono|AI_AIM}} || Yes | |||
|- | |||
| {{mono|AI_RANDOMLOOK}} || No | |||
|- | |||
| {{mono|AI_RANDOMFACEFLEX}} || No | |||
|- | |||
| {{mono|AI_RANDOMHEADFLEX}} || No | |||
|- | |||
| {{mono|AI_IGNORECOLLISION}} || Yes | |||
|- | |||
| {{mono|AI_DISABLEAI}} || No | |||
|- | |||
| {{mono|debugtext}} || No | |||
|} | |||
{{note|<code>debugtext</code> takes one parameter in an untraditional way, it is taken after its name. <code>param "debugtext Hi !"</code> for instance.}} | |||
;<code>[param2 <[[string]]></code> : Takes an actor name used as a target. | |||
{{expand|title=Examples :|{{clr}} | |||
'''Example 1 :''' | |||
<source lang=js> | |||
event generic "Holster event" | |||
{ | |||
time 0.000000 1.000000 | |||
param "AI_HOLSTER" | |||
} | |||
</source> | |||
'''Example 2 :''' | |||
<source lang=js> | |||
event generic "Aim at Alyx" | |||
{ | |||
time 0.000000 1.000000 | |||
param "AI_AIM" | |||
param2 "Alyx" | |||
} | |||
</source> | |||
'''Example 3 :''' | |||
<source lang=js> | |||
event generic "Show debug text" | |||
{ | |||
time 0.000000 1.000000 | |||
param "debugtext Hi !" | |||
} | |||
</source> | |||
}} | |||
=== Sequence === | |||
;<code>param <[[string]]></code> : Takes a sequence name. | |||
;<code>fixedlength</code> : Is always set by {{faceposer|2|nt=0}} because only gestures can be resized. | |||
'''Example :''' | |||
<source lang=js> | |||
event generic "Play animation" | |||
{ | |||
time 0.000000 1.833334 | |||
param "ThrowItem" | |||
fixedlength | |||
} | |||
</source> | |||
=== Flex animation === | |||
Before starting with the suvtype definition, let's define what curvetypes are. | |||
* A curve type always starts with <code>curve_</code>. | |||
* A curvetype takes two curve types separated by <code>_to_</code> | |||
* They can be : | |||
{| class="wikitable" | |||
|- | |||
| {{mono|default}} | |||
|- | |||
| {{mono|catmullrom_normalize_x}} | |||
|- | |||
| {{mono|easein}} | |||
|- | |||
| {{mono|easeout}} | |||
|- | |||
| {{mono|easeinout}} | |||
|- | |||
| {{mono|bspline}} | |||
|- | |||
| {{mono|linear_interp}} | |||
|- | |||
| {{mono|kochanek}} | |||
|- | |||
| {{mono|kochanek_early}} | |||
|- | |||
| {{mono|kochanek_late}} | |||
|- | |||
| {{mono|simple_cubic}} | |||
|- | |||
| {{mono|catmullrom}} | |||
|- | |||
| {{mono|catmullrom_normalize}} | |||
|- | |||
| {{mono|catmullrom_tangent}} | |||
|- | |||
| {{mono|exponential_decay}} | |||
|- | |||
| {{mono|hold}} | |||
|} | |||
'''Example :''' | |||
<code>"curve_catmullrom_normalize_x_to_curve_catmullrom_normalize_x"</code> | |||
;<code>param <[[string]]></code> : Is unused, it is therefore left as empty quotes. | |||
;<code>flexanimations samples_use_time defaultcurvetype=<curvetype></code> | |||
:{{note|<code>defaultcurvetype</code> will always be set to <code>curve_catmullrom_normalize_x_to_curve_catmullrom_normalize_x</code> by default.}} | |||
:{{confirm|Is <code>samples_use_time</code> optional ?}} | |||
:;<code><[[string]]> [disabled] [leftedge <curvetype> <[[float]]>] [rightedge <curvetype> <[[float]]>] [combo]</code> : The first string is a flex controller name. | |||
:{{note|There can only be 128 flex animation keyframes.}} | |||
::;<code><[[float]]> <[[float]]> [<curvetype>]</code> | |||
::;<code>[<[[float]]> <[[float]]> [<curvetype>]]</code> | |||
::{{note|The second block is only created if the flex controller supports combo editing.}} | |||
;<code>flextimingtags</code> | |||
;<code><[[string]]> <[[float]]> <[[bool]]></code> : The string is the tag name, the float is a duration, and the boolean a lock state. | |||
:{{note|There can only be 128 flex timing tags.}} | |||
{{expand|title=Example :|{{clr}} | |||
<source lang=js> | |||
event flexanimation "Flex event" | |||
{ | |||
time 0.000000 5.000000 | |||
param "" | |||
flexanimations samples_use_time defaultcurvetype=curve_catmullrom_normalize_x_to_curve_catmullrom_normalize_x | |||
{ | |||
"lid_tightener" combo | |||
{ | |||
0.4000 0.6100 "curve_easein_to_curve_easeout" | |||
2.4000 0.1200 "curve_linear_interp_to_curve_linear_interp" | |||
4.4000 0.5900 "curve_easein_to_curve_easeout" | |||
} | |||
{ | |||
1.0000 0.7700 "curve_bspline_to_curve_bspline" | |||
1.8000 0.2700 "curve_bspline_to_curve_bspline" | |||
3.0000 0.7500 "curve_bspline_to_curve_bspline" | |||
4.0000 0.2900 "curve_bspline_to_curve_bspline" | |||
} | |||
"smile" leftedge curve_default_to_curve_hold 0.500 rightedge curve_kochanek_late_to_curve_default 0.250 | |||
{ | |||
0.8000 0.7100 | |||
1.6000 0.2700 "curve_easein_to_curve_easeout" | |||
2.2000 0.6000 "curve_easein_to_curve_easein" | |||
3.0000 0.2600 "curve_easeout_to_curve_easeout" | |||
3.6000 0.5900 "curve_linear_interp_to_curve_linear_interp" | |||
} | |||
} | |||
} | |||
} | |||
</source> | |||
}} | |||
=== Sub-scene === | |||
;<code>param <[[string]]></code> : Takes a path. | |||
;<code>fixedlength</code> : Is always set by {{faceposer|2|nt=0}} because the length of the sub-scene is defined by the scene itself. | |||
{{confirm|Is the sub-scene path absolute ? I didn't see a single sub-scene in all of the first party games VCDs}} | |||
=== Interrupt === | |||
;<code>param <[[string]]></code> : Takes no parameter, it isn't parsed. | |||
:{{note|Even if <code>param</code> doesn't need to be specified, an empty dropdown exists for it in {{faceposer|1|nt=0}}.}} | |||
'''Example :''' | |||
<source lang=js> | |||
event generic "Interrupt event" | |||
{ | |||
time 0.000000 1.000000 | |||
param "" | |||
} | |||
</source> | |||
=== Permit Responses === | |||
;<code>param <[[string]]></code> : Takes no parameter, it isn't parsed. | |||
'''Example :''' | |||
<source lang=js> | |||
event permitresponses "Permit responses event" | |||
{ | |||
time 0.000000 1.000000 | |||
param "" | |||
} | |||
</source> | |||
=== Camera === | |||
{{since|{{asw}}}} | |||
;<code>param <[[string]]></code> : Is a "shot type", it is meant to be used as a simple [[string]]. Called "Camera AI event" by {{faceposer|2|nt=0}}. | |||
;<code>param2 <[[string]]></code> : Takes an actor name. | |||
;<code>param3 <[[string]]></code> : Takes an actor name. | |||
This event finds the first {{ent|point_viewcontrol}}</code> (''NOT'' the closest, the first entity in the entity list) and call the <code>ScriptCameraShot()</code> Vscript function on it. This function has the following syntax : <code>void ScriptCameraShot(string ''pszShotType'', handle ''pSceneEntity'', handle ''pActor1'', handle ''pActor2'', float ''duration'')</code>. | |||
{{note|While it is not used anywhere in {{asw}} or {{portal2}}, it is still functional.}} | |||
'''Example :''' | |||
<source lang=js> | |||
event camera "Camera event" | |||
{ | |||
time 1.000000 5.000000 | |||
param "Hi !" | |||
param2 "!target1" | |||
param3 "!target2" | |||
} | |||
</source> | |||
=== Script === | |||
{{since|{{asw}}}} | |||
{{warning|This event is not handled by {{faceposer|2|nt=0}} ! It must be added in with a text editor.}} | |||
;<code>param <[[string]]></code> : Takes a [[targetname]]. | |||
;<code>param2 <[[string]]></code> : Takes a [[Vscript]] function name. | |||
;<code>param3 <[[string]]></code> : Takes a string meant to be used as a function argument. | |||
This event triggers the function referenced in <code>param2</code> from the entity scripts of the entity referenced in <code>param</code> with the arguements written in <code>param3</code> as it follows : <code>void FunctionName(handle ''pActor'', handle ''pThisSceneEntity'', string ''param3'', float ''duration'')</code>. | |||
{{note|While it is not used anywhere in {{asw}} or {{portal2}}, it is still functional.}} | |||
'''Example :''' | |||
<source lang=js> | |||
event script "Script event" | |||
{ | |||
time 1.000000 -1.000000 | |||
param "scriptent" | |||
param2 "TestFunc" | |||
param3 "Hi !" | |||
} | |||
</source> | |||
=== Section Pause === | |||
;<code>param <[[string]]></code> : Takes options, they can diverge in two different branches in function of if {{faceposer|1|nt=0}}'s "Automatically" flag is checked : | |||
::If the flag is not checked : | |||
::;<code>param "noaction"</code> | |||
::If the flag is checked : | |||
::;<code>param "automate Resume/Cancel <[[float]]>"</code> : The float is a duration. | |||
{{expand|title=Examples :|{{clr}} | |||
'''Example 1 :''' | |||
<source lang=js> | |||
event section "Pause point 1" | |||
{ | |||
time 1.000000 -1.000000 | |||
param "automate Resume 2.000000" | |||
} | |||
</source> | |||
'''Example 2 :''' | |||
<source lang=js> | |||
event section "Pause point 2" | |||
{ | |||
time 1.000000 -1.000000 | |||
param "noaction" | |||
} | |||
</source> | |||
}} | |||
=== Loop === | |||
;<code>param <[[string]]></code> : Takes a timestamp, which is the loop back point. | |||
;<code>loopcount <[[string]]></code> : Is infinite if set to -1. | |||
'''Example :''' | |||
<source lang=js> | |||
event loop "Loop" | |||
{ | |||
time 1.000000 -1.000000 | |||
param "2.000000" | |||
loopcount "5" | |||
} | |||
</source> | |||
=== Fire Completion === | |||
;<code>param <[[string]]></code> : Doesn't take any parameter, it is only written as <code>noaction</code>. | |||
'''Example :''' | |||
<source lang=js> | |||
event stoppoint "Fire Completion" | |||
{ | |||
time 1.000000 -1.000000 | |||
param "noaction" | |||
} | |||
</source> | |||
== See also == | |||
* {{ent|logic_choreographed_scene}} | |||
* [[scenes.image]] | |||
* [[VCE]] | |||
* [[Choreography Tool reference]] | |||
[[Category:Choreography]] | |||
[[Category:File formats]] |
Latest revision as of 11:55, 8 July 2025
Valve Choreography Data (VCD) is a proprietary file format used to store choreography data.
VCDs are authored in Faceposer and played in your map via the logic_choreographed_scene entity.




Format
VCD uses a plain-text format that superficially resembles a simplified version of JSON and can be edited with any text editor. Each file contains a nested list of objects that each have properties of their own. Properties can be strings, floats, or other objects and are denoted using a simple system of key-value pairs without separators.
The basic notation is as follows:
// Very insightful comment
object_type <object subtype> "name" <parameters>
{
property "value"
property value
object_type <name> <parameters>
{
property "value"
}
}
Objects
Each object is denoted using the syntax type (subtype) "name" (parameters)
. Names, subtypes and paremeters may be optional depending on object type; the most simple declaration possible consists solely of an object type, such as with event_ramp. Common objects are actors, channels, and events.
Object types
Type | Function | Takes a name ? | Parameters | Example |
---|---|---|---|---|
actor | A single actor, with channels as children | Yes | None | actor "Alyx" { ... } |
channel | A single channel, with events as children | Yes | None | channel "look at" { ... } |
event | A single event, possibly with an event ramp or tags as children | Yes | None | event lookat "look at player" { ... } |
event_ramp | Used for storing ramp data for blending events | No | None | event_ramp { ... } |
tags | Used for event timing tags | No | none | tags { ... } |
absolutetags | Used for gestures | No | playback_time or shifted_time |
absolutetags shifted_time { ... } |
relativetags | Unimplemented, meant to be used for WAV events | No | Unknown | Unknown |
flexanimations | Used for flex animation data | No | See its dedicated section | flexanimations <options> { ... } |
flextimingtags | Used for flex animation tags | No | None | flextimingtags { ... } |
scalesettings | Obsolete way of saving UI data | No | None |
scalesettings
{
"CChoreoView" "25"
"ExpressionTool" "100"
"GestureTool" "100"
"RampTool" "52"
"SceneRampTool" "100"
} |
Object hierarchy/order
- Actor(s)
- Channel(s)
- Event(s)
- Event properties
- Timing tags
- Channel properties
- Actor properties
- Scene properties
Properties
Properties of objects are denoted using their name (key) without parentheses, followed by a one or more values separated by spaces. Strings are enclosed in double quotes (" "), floats are not. Properties may be other objects, each with their own properties. The amount and type of available or required properties depend on the object type.
A few properties are common across many object types, such as time (float) (float)
and param (string)
, indicating time codes and parameters that are to be passed to certain events. One such example is the lookat
type event, which takes two time values for its position and duration or end point on the timeline and one param value to determine the entity an actor should look at:
Properties not followed by any value are flags. For instance : fixedlength
. Every flag is optional, but they might be forced to appear by Faceposer.
// From scenes/eli_lab/al_cmon.vcd
...
event lookat "look_player"
{
time 0.053333 2.553333
param "!player"
...
}
Comments
Single-line comments may be created by prefacing a line with two slashes, for example:
// This is another insightful comment
channel "look_at"
{
...
}
Scene properties
Map name
mapname <string>
- It is the name of the tied .bsp, which is used for loading entity names. It should be a relative path starting from the
maps/
folder.
Window settings
scalesettings
is an obsolete way of storing UI preferences, it doesn't have any effect on the UI as this data is stored in registry keys. It is however always written in VCD files by Faceposer.


Format :
scalesettings { "CChoreoView" "scale" <string> <string> }


CChoreoView
settings (the timeline window) are always written.Fps
fps <int>
- It is the fps number used for snapping. Its default value is 60. In
Faceposer, the minimum value acceptable is 1 and the maximum is the 32 bit signed integer limit (2'147'483'647). But when loaded, the values will be snapped to 10 and 240 respectively.
Snap
snap <on/off>
- It is used by
Faceposer to save if the user wants snapping enabled, it is disabled by default.
Ignore phonemes
[Todo]



ignorePhonemes <on/off>
Actor properties
Model
faceposermodel <string>
- It is the tied model name.

mapname
.Activity
active <bool>
- It is used for the actor disabling feature.

Channel properties
Activity
active <bool>
- It is used for the channel disabling feature.

Event subtypes
Subtype table
"1D events" are events with an end time of -1.
Faceposer event type | VCD subtype | Is 1D ? |
---|---|---|
Unspecified | unspecified | --- |
Expression | expression | No |
WAV File | speak | No |
Gesture | gesture | No |
Look at actor | lookat | No |
Move to actor | moveto | No |
Face actor | face | No |
Fire Trigger | firetrigger | Yes |
Generic(AI) | generic | No |
Sequence | sequence | No |
Flex animation | flexanimation | No |
Sub-scene | subscene | No |
Interrupt | interrupt | No |
Permit Responses | permitresponses | No |
Camera (in all games since ![]() |
camera | No |
Script (in all games since ![]() |
script | Yes |
The following subtypes are not treated as regular events by Faceposer | --- | --- |
Section Pause | section | Yes |
Loop | loop | Yes |
Fire Completion | stoppoint | Yes |
Common properties
Every event share these properties :
time <float> <float>
Note:If the second float is 0 (it is always written -1 by
Faceposer) or lower, the event will act like a single point. It will disable the "End time" checkbox.
param <string>
[param2 <string>]
[param3 <string>]
fixedlength
- Makes resizing the event in
Faceposer impossible.
resumecondition
[active <bool>]
active
is simply nonexistent if set to 1.[tags { ... }]
- The string represents a name, and the float a timestamp.
Note:There can only be 128 tags for one event.
[event_ramp { ... }]
- The first float represents a timestamp, and the second a ratio.
Note:There can only be 128 ramp values for one event.
Unspecified and unhandled events
These events cannot be edited or exported, but can be moved and imported in Faceposer. The "Unspecified" event should never appear in Faceposer in normal circumstances. Every unhandled event (such as the "Script" event) will acts in the same way in Faceposer, but they might function properly in-game.
Expression
param <string>
- Takes a phoneme class.
Note:The most common phoneme classes to exist are
phonemes
,phoneme_weak
,phoneme_strong
because they are always precached.Note:The
Half-Life 2 series additionaly precaches
random
andrandomAlert
.
param2 <string>
- Takes a phoneme.
Example :
expression "Expression event 1"
{
time 0.000000 1.000000
param "phonemes"
param2 "w"
}
WAV File
param <string>
- Takes a soundscript or a raw sound name.
param2 <string>
- Takes a float (in text form, between quotes) or
VOL_NORM
for its sound volume. Note:In
Source 2004,
param2
has to take one of these following dB values :
60dB
65dB
70dB
75dB
80dB
85dB
90dB
Confirm:Does it still work in games made after
Source 2006 ?
fixedlength
- Is always set by
Faceposer because sounds cannot be stretched.
cctype <string>
- Is used for closed captions, it can be
cc_master
,cc_slave
orcc_disabled
.
cctoken <string>
- Can be used to override caption tokens. It is most notably used for combined audio files.
[cc_noattenuate]
- Is tied to the "Don't attenuate captions" checkbox.
[cc_usingcombinedfile]
speak "Sound event 1"
{
time 0.000000 3.407483
param "npc_citizen.question06"
param2 "VOL_NORM"
fixedlength
cc_type "cc_master"
cctoken ""
cc_noattenuate
}
|
Gesture
param <string>
- Takes a sequence name.
[synctofollowingestures]
absolutetags playback_time
- It is the data in the playback time section.
absolutetags shifted_time
- It is the data in the original time section. It shouldn't be modifiable in
Faceposer.
Note:It stores the data taken directly from the sequences'
$keyvalues
block. See Creating Faceposer gestures for more information.apex <float>
accent <float>
loop <float>
end <float>
<string> <float>
Note:Tags have to be defined in both blocks.
sequenceduration <float>
- Defines the duration of the currently used sequence, it is read-only.
event gesture "Gesture event 1"
{
time 1.000000 4.502899
param "G_shrug"
synctofollowinggesture
absolutetags playback_time
{
"apex" 0.077650
"accent" 0.116475
"loop" 0.155300
"end" 0.728225
"exampletag" 0.165000
}
absolutetags shifted_time
{
"apex" 0.160000
"accent" 0.240000
"loop" 0.320000
"end" 0.440000
"exampletag" 0.150000
}
}
|
NULL gesture
Null gestures are simple gestures with NULL
as their name. They can take every property regular gestures can take, but those will not be parsed.
Example :
event gesture "NULL"
{
time 0.000000 1.000000
param ""
}
Look at actor

Example 1 : event lookat "Look at player"
{
time 0.000000 1.0000000
param "!player"
}
Example 2 : event lookat "Look at desk"
{
time 0.000000 1.000000
param "target_desk01"
}
Example 3 : event lookat "Look at marker"
{
time 0.000000 1.000000
param "target_desk01"
pitch 10
yaw -10
}
|
Move at actor
param <string>
- Takes an actor name.
param2 <string>
- Takes a move type, it can be
Walk
,Run
orCrouchWalk
. Note:If a sequence name is specified, it will be used instead.
[param3 <string>]
- Takes an actor name.
param3
really doesdistancetotarget <float>
Note:The maximum stop distance in
Faceposer is 200, higher values are still valid, however.
[forceshortmovement]
Example 1 : event moveto "Run to player"
{
time 0.000000 1.0000000
param "!player"
param2 "Run"
}
Example 2 : event moveto "Crouch-walk to desk"
{
time 0.000000 1.0000000
param "target_desk02"
param2 "CrouchWalk"
distancetotarget 15.00
forceshortmovement
}
|
Face actor
param <string>
- Takes an actor name.
[lockbodyfacing]
- Makes the actor's legs not move.
Example :
event moveto "Face player"
{
time 0.000000 1.0000000
param "!player"
lockbodyfacing
}
Fire Trigger
param <string>
- Takes a number ranging from 1 to 16. It is meant to be used in conjunction with logic_choreographed_scene's OnTriggerX output.
Example :
event firetrigger "Fire Trigger event"
{
time 0.000000 -1.000000
param "5"
}
Generic(AI)
param <string>
- Takes an AI action.
The AI actions can be :
Action name | Takes a target ? |
---|---|
AI_BLINK | No |
AI_HOLSTER | No |
AI_UNHOLSTER | No |
AI_AIM | Yes |
AI_RANDOMLOOK | No |
AI_RANDOMFACEFLEX | No |
AI_RANDOMHEADFLEX | No |
AI_IGNORECOLLISION | Yes |
AI_DISABLEAI | No |
debugtext | No |

debugtext
takes one parameter in an untraditional way, it is taken after its name. param "debugtext Hi !"
for instance.
[param2 <string>
- Takes an actor name used as a target.
Example 1 : event generic "Holster event"
{
time 0.000000 1.000000
param "AI_HOLSTER"
}
Example 2 : event generic "Aim at Alyx"
{
time 0.000000 1.000000
param "AI_AIM"
param2 "Alyx"
}
Example 3 : event generic "Show debug text"
{
time 0.000000 1.000000
param "debugtext Hi !"
}
|
Sequence
param <string>
- Takes a sequence name.
fixedlength
- Is always set by
Faceposer because only gestures can be resized.
Example :
event generic "Play animation"
{
time 0.000000 1.833334
param "ThrowItem"
fixedlength
}
Flex animation
Before starting with the suvtype definition, let's define what curvetypes are.
- A curve type always starts with
curve_
. - A curvetype takes two curve types separated by
_to_
- They can be :
default |
catmullrom_normalize_x |
easein |
easeout |
easeinout |
bspline |
linear_interp |
kochanek |
kochanek_early |
kochanek_late |
simple_cubic |
catmullrom |
catmullrom_normalize |
catmullrom_tangent |
exponential_decay |
hold |
Example :
"curve_catmullrom_normalize_x_to_curve_catmullrom_normalize_x"
param <string>
- Is unused, it is therefore left as empty quotes.
flexanimations samples_use_time defaultcurvetype=<curvetype>
Note:
defaultcurvetype
will always be set tocurve_catmullrom_normalize_x_to_curve_catmullrom_normalize_x
by default.Confirm:Is
samples_use_time
optional ?Note:There can only be 128 flex animation keyframes.
flextimingtags
<string> <float> <bool>
- The string is the tag name, the float is a duration, and the boolean a lock state.
Note:There can only be 128 flex timing tags.
event flexanimation "Flex event"
{
time 0.000000 5.000000
param ""
flexanimations samples_use_time defaultcurvetype=curve_catmullrom_normalize_x_to_curve_catmullrom_normalize_x
{
"lid_tightener" combo
{
0.4000 0.6100 "curve_easein_to_curve_easeout"
2.4000 0.1200 "curve_linear_interp_to_curve_linear_interp"
4.4000 0.5900 "curve_easein_to_curve_easeout"
}
{
1.0000 0.7700 "curve_bspline_to_curve_bspline"
1.8000 0.2700 "curve_bspline_to_curve_bspline"
3.0000 0.7500 "curve_bspline_to_curve_bspline"
4.0000 0.2900 "curve_bspline_to_curve_bspline"
}
"smile" leftedge curve_default_to_curve_hold 0.500 rightedge curve_kochanek_late_to_curve_default 0.250
{
0.8000 0.7100
1.6000 0.2700 "curve_easein_to_curve_easeout"
2.2000 0.6000 "curve_easein_to_curve_easein"
3.0000 0.2600 "curve_easeout_to_curve_easeout"
3.6000 0.5900 "curve_linear_interp_to_curve_linear_interp"
}
}
}
}
|
Sub-scene
param <string>
- Takes a path.
fixedlength
- Is always set by
Faceposer because the length of the sub-scene is defined by the scene itself.

Interrupt
param <string>
- Takes no parameter, it isn't parsed.
Note:Even if
param
doesn't need to be specified, an empty dropdown exists for it in Faceposer.
Example :
event generic "Interrupt event"
{
time 0.000000 1.000000
param ""
}
Permit Responses
param <string>
- Takes no parameter, it isn't parsed.
Example :
event permitresponses "Permit responses event"
{
time 0.000000 1.000000
param ""
}
Camera
(in all games since )
param <string>
- Is a "shot type", it is meant to be used as a simple string. Called "Camera AI event" by
Faceposer.
param2 <string>
- Takes an actor name.
param3 <string>
- Takes an actor name.
This event finds the first point_viewcontrol (NOT the closest, the first entity in the entity list) and call the ScriptCameraShot()
Vscript function on it. This function has the following syntax : void ScriptCameraShot(string pszShotType, handle pSceneEntity, handle pActor1, handle pActor2, float duration)
.
Example :
event camera "Camera event"
{
time 1.000000 5.000000
param "Hi !"
param2 "!target1"
param3 "!target2"
}
Script
(in all games since )


param <string>
- Takes a targetname.
param2 <string>
- Takes a Vscript function name.
param3 <string>
- Takes a string meant to be used as a function argument.
This event triggers the function referenced in param2
from the entity scripts of the entity referenced in param
with the arguements written in param3
as it follows : void FunctionName(handle pActor, handle pThisSceneEntity, string param3, float duration)
.
Example :
event script "Script event"
{
time 1.000000 -1.000000
param "scriptent"
param2 "TestFunc"
param3 "Hi !"
}
Section Pause
param <string>
- Takes options, they can diverge in two different branches in function of if Faceposer's "Automatically" flag is checked :
- If the flag is not checked :
param "noaction"
- If the flag is checked :
param "automate Resume/Cancel <float>"
- The float is a duration.
- If the flag is not checked :
Example 1 : event section "Pause point 1"
{
time 1.000000 -1.000000
param "automate Resume 2.000000"
}
Example 2 : event section "Pause point 2"
{
time 1.000000 -1.000000
param "noaction"
}
|
Loop
param <string>
- Takes a timestamp, which is the loop back point.
loopcount <string>
- Is infinite if set to -1.
Example :
event loop "Loop"
{
time 1.000000 -1.000000
param "2.000000"
loopcount "5"
}
Fire Completion
param <string>
- Doesn't take any parameter, it is only written as
noaction
.
Example :
event stoppoint "Fire Completion"
{
time 1.000000 -1.000000
param "noaction"
}