Skip to content

Judge Line

Introduction to the fundamental component in chart: Judge Line.

Note

Compatibility level for each field is specified individually.

JSON Example

json
{
  "TextureData": null,
  "IsGifTexture": false,
  "XMoveEvents": [],
  "YMoveEvents": [],
  "RotateEvents": [],
  "AlphaEvents": [],
  "SpeedEvents": [],
  "Notes": [],
  "FatherIndex": -1,
  "RotateWithFather": true,
  "IsCover": true,
  "AttachUi": "None",
  "Anchor": [
    0.5,
    0.5,
    0.5,
    0.5
  ],
  "BpmFactor": 1.0,
  "ZOrder": 0,
  "ExtendedEvents": [],
  "TexturePath": null
}

Structural Specifications

Unique IdentifierField NameTypeDescriptionDefault ValueCompatibility LevelAdded Version
1TextureDatabyte[]?Custom texture data of the judge line. Null means default texture is used.null21
2IsGifTextureboolWhether TextureData is a GIF animation texture.false31
3XMoveEventsList<Event<float>>List of X-axis movement events[]01
4YMoveEventsList<Event<float>>List of Y-axis movement events[]01
5RotateEventsList<Event<float>>List of rotation events[]01
6AlphaEventsList<Event<int>>List of opacity (alpha) change events[]0 ~ 11
7SpeedEventsList<Event<float>>List of speed change events[]01
8NotesList<Note>List of notes attached to this judge line[]01
9FatherIndexintIndex of parent judge line, -1 means no parent-111
10RotateWithFatherboolWhether this line rotates with its parenttrue11
11IsCoverboolWhether this line covers notes behind ittrue11
12AttachUienumUI element bound to this judge lineAttachUi.None21
13Anchorfloat[]Anchor point of the judge line texture[0.5, 0.5]21
14BpmFactorfloatBPM factor for this judge line1.011
15ZOrderintZ-order of the judge line (rendering priority)011
16ExtendedEventsExtendedLayerList of extended events[]31
100TexturePathstring?Path to external texture file (for compatibility)null21

Behavior Rules

TextureData

  • Stores binary data of a custom texture, usually PNG or JPEG format.
  • Can be null, meaning the default texture should be used.
  • Cannot be used together with TexturePath.
  • When using a custom texture, FC/AP indicators should not affect the line's color.

IsGifTexture

  • Indicates whether TextureData contains GIF animation data.
  • If true, TextureData must contain a valid GIF binary stream.

XMoveEvents, YMoveEvents, RotateEvents, AlphaEvents, SpeedEvents

  • Events are sorted by StartBeat in ascending order.
  • Overlapping events are not allowed.
  • When no event is active at current beat, the last event’s end value is used.
  • Empty lists are allowed; default values per event type:
Event TypeDefault Value
XMove0.0f
YMove0.0f
Rotate0.0f
Alpha0
Speed10.0f
  • Example code for retrieving current beat value:
csharp
// This example uses binary search to find the event corresponding to time t
public float GetValueAtBeat(float t)
{     
    if (Count == 0)
        return 0;
    
    // If time is earlier than the first event's start time
    if (t < this[0].StartBeat)
        return 0;
    
    // If time is later than the last event's end time
    if (t > this[Count - 1].EndBeat)
        return this[Count - 1].EndValue;
    
    // Binary search to find the matching event
    int left = 0;
    int right = Count - 1;
    
    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        var e = this[mid];
        
        // Found matching event
        if (t >= e.StartBeat && t <= e.EndBeat)
            return e.GetValueAtBeat(t); // This method should be implemented in the Event class to get value at time t
        
        // Adjust search range
        if (t < e.StartBeat)
            right = mid - 1;
        else
            left = mid + 1;
    }
    
    // If no event contains this time, return the end value of the most recent previous event
    for (int i = left - 1; i >= 0; i--)
    {
        if (t > this[i].EndBeat)
            return this[i].EndEndValue;
    }
    
    return 0;
}

AttachUi

  • When UI binding is enabled, the judge line behaves relative to the specified UI element.
  • The anchor point of the judge line becomes relative to the UI position.
  • Rotation events should directly rotate both the UI and the line, not as child elements.
  • Supported values:
