GraFx Beginner's Tutorial for Crystal Focus X
What is GraFx?
GraFx (short for Graphics Efx) is the Crystal Focus X pixel blade animation system. Instead of generating blade effects algorithmically, GraFx plays BMP image files frame-by-frame on your LED blade. Each row of pixels in the BMP image becomes one animation frame, giving you full per-pixel color control over every moment of every effect — ignition, idle blade, retraction, lockup, clash, blaster, and more. On top of the bitmap colors, GraFx can also modify per-pixel behavior (pulsing, audio-reactivity, color-shifting, etc.) via accent types.
Think of it like a flipbook: you draw your animation as an image, and the CFX plays it back on your blade LEDs.
What You Need
- A Crystal Focus X saber with a pixel blade (WS2812B / Neopixel style LED strip)
- An SD card with your sound font already working
- An image editor that can save 24-bit BMP files (e.g. GIMP, Photoshop, Paint.NET, or Aseprite)
- Basic familiarity with editing text files on the SD card
Part 1: How GraFx Works (The Big Picture)
Your CFX SD card has a special folder for GraFx sets:
SD Card
└── extra/
└── GRAFX/
├── 1-MyFirstGraFx/
│ ├── grafx1.txt <-- GraFx config file
│ ├── normal1.bmp <-- Main blade animation
│ ├── poweron1.bmp <-- Ignition animation
│ ├── poweroff1.bmp <-- Retraction animation
│ └── ...more BMPs...
├── 2-AnotherStyle/
│ ├── grafx1.txt
│ ├── normal1.bmp
│ └── ...
└── 3-YetAnother/
└── ...
Each numbered folder (the `1-`, `2-`, etc. prefix) is one complete GraFx set. The number prefix is how the CFX identifies and selects different GraFx sets. The name after the number is just for your reference.
Key concept: The number prefix (e.g. `1`, `2`, `3`) is what the firmware uses to select your GraFx folder. The text after the dash or underscore is for your own reference — the firmware needs it as a separator but does not use it for matching.
Part 2: Creating Your BMP Files
Image Dimensions
- Width = the number of LEDs in your blade (e.g., 144 pixels for a 144-LED blade)
- Height = the number of animation frames (e.g., 50 rows = 50 frames of animation)
Image Format
- 24-bit color BMP (standard Windows bitmap, uncompressed)
- Full RGB color — use any color you like
- Near-black pixels are transparent: any pixel where all color channels (R, G, B, W) are 6 or below is treated as transparent — that pixel is simply not drawn, so the existing LED color is preserved
How Frames Work
Because standard BMP files store pixel data bottom-up, the CFX reads frames from the bottom row to the top row:
Row 0 (bottom) → Frame 1 (first frame shown)
Row 1 → Frame 2
Row 2 → Frame 3
...
Row N (top) → Frame N+1 (last frame shown)
Important: This is standard BMP convention — pixel data starts at the bottom of the image. When you design your animation in an image editor, the bottom of the image is the first frame.
Each pixel in the row maps to one LED on your blade. Pixel 0 (left) is the base (emitter end), pixel N (right) is the tip.
Your First Main Blade BMP
Let's make a basic normal1.bmp for a 144-LED blade:
- Open your image editor
- Create a new image: 144 pixels wide × 20 pixels tall
- Paint each row with a solid color — try a bright blue
#0044FF - To make it interesting, vary the brightness slightly across rows for a subtle pulse effect
- Save as 24-bit BMP (uncompressed) named
normal1.bmp
That's it — you now have a 20-frame main blade animation for the normal lit saber state!
Your First Ignition BMP: poweron1.bmp
For ignition, you want the blade to "grow" from base to tip. Remember: the bottom row is Frame 1.
- Create a new image: 144 wide × 30 tall
- Bottom row (Row 0): only the first few pixels colored (near the base), rest is black
- Row 1 (one row up): a few more pixels colored
- ...gradually fill more pixels across each row as you go upward...
- Top row (Row 29): all 144 pixels fully lit
Each row adds a bit more "blade" — creating an ignition scroll effect. The near-black pixels (transparent) leave the existing LED state untouched.
Retraction BMP: poweroff1.bmp
The reverse of ignition — the bottom row is fully lit, and as you move upward through the rows, pixels darken from tip to base.
Part 3: The grafx1.txt Config File
Every GraFx folder needs a file called grafx1.txt. This tells the CFX how to play your BMPs.
Basic Structure
The config file is organized into sections, one for each type of effect:
[LEDS]
delay=40
many=1
[POWERON]
delay=30
many=1
[POWEROFF]
delay=30
many=1
Section Names
| Section | What it controls | BMP prefix |
|---|---|---|
[LEDS] |
The normal main blade while the saber is on | normal |
[IDLE] |
Standby animation (when saber blade is OFF) | idle |
[POWERON] |
The ignition (power-on) animation | poweron |
[POWEROFF] |
The retraction (power-off) animation | poweroff |
[PREON] |
Pre-ignition effect (before ignition starts) | preon |
[POSTOFF] |
Post-retraction effect (residual glow, etc.) | pstoff ⚠️ |
[LOCKUP] |
Lockup effect (blade-on-blade contact) | lockup |
[BLASTER] |
Blaster deflection bolt effect | blaster |
[FOREVER] |
Always-on fallback / background animation | forever |
normal1.bmp refers to the saber's regular blade-on state and belongs to the [LEDS] section. That is different from the separate [IDLE] stage, which is used for standby behavior when the blade is off.
⚠️ POSTOFF naming: The section is called
[POSTOFF]but the BMP file prefix ispstoff(shortened), notpostoff. So your files should be namedpstoff1.bmp,pstoff2.bmp, etc. This follows the legacy sound file naming convention.FOREVER: Acts as a fallback sequence — when no other sequence is active, FOREVER plays. Commonly used for persistent accent effects on auxiliary strips (e.g. crystal chamber, BLASTER overlays).
Key Parameters
delay=
The time in milliseconds between each frame. It controls animation speed.
delay=40→ 25 frames per seconddelay=100→ 10 frames per seconddelay=20→ 50 frames per second
Important: delay also has a special auto-sync mode:
delay=NwhereN > 0: fixed frame rate, withNmilliseconds between framesdelay=0: auto-calculate the frame delay from the associated sound length and the number of BMP frames. In practice, the firmware divides the sound duration by the BMP height so the animation finishes when the sound ends
This makes delay=0 especially useful for GraFx sequences tied to a timed sound event:
[POWERON][POWEROFF][PREON][POSTOFF][BLASTER]
For looping sections such as [LEDS], [IDLE], [FOREVER], and [LOCKUP], there is no sound duration context to calculate from. So for those sections, you should always set a real fixed delay value yourself instead of using delay=0.
many=
The number of BMP variants available for this sequence. If you have normal1.bmp and normal2.bmp, set many=2. The CFX will cycle through them sequentially (1 → 2 → 1 → 2 → ...) each time the sequence loads.
power=
Brightness for this sequence, from 0 to 100 (percent).
[LEDS]
delay=40
many=2
power=80
accents=
Defines how each individual LED behaves. This is a string where each character maps to one LED position on the strip.
Example: for a 10-LED strip, accents=aaaaaaaaaa means all pixels behave as regular sequenced accents and use the BMP colors directly.
| Character | Behavior |
|---|---|
a | Regular sequenced accent. Color comes directly from the BMP. |
H | Color-shifted pixel. Tints the gray/white parts of the BMP pixel toward the blade color from your color profile, while leaving saturated colors untouched. Controlled by colorshift_intensity= and colorshift_threshold=. |
s | Mirror of the main blade. Uses the color of pixel #1 of the main blade. |
@ | Audio flicker. Brightness follows audio volume, while color comes from the BMP and can change over time. |
# | Reverse audio flicker. Audio beat dims the pixel instead of brightening it. Color comes from the BMP. |
m | Morphing accent. Smoothly transitions from one state to the next over the stage duration. |
r | Random sequenced accent. Changes randomly at the sequence frame rate using fully random RGB values. |
R | Random sequenced accent using the color wheel at maximum brightness. |
~ | Self-pulsing accent using the BMP color. |
^ | Inverted self-pulsing accent using the BMP color. |
B | Self-pulsing accent using the blade color from the active color profile. |
I | Inverted self-pulsing accent using the blade color. |
X | Self-pulsing accent using the crystal color from the active color profile. |
L | Inverted self-pulsing accent using the crystal color. |
* | Audio flicker applied to the blade color. |
$ | Audio flicker applied to the crystal color. |
p | PLI indicator on a single pixel. Shifts green → yellow → orange → red across the battery scale. |
P | PLI across a range of pixels. Turns BMP pixels on or off based on the battery scale. |
M | Magnetic level controls brightness using the blade color. |
C | Magnetic level controls brightness using the crystal color. |
S | Magnetic field controls blade-color self-pulsing. |
T | Magnetic field controls crystal-color self-pulsing. |
A | Magnetic score controls the brightness of the BMP sequence itself, revealing animated pixels as the field gets stronger. |
Important: Always specify accents= explicitly for reliable behavior. The length of the string should match the number of LEDs for the strip that sequence is intended for.
Good beginner default: start with all a characters so every pixel simply follows the BMP. Then experiment with pulsing, audio flicker, PLI, or magnetic-driven accents once the base animation is working.
colorshift_intensity=
When using H type pixels, this controls how much the BMP color gets blended toward the blade color (0–255). Higher values mean more blade color.
colorshift_threshold=
Minimum pixel brightness before color shifting kicks in. Keeps dark areas in the BMP from being shifted.
Part 4: Setting Up the SD Card
Step 1: Create the GraFx Folder
On your SD card, create this folder structure:
extra/
└── GRAFX/
└── 1-MyGraFx/
Step 2: Add Your BMP Files
Copy your BMP files into the folder:
extra/GRAFX/1-MyGraFx/
├── grafx1.txt
├── normal1.bmp
├── poweron1.bmp
└── poweroff1.bmp
Step 3: Create the grafx1.txt File
Create a text file named grafx1.txt inside that same folder:
[LEDS]
delay=40
many=1
[POWERON]
delay=25
many=1
[POWEROFF]
delay=25
many=1
Step 4: Tell Your Font to Use GraFx
Open your saber's config.txt and add/edit these lines in the relevant Blade Profile:
## GRAFX BLADE SETUP
## Set the main blade effect to GraFx mode (17 = GRAFX_FX)
unstable=17
## Point to GraFx folder #1 (the "1-" folder)
style_grafx1=1
## Set power-on animation to GraFx mode (10 = POWERON_STYLE_GRAFX)
style_pon=10
## Set power-off animation to GraFx mode (11 = POWEROFF_STYLE_GRAFX)
style_poff=11
What Those Numbers Mean
The firmware identifies styles by number. Here are the GraFx style numbers for each effect:
| Config Key | GraFx Value | What It Does |
|---|---|---|
unstable= |
17 |
Main blade effect = GraFx |
style_pon= |
10 |
Power-on animation = GraFx |
style_poff= |
11 |
Power-off animation = GraFx |
style_lockup= |
7 |
Lockup effect = GraFx |
style_blaster= |
9 |
Blaster bolt = GraFx |
style_clash= |
8 |
Clash effect = GraFx |
style_drag= |
5 |
Drag effect = GraFx |
style_preon= |
4 |
Pre-ignition = GraFx |
style_postoff= |
4 |
Post-retraction = GraFx |
You only need to set the ones you actually want to use GraFx for in that blade profile. The others can use the regular built-in effects.
Part 5: A Complete Minimal Example
SD Card Layout
SD Card/
├── 1-MyFont/ <-- your sound font folder
│ ├── font_config.txt
│ ├── hum.wav
│ ├── poweron.wav
│ ├── poweroff.wav
│ ├── clash1.wav
│ └── ...
└── extra/
└── GRAFX/
└── 1-BlueFire/
├── grafx1.txt
├── normal1.bmp
├── poweron1.bmp
└── poweroff1.bmp
config.txt Blade Profile
unstable=17
style_grafx1=1
style_pon=10
style_poff=11
Important: These style parameters belong to the relevant Blade Profile in config.txt. They are not part of font_config.txt.
grafx1.txt
[LEDS]
delay=40
many=1
[POWERON]
delay=25
many=1
[POWEROFF]
delay=30
many=1
BMP Files (for a 144-LED blade)
normal1.bmp— 144 × 20 pixels, your idle blade animationpoweron1.bmp— 144 × 30 pixels, your ignition animationpoweroff1.bmp— 144 × 30 pixels, your retraction animation
Part 6: Multiple Blades (Auxiliary & Quillon)
If your saber has multiple pixel strips (main blade, aux strip, quillon / crossguard), you can assign different GraFx sets to each:
| Config Key | Strip |
|---|---|
style_grafx1= |
Main blade |
style_grafx2= |
Auxiliary strip |
style_grafx3= |
Quillon / crossguard |
Each can point to a different numbered GraFx folder, or the same one.
Part 7: Adding More Effects
Once you're comfortable with the basics, you can add GraFx animations for all the other effects.
Adding a Lockup GraFx
- Create
lockup1.bmpin your GraFx folder (e.g. 144 × 10 pixels) - Add to
grafx1.txt:[LOCKUP] delay=40 many=1 - Add to the relevant blade profile in
config.txt:style_lockup=7
Adding a Blaster GraFx
- Create
blaster1.bmpin your GraFx folder - Add to
grafx1.txt:[BLASTER] delay=20 many=1 - Add to the relevant blade profile in
config.txt:style_blaster=9
Adding Pre-On / Post-Off
- Create
preon1.bmpand/orpstoff1.bmp - Add to
grafx1.txt:[PREON] delay=30 many=1 [POSTOFF] delay=40 many=1 - Add to the relevant blade profile in
config.txt:style_preon=4 style_postoff=4
Adding Multiple Variants
Want some variety? Create multiple BMPs for the same effect:
normal1.bmp
normal2.bmp
normal3.bmp
Then set many=3 in the [LEDS] section. The CFX cycles through them sequentially (1 → 2 → 3 → 1 → ...) each time the sequence is triggered.
Part 8: Using Themes
If your saber uses themes (multiple visual themes per font), each theme can have its own GraFx library. The CFX looks for GraFx folders inside the theme's folder first:
1-MyFont/
└── 1-ThemeName/
└── extra/
└── GRAFX/
└── 1-ThemedGraFx/
├── grafx1.txt
└── ...
If a themed GraFx folder isn't found, the CFX falls back to the global /extra/GRAFX/ folder.
Tips & Troubleshooting
Image Tips
delay=0is not for general looping sections. Use it only for sequences tied to a sound length, such as power-on, power-off, preon, postoff, or blaster. For[LEDS],[IDLE],[FOREVER], and[LOCKUP], always choose an explicit fixed delay.- Always match your BMP width to your blade pixel count. If your blade has 144 LEDs, your BMPs must be exactly 144 pixels wide.
- Use 24-bit BMP format. Not PNG, not JPEG, not 8-bit BMP — 24-bit uncompressed Windows BMP.
- Near-black = transparent. Any pixel where all channels (R, G, B, W) are ≤ 6 is treated as transparent — that pixel is simply not drawn (the existing LED color stays). Use
#000000(pure black) for transparent areas. - More rows = longer animation. Short BMPs play quickly; tall BMPs play longer.
- The
delay=setting times the frame rate. Multiplydelay × heightto get the total animation duration in milliseconds. For example:delay=30with a 40-row BMP = 1200ms = 1.2 seconds.
Common Mistakes
- Folder numbering: Make sure folders start with a number like
1-,2-, etc. The firmware uses this number to identify the folder. - Config file name: The config file must be exactly
grafx1.txt(notgrafx.txtorconfig.txt). - Missing
unstable=17: Without these values in the relevant blade profile insideconfig.txt, the main blade won't use GraFx even if everything else is set up correctly. - Wrong BMP width: The BMP width must match the exact LED count of the strip it's assigned to. If your main blade has 144 LEDs but the BMP is 100 pixels wide, the animation will not map correctly.
Testing
- Start simple — get just
normal1.bmpworking withunstable=17andstyle_grafx1=1before adding ignition/retraction effects. - If nothing shows up, double-check your folder numbering and that
style_grafx1=points to the right number. - The
many=count should match the actual number of BMP files present. If you specifymany=3but only havenormal1.bmpandnormal2.bmp, the firmware will attempt to opennormal3.bmpand skip the missing file.
Quick Reference Card
Folder Structure
extra/GRAFX/<N>-<name>/grafx1.txt (config)
extra/GRAFX/<N>-<name>/normal1.bmp (main blade)
extra/GRAFX/<N>-<name>/poweron1.bmp (ignition)
extra/GRAFX/<N>-<name>/poweroff1.bmp(retraction)
extra/GRAFX/<N>-<name>/lockup1.bmp (lockup)
extra/GRAFX/<N>-<name>/clash1.bmp (clash)
extra/GRAFX/<N>-<name>/blaster1.bmp (blaster)
extra/GRAFX/<N>-<name>/preon1.bmp (pre-ignition)
extra/GRAFX/<N>-<name>/pstoff1.bmp (post-retraction)
extra/GRAFX/<N>-<name>/idle1.bmp (standby, blade OFF)
extra/GRAFX/<N>-<name>/forever1.bmp (looping background)
font_config.txt Keys
unstable=17 # Main blade = GraFx
style_grafx1=<N> # Which GRAFX folder (by number prefix)
style_grafx2=<N> # Aux strip GRAFX folder
style_grafx3=<N> # Quillon GRAFX folder
style_pon=10 # Power-on = GraFx
style_poff=11 # Power-off = GraFx
style_lockup=7 # Lockup = GraFx
style_clash=8 # Clash = GraFx
style_blaster=9 # Blaster = GraFx
style_drag=5 # Drag = GraFx
style_preon=4 # Pre-on = GraFx
style_postoff=4 # Post-off = GraFx
grafx1.txt Sections & Parameters
[LEDS] # Main blade while ON
[IDLE] # Standby (blade OFF)
[POWERON] # Ignition
[POWEROFF] # Retraction
[PREON] # Pre-ignition
[POSTOFF] # Post-retraction
[LOCKUP] # Lockup
[BLASTER] # Blaster
[FOREVER] # Continuous loop
# Parameters (per section):
delay=<ms> # Frame delay in milliseconds
many=<count> # Number of BMP variants
power=<0-100> # Brightness percentage
accents=<string> # Per-LED behavior characters
colorshift_intensity=<0-255>
colorshift_threshold=<0-255>
Happy saber building!