A comprehensive Excel-based solution that replaced NaNoWrimo's discontinued platform, transforming daily reading and summarization habits into actionable insights. This system tracks vocabulary acquisition, writing speed improvement, spelling accuracy, and grammar development through advanced Excel formulas, VBA automation, and interactive dashboards—providing complete data ownership and unlimited customization for habit optimization.
Note About VBA Functionality
The VBA buttons and goal selection dropdown list do not appear in this Excel web view — this is the only difference from the desktop Excel file. To use the VBA automation features and interactive goal selector, please open the file in the Microsoft Excel desktop application.
After successfully tracking 100 chapters of daily reading and summarization on NaNoWrimo, the platform's shutdown disrupted a valuable habit that was improving vocabulary, writing speed, spelling, and grammar skills. This project aimed to create a comprehensive local Excel-based replacement that would provide complete data ownership, unlimited customization, and advanced analytics to optimize the daily reading comprehension and summarization routine.
The project evolved through systematic development: First, designed a 6-sheet relational data model with comprehensive tracking of 20+ variables per session. Second, implemented advanced Excel formulas using LET, FILTER, SUMPRODUCT, and INDEX/MATCH functions for dynamic calculations and real-time analytics. Third, built VBA UserForms with smart defaults and validation for streamlined data entry. Finally, created an interactive dashboard with 13 KPI cards, 3 charts, ActiveX controls, and goal-switching functionality that mirrors and exceeds the original NaNoWrimo experience.
This project developed a comprehensive Excel-based writing habit tracker to replace the discontinued NaNoWrimo platform after 100 successful chapters. The solution implements a sophisticated 6-sheet data model with advanced Excel formulas, VBA automation, and interactive dashboards to track daily reading comprehension and summarization activities. The system provides complete local data ownership, unlimited customization, and superior analytics compared to the original platform.
Core Achievement: Successfully maintained and enhanced a daily habit that improves vocabulary acquisition, writing speed, spelling accuracy, and grammar through systematic tracking of 20+ variables per writing session, with real-time analytics and predictive goal management.
My daily routine involves reading a chapter out loud, then writing a comprehensive summary. This habit systematically improves:
As a data analyst, I needed precise tracking to understand progress patterns and optimize the habit. NaNoWrimo provided basic goal tracking (3000 words/month), but after 100 chapters, the platform went down, disrupting my routine and data continuity.
Rather than seeking another platform with limitations, I decided to build a comprehensive local solution that could:
Master table (tblData) capturing every writing session with 20 columns:
Goals_Master table with calculated fields:
Goal Name: Novel goal 6
Target Words: 3000
Start Date: 12/7/2025
End Date: 31/7/2025
Duration (days): =[@[End Date]] - [@[Start Date]]
Daily Avg Required: =[@[Target Words]] / [@[Duration (days)]]
Lists Sheet: Data validation tables
Daily Progress Sheet: Aggregated analytics engine
HourlyKPI Sheet: Time-based productivity analysis
Dashboard Sheet: Interactive visualization layer
Every data entry column includes validation rules to ensure data integrity:
Data Validation Settings:
Allow: List
Source: =INDIRECT("Goals_Master[Goal Name]")
Input Message: "Select from available goals"
Error Alert: "Please select a valid goal from the dropdown"
Show dropdown in cell: ✓
Ignore blank: ✓
This validation system prevents data entry errors and maintains consistency across all tracking variables.
The analytics engine starts with goal selection in cell L1, then dynamically loads all goal parameters:
Start Day: =INDEX(Goals_Master[Start Date],
MATCH($L$1, Goals_Master[Goal Name], 0))
End Day: =INDEX(Goals_Master[End Date],
MATCH($L$1, Goals_Master[Goal Name], 0))
Duration: =INDEX(Goals_Master[Duration (days)],
MATCH($L$1, Goals_Master[Goal Name], 0))
Word Goal: =INDEX(Goals_Master[Target Words],
MATCH($L$1, Goals_Master[Goal Name], 0))
Today: =TODAY()
First row: =L2 // Start day
Subsequent rows: =IF(B2 < $L$3, B2 + 1, NA())
// Creates daily rows from start to end date
// NA() ensures unused rows don't appear in charts
=IF(B2="", "", SUMIFS(
tblData[Words],
tblData[StartDate], B2, // Match this specific date
tblData[Goal Name], $L$1 // Match selected goal
))
// Sums all word counts for multiple chapters on same day
// Filters by both date and goal for accurate aggregation
=IF(
B2="", "",
IF(
B2 > $L$6, // Future date check
NA(), // Hide future progress
C2 + IF(ROW()=2, 0, D1) // Running total
)
)
// Running sum that stops at TODAY()
// Prevents showing fake future progress in charts
=IF(
$B2="", "",
IF(
B2 > $L$6, NA(),
IF(D2 = L$5, 0, // Exact goal achieved
IF(D2 < L$5, L$5 - D2, // Words still needed
"+" & (D2 - L$5))) // Words exceeded
)
)
// Displays remaining words or excess with + prefix
=IF(
$B2 = "", "",
IF(
B2 > $L$6, NA(),
IF(
D2 >= $L$5, 0, // Goal achieved
IF(
(L$4 - F2) > 0, // Days remaining > 0
E2 / (L$4 - F2), // Words left ÷ days left
E2 // Last day: show remaining
)
)
)
)
// Recalculates daily target based on progress
// Example: 400 words left, 5 days = 80 words/day
=IF(B2 = "", "", ($L$5/$L$4)*[@[the day number]])
// Linear progression from day 1 to goal completion
// Provides comparison baseline for actual progress
=LET(
_AllRows, CHOOSE({1,2}, tblData[StartDate], tblData[Words]),
_FilterCond, (tblData[Goal Name] = 'Daily Progress'!$L$1) *
(tblData[StartDate] <= TODAY()),
_Filtered, FILTER(_AllRows, _FilterCond, ""),
SORT(_Filtered, 1, -1)
)
// Step-by-step breakdown:
// 1. Creates 2-column array: [Date, Words]
// 2. Filters for selected goal AND dates up to today
// 3. Sorts by date descending (latest first)
=LET(
_Today, $L$6,
_EndDate, $L$3,
_GoalTotal,$L$5,
_LastDate, IF(_Today > _EndDate, _EndDate, _Today),
_Row, MATCH(_LastDate, tblProgress[Date], 0),
_CumNow, INDEX(tblProgress[CumulWords], _Row),
_CumNow & " / " & _GoalTotal
)
// Shows: "3067 / 3000"
// Freezes at end date for completed goals
=LET(
_Today, $L$6,
_StartDate, $L$2,
_EndDate, $L$3,
_RowToday, IF(OR(_Today < _StartDate, _Today > _EndDate),
NA(), MATCH(_Today, tblProgress[Date], 0)),
_WordsToday, IFNA( INDEX(tblProgress[Words], _RowToday), 0 ),
_AvgNeeded, IFNA( INT( INDEX(tblProgress[Avg Daily Needed], _RowToday) ), 0 ),
_IsOver, _Today > _EndDate,
IF(_IsOver, "0/0" & CHAR(10) & "words needed today" & CHAR(10),
_WordsToday & "/" & _AvgNeeded & CHAR(10))
)
// Shows: "120 / 150" (Today's words vs daily target)
// Displays "0/0" after goal period ends
=LET(
_Today, $L$6,
_StartDate, $L$2,
_EndDate, $L$3,
_IsOver, _Today > _EndDate,
_LastWriteDate, MAXIFS(tblProgress[Date], tblProgress[Words], ">0",
tblProgress[Date], "<=" & _Today),
_ValidDate, IF(_LastWriteDate < _StartDate, _StartDate - 1, _LastWriteDate),
_LastZeroDate, MAXIFS(tblProgress[Date], tblProgress[Words], 0,
tblProgress[Date], "<=" & _ValidDate),
_BaseZero, IF(_LastZeroDate < _StartDate, _StartDate - 1, _LastZeroDate),
_Streak, _ValidDate - _BaseZero,
IF(_IsOver, "0" & CHAR(10),
IF(_ValidDate >= _Today - 1, _Streak & CHAR(10), "0" & CHAR(10)))
)
// Calculates consecutive days with writing activity
// Resets to 0 after missed day or goal completion
=SUMPRODUCT(
(tblData[Goal Name]=$D$1) * // Filter for current goal
((
IF( // Calculate effective end time
(tblData[EndTime] + (tblData[EndTime] < tblData[StartTime])) < (A2+1)/24,
tblData[EndTime] + (tblData[EndTime] < tblData[StartTime]),
(A2+1)/24
)
-
IF( // Calculate effective start time
tblData[StartTime] > A2/24,
tblData[StartTime],
A2/24
)
) * 1440) * // Convert time to minutes
( // Validate positive time
... // (Validation logic)
)
)
// Calculates minutes spent writing during each hour
// Splits sessions that span multiple hours
The dashboard is composed of three layers:
Data (tblData / Goals_Master / tblProgress), Analytics (daily aggregates, rolling averages, projections), and Presentation (13 KPI cards, 3 charts, control widgets).
Each card and chart reads the active goal from Daily Progress!$L$1
and is driven by the daily-progress table (tblProgress) which intentionally uses NA()
for future days so charts stop at today.
Contents (expand any item for formulas, explanation, and implementation details):
Each KPI below is a self-contained fork — click any card to open a focused explanation, the exact formula used in the workbook, what the KPI answers, and common edge-cases (watchouts).
What it shows: cumulative words written so far vs target (example: 3067 / 3000
). Freezes after goal end date so the card doesn't keep changing.
Formula (recommended, robust):
=LET(
_Today, $L$6,
_End, $L$3,
_Goal, $L$5,
_UseDate, IF(_Today > _End, _End, _Today),
_Row, IFERROR(MATCH(_UseDate, tblProgress[Date], 0), NA()),
_Cum, IFERROR(INDEX(tblProgress[CumulWords], _Row), 0),
TEXT(_Cum, "#,##0") & " / " & TEXT(_Goal, "#,##0")
)
Explanation:
_UseDate
picks today's date but clamps at the goal _End
date (freezing display after the period ends).MATCH
finds the progress row for that date; INDEX(...)
returns the cumulative words.Watchouts:
tblProgress[Date]
contains date-only values (no time component). If not, use =INT(...)
or ensure the table stores date-only.IFERROR
so the KPI shows friendly zeros rather than #N/A
when no data exists.What it shows: words written today versus the dynamically recalculated daily target (example: 120 / 150
).
Formula (clean):
=LET(
_Today, $L$6,
_Start, $L$2,
_End, $L$3,
_RowToday, IF(OR(_Today < _Start, _Today > _End), NA(), IFERROR(MATCH(_Today, tblProgress[Date], 0), NA())),
_WordsToday, IFNA(INDEX(tblProgress[Words], _RowToday), 0),
_AvgNeeded, IFNA(INT(INDEX(tblProgress[Avg Daily Needed], _RowToday)), 0),
IF(_Today > _End, "0 / 0 (goal ended)", _WordsToday & " / " & _AvgNeeded)
)
Notes:
INT
purely for display — store precise averages elsewhere if you need decimals.What it shows: count of consecutive days with >0 words written (resets on a missed day or when the goal ends).
Formula (readable):
=LET(
_Today, $L$6,
_Start, $L$2,
_End, $L$3,
_LastWrite, IFERROR(MAXIFS(tblProgress[Date], tblProgress[Words], ">0", tblProgress[Date], "<="&_Today), NA()),
_LastZero, IFERROR(MAXIFS(tblProgress[Date], tblProgress[Words], 0, tblProgress[Date], "<="&_LastWrite), _Start-1),
_Streak, IFERROR(_LastWrite - _LastZero, 0),
IF(_Today > _End, "0 (goal ended)", _Streak)
)
Explanation:
MAXIFS(... "<=" & _Today)
finds the most recent positive day and the most recent zero day to compute the run length.IFERROR
and falls back to zero when necessary.What it shows: sum of distraction counts for the active goal (1 distraction = ~5 mins stop).
=LET(
_Goal, $L$1,
_Today, $L$6,
_Start, INDEX(Goals_Master[Start Date], MATCH(_Goal, Goals_Master[Goal Name], 0)),
_Sum, SUMIFS(tblData[DistractionsCnt], tblData[Goal Name], _Goal, tblData[StartDate], ">="&_Start, tblData[StartDate], "<="&_Today),
IF(_Sum=0,"Great news — no distractions so far!","Total distractions: " & _Sum)
)
Tip: show trend sparkline or % of distraction-days to total-days for richer insight.
What it shows: integer average words/day for the active goal period up to today.
=LET(
_Goal,$L$1,
_Start, INDEX(Goals_Master[Start Date], MATCH(_Goal, Goals_Master[Goal Name], 0)),
_LastDate, IF($L$6 < _Start, _Start, IF($L$6 > $L$3, $L$3, $L$6)),
_Days, MAX(0, _LastDate - _Start + 1),
_Total, SUMIFS(tblData[Words], tblData[Goal Name], _Goal, tblData[StartDate], ">="&_Start, tblData[StartDate], "<="&_LastDate),
_Avg, IF(_Days=0,0,INT(_Total/_Days)),
"On average, you write" & CHAR(10) & _Avg & " words per day!"
)
Note: use rolling averages (7-day) on a secondary card to capture recent pace changes.
What it shows: rounded mood average with descriptive emoji/comment.
=IFERROR(
LET(
_Goal,$L$1,
_Start, INDEX(Goals_Master[Start Date], MATCH(_Goal, Goals_Master[Goal Name], 0)),
_All, FILTER(tblData[Mood(1-5)], (tblData[Goal Name]=_Goal)*(tblData[StartDate]>=_Start)*(tblData[StartDate]<=$L$6)),
_Avg, ROUND(AVERAGE(_All),0),
_Comment, CHOOSE(_Avg,"Very low 😕","Low 🙂","Neutral 😐","Good 😀","Excellent 😃"),
"Average mood: " & _Avg & CHAR(10) & _Comment
),
"📭 No mood entries yet."
)
Watchout: FILTER
errors if no rows exist — that's why the IFERROR
wrapper is used.
What they show: the most-used device and most-used location for the active goal (min. 3 samples to be confident).
=LET(
_Goal,$L$1,
_Start, INDEX(Goals_Master[Start Date], MATCH(_Goal, Goals_Master[Goal Name], 0)),
_DevList, FILTER(tblData[Device], (tblData[Goal Name]=_Goal)*(tblData[StartDate]>=_Start)*(tblData[StartDate]<=$L$6)),
_U, UNIQUE(_DevList),
_Counts, COUNTIFS(tblData[Device], _U, tblData[Goal Name], _Goal, tblData[StartDate], ">="&_Start, tblData[StartDate], "<="&$L$6),
_TopCount, MAX(_Counts),
_Top, IF(_TopCount<3, "More data needed", INDEX(_U, MATCH(_TopCount,_Counts,0))),
_Top
)
Tip: show count beside the card (e.g., "Desktop PC (8 sessions)").
What it shows: average writing speed (words divided by duration in minutes).
=LET(
_Goal,$L$1,
_Start, INDEX(Goals_Master[Start Date], MATCH(_Goal, Goals_Master[Goal Name], 0)),
_List, FILTER(tblData[WPM], (tblData[Goal Name]=_Goal)*(tblData[StartDate]>=_Start)*(tblData[StartDate]<=$L$6)),
_Avg, IFERROR(INT(AVERAGE(_List)), 0),
"Your average writing speed is" & CHAR(10) & _Avg & " words per minute!"
)
Important: ensure duration is stored as numeric minutes — WPM = ROUND(Words / DurationMinutes,1).
What it shows: final status message if complete, otherwise a dynamic projection that estimates completion date at current pace.
=LET(
_Goal,$L$1,
_Today,$L$6,
_Start, INDEX(Goals_Master[Start Date], MATCH(_Goal, Goals_Master[Goal Name], 0)),
_End, INDEX(Goals_Master[End Date], MATCH(_Goal, Goals_Master[Goal Name], 0)),
_WordGoal, INDEX(Goals_Master[Target Words], MATCH(_Goal,Goals_Master[Goal Name],0)),
_Cum, SUMIFS(tblData[Words], tblData[Goal Name], _Goal, tblData[StartDate], ">="&_Start, tblData[StartDate], "<="&_Today),
_DaysSoFar, MAX(0, _Today - _Start + 1),
_Avg, IF(_DaysSoFar=0, 0, INT(_Cum / _DaysSoFar)),
IF(
_Today > _End,
IF(_Cum >= _WordGoal, "✅ Goal complete! You hit " & _Cum & " words!", "⚠️ Goal missed. You wrote " & _Cum & " of " & _WordGoal),
IF(_Avg=0, "Start writing to get predictions.",
LET(
_WordsLeft, MAX(0, _WordGoal - _Cum),
_DaysNeeded, CEILING(_WordsLeft / _Avg, 1),
_PredDate, _Today + _DaysNeeded,
_Delta, _End - _PredDate,
IF(_Delta>0, "🎉 On track! Finish by " & TEXT(_PredDate,"dd/mmm") & " (" & _Delta & " day(s) early)",
IF(_Delta=0,"🎯 On track to finish on time: " & TEXT(_End,"dd/mmm"),
"⏳ Behind. Finish by " & TEXT(_PredDate,"dd/mmm") & " (" & ABS(_Delta) & " day(s) late)"
))
)
)
)
)
Notes:
Formula: =TEXT($L$6,"dd/mmm/yyyy")
Note: $L$6 is your single source of truth for date — useful for reproducible reports by changing that cell manually.
What it does: computes minutes written in each hour (0–23), correctly splitting sessions that span hours or midnight.
Core per-hour minutes (LET version):
=LET(
hrStart, A2/24,
hrEnd, (A2+1)/24,
starts, tblData[StartTime],
endsRaw, tblData[EndTime],
ends, endsRaw + (endsRaw < starts), /* adjust for sessions that cross midnight */
effStart, IF(starts > hrStart, starts, hrStart),
effEnd, IF(ends < hrEnd, ends, hrEnd),
mins, MAX(0,(effEnd - effStart) * 1440),
SUMPRODUCT((tblData[Goal Name]=$D$1) * mins)
)
Implementation notes:
StartTime
and EndTime
as actual Excel time/datetime values (not strings). In VBA, write them as Date/Time values (use TimeValue()
/ CDate()
).MAX
, INDEX
PeakHour, and formatted labels (TEXT(TIME(...),"h:mm AM/PM")
).What it shows: friendly label derived from your peak-writing hour.
=LET(
_Peak, INDEX($A$2:$A$25, MATCH(MAX($B$2:$B$25), $B$2:$B$25, 0)),
IF(OR(_Peak>=19, _Peak<5),"Night Owl",
IF(_Peak>=5 & _Peak<11,"Early Bird",
IF(_Peak>=11 & _Peak<15,"Noon Lark", "Flamingo")
)
)
)
Tip: pair this label with a recommendation (e.g., "Schedule focused sessions at your peak window").
Data source: tblProgress[Date]
(X), tblProgress[CumulWords]
(Y), tblProgress[PathOfSuccess]
(baseline). Use NA()
for future rows so the line stops at today.
Use a column series for daily words and a line series for cumulative or path baseline. Configure secondary axis only if scales diverge widely.
Line with markers for daily words and optional 7-day moving average (helper column: =IFERROR(AVERAGE(INDEX(tblProgress[Words],ROW()-6):INDEX(tblProgress[Words],ROW())),0)
).
Chart tips:
This section documents the interactive controls on the Dashboard: the Goal-selection ComboBox, the scrollable Progress History ListBox, and the command buttons that launch VBA UserForms. Each control has two concerns: (A) the visual/properties setup in Excel, and (B) the VBA glue that keeps the dashboard consistent, performant, and robust.
Create a table for goals and use that table column as the list. Example:
-- Make Goals_Master a proper Excel Table with a column 'Goal Name'
Named range (optional): GoalList → =Goals_Master[Goal Name]
-- Then set ComboBox ListFillRange = GoalList (or directly Goals_Master[Goal Name])
GoalList
(or Goals_Master[Goal Name]
)'Daily Progress'!L1
(the single source-of-truth for active goal)Populate via VBA on workbook open or when Goals_Master changes (example):
Private Sub Workbook_Open()
Dim arr As Variant
arr = ThisWorkbook.Sheets("Goals").ListObjects("Goals_Master").ListColumns("Goal Name").DataBodyRange.Value
With ThisWorkbook.Sheets("Dashboard").cmbGoals
.Clear
Dim i As Long
For i = 1 To UBound(arr, 1)
.AddItem arr(i, 1)
Next i
End With
End Sub
Private Sub cmbGoals_Change()
' Write selection into the canonical cell
Sheets("Daily Progress").Range("L1").Value = Me.cmbGoals.Value
' Recalculate and refresh derived ranges/charts
Call RefreshDashboard
End Sub
Sub RefreshDashboard()
'Minimal: force recalculation and refresh pivot caches/charts if needed
Application.CalculateFullRebuild
' Optionally refresh pivots:
' Dim pc as PivotCache: For Each pc In ThisWorkbook.PivotCaches: pc.Refresh: Next pc
End Sub
LinkedCell
as the single source of truth ('Daily Progress'!L1
) so all formulas read from one place — easier to debug.ActiveX ListBox gives fine-grained control of column counts, widths, and can be populated with an array from VBA (fast, avoids volatile ListFillRange issues).
lstProgress
80 pt; 50 pt
Use a VBA routine to read the visible / filtered range (the output of your LET+FILTER table) and assign the 2D array to the ListBox:
Sub PopulateProgressListBox()
Dim wsDP As Worksheet
Dim rng As Range
Dim arr As Variant
Set wsDP = ThisWorkbook.Sheets("Daily Progress")
' ProgListRange should be a contiguous 2-col range that contains the date and words (the output of your FILTER+SORT)
Set rng = wsDP.Range("ProgListRange") ' e.g. $K$16:$L$100
If Application.WorksheetFunction.CountA(rng) = 0 Then
Sheets("Dashboard").lstProgress.Clear
Exit Sub
End If
arr = rng.Value ' arr becomes a 2D array (rows x 2)
With Sheets("Dashboard").lstProgress
.Clear
.ColumnCount = 2
.List = arr
End With
End Sub
Workbook_Open
),cmbGoals_Change
),cmdOK
save),If you want clicking an entry to navigate to the matching row in Daily Progress, use the _Click
event to look up the selected date and select that row on the underlying sheet.
Assign the array to .List
in one operation — looping AddItem row-by-row is slower on large lists.
cmdOK_Click
), but less portable between Excel versions/OS.Open Add Progress form
Sub OpenAddProgress()
frmAddProgress.Show vbModal
End Sub
Open Add Goal form
Sub OpenAddGoal()
frmAddGoal.Show vbModal
End Sub
Private Sub cmdOK_Click()
Dim ws As Worksheet, tbl As ListObject, nr As ListRow
Dim sDate As Date, sTime As Date, eTime As Date, startDT As Date, endDT As Date
Dim words As Long
Set ws = ThisWorkbook.Sheets("Data")
Set tbl = ws.ListObjects("tblData")
' -- validate inputs (omitted for brevity) --
sDate = CDate(txtDate.Value) ' date
sTime = TimeValue(txtStartTime.Value) ' time
eTime = TimeValue(txtEndTime.Value) ' time (may be < sTime if crosses midnight)
startDT = sDate + sTime
endDT = sDate + eTime
If endDT < startDT Then endDT = endDT + 1 ' crosses midnight: add 1 day
words = CLng(txtWords.Value)
Set nr = tbl.ListRows.Add
With nr.Range
.Cells(1, tbl.ListColumns("Goal Name").Index).Value = cboGoalName.Value
.Cells(1, tbl.ListColumns("Chapter N").Index).Value = CLng(txtChapter.Value)
.Cells(1, tbl.ListColumns("StartDate").Index).Value = Int(startDT) ' date-only cell if desired
.Cells(1, tbl.ListColumns("StartTime").Index).Value = TimeValue(startDT)
.Cells(1, tbl.ListColumns("EndTime").Index).Value = TimeValue(endDT)
.Cells(1, tbl.ListColumns("Words").Index).Value = words
.Cells(1, tbl.ListColumns("Duration (min)").Index).Value = DateDiff("n", startDT, endDT)
.Cells(1, tbl.ListColumns("WPM").Index).Value = IIf(.Cells(1, tbl.ListColumns("Duration (min)").Index).Value > 0, _
Round(words / .Cells(1, tbl.ListColumns("Duration (min)").Index).Value, 1), 0)
' other columns...
End With
' refresh dashboard artifacts
Call PopulateProgressListBox
Call RefreshDashboard
Unload Me
End Sub
endDT
when endDT < startDT
.Keep 'Daily Progress'!L1
as the canonical "active goal" cell. All KPI formulas reference it — when controls change this cell, the dashboard updates.
Application.CalculateFullRebuild
or targeted Range.Calculate
where possible.Streamlined data entry form with smart defaults and validation:
Private Sub UserForm_Initialize()
' Populate combo box with Goal Names from Goals sheet
Dim wsLists As Worksheet
Dim goalTable As ListObject
Dim cell As Range
Dim lastGoal As String
Dim wsData As Worksheet
Dim tblData As ListObject
Dim lastRow As ListRow
Dim lastChapter As Long
Dim lastLocation As String
Dim lastDevice As String
Dim defaultDate As Date
On Error GoTo ErrHandler
' === Goals ComboBox ===
Set wsLists = ThisWorkbook.Sheets("Goals")
Set goalTable = wsLists.ListObjects("Goals_Master")
cboGoalName.Clear
For Each cell In goalTable.ListColumns(1).DataBodyRange
cboGoalName.AddItem cell.Value
Next
' pre-select last goal
If goalTable.ListRows.Count > 0 Then
lastGoal = goalTable.ListRows(goalTable.ListRows.Count) _
.Range.Cells(1, goalTable.ListColumns("Goal Name").Index).Value
cboGoalName.Value = lastGoal
End If
' === Data defaults ===
' Date
defaultDate = Date
txtDate.Value = Format(defaultDate, "yyyy-mm-dd")
' Start/End Time: default Start = now, End = +30min
txtStartTime.Value = Format(Time, "HH:mm")
txtEndTime.Value = Format(DateAdd("n", 30, Time), "HH:mm")
' === Chapter, Location, Device from last entry ===
Set wsData = ThisWorkbook.Sheets("Data")
Set tblData = wsData.ListObjects("tblData")
If tblData.ListRows.Count > 0 Then
Set lastRow = tblData.ListRows(tblData.ListRows.Count)
' Chapter +1
lastChapter = CLng(lastRow.Range.Cells(1, tblData.ListColumns("Chapter N").Index).Value
txtChapter.Value = lastChapter + 1
' Location and Device
lastLocation = lastRow.Range.Cells(1, tblData.ListColumns("Location").Index).Value
cboLocation.Value = lastLocation
lastDevice = lastRow.Range.Cells(1, tblData.ListColumns("Device").Index).Value
cboDevice.Value = lastDevice
Else
txtChapter.Value = 1
End If
Exit Sub
ErrHandler:
MsgBox "Error initializing form: " & Err.Description, vbCritical
Unload Me
End Sub
Simplified goal creation with automatic calculations:
Finding: Average writing speed of 12 words per minute, with peak productivity between 6:00 PM and 7:00 PM. Writing persona identified as "Flamingo" (afternoon writer).
Interpretation: Evening writing sessions are most productive, possibly due to fewer distractions or higher creative energy at that time. The 12 WPM baseline provides a measurable metric for tracking typing improvement over time.
Recommendation: Schedule writing sessions during peak hours (6-7 PM) and protect this time from interruptions. Implement targeted exercises to improve WPM by 2-3 points over the next goal period.
Finding: Home office environment with Desktop PC resulted in highest productivity with minimal distractions (only 6 recorded across all sessions).
Interpretation: Consistent environment and proper equipment significantly impact focus and output quality. The Desktop PC likely provides better ergonomics and fewer distractions than mobile devices.
Recommendation: Create a dedicated writing space at home with desktop computer setup to optimize writing conditions. Minimize writing on mobile devices or in suboptimal environments.
Finding: Successfully exceeded first goal target (3067/3000 words) but with inconsistent daily writing patterns. The system revealed the initial goal was too easy, leading to unconscious negligence.
Interpretation: While the goal was technically achieved, the irregular writing pattern (11 writing days out of 20) indicates motivational challenges with the goal difficulty level.
Recommendation: Set more challenging goals (200+ words daily) with consistent daily writing habit to build momentum. Use the system's predictive analytics to calibrate goals that are ambitious yet achievable based on historical performance.
Finding: Average mood rating of 4/5 during writing sessions, indicating generally positive writing experiences despite the habit being challenging.
Interpretation: The high mood rating suggests intrinsic motivation and enjoyment of the writing process, which is crucial for long-term habit sustainability.
Recommendation: Leverage positive writing experiences to establish habit formation through consistent scheduling and reward mechanisms. Consider adding more granular mood tracking to identify specific factors that contribute to peak writing experiences.
Finding: The tracking system successfully captured the core habit improvement metrics: vocabulary expansion, summarization skill development, typing speed, and error reduction.
Interpretation: While quantitative measurement of some skills (like vocabulary acquisition) requires additional tracking mechanisms, the system provides a strong foundation for monitoring writing proficiency development.
Recommendation: Enhance the system with additional tracking for specific vocabulary learned, grammar patterns practiced, and error frequency reduction to create a more comprehensive skill development dashboard.
Use the system's predictive analytics to adjust your goals. If you consistently exceed targets, increase the next goal's difficulty by 20-30%. If you're struggling, consider adjusting your schedule or breaking goals into smaller milestones.
For full technical documentation and implementation details, all formulas, VBA code, and the template are available in a GitHub repository:
View Repository