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

Ship #5

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

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

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

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
Ship #4

WHAT I MADE/THINK?

I expanded TickTock from a single timer into a multi-tool station (Hub)! This time, I built a Pomodoro Timer and a Time Progress Displayer. 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#
  • ⭐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

⭐means new features of the previous ship

WHAT I LEARNT?

  • A lot of new things about git
  • JS, Astro…

TRY IT!

  • 13 devlogs
  • 22h
  • 15.66x multiplier
  • 346 Stardust
Try project → See source code →
Open comments for this post

29m 32s logged

Devlog 36: Update Docs & Merge

Update Docs

  • Readme: Add the links of the new tools
  • Ship#4: Write Ship#4.md

Merge!!!!!

  • Merge feature/pomodoro into main
  • Fortunately no error poping out!
0
0
13
Open comments for this post

52m 27s logged

Devlog 35: Pomodoro State Transition & Auto-Loop Refactoring

Core Logic & State Fixes

  • Auto-Phase Transition Fix: Resolved state lock (status: 'running') preventing automatic transition from Focus to Break. Added explicit status resetting in handlePhaseEnd before invoking startTimer.
  • Timer Precision: Replaced Math.round with Math.ceil in countdown logic to eliminate early sound triggers caused by rounding errors.
  • Timestamp Recalibration: Implemented dynamic endTime re-calculation when switching modes (workbreak) to maintain state consistency.
0
0
11
Open comments for this post

2h 12m 45s logged

Devlog 34: Pomodoro Core Timer & Segmented Timeline Integration

Features

  • Implemented static audio notification system via HTML5 Audio API targeting public/sounds/notification.mp3.

