You are browsing as a guest. Sign up (or log in) to start making projects!

ryderklh

@ryderklh

Joined June 1st, 2026

  • 61Devlogs
  • 4Projects
  • 6Ships
  • 84Votes
cheers!
Ship

WHAT I MADE/THINK?

I expanded TickTock from a single timer into a multi-tool station (Hub)! This time, I built a Timer and a Stopwatch. It was a huge challenge for me to handle standard browser behaviors, especially turning a single-page SPA into a structured Astro website with a homepage and sub-pages. It took lots of testing, but I feel so proud when everything finally aligned perfectly.

Features

  • Homepage Hub Dashboard
  • Live Countdown
    • Customizable Countdown
    • Full mode / Days mode
    • Change Target Date
    • Edit Event Title
    • automatically save in localStorage & url#
  • Digital Clock
    • 12-hour / 24-hour format
    • 3 Font styles (Sans, Serif, Mono)
    • Fullscreen mode (Header/Footer kept!)
    • Smooth breathing colon animation
    • automatically save in localStorage & url#
  • ⭐Timer
    • ⭐Mutiple timers at one page
    • ⭐Keep going after refreshing website
    • ⭐Circular progress bar
    • ⭐Sortable timers
    • ⭐Alarm and flash on completion
  • ⭐Stopwatch
    • ⭐Mutiple stopwatches at one page
    • ⭐Keep going after refreshing website
    • ⭐Sortable timers
    • ⭐Able to lap and split
    • ⭐Able to copy total time and laps info
  • Time Progress Bar
    • Export as image
    • Switchable hide/show
  • Pomodoro Timer
    • Customable number of cycles
    • Pause at any time
    • Notification Sound
  • Lightweight
  • Light mode/Dark mode
  • Quick link to other tools

WHAT I LEARNT?

  • A lot of new things about git
  • How to write devlogs
  • JS, Astro…

TRY IT!

⭐means new features of the previous ship

  • 16 devlogs
  • 30h
  • 12.69x multiplier
  • 386 Stardust
Try project → See source code →
Open comments for this post

45m 57s logged

Devlog 52: GitHub Pages Audio Path Resolution Fixes

Absolute Repository Subpath Hardcoding

  • Replaced environment variable dynamic paths (import.meta.env.BASE_URL) with direct base-path URLs ('/TickTock/sounds/alarm.wav') in playAlarm().

i have no idea why that happened

2
0
143
Open comments for this post

28m 57s logged

Devlog 51: Asset Migration

Asset Directory Migration

  • Moved audio assets (alarm.wav and notif.wav) from the static /public/sounds/ directory into the source-managed asset pipeline at src/assets/sounds/.

Module Import & Bundler Integration

  • Replaced hardcoded absolute URL paths ("/public/sounds/...") with explicit ES module imports (import alarmSoundUrl from '../assets/sounds/alarm.wav' and import notifSoundUrl from '../assets/sounds/notif.wav') across timer.js and pomodoro.js.
1
0
76
Open comments for this post

1h 0m 34s logged

Devlog 50 Layout Refactoring

Scroll Restructuring

  • Shifted .stopwatch-container layout from vertical wrapping (flex-wrap: wrap) to a single-row horizontal scroll track (flex-wrap: nowrap with overflow-x: auto).
0
0
67
Open comments for this post

2h 52m 44s logged

Devlog 49: Lap Data Export

Plaintext Lap Data Serialization

  • formatLapsOutput: a dedicated text formatter that converts active stopwatch data into structured tab-separated values (TSV) suitable for copying.

Async Clipboard Copy Logic

  • Implemented an async wrapper using navigator.clipboard.writeText() with built-in error handling (try/catch) and user alerts for unsupported environments or clipboard permission rejections.

Interactive Copy Feedback UI

  • Wired copyBtn click events to trigger text copying and dynamically update the button icon (check or error) and theme accent color.
0
0
61
Open comments for this post

1h 5m 2s logged

Devlog 48: DOM Selector Bugfixes & Homepage Quick Access

DOM Query Selector & Reference Repairs

  • Updated querySelector in updateListedStopwatch from target class .listed-stopwatch-demo to parent wrapper .listed-stopwatch[data-id="..."], resolving element lookup failures during live updates.

Homepage

  • Integrated direct links and dedicated preview cards for the Stopwatch application into index.astro and BaseLayout.astro.
1
0
101
Open comments for this post

38m 21s logged

Devlog 47: Pause Compensation

Pause Duration Offset

  • Implemented pauseDuration calculation Date.now() - pauseStartTime during resume actions status === "paused". Shifted all existing lap timestamps lap.endTime += pauseDuration forward to subtract paused time intervals.

