Skip to content

Fix/load time improved#315

Open
sidhacks wants to merge 3 commits into
piyushdotcomm:mainfrom
sidhacks:fix/load-time-improved
Open

Fix/load time improved#315
sidhacks wants to merge 3 commits into
piyushdotcomm:mainfrom
sidhacks:fix/load-time-improved

Conversation

@sidhacks
Copy link
Copy Markdown
Contributor

@sidhacks sidhacks commented May 26, 2026

Summary

  • what changed: Optimised landing page performance for low-end devices by reducing WebGL shader resolution and iterations, disabling mouse-tracking effects on touch devices, memoising animated grid cell data, replacing Framer Motion animation with CSS keyframe in hero code block, and reducing the loading screen timeout from 3200ms to 1800ms. Added prefers-reduced-motion support across all animations.
  • why it changed: The landing page was janky on low-end and mid-range devices due to a full-resolution WebGL shader running 35 aurora iterations at 60fps, 10 active pointermove listeners on feature cards that serve no purpose on touch devices, and random values being recomputed on every render in the commits grid.

Type of change

  • Bug fix
  • New feature
  • Refactor
  • Documentation
  • Test or CI improvement
  • Starter template change

Related issue

Closes #250

Validation

  • npm run lint
  • npm test
  • npm run build
    List any additional manual verification you performed:
  • Lighthouse mobile audit on editron.in — Performance score 88 (baseline before changes deployed)
  • Chrome DevTools Performance tab with 4x CPU throttle — reduced long tasks on main thread visible in flame chart

Screenshots or recordings

Screenshot 2026-05-27 at 3 39 30 AM Screenshot 2026-05-27 at 3 38 40 AM

Checklist

  • I kept this PR focused on one primary change
  • I updated documentation if behavior changed
  • I did not commit secrets, local logs, or scratch files
  • I am requesting review on the correct scope

Summary by CodeRabbit

  • New Features

    • Added performance detection for low-end devices with automatic rendering optimization.
    • Implemented page visibility detection to pause rendering when tab is inactive.
  • Improvements

    • Optimized loading animation timings for faster visual feedback.
    • Enhanced touch device support by disabling incompatible effects.
    • Improved template modal layout with sticky footer positioning.
    • Strengthened accessibility with refined reduced-motion animations.

Review Change Stack

@sidhacks sidhacks requested a review from piyushdotcomm as a code owner May 26, 2026 22:14
@qodo-code-review
Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@github-actions
Copy link
Copy Markdown

👋 Thanks for opening a PR, @sidhacks!

Your PR has entered the 🚦 PR Review Pipeline.

Standard PR detected — your PR will follow the standard review pipeline.


What happens next

Stage Reviewer Checks
Stage 1 — Automated Validation 🤖 Bot DCO · Format · AI/Slop · Duplicate
Stage 2 — Human Review 👥 Maintainer Code + Quality Review
Stage 3 — PA / Maintainer Review 🔑 Project Admin Final Merge Decision

A pipeline status comment will appear below and update automatically as your PR progresses.