Architecture & State Management

  • Implemented timestamp delta verification (endTime - Date.now()) to maintain countdown accuracy during background tab throttling or page reloads.
  • Decoupled primary control actions across main page and sidebar controls (#menu-start-btn, #cycles-input).

Bug Fixes & Refactoring

  • Fixed ReferenceError during event initialization by enforcing state argument scoping within bindEvents.
  • Refactored loadStateFromLocalStorage parsing logic to filter "undefined" string literals and clear corrupted cache gracefully.
0
0
11
Open comments for this post

4h 2m 19s logged

Devlog 33: Pomodoro Segmented Timeline & Layout Integration

Segmented Timeline Layout

  • Integrated BaseLayout slots for the new Pomodoro page, separating sidebar settings from the main dashboard.
  • Built a visual segmented timeline (.timeline-track) with flex-proportional work/break segments and a dynamic progress pin (.timeline-pin).

Core Logic & State Setup

  • Refactored state object fields (workDuration, breakDuration, timeRemaining) to ensure clean state initialization.
  • Added timestamp delta checking on startup to preserve accurate remaining time across page reloads or background tabs.
0
0
13
Open comments for this post

18m 20s logged

Devlog 32: Dynamic Canvas Aspect Ratio Calculation

Features & Refactoring

  • Implemented dynamic aspect ratio calculation for PNG exports (Height = 140 * Count + 180).
  • Applied responsive auto-scaling for .export-canvas to ensure optimal vertical spacing regardless of selected cards count.
  • Merged feature/export-image branch into main after verifying clean template rendering and correct node referencing.
0
0
19
Open comments for this post

2h 17m 24s logged

Devlog 31: Template Canvas Architecture & Reference Refactoring

Independent Canvas Architecture

  • Replaced direct DOM manipulation of live dashboard elements with a dedicated, off-screen template canvas (.export-canvas).
  • Cloned active .progress-card elements into an isolated container (.export-cards-holder), ensuring the on-screen UI remains completely untouched and non-flickering during image generation.
  • Moved aspect ratio, high-resolution dimensions (600x600), padding, and font-scaling rules directly into CSS for clean separation of concerns.

Error Fixes & Cleanup

  • Fixed ReferenceError caused by leftover references to targetContainer and stampEl inside initExportImageFeature.
  • Updated html2canvas target from main dashboard container to the temporary canvasEl.
  • Streamlined fallback DOM cleanup logic inside the try...catch block to guarantee off-screen elements are properly garbage collected.
0
0
8
Open comments for this post

1h 23m 25s logged

Devlog 30: Image Export Feature & Template Refactoring

Image Export Feature

  • Integrated html2canvas library to enable one-click PNG image export of the active progress dashboard.
  • Added an “Export as Image” button inside the custom sidebar menu with dedicated styling.
  • Handled theme-aware background rendering by dynamically querying computed global CSS variables (--bg-app).

DOM Template & Dynamic Watermark

  • Refactored dynamic watermark creation using the HTML <template> element (#export-watermark-template), cleanly separating DOM structure from JavaScript execution logic.
  • Configured dynamic timestamps using now.toLocaleString() to inject real-time snapshot dates and times into exported images.
  • Added ignoreElements filtering in html2canvas to prevent unchecked/hidden .progress-card elements from creating top/bottom visual gaps in exported images.

Bug Fixes & Refactor

  • Fixed a TypeError on insertBefore/appendChild by referencing clone.firstElementChild to extract the correct Element Node from DocumentFragment.
  • Resolved HTML/JS ID typos (export-watermark-template) and method call mismatches to ensure reliable script execution.
0
0
4
Open comments for this post

58m 3s logged

Devlog 29: URL Hash Sync, LocalStorage Persistence & Universal Share Event

URL & State Persistence

  • Integrated URL Hash (#year,month,...) and localStorage synchronization into time-progress.js to preserve users’ toggle preferences across reloads and shares.
  • Added a hashchange event listener to ensure UI check states dynamically update when users use browser navigation (Back/Forward).

Centralized Layout Share Event

  • Refactored the #share-menu-btn event listener into BaseLayout.astro, eliminating duplicate share logic across individual tool pages.
  • Leveraged document.title dynamically to provide clean, contextual titles for native Web Share API and clipboard copy fallbacks.
0
0
4
Open comments for this post

1h 3m 57s logged

Devlog 28: Layout Overflow Fixes and UI Polish

Layout & Scrollbar Stability

  • Added scrollbar-gutter: stable to html in global.css to reserve vertical scrollbar space, preventing horizontal overflow caused by layout reflow.
  • Applied overflow-x: hidden to main containers and .progress-card to prevent percentage tags and thumbs from clipping past container edges at 100%.

CSS Rule Corrections

  • Fixed CSS property error by setting .track width to 100% instead of unitless value.
  • Fine-tuned progress bar wrapper styles to ensure smooth visual layout under both dark and light themes.
0
0
2
Open comments for this post

4h 3m 58s logged

Devlog 27: Time Progress Bar Feature Porting and JS Modular Refactoring

Astro Slot Architecture & CSS Variable Integration

  • Ported the standalone Time Progress Bar tool into the Astro layout system using designated slots (#head, #header-content, #custom-menu, and #main-content).
  • Converted hardcoded hex colors into semantic global theme CSS variables (--accent-color, --component-bg-standard, --text-heading), ensuring native support for Dark and Light mode toggling.
  • Replaced the dropdown filter with sidebar multi-select checkboxes for custom control over visible time progress units.

JavaScript Modular Refactoring & Bug Fixes

  • Decoupled single-script logic into dedicated, single-responsibility functions (initSidebarToggles, calculateTimeProgress, updateTicksUI, updateProgressCardUI, and updateSingleCardUI).
  • Resolved JavaScript syntax errors, including missing function keywords, JS Automatic Semicolon Insertion (ASI) line-break issues on return statements, and uncalled Date method parentheses.
  • Streamlined animation frame rendering by passing structured data from math calculations directly into UI updater functions.
0
0
4
Open comments for this post

52m 8s logged

Devlog 26: Typo Correction and Expandable Directory Menu

Typo Correction

  • Fixed property naming error from –accent-contract-text to –accent-contrast-text in global CSS.

Expandable Tools Directory

  • Converted static directory links into a native component with smooth arrow rotation styling.
  • Enabled server-side open status via open={isHomePage} in BaseLayout, defaulting to expanded on the home hub and collapsed on sub-tool pages.
0
0
1
Open comments for this post

1h 22m 22s logged

Devlog 25: Theme Toggle Implementation with Dark and Light Modes

Light Theme Tokens Override

  • Added :root[data-theme=“light”] in global.css to swap semantic theme variables for light background, borders, and high-contrast amber accents.
  • Preserved existing component styles while smoothly transitioning body colors on theme switch.

Sidebar Toggle Component and Logic

  • Integrated a theme toggle button (#theme-toggle-btn) inside the BaseLayout header actions.
  • Built persistent theme state logic using localStorage and system prefers-color-scheme detection.
  • Used textContent on icon elements to dynamically switch between dark_mode and light_mode icons without type errors.
0
0
4
Open comments for this post

2h 14m 41s logged

Devlog 24: Color Architecture Refactoring with Design Tokens

Two-Tier CSS Variables

  • Global Tokens: Extracted hardcoded hex colors into primitive color names inside global.css.
  • Theme Tokens: Created a semantic layer mapping elements like –bg-app and –accent-color directly to global tokens.

Clean Codebase Update

  • Component Styles: Replaced absolute colors across the layout, dashboard hub, countdown, and clock templates with var() variables.
  • Script Alignment: Updated dynamic checkmark colors in JavaScript to read –accent-color instead of raw hex values.
  • Future Scope: The design is now fully abstracted, meaning light mode implementation will only require token swapping without editing individual component code.
0
0
4
Ship #3

WHAT I MADE/THINK?

I expanded TickTock from a single timer into a multi-tool station (Hub)! This time, I built a beautiful, highly customizable Digital Clock. 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
  • ⭐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#
  • Lightweight

⭐means new features of the previous ship

WHAT I LEARNT?

  • A lot of new things about Astro and NodeJS
  • How to structure routes for multiple tools (Refactoring files)
  • Advanced CSS (using global variables to adjust layout gaps dynamicly)

REPLIES

Thank you so much for the 115 stardust and the amazing feedback! I read every single review from Ship #2, and they helped me make this update so much better.

1. ABOUT MORE FEATURES

Many suggested adding more tools or events. I turned the website into a Hub and built the Digital Clock as our second official tool!

2. ABOUT THE SCREENSHOT IN README

Two reviewers mentioned adding screenshots. I’ve updated the README with fresh screenshots so people skimming through can see the UI instantly.

TRY IT!

  • 9 devlogs
  • 18h
  • 7.76x multiplier
  • 136 Stardust
Try project → See source code →
Open comments for this post

16m 25s logged

Devlog 23: Global Branding Relocation and Logo Navigation

Moving Title Label to BaseLayout

Unifying the brand and improving UX

  • Header Linkification: Refactored the main title-label (“TickTock”) out of individual page templates and integrated it directly into the global BaseLayout.astro.
  • Back-to-Home UX: Wrapped the brand title in an <a> tag. Now, clicking the brand logo on any sub-tool instantly routes the user back to the home dashboard Hub, offering an intuitive, web-app-like navigation experience.
0
0
5
Open comments for this post

25m 7s logged

Devlog 22: F11-Equivalent Fullscreen via Root Element

Standardizing Fullscreen to document.documentElement

Fixing disappearing layout elements

  • The Pitfall: Previously, calling requestFullscreen() on the individual #clock-screen container caused the browser to isolate it from the DOM layout. This triggered default browser styling which rendered a pitch-black backdrop, and completely hid crucial layout parts like the header, footer, and side menu buttons.
  • The Solution: We shifted the fullscreen API target from the sub-container directly to document.documentElement (the global <html> node). This aligns the button’s behavior perfectly with standard keyboard F11 fullscreen events.
  • The Result: All global UI elements (header, footer, navigation) now scale smoothly and remain perfectly visible and interactive without any layout shifts or z-index clashing.
0
0
6
Open comments for this post

1h 11m 1s logged

Devlog 21: Architecture Normalization and Layout Fine-Tuning

Directory Restructuring & Future-Proofing

Preparing for scalability

  • Digital Clock Renaming: To prevent future routing conflicts as the project scales, we successfully renamed clock.js to digital-clock.js and adjusted the main page path to /src/pages/digital-clock/. This cleanly isolates this feature from upcoming modules like World Clock or Pomodoro Timer.
  • Dependency Clean-up: Updated all asset paths and module script injections across the hub, fully standardizing the multi-tool routing structure under the /TickTock/ basePath.

Layout Fixes with Global CSS Variables

Resolving invalid CSS properties via JS injection

  • Replacing Non-Standard Styles: Fixed a crucial layout issue where arbitrary if(...) conditions inside CSS were breaking colon component constraints.
  • Dynamic Width Injection: Migrated the layout parameters directly into digital-clock.js using the standard document.documentElement.style.setProperty API. The .colon element now seamlessly reads the responsive --clock-colon-width CSS variable, adapting perfectly across Sans, Serif, and Mono configurations without any jumping side effects.
0
0
3
Open comments for this post

2h 33m 57s logged

Devlog 20: Settings Memory and Dynamic Sharing

Adding Setting Memory and URL Sync

Keeping your clock layout saved

  • Persistent settings: The clock now remembers your favorite layout. Your choice of time format (12/24h) and font style is instantly saved directly to your browser’s local storage.
  • URL sync: We linked these settings directly to the URL hash (like #12hr&mono). When you refresh or load the page, your exact preferred theme loads up right away.

Smart Sharing and Hub Integration

Spreading the time and completing the hub

  • Dynamic sharing: Added a share button that grabs your exact custom clock URL. It uses the Web Share API when available, and easily falls back to copying the link to your clipboard with a smooth checkmark animation on success.
  • Connecting the dashboard: Linked the completed clock page to our homepage hub grid and updated the site layout, officially making TickTock a multi-tool station.
0
0
0
Open comments for this post

3h 34m 38s logged

Devlog 19: Building the Adaptable Digital Clock

Implementing Native Date Formatting

  • Problem: The clock header needed to show the full current date (e.g., “Sunday, July 12, 2026”) dynamically without taxing browser performance or importing heavy external date libraries.
  • Solution: Added a #date-label placeholder to the template and used the native JavaScript toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }) inside the main runtime loop to render lightweight, perfectly formatted timestamps on every update.

Creating Fluid Visual Oscillations via Math.sin()

  • Problem: Traditional blinking colons look rigid and distracting, failing to deliver a premium, organic feel for an active time-management tool.
  • Solution: Avoided simple CSS toggles and leveraged a true trigonometric formula inside a requestAnimationFrame loop. By mapping high-precision timestamps through Math.sin(), the opacity gracefully curves between 0.2 and 1.0, producing a perfectly smooth, wave-like breathing animation.

Binding Custom Display and Layout Controls

  • Problem: The interface required instant controls for 12/24-hour formats, font adjustments, and a standalone full-screen view while managing layout side effects.
  • Solution: Wired up event listeners to modify global runtime states and inline CSS font families on the fly. Integrated the HTML5 Fullscreen API onto the #clock-screen element, backed by a global fullscreenchange listener to seamlessly catch manual ESC escapes and keep the toggle button states perfectly in sync.
0
0
1
Open comments for this post

26m 27s logged

Devlog 18: Adding Hub Sharing Functionality

Integrating Client-Side Script Safely

Implementing the Homepage Share Button

  • Problem: The dashboard needed a simple button to share the current hub URL, but running browser APIs directly could break Astro’s static site generation (SSG) compiler.
  • Solution: Added an inline <script is:inline> block to the index page. This bypasses the server-side build process and safely binds the sharing and clipboard logic only when the page loads in the user’s browser.
0
0
3
Open comments for this post

1h 37m 44s logged

Devlog 17: Project Hub and README Expansion

Moving from a Single Page to a Tool Hub

  • Goal: Transformed TickTock from a single countdown page into a comprehensive time-management utility hub powered by Astro.
  • Implementation: Created a main dashboard page (src/pages/index.astro) to serve as the gateway for current and future time tools, using a shared layout for a consistent user experience.

Adding Future Roadmap and Project Documentation

  • Goal: Wrote a complete README.md to document the new project architecture, local testing steps, and automated GitHub Pages deployment.
  • Future Vision: Updated the repository roadmap to announce upcoming tools built for the Hack Club Stardance event, including a Pomodoro Timer, World Clock Board, Minimalist Timer, and Time Progress Bars.
0
0
3
Open comments for this post

1h 46m 13s logged

Devlog 16: Dashboard Layout Fixes

Fixing Layout and Compression Issues

Compressed Card Icons

  • Problem: The card icons shrank and deformed when the screen size changed.
  • Solution: Added flex-shrink: 0; to the icon class to force them to keep their correct size.

Cards Stacking Vertically

  • Problem: The tool cards unexpectedly stacked into a narrow, single column right in the middle of the screen. Even though there was plenty of empty space on both sides of the desktop browser, the grid refused to expand horizontally and display the cards side-by-side.
  • Troubleshooting:
    • The grid’s layout formula was correctly set to repeat(auto-fit, minmax(250px, 1fr)), which should have allowed multiple columns.
    • However, the parent container (.home-container) was set to display: flex with align-items: center. In a vertical Flexbox layout, this alignment forces child elements like the grid to shrink to their absolute minimum width based on content, instead of filling the screen.
    • To make matters worse, a strict max-width: 300px; was hardcoded onto the .tool-grid. Since two cards plus their gaps required at least 525px to sit side-by-side, the 300px restriction made it mathematically impossible for the browser to create a second column.
  • Solution:
    • Removed the restrictive max-width: 300px; from the grid and replaced it with a generous max-width: 1200px; to allow proper breathing room on large screens.
    • Added width: 100%; to the grid class, forcing the grid container to break out of the Flexbox compression and stretch completely across the parent container.
    • This allowed the responsive auto-fit engine to finally see the available width and cleanly arrange the cards into multiple columns.

Fixing Grid Spacing and Syntax Errors

Layout Breaking Off-Screen

  • Problem: The grid expanded past the screen edges and cut off the card content.
  • Solution: Added box-sizing: border-box; to the main container so that padding is counted inside the total width.

Broken Units and Side Scrollbars

  • Problem: An annoying horizontal scrollbar appeared at the bottom of the page.
  • Solution: Fixed a typo where width: 100sww; was written instead of 100svw, and added body { margin: 0; } to clear default browser spaces.
0
0
2
Open comments for this post

5h 43m 42s logged

Devlog 15

Phase 1: Creating the Skeleton and Splitting Components

Overextending the Style Files

The project started as a single page where all HTML, CSS, and JS lived together. When I created the unified BaseLayout.astro, I kept the old global.css. However, that file had specific styles just for the countdown page, which broke the layout of the new homepage.

Cleaning Up Style Pollution

To fix this, I moved the countdown-specific CSS directly into the <style> tag of the countdown page (index.astro). Astro automatically confines these styles to their own page, ensuring they no longer mess up the homepage layout.

Phase 2: Fixing Astro’s Route Misinterpretation

Keeping Scripts in the Wrong Folder

I originally placed the logic script (script.js) inside the src/pages/countdown/ folder to keep it close to the page. During local testing, Astro threw an error saying there was no API route handler for that JavaScript file.

Moving Scripts to a Dedicated Folder

I learned that Astro treats every file inside src/pages/ as a public URL or an API route. To fix this, I moved the file to a new src/scripts/ folder and renamed it countdown.js, keeping the pages folder strictly for actual web pages.

Phase 3: Resolving Build Crashes from File Names

Using Special Characters in Names

Inside my documentation folder, I named a development note file ship#2.md. When I ran npm run build, the entire build process crashed immediately with a path error.

Removing the Broken Characters

The build tool (Vite) treats the # symbol as a URL anchor link, which breaks file path reading. I renamed the file to ship2.md, and the system was able to parse the path and build successfully.

Phase 4: Overcoming the Environment Conflict (Server vs. Client)

Running Browser Code on the Server

This was the biggest challenge. When I imported countdown.js into the page, the build failed multiple times, throwing errors like window is not defined and document is not defined.

Protecting the Code with Environment Guards

Astro runs pages on the server to generate static HTML during the build step. Because Node.js does not have browser features like window or document, the script crashed.

I fixed this with two steps:

  1. I imported the script using the ?url suffix in Astro so the server only records its path instead of running it.
  2. I wrapped all the browser-specific logic inside a typeof window !== "undefined" check. This ensures the script stays quiet during the server build and only runs once it reaches the user’s browser.
0
0
2
Ship #2

WHAT I MADE/THINK?

I made a long-term countdown timer for events. It’s really hard for me to build things in a way that is completely new to me. I’ve been stuck not only with programming languages but also with English. However, through this project (STARDANCE), though I didn’t create something really impressive, I think I learnt A LOT.

Features

  • Live Countdown
    • Full mode
    • ⭐Days mode
  • Customizable
    • ⭐Change Target Date
    • ⭐Edit Event Title
  • ⭐automatically save in localStorage & url#
  • ⭐share btn
  • Dark Mode UI

⭐means new features of the previous ship

WHAT I LEARNT?

  • basic GIT code
  • basic HTML/CSS3/JS
  • How to write DevLogs

REPLIES

I’ve read all the replies of the ship#1. And lots of them mentioned the same thing. Thanks to everyone who give me feedback. Hope there’s the better version of previous ships.

1. ABOUT CHANGEABLE TARGET

Now you can pick any target date and even edit the event title right from the sidebar.

2. ABOUT LANGUAGE

I’ve fully migrated the app to English now.

3. ABOUT DEVLOG

I’ve leveled up my devlog game for this update—documented all the engineering details and bugs I fixed this time.

TRY IT!

  • 13 devlogs
  • 13h
  • 9.33x multiplier
  • 115 Stardust
Try project → See source code →
Open comments for this post

50m 12s logged

Devlog 14: Localization Migration and Pre-Ship Consolidation

UI Text Internationalization

  • Migrated all hardcoded multi-byte interface character arrays across template structures (index.html) and operational state modules (script.js) into standardized Western European typography strings.
  • Refactored semantic definitions within input control placeholders and baseline reference containers to achieve uniform structural layout scaling under single-byte font rendering constraints.

Documentation and Release Management

  • Compiled a foundational system architectural reference (README.md) specifying setup logic, reactive routing hooks, and custom persistence implementations.
  • Executed full client-side behavior validations on state-tracking components ahead of the definitive production deployment pipeline for Ship #2.
0
0
4
Open comments for this post

2h 6m 22s logged

Devlog 13: Native Sharing Integration and Address Synchronization Control

Native Sharing and Fallback Mechanics

  • Integrated a social propagation module (#share-menu-btn) inside the header actions block, utilizing the Web Share API to access native mobile distribution panels.
  • Engineered an automated asynchronous clip fallback sequence that overrides processing blocks on unsupported desktop environments, programmatically duplicating host URL hashes via the navigator clipboard asset pool.
  • Applied stateful visual interaction hints onto the interactive sharing interface, dynamically toggling system icons to verify action fulfillment before returning properties to base states.

Hash Serialization and Router Interdependency Fixes

  • Resolved an critical structural validation bug inside the initial state loader (loadInitialState) where an premature execution return statement truncated processing flows, preventing state restorations.
  • Re-architected data assignment flows inside initialization cycles (initTimer), deploying window.history.replaceState() to inject fully compiled variable string parameters back into empty browser URI paths.
  • Secured total address compliance across baseline entries, guaranteeing structural data layers are available to secondary network nodes even when sharing operations occur prior to custom value updates.
0
0
4
Open comments for this post

32m 32s logged

Devlog 12: Fluid Typography and Viewport-Adaptive Interface Spacing

Viewport-Proportional Layout Calibration

  • Implemented fluid layout scaling mechanics across the primary text blocks utilizing the CSS clamp() function, anchoring layout metrics dynamically between absolute pixel boundaries and relative viewport height units (vh).
  • Re-architected spacing margins below the core header display (#event-label) to smoothly scale inside an adaptive range (clamp(5px, 2vh, 30px)), optimizing structural vertical padding on shifting device orientations.
  • Calibrated upper layout boundaries for the structural footer element (#target-label) using fluid scaling boundaries (clamp(15px, 3vh, 40px)), ensuring consistent geometric clear space relative to adjacent countdown blocks.

Text Alignment and Flow Refactoring

  • Transformed the target calendar description layer (#target-label) from inline formatting definitions into explicit block layout models (display: block), stabilizing custom spacing calculations and forcing uniform horizontal element boundaries.
  • Enforced complete cross-axis block isolation by assigning absolute width restrictions (width: 100%) onto trailing description elements, smoothly pushing metadata strings down beneath the dynamic flexible tracking container.
0
0
1
Open comments for this post

1h 57m 47s logged

Devlog 11: Modular Display Mode Architecture and Layout Jitter Resolution

Feature Implementation & State Persistence

  • Introduced a feature toggle layout inside the sidebar control node, offering real-time transitions between comprehensive chronological breakdowns and solitary metric configurations.
  • Wired state persistence modules utilizing the local browser data subsystem (localStorage) to preserve client display configurations across session cycles and application reboots.
  • Updated the data ingestion routing logic (loadInitialState) to safely aggregate user layout states without stepping over parameter strings delivered via URL fragment references.

Precision Calculation & Dynamic Interface Masking

  • Integrated an isolated decimal extraction calculation routine within the interval processing tree (updateTimer) dedicated to managing strict single-unit tracking parameters.
  • Configured programmatic style visibility switches across atomic timer components, enforcing clean element masking on non-applicable duration counters when single-unit modes trigger.

Typographic Stabilization & Layout Shifting Mitigation

  • Corrected a severe layout jitter anomaly inside flexible grid clusters caused by variable font character dimensions shifting container boundaries during fast string state invalidations.
  • Implemented font-variant-numeric: tabular-nums to enforce strict monospaced numeral allocation, keeping external box dimensions static regardless of structural text mutations.
  • Introduced a dynamic responsive structural modifier block (.mode-single) to adjust component paddings, implement generous baseline tracking, and elevate text sizing bounds when processing simplified metrics.
0
0
1
Open comments for this post

1h 27m 6s logged

Devlog 10: Structural File Extraction and Modular Synchronization Stability

Code Base Decomposition and Externalization

  • Refactored the unified codebase by isolating inline design frameworks and layout scripts into dedicated style.css and script.js internal resources.
  • Streamlined index.html structure down to essential structural markup definitions, using external linkages to boost source reading efficiency and code maintainability.

Character Processing and Stability Verification

  • Verified text encoding boundaries across external routing changes to preserve multibyte text inputs (“目標日”, “目標”) without producing character distortion issues.
  • Maintained responsive flex alignments and layout fluid bounds on smaller screens while decoupling runtime system layers.
0
0
2
Open comments for this post

1h 28m 28s logged

Devlog 09: Synchronization Bug Fixes and URL Component Decoding

Argument Reference and Logic Rectification

  • Corrected a ReferenceError inside the titleInput listener by swapping an un-sanitized token (newDate) with the valid, persistent variable targetString.
  • Fixed an assignment error where a single operator (if(newTitle="")) muted intended comparison logic, replacing it with a strict equality check (newTitle === "").

URL Normalization and Component Decoding

  • Integrated decodeURIComponent() into loadInitialState() and the hashchange observer to prevent percent-encoded character corruption.
  • Resolved text distortion for multibyte layouts (e.g., Chinese characters), ensuring continuous string fidelity across shared links.
  • Established a default text fallback (“目標”) to secure interface rendering stability during empty input states.
0
0
3
Open comments for this post

57m 28s logged

Devlog 08: Viewport Configuration and Responsive Layout Calibration

Viewport Meta Integration and RWD Layering

  • Integrated the standard responsive configuration tag <meta name="viewport" content="width=device-width, initial-scale=1.0"> into the document structure header.
  • Resolved a layout compression behavior where mobile rendering engines applied fallback desktop scaling parameters (typically a virtual width of 980px), forcing severe global downscaling on compact displays.
  • Enabled native device pixel scale translations, forcing media container thresholds to evaluate against true hardware dimensions rather than high-density viewport projections.

Fluid Grid and Token-Based Scaling

  • Fixed an interface clipping issue where structural boundaries failed to dynamically contract on viewport widths below 600px.
  • Activated the custom @media (max-width: 600px) breakpoint directives, downscaling internal flex container gaps from 15px to 10px and adjusting modular countdown component nodes for enhanced display symmetry.
  • Re-calibrated proportional font metrics across mobile layouts, mapping secondary tracking units down to a structured 1.6rem baseline and bringing the primary title signature to an optimized 2rem boundary.

Cross-Platform Interface Layout Fixes

  • Restructured flex-wrap component mechanics within the core visualization container to smoothly adapt from unified desktop rows into multi-line mobile block grids.
  • Eliminated persistent scrollbar overheads on handheld viewports by normalizing absolute coordinate assets and applying elastic percentage constraints across core elements.
0
0
4
Open comments for this post

23m 7s logged

Devlog 07: URL Hash Routing Priority and Timer Encapsulation Debugging

Feature and Priority Cascading

  • Extended the state management architecture to support deep-linking properties using URL fragments (window.location.hash).
  • Established a strict target resolution cascading hierarchy where URL fragment inputs take precedence over local user configuration memory, which in turn overrides the default fallback value (URL Hash > LocalStorage > “2027-01-01”).
  • Implemented a regex filter pattern (/^\d{4}-\d{2}-\d{2}$/) to sanitize incoming window location string tokens prior to committing them to the execution state.

Refactoring and State Synchronization

  • Modularized individual timer logic fragments into a single initialization routine initTimer(). This routine synchronously updates text container parameters, binds default input values, clears residual interval clocks, and re-allocates tracking loops.
  • Modified input element state transformation bindings to mirror newly elected target values into the URL fragment row (window.location.hash) concurrently with local system memory blocks.

Resolution of Block Scope Diagnostics

  • Scope Overlap Fix: Corrected a critical runtime ReferenceError located inside the initTimer() wrapper where repeating the let primitive on the timerId reference allocated a local block-scope variable that collided with pre-initialization clear routines. Removing the redundant declarative keyword reinstated proper execution.
    -Missing Invocation Fix: Appended an initial entry point declaration initTimer(targetString) to successfully boot up active countdown cycles on fresh page load sequences.
0
0
2
Open comments for this post

55m 11s logged

Devlog 06: Sidebar Menu and Persistent LocalStorage Integration

Requirements and Architecture

  • Adopted the HTML5 semantic element to create a dedicated, off-screen sidebar panel for user controls, separating configuration options from the main countdown content.
  • Integrated Google Material Icons stylesheet to render interactive trigger (“menu”) and dismissal (“close”) action elements.
  • Implemented a native calendar interface using to capture target date modifications directly from the client view.

Styling and Motion Mechanics

  • Utilized fixed positioning (position: fixed) to pin the sidebar along the right viewport boundary, utilizing full height (100vh) to serve as a slide-out drawer.
  • Applied transform: translateX(100%) to fully obscure the panel behind the right viewport edge by default, attaching a smooth CSS transition property (0.3s ease).
  • Created a structural “.open” modifier class applied to the sidebar element (sidebar.open) that neutralizes the horizontal translation (translateX(0)) to bring the drawer into view upon click events.

State Persistence via LocalStorage

  • Refactored the global variable initialization to prioritize data retrieval from browser memory using localStorage.getItem(“targetDate”), ensuring fallback capability to the hardcoded default date string (“2027-01-01”) if empty.
  • Bound a “change” event listener to the date input element. When a user updates the field, the new value is mirrored into localStorage under the unified key “targetDate”.
  • Configured runtime updates where changing the input dynamically forces a complete recalculation of the timestamp integer and immediately restarts the global interval timer thread to prevent rendering stale countdown frames.

Critical Bugs and Diagnostics Code Review

  • Syntax Error Fix: Corrected an unescaped double-quote attribute typo inside the HTML element declaration where id=”“sidebar was breaking JavaScript’s DOM node selection lookup query.
  • Selector Misalignment Fix: Resolved an animation breakdown where the “.open” conditional style rule was incorrectly targeted at the menu button instead of the sidebar wrapper element, preventing the slide-out sequence.
  • Namespace Sync Fix: Addressed a string mismatch bug where initialization logic incorrectly requested the corrupted key string “targerDate” while event dispatchers stored mutations under “targetDate”, which consistently caused storage caching to break on reload.
0
0
1
Open comments for this post

33m 8s logged

Devlog 05: Integrating Google Fonts Icons

1. Goal

  • Implement a hamburger menu button by integrating Google Material Icons into the project.

2. Step 1 Implementation

  • Added the Google Material Icons stylesheet link to the .
  • Created a <button> containing a <span> with the material-icons class and the text “menu” to render the hamburger icon.
  • Styled the button using CSS (background: none, border: none) to remove default browser styling and positioned it at the top-left corner using position: absolute.
0
0
1
Open comments for this post

25m 2s logged

Devlog 04: Dynamic Time Box

VisibilityRequirement

Hide time boxes that have a value of 0 to keep the UI clean, but prevent a box from hiding if a larger time unit still holds a value (e.g., if years > 0, months must not be hidden even if months == 0).

Solution

Implemented a cascading flag logic (let hasValue = false) executed from the largest unit (years) down to the smallest (minutes). Once any larger unit turns the flag true, all subsequent boxes remain visible regardless of their own value. Box elements are hidden dynamically using parentElement.style.display = "none".

0
0
1
Open comments for this post

37m 49s logged

Devlog #2: Precision Countdown Algorithm Fixes

Problem

The previous countdown relied on dividing total seconds, which failed to calculate years and months accurately because real-world months have a variable number of days (28, 30, 31).

Solution

Shifted from pure division to a calendar-based object subtraction method. The system now calculates the differences for Y, M, D, H, M, S individually and applies a borrowing logic from the smallest unit up to the largest. It uses new Date(Y, M, 0).getDate() to dynamically fetch the exact number of days in the previous month when borrowing days.

Logic Debunk: mo < 0 vs mo <= 0

The correct condition is mo < 0. The variable represents the difference between months. If mo equals 0, the target month and current month are the same, meaning no year needs to be borrowed. Using <= 0 would trigger a false borrow when months are identical, causing the month value to incorrectly jump by +12 and the year to decrease by 1.

Bug Fixes

Corrected the day borrowing condition from if (mo < 0) to if (d < 0).
Fixed a typo where let m (minutes) was mistakenly subtracting now.getMonth() instead of now.getMinutes().

0
0
3
Ship #1

What I Made
I made a Countdown Web App called “Tick Tock.” It shows the exact years, months, days, hours, minutes, and seconds left until January 1, 2027.

What Was Challenging
Calculating months and years was hard. Months have different days (28, 30, or 31), so I had to write smart JavaScript code to borrow days and keep the timer 100% accurate.

What I Am Proud Of

  1. It Works!: Actually this is my first time using html to build a website.
  2. Clean Design: I fixed the layout bugs and made a dark-mode interface.

How to Test It
https://klhrd.github.io/TickTock/

  • 1 devlog
  • 2h
  • 2.98x multiplier
  • 5 Stardust
Try project → See source code →

Delete project?

Are you sure you want to permanently delete this project? This action cannot be undone.

All devlogs, followers, and associated data will be removed.

Followers

Loading…