State-Aware Timestamp Resolution

  • Standardized timestamp evaluation across renderers handleLap, renderListedStopwatch, updateListedStopwatch, and updateCardUI using ternary state checks:
    const now = stopwatch.status === "running" ? Date.now() : stopwatch.pauseStartTime;
    
    
0
0
79
Open comments for this post

1h 55m 40s logged

Devlog 46: UI Fine-tuning & Timing Logic Optimization

Lap Calculations

-Replaced laps.forEach with for (let j = 0; j <= i; j++) to ensure cumulative total times (totalMS) strictly correspond to the current lap index.

Layout

  • Enhanced formatTime() rendering logic by applying inline styles width, transform: scaleX(0.8), text-align: center to dynamic span elements, preventing font-width shifting during rapid ticker updates.

Dynamic Rendering

  • Integrated updateListedStopwatch() into the global interval loop, enabling sidebar preview labels to tick synchronously with active main cards.
  • Optimized state updates to target individual time elements instead of triggering full list re-renders on every ticker frame.
  • Added optional chaining laps?.[0]?.startTime across rendering pipelines to prevent runtime exceptions when initializing empty stopwatches.
0
0
14
Open comments for this post

3h 38m 25s logged

Devlog 45: Initial Stopwatch Logic & Dynamic State Scaffolding

Core State & Lap Data Architecture

  • Designed a stopwatch schema tracking dynamic state (idle | running | paused) and an array of individual lap records (laps).
  • Streamlined time calculation to compute elapsed milliseconds dynamically directly using timestamps (Date.now() - lap.startTime), eliminating redundant accumulator fields like startTime or elapsedTime.

Interactive Handlers & Lifecycle Operations

  • Implemented core lifecycle handlers: handleStart, handlePause, handleReset, handleLap, and handleDelete.
  • Integrated updateCardUI and updateCardBtns to reflect running, paused, and idle UI visual feedback dynamically.
  • Built active DOM updates for lap histories inside updateCardLapGrid using index-based duration summation for lap and total times.
  • Enabled global runtime updates via startGlobalTick() timer intervals and list reordering via handleMoveStopwatch().
0
0
60
Open comments for this post

4h 5m 49s logged

devlog #6
in track-06 i used the A Dorian
A-B-C-D-E-F#-G

it is not as dark as the previous track

mi opinias, ke gxi ne estas bona, sed gxi estas pli bona ol trako-03

i added some sleep to the main melody, so a part of the music would sound like something different

0
0
5
Open comments for this post

1h 43m 43s logged

Devlog 44: Stopwatch Layout