Enum ValueDescriptionValue
AttachUi.NoneNo UI binding0
AttachUi.PausePause button1
AttachUi.ComboNumberCombo counter2
AttachUi.ComboTextText below combo counter3
AttachUi.ScoreScore display4
AttachUi.ProgressBarProgress bar5
AttachUi.NameChart name display6
AttachUi.LevelChart difficulty level7

Anchor

  • Defines the anchor point of the texture (0.0,0.0 = bottom-left, 1.0,1.0 = top-right).
  • Affects texture alignment and text positioning from TextEvents.

BpmFactor

  • Used to adjust BPM for this line. Effective BPM = Global BPM / BpmFactor.

ZOrder

  • Controls rendering order; higher values appear on top.

IsCover

  • Determines whether this line covers notes behind it.
  • For Hold notes, only the head position determines coverage.

FatherIndex

  • Stores index of parent judge line, -1 means none.
  • Position is calculated relative to parent.
  • Rotation behavior is controlled by RotateWithFather.
  • When if parent dose exist, example code for judge line position calculation:
csharp
JudgeLine[] this; // Assume this is the current JudgeLine array
public (float, float) GetLinePosition(int index, float time)
{     
    // Return directly if there's no parent line
    if (this[index].Father == -1) return (this[index].GetXAtTime(time), this[index].GetYAtTime(time));
    
    int fatherIndex = this[index].FatherIndex;
    // Get parent line position
    var (fatherX, fatherY) = GetLinePosition(fatherIndex, time);
    
    // Get offset relative to parent line
    float offsetX = this[index].GetXAtTime(time);
    float offsetY = this[index].GetYAtTime(time);
    
    // Get parent rotation and convert to radians. The GetRotateAtTime method is defined below.
    float angleDegrees = GetRotateAtTime(index, time);
    float angleRadians = (angleDegrees % 360 + 360) % 360 * Math.PI / 180f;
    
    // Rotate the offset
    float rotatedOffsetX = (float)(offsetX * Math.Cos(angleRadians) - offsetY * Math.Sin(angleRadians));
    float rotatedOffsetY = (float)(offsetX * Math.Sin(angleRadians) + offsetY * Math.Cos(angleRadians));
    
    // Add parent position to get final position
    return (fatherX + rotatedOffsetX, fatherY + rotatedOffsetY); 
}

RotateWithFather

  • If true, this line rotates along with its parent.
  • If parent does not exist, this flag has no effect.
  • Example code for judge line rotation calculation:
csharp
public float GetRotateAtTime(int index, float time)
{
    // Return directly if there's no parent or not rotating with parent
    if (this[index].Father == -1 || !this[index].RotateWithFather) return this[index].GetRotateAtTime(time);
    
    int fatherIndex = this[index].Father;
    // Get parent line rotation
    float fatherAngle = GetRotateAtTime(fatherIndex, time);
    // Get current line rotation
    float currentAngle = this[index].GetRotateAtTime(time);
    // Return the sum of parent and current rotation
    return fatherAngle + currentAngle;
}

ExtendedEvents

TexturePath

  • Allows specifying an external texture path instead of embedding it.
  • Can be a local path like Assets/0721.png, or a URL.
  • Must be null when TextureData is used.

Proto Paragraph

protobuf
syntax = "proto3";
package PhiCommonChart.ChartStructs;

message JudgeLine {
   bytes TextureData = 1;
   bool IsGitTexture = 2;
   repeated Event_Single XMoveEvents = 3;
   repeated Event_Single YMoveEvents = 4;
   repeated Event_Single RotateEvents = 5;
   repeated Event_Byte AlphaEvents = 6;
   repeated Event_Single SpeedEvents = 7;
   repeated Note Notes = 8;
   int32 FatherIndex = 9;
   bool RotateWithFather = 10;
   bool IsCover = 11;
   AttachUi AttachUi = 12;
   repeated float Anchor = 13 [packed = false];
   float BpmFactor = 14;
   int32 ZOrder = 15;
   ExtendedEventLayer ExtendedEvents = 16;
   string TexturePath = 100;
}
enum AttachUi {
  None = 0;
  Pause = 1;
  ComboNumber = 2;
  ComboText = 3;
  Score = 4;
  ProgressBar = 5;
  Name = 6;
  Level = 7;
}