Real Dark Mode util
Really dark (◐‿◑)
Inspired by this work.
Examples
Basic Usage
The light follows your cursor. When you press and hold, the light stops moving and points at the mouse position.
Use the v-util-real-dark directive to mark the elements that should cast shadows.
Dark Mode is a display mode that darkens the interface background and brightens the text.
The main purpose is to reduce the bright brightness of the screen in low light environments, reduce visual fatigue, and save a little electricity on some devices.
Another benefit is that when you can't sleep at night and want to sing your mood in the dark, avoid the phone turning into a flash grenade when you slide it open.
After enabling the dark mode, you will find:
- Look more professional, but still can't leave early
- Less eye strain when scrolling social media, but still get blinded by the flash
Above, now you know what black is (⌐■_■)✧
Bystander: I'm pretty sure your "dark" isn't the "dark" of dark mode Σ(ˊДˋ;)
View the example source code
<template>
<div class="w-full border border-gray-200 rounded-xl p-4">
<div
v-util-real-dark
class="w-full border border-gray-200 rounded-xl"
>
<base-checkbox
v-model="enable"
:label="t('enableRealDarkMode')"
class="p-4"
/>
</div>
<div class="w-full py-4">
<div class="mb-3 text-2xl font-bold">
{{ t('whatIsDarkMode') }}
</div>
<div class="text-base leading-relaxed space-y-3">
<p>
{{ t('darkModeDescription') }}
</p>
<p>
{{ t('darkModePurpose') }}
</p>
<p>
{{ t('darkModeBenefit') }}
</p>
<p>
{{ t('darkModeAfterEnable') }}
</p>
<ul class="list-disc list-inside space-y-1">
<li>{{ t('darkModeAfterEnableList1') }}</li>
<li>{{ t('darkModeAfterEnableList2') }}</li>
</ul>
<p>
{{ t('darkModeAfterEnableConclusion') }}
</p>
</div>
<!-- tags -->
<div class="mt-4 flex gap-2">
<span
v-util-real-dark
class="border border-gray-200 rounded-full p-2 px-4 text-sm text-gray-500"
>
#Canvas
</span>
<span
v-util-real-dark
class="border border-gray-200 rounded-full p-2 px-4 text-sm text-gray-500"
>
#Shader
</span>
</div>
</div>
<util-real-dark
class="fixed left-0 top-0 z-[100] h-full w-full"
:disabled="!enable"
/>
</div>
</template>
<script setup lang="ts">
import { useData } from 'vitepress'
import { onBeforeUnmount, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import BaseCheckbox from '../../base-checkbox.vue'
import UtilRealDark from '../util-real-dark.vue'
import { vUtilRealDark } from '../v-util-real-dark'
const { isDark } = useData()
const oriValue = isDark.value
const { t } = useI18n()
const enable = ref(false)
watch(enable, (value) => {
if (value) {
isDark.value = false
}
else {
isDark.value = oriValue
}
})
onBeforeUnmount(() => {
isDark.value = oriValue
})
</script>How it works
I originally implemented it with drawing-related libraries like p5.js, but recreating effects like light projection and bloom/glow was just too hard, so this component ended up sitting idle for quite a while...(›´ω`‹ )
One day I suddenly had an idea: “Don’t 3D engines already have light sources built in?” So I switched to implementing it with Babylon.js.
The key is using a shader to set alpha based on grayscale values—making brighter areas more transparent—to achieve the light-beam effect.
Finally, after adding the moving light source effect, it worked! ( •̀ ω •́ )✧
Source Code
API
Props
interface Props {
disabled?: boolean;
/** 平滑係數。越小越慢,延遲越明顯 */
ease?: number;
/** 甩尾強度。越大越明顯 */
offsetStrength?: number;
/** 燈光尺寸 */
size?: number;
lightColor?: string;
/** 透明度 @default 0.9 */
opacity?: number;
}