Template & Layout Migration

  • Ported side-menu and main container structures from Timer to Stopwatch layout (index.astro).
  • Structured sidebar elements: .stopwatch-adding-action-btn and .stopwatch-list-container for dynamic item injection.
  • Added template placeholders (#listed-stopwatch-template and #stopwatch-card-template).

Stopwatch Card & Lap Data Display

  • Integrated core display components: .stopwatch-text and .stopwatch-text-sub.
  • Created interactive control group (.stopwatch-card-action-btn) supporting Start, Pause, Replay, and Lap actions.
  • Designed a 3-column CSS Grid table (.stopwatch-lap-container) to organize lap metrics (i, lap, total).
0
0
98
Open comments for this post

23m 29s logged

Devlog 43: Timer Integration & Navigation Update

Navigation & Home Page Integration

  • Added Timer card entry to the main landing page (tool-card layout with hourglass Material symbol).
  • Added direct Timer link to the global navigation bar in BaseLayout.astro.

Feature Branch Merge

  • Merged feature/timer-main into main, bringing in the new /timer page route, timer.js logic, sound assets (alarm.wav), and updated layout components.

YEAYYY

0
0
109
Open comments for this post

2h 13m 9s logged

devlog #5

track-05 is a copy of track-04
04 is brighter; 05 is darker

i used

  • Am-Bdim-C-Dm-Em-F-G-Am (A minor)
  • bells
  • min7 chord & dom7 chord
  • diminished fifth (not perfect fifth)

just after turning F# C# G# to F C G, it created a obviously dark, gloomy and somber feeling

now i understand why Barkla chose the letter k to start with
thanking my past self for doing that a few days ago…

0
0
8
Open comments for this post

1h 47m 59s logged

Devlog 42: Timer Reordering & List Re-Sorting

Reordering UI Controls

  • Added .sort-action control group with .sort-up and .sort-down arrow buttons to the template layout.

Dynamic Array Mutation & Re-rendering

  • Implemented handleMoveTimer(id, direction) to handle array element swapping with upper and lower boundary bounds checks.
  • Bound click handlers in renderListedTimer() to execute reordering operations, trigger LocalStorage updates, and instantly re-render the UI layout via renderAll().
0
0
64
Open comments for this post

28m 24s logged

Devlog 41: Dual-Text Display & Running Animation

Sub-Text Total Duration Display

  • Added .timer-text-sub element inside the ring container to preserve and display the initial totalSeconds value.
  • Styled sub-text using lighter font weights and var(--text-muted).

Dynamic Running Visual Effects

  • Added .is-running state toggle based on timer.status === "running".
  • Implemented @keyframes timer-text-flash pulsing animation to provide continuous visual feedback while countdown is active.
0
0
111
Open comments for this post

1h 15m 57s logged

Devlog 40: Alarm Audio & LocalStorage

Independent Alarm Audio Handling

  • new Audio() allowing each finished timer to play independent looping sound effects concurrently.
  • Bound alarm termination directly to handleReset() and handleDelete() .

LocalStorage Serialization Fixes

  • Sanitized timer state object before serialization in saveTimers() by stripping transient DOM/Audio references (alarmAudio) to prevent JSON stringification crashes.
  • Added type validation (typeof alarmAudio.pause === "function") inside stopAlarm() to prevent runtime TypeError issues during state rehydration.

Post-Reload Alarm & Visual Sync

  • Updated renderAll() to resume alarm sound playback and background pulse animation for ended timers across page reloads.
  • Cleared endTime correctly during timer reset to normalize state lifecycle.

alarm.wav

  • Using LMMS to create alarm.wav for the alarming when timer.status==="ended".
0
0
75
Open comments for this post

4h 31m 28s logged

devlog #4

i think this is a big improvement
i added

    live_loop :printer do
      tick
      i=1
      while i < 5
        print "#{look+1}:#{i}"
        i += 1
        sleep 1
      end
    end

though it didnt contain any advanced functions, it did help a lot when i was trying to figure out why the two loops ended at different times
track-04 is much better than track-03

when using A-Bm-C#m-D-E-F#m-G#dim-A, it sounds peaceful and … neat?
i also added #5, #13, #21… to match `print “#{look+1}:#{i}”

`track-04 is much better than track-03, indeed
and the ui of displaying website has been upgraded

0
0
5
Open comments for this post

35m 37s logged

Devlog 39: Smooth Action Button Transitions

Button Collapse & Spacing Animate

  • Added max-width, margin: 0, and padding: 0 constraints to .is-hidden to smoothly collapse hidden buttons without leaving blank layout gaps.
  • Expanded base state with explicit max-width boundary to allow width-based CSS transitions.

much smoother ♪(´▽`)

0
0
50
Open comments for this post

4h 29m 56s logged

Devlog 38: Multi-Timer Logic & Bug Fixes

JS

  • Managed multi-timer state using plain object arrays.
  • Implemented saveTimers() and loadTimers() for LocalStorage persistence.
  • Linked input fields with setupArrowBtns() to handle unit value increment and decrement bounds.
  • Cloned <template> elements to dynamically generate sidebar list items and main cards via renderAll().
  • Added item deletion logic via handleDelete() to update state and UI.
  • Established a startGlobalTick() loop running every 200ms using endTime offsets to prevent background tab drift.
  • Calculated SVG circle strokeDashoffset dynamically based on remaining time ratios.

Debugging & UI Patching

  • Placing <template> tags inside slot="template-content".
  • Adding missing id="timer-container".
  • .textContent.textContent to .textContent
  • Data.now() to Date.now().
  • timers.status to timer.status.

finally got multi-timer state and progress rings syncing properly… bugs fixed and back to smooth sailing…

0
0
53
Open comments for this post

7h 12m 8s logged

Devlog 37: Multi-Timer UI Layout & Input Controls

Form Inputs & Adjustments

  • Built HH/MM/SS number input boxes with range limits and zero-padding logic on blur.
  • Implemented stepper adjustment buttons for quick time value tweaking.

Sidebar Timer List Layout

  • Added sidebar timer list container to preview user-created countdown items.
  • Integrated quick action delete buttons for item removal.

Main Dashboard Circular Timer

  • Constructed countdown card layout featuring SVG dynamic progress ring.
  • Centered time readout using tabular-nums formatting to eliminate number jitter.

Action Control Group

  • Laid out card control buttons including play, pause, and replay.

the ui was so tiring… i DID remember to open a new branch (feature/timer-main) …

0
0
7
Loading more…

Followers

Loading…