While you wait

  • Sign all commits (git commit -s)
  • Link your issue (Closes #123)
  • Use a feature branch (not main)
  • Avoid unrelated changes

This comment is posted only once.

@github-actions github-actions Bot added the bug Something isn't working label May 26, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Walkthrough

This PR implements device-aware performance optimization and animation refinement across the landing page and UI components. Low-end device detection triggers shader iteration reduction and frame throttling. Touch devices automatically disable expensive glow effects. Animation timings are streamlined, and the commits grid is refactored to precompute cell state, eliminating per-render randomness.

Changes

Device-Aware Rendering Optimization

Layer / File(s) Summary
Shader background low-end device optimization
components/ui/animated-shader-background.tsx
Detects device memory and hover support via navigator.deviceMemory and media query matching. Adjusts pixel ratio and disables WebGL antialiasing for low-end devices. Adds iIterations uniform to the fragment shader and rewrites the animation loop to enforce a per-frame time budget. Pauses/resumes rendering based on document.hidden via a new visibilitychange listener; cleanup removes the listener on unmount.
Glowing effect touch device detection
components/ui/glowing-effect.tsx
Adds isTouchDevice helper that detects touch capability via (hover: none) media query. Combines detected touch state with the existing disabled prop into an effectivelyDisabled flag. Updates all effect guards, dependency arrays, and conditional rendering logic to use effectivelyDisabled instead of disabled alone.

Animation Refinements & UI Polish

Layer / File(s) Summary
CSS hero animation and reduced-motion support
app/globals.css
Introduces hero-card-in keyframe animation and .animate-hero-card utility class for fade/translate entrance effects. Extends the prefers-reduced-motion: reduce rule to disable hero-card and other animations by setting animation: none, opacity: 1, and transform: none !important.
Home page animation timing adjustments
components/marketing/home-page-client.tsx
Reduces isLoading transition delay and shortens section animation durations to duration-500 with slide-in-from-bottom-6. Removes conditional loading state from the features section, now always rendering with constant w-full relative class instead of opacity-0 and animate-in variants.
Commits grid render optimization with memoization
components/ui/commits-grid.tsx
Introduces COMMIT_COLORS constant and buildCellData helper to precompute isHighlighted, shouldFlash, color, and delay for each grid cell. Uses useMemo to memoize cellData based on grid text/dimensions, then renders the grid by iterating over precomputed objects instead of per-render randomness and highlight checks.
Modal action footer sticky positioning
modules/dashboard/components/template-selecting-modal.tsx
Changes template selection modal's "select" step footer from a static bordered flex container to a sticky, centered bottom bar with backdrop blur, translucent background, and rounded corners.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • piyushdotcomm/Editron#230: Both PRs update modules/dashboard/components/template-selecting-modal.tsx to change the "select" step's bottom action area into a sticky, blurred/rounded action bar with Continue/Cancel controls inside it.
  • piyushdotcomm/Editron#157: Both PRs modify modules/dashboard/components/template-selecting-modal.tsx within TemplateSelectionModal's "select" step UI, so the changes overlap in the same component code path.

Suggested labels

ui-ux, area: ui, type:refactor, level:critical, quality:exceptional

Suggested reviewers

  • piyushdotcomm

Poem

🐰 The rabbit hops through code so bright,
Low-end devices now render right,
Touch they detect, animations they trim,
Sixty frames smooth, no stutter or grim!
Memoized grids dance, shaders run lean—
Performance magic on every screen!

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Fix/load time improved' is vague and does not clearly convey the specific optimization work (WebGL, touch devices, animations, etc.) performed in the changeset. Use a more descriptive title like 'Optimize landing page performance for low-end devices' or 'Improve load time via WebGL and animation optimizations'.
Out of Scope Changes check ❓ Inconclusive The template-selecting-modal.tsx change (sticky footer styling) appears unrelated to the landing page performance optimization objectives in #250 and may represent scope creep. Clarify whether the template modal sticky footer change is related to performance goals or should be separated into a distinct PR for better focus.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The PR description is comprehensive, covering what changed, why it changed, includes proper validation evidence (Lighthouse score, DevTools profiling), and provides supporting screenshots.
Linked Issues check ✅ Passed The PR addresses most core objectives from #250: detects low-end devices and reduces WebGL iteration count [animated-shader-background.tsx], disables mouse-tracking on touch devices [glowing-effect.tsx], memoizes grid data [commits-grid.tsx], replaces Framer Motion with CSS animations [home-page-client.tsx, globals.css], and adds prefers-reduced-motion support.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/ui/animated-shader-background.tsx`:
- Around line 21-24: The component currently starts the WebGL RAF animation
unconditionally; check window.matchMedia('(prefers-reduced-motion:
reduce)').matches early (e.g., inside the AnimatedShaderBackground mount/setup)
and, if true, skip creating the RAF loop and heavy shader setup and instead
render a single static frame or don't mount the shader; apply this gating both
where lowEnd/pixelRatio/numIterations are computed and in the code that starts
requestAnimationFrame (and any RAF start in the 117-135 block), ensuring you
bail out before allocating GL resources and avoid calling requestAnimationFrame
or starting the animation loop when prefers-reduced-motion is set.
- Around line 22-29: The shader's iResolution must reflect backing-buffer pixels
(devicePixelRatio) not CSS pixels: after you call
renderer.setPixelRatio(pixelRatio) and renderer.setSize(...), compute and pass
iResolution as (window.innerWidth * pixelRatio, window.innerHeight * pixelRatio)
to the shader uniform used by the fragment shader (update the code where
iResolution is set/updated), and do the same on window resize—use the pixelRatio
variable (from pixelRatio = lowEnd ? 0.5 : Math.min(window.devicePixelRatio,
1.5)) when constructing the THREE.Vector2 or uniform value so gl_FragCoord and
iResolution are in the same coordinate space.

In `@components/ui/commits-grid.tsx`:
- Around line 84-88: cellData is memoized with React.useMemo calling
buildCellData(highlightedSet, total) but the deps array only includes [total],
causing stale cells when highlightedSet changes; update the React.useMemo call
for cellData to include highlightedSet in the dependency array (e.g.,
[highlightedSet, total]) and remove the eslint-disable-next-line comment so the
hook lint rule correctly enforces dependencies for buildCellData/highlightedSet.

In `@components/ui/glowing-effect.tsx`:
- Around line 7-8: GlowingEffect currently calls isTouchDevice() during render
which returns false on the server and can flip on first client render; change
touch detection to client state: remove the render-time isTouchDevice() call and
instead add a useState e.g. const [isTouchDevice, setIsTouchDevice] =
useState(false) and set it in a useEffect that runs window.matchMedia("(hover:
none)").matches (or use addEventListener for changes); update
effectivelyDisabled to depend on this state (the existing effectivelyDisabled
variable in GlowingEffect) so initial SSR markup is deterministic, and ensure
any class toggles that use effectivelyDisabled (the !block/!hidden logic) use
the state value rather than calling isTouchDevice() directly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4f6ac891-0ac5-4767-9b96-d9d68b8f9f76

📥 Commits

Reviewing files that changed from the base of the PR and between f12b223 and efba2d2.

📒 Files selected for processing (6)
  • app/globals.css
  • components/marketing/home-page-client.tsx
  • components/ui/animated-shader-background.tsx
  • components/ui/commits-grid.tsx
  • components/ui/glowing-effect.tsx
  • modules/dashboard/components/template-selecting-modal.tsx

Comment on lines +21 to +24
const lowEnd = isLowEnd();
const pixelRatio = lowEnd ? 0.5 : Math.min(window.devicePixelRatio, 1.5);
const numIterations = lowEnd ? 18 : 35;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Honor prefers-reduced-motion before starting the RAF loop.

This still runs the WebGL animation continuously for users who request reduced motion, so the page keeps its heaviest motion effect alive in the mode that should degrade gracefully. Gate the animation setup on prefers-reduced-motion and render a static frame or skip mounting the shader in that case.

Also applies to: 117-135

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/ui/animated-shader-background.tsx` around lines 21 - 24, The
component currently starts the WebGL RAF animation unconditionally; check
window.matchMedia('(prefers-reduced-motion: reduce)').matches early (e.g.,
inside the AnimatedShaderBackground mount/setup) and, if true, skip creating the
RAF loop and heavy shader setup and instead render a single static frame or
don't mount the shader; apply this gating both where
lowEnd/pixelRatio/numIterations are computed and in the code that starts
requestAnimationFrame (and any RAF start in the 117-135 block), ensuring you
bail out before allocating GL resources and avoid calling requestAnimationFrame
or starting the animation loop when prefers-reduced-motion is set.

Comment on lines +22 to 29
const pixelRatio = lowEnd ? 0.5 : Math.min(window.devicePixelRatio, 1.5);
const numIterations = lowEnd ? 18 : 35;

const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
const renderer = new THREE.WebGLRenderer({ antialias: true });
const renderer = new THREE.WebGLRenderer({ antialias: !lowEnd, powerPreference: "low-power" });
renderer.setPixelRatio(pixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep iResolution aligned with the actual render buffer size.

After setPixelRatio(...), gl_FragCoord is measured in backing-buffer pixels but iResolution still tracks CSS pixels. That changes the shader coordinate space on low-end and high-DPR devices, so the aurora zoom/stretch varies with DPR instead of just getting cheaper to render.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/ui/animated-shader-background.tsx` around lines 22 - 29, The
shader's iResolution must reflect backing-buffer pixels (devicePixelRatio) not
CSS pixels: after you call renderer.setPixelRatio(pixelRatio) and
renderer.setSize(...), compute and pass iResolution as (window.innerWidth *
pixelRatio, window.innerHeight * pixelRatio) to the shader uniform used by the
fragment shader (update the code where iResolution is set/updated), and do the
same on window resize—use the pixelRatio variable (from pixelRatio = lowEnd ?
0.5 : Math.min(window.devicePixelRatio, 1.5)) when constructing the
THREE.Vector2 or uniform value so gl_FragCoord and iResolution are in the same
coordinate space.

Comment on lines +84 to +88
const cellData = React.useMemo(
() => buildCellData(highlightedSet, total),
// eslint-disable-next-line react-hooks/exhaustive-deps
[total]
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the memo dependency currently excludes highlightedSet in CommitsGrid
rg -n -C3 'const cellData = React\.useMemo|react-hooks/exhaustive-deps|\[total\]' components/ui/commits-grid.tsx

Repository: piyushdotcomm/Editron

Length of output: 415


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show more context around highlightedSet, cellData, and buildCellData usage/definition
sed -n '60,140p' components/ui/commits-grid.tsx

# Find and print buildCellData definition block (function or const) if present
rg -n "buildCellData" components/ui/commits-grid.tsx

Repository: piyushdotcomm/Editron

Length of output: 3274


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate exact line for buildCellData
rg -n "buildCellData" components/ui/commits-grid.tsx

# Print buildCellData implementation
line=$(rg -n "function buildCellData" components/ui/commits-grid.tsx | head -n1 | cut -d: -f1)
start=$((line-20))
end=$((line+120))
sed -n "${start},${end}p" components/ui/commits-grid.tsx

# Locate and print generateHighlightedCells to see how width/height (thus total) depends on text
rg -n "generateHighlightedCells" components/ui/commits-grid.tsx
line2=$(rg -n "function generateHighlightedCells|const generateHighlightedCells|generateHighlightedCells\s*=\s*\(" components/ui/commits-grid.tsx | head -n1 | cut -d: -f1 || true)
if [[ -n "${line2}" ]]; then
  start2=$((line2-20))
  end2=$((line2+140))
  sed -n "${start2},${end2}p" components/ui/commits-grid.tsx
fi

Repository: piyushdotcomm/Editron

Length of output: 2033


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Print the beginning of the file (where buildCellData should live) with line numbers
nl -ba components/ui/commits-grid.tsx | sed -n '1,220p'

# Also show the specific memo section again with a bit more context
nl -ba components/ui/commits-grid.tsx | sed -n '60,120p'

Repository: piyushdotcomm/Editron

Length of output: 108


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="components/ui/commits-grid.tsx"

bline=$(rg -n "function buildCellData" "$file" | head -n1 | cut -d: -f1)
gline=$(rg -n "function generateHighlightedCells|const generateHighlightedCells\s*=\s*\(" "$file" | head -n1 | cut -d: -f1 || true)

echo "buildCellData line: $bline"
echo "generateHighlightedCells line: ${gline:-<not found>}"

# Print around buildCellData (clamp start to 1 to avoid sed negative-range errors)
start=$(( bline > 30 ? bline-30 : 1 ))
end=$(( bline + 160 ))
sed -n "${start},${end}p" "$file"

# Print around generateHighlightedCells if found
if [[ -n "${gline:-}" ]]; then
  gstart=$(( gline > 30 ? gline-30 : 1 ))
  gend=$(( gline + 200 ))
  echo "----"
  sed -n "${gstart},${gend}p" "$file"
fi

# Finally, ensure we see the highlightedSet and cellData memo block
echo "----"
sed -n '70,110p' "$file"

Repository: piyushdotcomm/Editron

Length of output: 14196


Fix cellData memo deps to include highlightedSet

buildCellData(highlightedSet, total) uses highlightedSet.has(index) to compute isHighlighted, but cellData is memoized with deps only [total]. When text changes but yields the same total (e.g., same cleaned length), highlightedSet changes while cellData stays stale.

🔧 Proposed fix
-    const cellData = React.useMemo(
-        () => buildCellData(highlightedSet, total),
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-        [total]
-    );
+    const cellData = React.useMemo(
+        () => buildCellData(highlightedSet, total),
+        [highlightedSet, total]
+    );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const cellData = React.useMemo(
() => buildCellData(highlightedSet, total),
// eslint-disable-next-line react-hooks/exhaustive-deps
[total]
);
const cellData = React.useMemo(
() => buildCellData(highlightedSet, total),
[highlightedSet, total]
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/ui/commits-grid.tsx` around lines 84 - 88, cellData is memoized
with React.useMemo calling buildCellData(highlightedSet, total) but the deps
array only includes [total], causing stale cells when highlightedSet changes;
update the React.useMemo call for cellData to include highlightedSet in the
dependency array (e.g., [highlightedSet, total]) and remove the
eslint-disable-next-line comment so the hook lint rule correctly enforces
dependencies for buildCellData/highlightedSet.

Comment on lines +7 to +8
const isTouchDevice = () =>
typeof window !== "undefined" && window.matchMedia("(hover: none)").matches;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
from pathlib import Path

for path in Path(".").rglob("*.tsx"):
    try:
        text = path.read_text(encoding="utf-8", errors="ignore")
    except Exception:
        continue

    if "<GlowingEffect" not in text and "glowing-effect" not in text:
        continue

    print(f"--- {path}")
    for i, line in enumerate(text.splitlines()[:12], 1):
        print(f"{i}: {line}")
    for i, line in enumerate(text.splitlines(), 1):
        if "<GlowingEffect" in line or "glowing-effect" in line:
            print(f"{i}: {line}")
    print()
PY

rg -n -C2 'dynamic\(|ssr:\s*false' app components modules

Repository: piyushdotcomm/Editron

Length of output: 1872


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect the relevant portion of glowing-effect.tsx
echo "===== components/ui/glowing-effect.tsx (around isTouchDevice / effectivelyDisabled) ====="
nl -ba components/ui/glowing-effect.tsx | sed -n '1,220p'

# 2) Find all GlowingEffect callsites
echo
echo "===== All GlowingEffect usages ====="
rg -n --hidden --no-ignore-vcs "<GlowingEffect" .

echo
echo "===== All imports of glowing-effect ====="
rg -n --hidden --no-ignore-vcs "glowing-effect" .

# 3) Check if any callsite is protected by dynamic(..., { ssr: false })
echo
echo "===== dynamic(..., { ssr: false }) near GlowingEffect usage files ====="
rg -n -C4 "dynamic\([^)]*ssr:\s*false" modules components app || true

Repository: piyushdotcomm/Editron

Length of output: 216


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "===== Print components/ui/glowing-effect.tsx (first 260 lines with line numbers via python) ====="
python3 - <<'PY'
from pathlib import Path
p = Path("components/ui/glowing-effect.tsx")
text = p.read_text(encoding="utf-8", errors="ignore").splitlines()
for i, line in enumerate(text[:260], 1):
    print(f"{i:4d}: {line}")
PY

echo
echo "===== All GlowingEffect usages ====="
rg -n --hidden --no-ignore-vcs "<GlowingEffect" .

echo
echo "===== All imports of glowing-effect ====="
rg -n --hidden --no-ignore-vcs "glowing-effect" .

echo
echo "===== Any dynamic(..., { ssr: false }) in files that import GlowingEffect ====="
python3 - <<'PY'
from pathlib import Path
import re

# find files that import GlowingEffect
matches = []
for p in Path(".").rglob("*.ts*"):
    try:
        s = p.read_text(encoding="utf-8", errors="ignore")
    except Exception:
        continue
    if "from \"`@/components/ui/glowing-effect`\"" in s or "from '`@/components/ui/glowing-effect`'" in s:
        matches.append(str(p))
print("IMPORTING_FILES:")
for m in matches:
    print(m)

print("\nDYNAMIC_SSR_FALSE_NEARBY:")
for m in matches:
    # show any dynamic(..., { ssr: false }) occurrences with context
    import subprocess, shlex
    cmd = ["bash","-lc", f"rg -n -C3 'dynamic\\([^)]*ssr:\\s*false' {shlex.quote(m)} || true"]
    out = subprocess.check_output(cmd, stderr=subprocess.STDOUT).decode()
    if out.strip():
        print(f"\n--- {m}\n{out.rstrip()}")
PY

echo
echo "===== Where effectivelyDisabled is computed/used (quick search) ====="
rg -n "effectivelyDisabled|isTouchDevice" components/ui/glowing-effect.tsx

Repository: piyushdotcomm/Editron

Length of output: 11090


Avoid render-time window.matchMedia detection in GlowingEffect.

components/ui/glowing-effect.tsx computes effectivelyDisabled during render via isTouchDevice() (lines 7-8, 40), which returns false on the server and can become true on the first client render, flipping the !block/!hidden classes (lines 150, 189). GlowingEffect is only used from modules/home/features.tsx and isn’t wrapped in a dynamic(..., { ssr: false }) boundary, so this can cause hydration/layout differences on touch devices. Move touch detection into client state from a useEffect (or handle the fallback in CSS) so initial markup is deterministic.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/ui/glowing-effect.tsx` around lines 7 - 8, GlowingEffect currently
calls isTouchDevice() during render which returns false on the server and can
flip on first client render; change touch detection to client state: remove the
render-time isTouchDevice() call and instead add a useState e.g. const
[isTouchDevice, setIsTouchDevice] = useState(false) and set it in a useEffect
that runs window.matchMedia("(hover: none)").matches (or use addEventListener
for changes); update effectivelyDisabled to depend on this state (the existing
effectivelyDisabled variable in GlowingEffect) so initial SSR markup is
deterministic, and ensure any class toggles that use effectivelyDisabled (the
!block/!hidden logic) use the state value rather than calling isTouchDevice()
directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Landing Page Lags on Low-End Devices

1 participant