diff --git a/QFSGT/@code.xml b/QFSGT/@code.xml
new file mode 100644
index 0000000..4273037
--- /dev/null
+++ b/QFSGT/@code.xml
@@ -0,0 +1,215 @@
+
+ QFSGT
+ timer
+ QFSGT
+ sup39(サポミク), Noki Doki
+ 0.1
+ Feb 24, 2024
+
+ Show Quarterframe timer with in-game timer appearance on shine get.
+
+
+
+
+
+
diff --git a/QFSGT/info.xml b/QFSGT/info.xml
new file mode 100644
index 0000000..0cae98f
--- /dev/null
+++ b/QFSGT/info.xml
@@ -0,0 +1,11 @@
+
+ QFSGT
+ timer
+ QFSGT
+ sup39(サポミク), Noki Doki
+ 0.1
+ Feb 24, 2024
+
+ Show Quarterframe timer with in-game timer appearance on shine get.
+
+
diff --git a/QFSGT/make.py b/QFSGT/make.py
new file mode 100644
index 0000000..68a4f45
--- /dev/null
+++ b/QFSGT/make.py
@@ -0,0 +1,21 @@
+from supSMSGecko import make_xml, symbols
+
+def main(g, ver):
+ S = symbols[ver]
+
+ g.C2(S['TMarDirector_direct'] + 0x88, 'src/onAreaInit.s')
+ g.C2(S['TMarDirector_delete_0'], 'src/onAreaDeinit.s')
+ g.C2(S['TMarDirector_fireGetStar'] + (0x48 if ver in ['GMSJ01', 'GMSE01'] else 0x84), 'src/onShineGet.s')
+ g.C2(S['TBathtub_startDemo'] + (0x21c if ver in ['GMSJ01', 'GMSJ0A'] else 0x21c), 'src/onBrowserFightDone.s')
+ g.C2(S['TCardLoad_changeScene'] + {
+ 'GMSJ01': 0x1278,
+ 'GMSE01': 0x1384,
+ 'GMSP01': 0x13b0,
+ 'GMSJ0A': 0x13b0,
+ }[ver], 'src/onFileStart.s')
+ g.C2(S['TMarDirector_nextStateInitialize'] + (0x56c if ver == 'GMSJ01' else 0x5bc), 'src/onMiss.s')
+ g.C2(S['TMarDirector_changeState'] + 0x328, 'src/onExitArea.s')
+ g.C2(S['TMarDirector_setNextStage'] + 0x50, 'src/onLoadingZone.s')
+ g.C2(S['TGCConsole2_drawWater'] - 0x28c, 'src/showTimer.s')
+
+make_xml(main)
diff --git a/QFSGT/src/onAreaDeinit.s b/QFSGT/src/onAreaDeinit.s
new file mode 100644
index 0000000..cb419da
--- /dev/null
+++ b/QFSGT/src/onAreaDeinit.s
@@ -0,0 +1,15 @@
+/** Disassemble from Noki Doki's Quarterframe Timer code */
+
+## if Stop at QFT Offset flag
+ lis r5, 0x817f
+ lhz r0, 0xb2(r5)
+ cmpwi r0, 0
+ bne- .done
+## cumulative time += globalQF
+ lwz r0, 0xb4(r5)
+ lwz r6, 0x5c(r3) ## globalQF
+ add r0, r0, r6
+ stw r0, 0xb4(r5)
+## orig
+.done:
+ mflr r0
diff --git a/QFSGT/src/onAreaInit.s b/QFSGT/src/onAreaInit.s
new file mode 100644
index 0000000..c042b87
--- /dev/null
+++ b/QFSGT/src/onAreaInit.s
@@ -0,0 +1,19 @@
+/** Disassemble from Noki Doki's Quarterframe Timer code */
+
+## orig
+ stb r0, 0x260(r26)
+## check if should reset QFT (0xb3 flag)
+ lis r7, 0x817f
+ lbz r0, 0xb3(r7)
+ cmpwi r0, 0
+## duration of timer freeze = 0
+# li r0, 0
+# stw r0, 0xbc(r7)
+ beq .done
+## reset QFT
+### stop at QFT offset flag = false
+ sth r0, 0xb2(r7)
+### cumulative time = -4
+ li r0, -4
+ stw r0, 0xb4(r7)
+.done:
diff --git a/QFSGT/src/onBrowserFightDone.s b/QFSGT/src/onBrowserFightDone.s
new file mode 100644
index 0000000..7cf54a8
--- /dev/null
+++ b/QFSGT/src/onBrowserFightDone.s
@@ -0,0 +1,15 @@
+/** Disassemble from Noki Doki's Quarterframe Timer code */
+
+## r8 = cumulative time + global QF
+ lis r8, 0x817f
+ lwz r6, 0xb4(r8) ## cumulative time
+ lwz r0, 0x5c(r3) ## global QF
+ add r6, r6, r0
+## round cumulative time to next 4x QF
+ addi r6, r6, 4
+ clrrwi r6, r6, 2 ## clear least significant 2 bits
+ stw r6, 0xb4(r8)
+## stop at QFT offset flag (0xb2 flag) = true (0xFF)
+## restart flag (0xb3 flag) = true (0xFF)
+ li r6, -1
+ sth r6, 0xb2(r8)
diff --git a/QFSGT/src/onExitArea.s b/QFSGT/src/onExitArea.s
new file mode 100644
index 0000000..43945c0
--- /dev/null
+++ b/QFSGT/src/onExitArea.s
@@ -0,0 +1,17 @@
+/** Disassemble from Noki Doki's Quarterframe Timer code */
+
+## restart flag = 1
+ lis r5, 0x817f
+ li r3, 1
+ stb r3, 0xb3(r5)
+## displayed time = rounded up frame
+# lwz r3, 0x5c(r31)
+# addi r3, r3, 3
+# clrrwi r3, r3, 2
+# stw r3, 0xb8(r5)
+## freeze duration = -1
+# li r3, -1
+# stw r3, 0xbc(r5)
+
+## orig ignored?
+# sth r28, 0x94(r1)
diff --git a/QFSGT/src/onFileStart.s b/QFSGT/src/onFileStart.s
new file mode 100644
index 0000000..0185db2
--- /dev/null
+++ b/QFSGT/src/onFileStart.s
@@ -0,0 +1,8 @@
+/** Disassemble from Noki Doki's Quarterframe Timer code */
+
+## r5 = 0x40005 in TFlagManager::getFlag()
+## orig
+ cmpwi r3, 1
+## restart flag = true
+ lis r3, 0x817f
+ stb r5, 0xb3(r3)
diff --git a/QFSGT/src/onLoadingZone.s b/QFSGT/src/onLoadingZone.s
new file mode 100644
index 0000000..14abffa
--- /dev/null
+++ b/QFSGT/src/onLoadingZone.s
@@ -0,0 +1,15 @@
+/** Disassemble from Noki Doki's Quarterframe Timer code */
+
+## r0 = 0
+## QFT restart flag = 0
+ lis r5, 0x817f
+ stb r0, 0xb3(r5)
+## round global QF to next 4x
+# lwz r0, 0x5c(r30)
+# addic r0, r0, 4
+# clrrwi r0, r0, 2
+## displayed time = rounded QF
+# stw r0, 0xb8(r5)
+## freeze duration = -1
+# li r0, -1
+# stw r0, 0xbc(r5)
diff --git a/QFSGT/src/onMiss.s b/QFSGT/src/onMiss.s
new file mode 100644
index 0000000..a4dbc0a
--- /dev/null
+++ b/QFSGT/src/onMiss.s
@@ -0,0 +1,7 @@
+/** Disassemble from Noki Doki's Quarterframe Timer code */
+
+## orig (r4 = 0x20001)
+ addi r4, r28, 1
+## restart flag = true (1)
+ lis r5, 0x817f
+ stb r4, 0xb3(r5)
diff --git a/QFSGT/src/onShineGet.s b/QFSGT/src/onShineGet.s
new file mode 100644
index 0000000..bdbf8b2
--- /dev/null
+++ b/QFSGT/src/onShineGet.s
@@ -0,0 +1,15 @@
+/** Disassemble from Noki Doki's Quarterframe Timer code */
+
+## r6 = cumulative time + global QF
+ lis r5, 0x817f
+ lwz r6, 0xb4(r5) ## cumulative time
+ lwz r0, 0x5c(r3) ## global QF
+ add r6, r6, r0
+## update cumulative time and round to next 4x QF
+ addi r6, r6, 4
+ clrrwi r6, r6, 2 ## clear least significant 2 bits
+ stw r6, 0xb4(r5)
+## stop at QFT offset flag (0xb2 flag) = true (0xFF)
+## restart flag (0xb3 flag) = true (0xFF)
+ li r6, -1
+ sth r6, 0xb2(r5)
diff --git a/QFSGT/src/showTimer.s b/QFSGT/src/showTimer.s
new file mode 100644
index 0000000..7993c4f
--- /dev/null
+++ b/QFSGT/src/showTimer.s
@@ -0,0 +1,38 @@
+## only start showing timer when finished (stop at QFT offset flag == true)
+ lis r3, 0x817f
+ lbz r4, 0xb2(r3)
+ cmpwi r4, 0
+ beq+ .done
+## reset stop at QFT offset flag (only start showing once)
+ li r4, 0
+ stb r4, 0xb2(r3)
+
+## tgcConsole2.startAppearTime(this, isCountDown=false)
+### r3 = this
+ mr r3, r31
+### r4 (isCountDown) = false (count up)
+# li r4, 0
+### call
+ lis r12, TGCConsole2_startAppearTimer@ha
+ la r12, TGCConsole2_startAppearTimer@l(r12)
+ mtlr r12
+ blrl
+
+## tgcConsole2.setTimer(this, time)
+### r3 = this
+ mr r3, r31
+### r4 = cumulative time
+ lis r4, 0x817f
+ lwz r4, 0xb4(r4)
+ li r0, 1200
+ mulli r4, r4, 1001
+ divwu r4, r4, r0
+### call
+ lis r12, TGCConsole2_setTimer@ha
+ la r12, TGCConsole2_setTimer@l(r12)
+ mtlr r12
+ blrl
+
+.done:
+## orig
+ lbz r0, 0x44(r31)