diff --git a/apps/www/public/llms-full.txt b/apps/www/public/llms-full.txt
index fa9715cf4..0b3dae9c8 100644
--- a/apps/www/public/llms-full.txt
+++ b/apps/www/public/llms-full.txt
@@ -5164,6 +5164,8 @@ export interface CoolParticleOptions extends BaseParticleOptions {
speedUp?: number
}
+const SVG_NS = "http://www.w3.org/2000/svg"
+
const getContainer = () => {
const id = "_coolMode_effect"
const existingContainer = document.getElementById(id)
@@ -5204,6 +5206,61 @@ const applyParticleEffect = (
const container = getContainer()
+ const appendCircleParticle = (particle: HTMLDivElement, size: number) => {
+ const circleSVG = document.createElementNS(SVG_NS, "svg")
+ const circle = document.createElementNS(SVG_NS, "circle")
+
+ circle.setAttributeNS(null, "cx", (size / 2).toString())
+ circle.setAttributeNS(null, "cy", (size / 2).toString())
+ circle.setAttributeNS(null, "r", (size / 2).toString())
+ circle.setAttributeNS(null, "fill", `hsl(${Math.random() * 360}, 70%, 50%)`)
+
+ circleSVG.appendChild(circle)
+ circleSVG.setAttribute("width", size.toString())
+ circleSVG.setAttribute("height", size.toString())
+
+ particle.appendChild(circleSVG)
+ }
+
+ const appendImageParticle = (
+ particle: HTMLDivElement,
+ imageSrc: string,
+ size: number
+ ) => {
+ const image = document.createElement("img")
+ image.src = imageSrc
+ image.width = size
+ image.height = size
+ image.alt = ""
+ image.style.borderRadius = "50%"
+
+ particle.appendChild(image)
+ }
+
+ const appendTextParticle = (
+ particle: HTMLDivElement,
+ particleContent: string,
+ size: number
+ ) => {
+ const fontSizeMultiplier = 3
+ const emojiSize = size * fontSizeMultiplier
+ const content = document.createElement("div")
+
+ content.textContent = particleContent
+ content.style.fontSize = `${emojiSize}px`
+ content.style.lineHeight = "1"
+ content.style.textAlign = "center"
+ content.style.width = `${size}px`
+ content.style.height = `${size}px`
+ content.style.display = "flex"
+ content.style.alignItems = "center"
+ content.style.justifyContent = "center"
+ content.style.transform = `scale(${fontSizeMultiplier})`
+ content.style.transformOrigin = "center"
+
+ particle.appendChild(content)
+ }
+
function generateParticle() {
const size =
options?.size || sizes[Math.floor(Math.random() * sizes.length)]
@@ -5218,34 +5275,14 @@ const applyParticleEffect = (
const particle = document.createElement("div")
if (particleType === "circle") {
- const svgNS = "http://www.w3.org/2000/svg"
- const circleSVG = document.createElementNS(svgNS, "svg")
- const circle = document.createElementNS(svgNS, "circle")
- circle.setAttributeNS(null, "cx", (size / 2).toString())
- circle.setAttributeNS(null, "cy", (size / 2).toString())
- circle.setAttributeNS(null, "r", (size / 2).toString())
- circle.setAttributeNS(
- null,
- "fill",
- `hsl(${Math.random() * 360}, 70%, 50%)`
- )
-
- circleSVG.appendChild(circle)
- circleSVG.setAttribute("width", size.toString())
- circleSVG.setAttribute("height", size.toString())
-
- particle.appendChild(circleSVG)
+ appendCircleParticle(particle, size)
} else if (
particleType.startsWith("http") ||
particleType.startsWith("/")
) {
- // Handle URL-based images
- particle.innerHTML = `
`
+ appendImageParticle(particle, particleType, size)
} else {
- // Handle emoji or text characters
- const fontSizeMultiplier = 3 // Make emojis 3x bigger
- const emojiSize = size * fontSizeMultiplier
- particle.innerHTML = `
${particleType}
`
+ appendTextParticle(particle, particleType, size)
}
particle.style.position = "absolute"
@@ -5424,8 +5461,7 @@ export default function CoolModeCustom() {
diff --git a/apps/www/public/r/cool-mode-custom.json b/apps/www/public/r/cool-mode-custom.json
index e1769f9e8..4969d9bef 100644
--- a/apps/www/public/r/cool-mode-custom.json
+++ b/apps/www/public/r/cool-mode-custom.json
@@ -10,7 +10,7 @@
"files": [
{
"path": "registry/example/cool-mode-custom.tsx",
- "content": "import { Button } from \"@/components/ui/button\"\nimport { CoolMode } from \"@/registry/magicui/cool-mode\"\n\nexport default function CoolModeCustom() {\n return (\n \n \n \n \n
\n )\n}\n",
+ "content": "import { Button } from \"@/components/ui/button\"\nimport { CoolMode } from \"@/registry/magicui/cool-mode\"\n\nexport default function CoolModeCustom() {\n return (\n \n \n \n \n
\n )\n}\n",
"type": "registry:example"
}
]
diff --git a/apps/www/public/r/cool-mode.json b/apps/www/public/r/cool-mode.json
index 026466d5a..8304a541a 100644
--- a/apps/www/public/r/cool-mode.json
+++ b/apps/www/public/r/cool-mode.json
@@ -7,7 +7,7 @@
"files": [
{
"path": "registry/magicui/cool-mode.tsx",
- "content": "\"use client\"\n\nimport React, { ReactNode, useEffect, useRef } from \"react\"\n\nexport interface BaseParticle {\n element: HTMLElement | SVGSVGElement\n left: number\n size: number\n top: number\n}\n\nexport interface BaseParticleOptions {\n particle?: string\n size?: number\n}\n\nexport interface CoolParticle extends BaseParticle {\n direction: number\n speedHorz: number\n speedUp: number\n spinSpeed: number\n spinVal: number\n}\n\nexport interface CoolParticleOptions extends BaseParticleOptions {\n particleCount?: number\n speedHorz?: number\n speedUp?: number\n}\n\nconst getContainer = () => {\n const id = \"_coolMode_effect\"\n const existingContainer = document.getElementById(id)\n\n if (existingContainer) {\n return existingContainer\n }\n\n const container = document.createElement(\"div\")\n container.setAttribute(\"id\", id)\n container.setAttribute(\n \"style\",\n \"overflow:hidden; position:fixed; height:100%; top:0; left:0; right:0; bottom:0; pointer-events:none; z-index:2147483647\"\n )\n\n document.body.appendChild(container)\n\n return container\n}\n\nlet instanceCounter = 0\n\nconst applyParticleEffect = (\n element: HTMLElement,\n options?: CoolParticleOptions\n): (() => void) => {\n instanceCounter++\n\n const defaultParticle = \"circle\"\n const particleType = options?.particle || defaultParticle\n const sizes = [15, 20, 25, 35, 45]\n const limit = 45\n\n let particles: CoolParticle[] = []\n let autoAddParticle = false\n let mouseX = 0\n let mouseY = 0\n\n const container = getContainer()\n\n function generateParticle() {\n const size =\n options?.size || sizes[Math.floor(Math.random() * sizes.length)]\n const speedHorz = options?.speedHorz || Math.random() * 10\n const speedUp = options?.speedUp || Math.random() * 25\n const spinVal = Math.random() * 360\n const spinSpeed = Math.random() * 35 * (Math.random() <= 0.5 ? -1 : 1)\n const top = mouseY - size / 2\n const left = mouseX - size / 2\n const direction = Math.random() <= 0.5 ? -1 : 1\n\n const particle = document.createElement(\"div\")\n\n if (particleType === \"circle\") {\n const svgNS = \"http://www.w3.org/2000/svg\"\n const circleSVG = document.createElementNS(svgNS, \"svg\")\n const circle = document.createElementNS(svgNS, \"circle\")\n circle.setAttributeNS(null, \"cx\", (size / 2).toString())\n circle.setAttributeNS(null, \"cy\", (size / 2).toString())\n circle.setAttributeNS(null, \"r\", (size / 2).toString())\n circle.setAttributeNS(\n null,\n \"fill\",\n `hsl(${Math.random() * 360}, 70%, 50%)`\n )\n\n circleSVG.appendChild(circle)\n circleSVG.setAttribute(\"width\", size.toString())\n circleSVG.setAttribute(\"height\", size.toString())\n\n particle.appendChild(circleSVG)\n } else if (\n particleType.startsWith(\"http\") ||\n particleType.startsWith(\"/\")\n ) {\n // Handle URL-based images\n particle.innerHTML = `
`\n } else {\n // Handle emoji or text characters\n const fontSizeMultiplier = 3 // Make emojis 3x bigger\n const emojiSize = size * fontSizeMultiplier\n particle.innerHTML = `${particleType}
`\n }\n\n particle.style.position = \"absolute\"\n particle.style.transform = `translate3d(${left}px, ${top}px, 0px) rotate(${spinVal}deg)`\n\n container.appendChild(particle)\n\n particles.push({\n direction,\n element: particle,\n left,\n size,\n speedHorz,\n speedUp,\n spinSpeed,\n spinVal,\n top,\n })\n }\n\n function refreshParticles() {\n particles.forEach((p) => {\n p.left = p.left - p.speedHorz * p.direction\n p.top = p.top - p.speedUp\n p.speedUp = Math.min(p.size, p.speedUp - 1)\n p.spinVal = p.spinVal + p.spinSpeed\n\n if (\n p.top >=\n Math.max(window.innerHeight, document.body.clientHeight) + p.size\n ) {\n particles = particles.filter((o) => o !== p)\n p.element.remove()\n }\n\n p.element.setAttribute(\n \"style\",\n [\n \"position:absolute\",\n \"will-change:transform\",\n `top:${p.top}px`,\n `left:${p.left}px`,\n `transform:rotate(${p.spinVal}deg)`,\n ].join(\";\")\n )\n })\n }\n\n let animationFrame: number | undefined\n\n let lastParticleTimestamp = 0\n const particleGenerationDelay = 30\n\n function loop() {\n const currentTime = performance.now()\n if (\n autoAddParticle &&\n particles.length < limit &&\n currentTime - lastParticleTimestamp > particleGenerationDelay\n ) {\n generateParticle()\n lastParticleTimestamp = currentTime\n }\n\n refreshParticles()\n animationFrame = requestAnimationFrame(loop)\n }\n\n loop()\n\n const isTouchInteraction = \"ontouchstart\" in window\n\n const tap = isTouchInteraction ? \"touchstart\" : \"mousedown\"\n const tapEnd = isTouchInteraction ? \"touchend\" : \"mouseup\"\n const move = isTouchInteraction ? \"touchmove\" : \"mousemove\"\n\n const updateMousePosition = (e: MouseEvent | TouchEvent) => {\n if (\"touches\" in e) {\n mouseX = e.touches?.[0].clientX\n mouseY = e.touches?.[0].clientY\n } else {\n mouseX = e.clientX\n mouseY = e.clientY\n }\n }\n\n const tapHandler = (e: MouseEvent | TouchEvent) => {\n updateMousePosition(e)\n autoAddParticle = true\n }\n\n const disableAutoAddParticle = () => {\n autoAddParticle = false\n }\n\n element.addEventListener(move, updateMousePosition, { passive: true })\n element.addEventListener(tap, tapHandler, { passive: true })\n element.addEventListener(tapEnd, disableAutoAddParticle, { passive: true })\n element.addEventListener(\"mouseleave\", disableAutoAddParticle, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener(move, updateMousePosition)\n element.removeEventListener(tap, tapHandler)\n element.removeEventListener(tapEnd, disableAutoAddParticle)\n element.removeEventListener(\"mouseleave\", disableAutoAddParticle)\n\n const interval = setInterval(() => {\n if (animationFrame && particles.length === 0) {\n cancelAnimationFrame(animationFrame)\n clearInterval(interval)\n\n if (--instanceCounter === 0) {\n container.remove()\n }\n }\n }, 500)\n }\n}\n\ninterface CoolModeProps {\n children: ReactNode\n options?: CoolParticleOptions\n}\n\nexport const CoolMode: React.FC = ({ children, options }) => {\n const ref = useRef(null)\n\n useEffect(() => {\n const element = ref.current\n let cleanup: (() => void) | null = null\n\n if (element) {\n cleanup = applyParticleEffect(element, options)\n }\n\n return () => {\n if (cleanup) {\n cleanup()\n }\n }\n }, [options])\n\n return {children}\n}\n",
+ "content": "\"use client\"\n\nimport React, { ReactNode, useEffect, useRef } from \"react\"\n\nexport interface BaseParticle {\n element: HTMLElement | SVGSVGElement\n left: number\n size: number\n top: number\n}\n\nexport interface BaseParticleOptions {\n particle?: string\n size?: number\n}\n\nexport interface CoolParticle extends BaseParticle {\n direction: number\n speedHorz: number\n speedUp: number\n spinSpeed: number\n spinVal: number\n}\n\nexport interface CoolParticleOptions extends BaseParticleOptions {\n particleCount?: number\n speedHorz?: number\n speedUp?: number\n}\n\nconst SVG_NS = \"http://www.w3.org/2000/svg\"\n\nconst getContainer = () => {\n const id = \"_coolMode_effect\"\n const existingContainer = document.getElementById(id)\n\n if (existingContainer) {\n return existingContainer\n }\n\n const container = document.createElement(\"div\")\n container.setAttribute(\"id\", id)\n container.setAttribute(\n \"style\",\n \"overflow:hidden; position:fixed; height:100%; top:0; left:0; right:0; bottom:0; pointer-events:none; z-index:2147483647\"\n )\n\n document.body.appendChild(container)\n\n return container\n}\n\nlet instanceCounter = 0\n\nconst applyParticleEffect = (\n element: HTMLElement,\n options?: CoolParticleOptions\n): (() => void) => {\n instanceCounter++\n\n const defaultParticle = \"circle\"\n const particleType = options?.particle || defaultParticle\n const sizes = [15, 20, 25, 35, 45]\n const limit = 45\n\n let particles: CoolParticle[] = []\n let autoAddParticle = false\n let mouseX = 0\n let mouseY = 0\n\n const container = getContainer()\n\n const appendCircleParticle = (particle: HTMLDivElement, size: number) => {\n const circleSVG = document.createElementNS(SVG_NS, \"svg\")\n const circle = document.createElementNS(SVG_NS, \"circle\")\n\n circle.setAttributeNS(null, \"cx\", (size / 2).toString())\n circle.setAttributeNS(null, \"cy\", (size / 2).toString())\n circle.setAttributeNS(null, \"r\", (size / 2).toString())\n circle.setAttributeNS(null, \"fill\", `hsl(${Math.random() * 360}, 70%, 50%)`)\n\n circleSVG.appendChild(circle)\n circleSVG.setAttribute(\"width\", size.toString())\n circleSVG.setAttribute(\"height\", size.toString())\n\n particle.appendChild(circleSVG)\n }\n\n const appendImageParticle = (\n particle: HTMLDivElement,\n imageSrc: string,\n size: number\n ) => {\n const image = document.createElement(\"img\")\n image.src = imageSrc\n image.width = size\n image.height = size\n image.alt = \"\"\n image.style.borderRadius = \"50%\"\n\n particle.appendChild(image)\n }\n\n const appendTextParticle = (\n particle: HTMLDivElement,\n particleContent: string,\n size: number\n ) => {\n const fontSizeMultiplier = 3\n const emojiSize = size * fontSizeMultiplier\n const content = document.createElement(\"div\")\n\n content.textContent = particleContent\n content.style.fontSize = `${emojiSize}px`\n content.style.lineHeight = \"1\"\n content.style.textAlign = \"center\"\n content.style.width = `${size}px`\n content.style.height = `${size}px`\n content.style.display = \"flex\"\n content.style.alignItems = \"center\"\n content.style.justifyContent = \"center\"\n content.style.transform = `scale(${fontSizeMultiplier})`\n content.style.transformOrigin = \"center\"\n\n particle.appendChild(content)\n }\n\n function generateParticle() {\n const size =\n options?.size || sizes[Math.floor(Math.random() * sizes.length)]\n const speedHorz = options?.speedHorz || Math.random() * 10\n const speedUp = options?.speedUp || Math.random() * 25\n const spinVal = Math.random() * 360\n const spinSpeed = Math.random() * 35 * (Math.random() <= 0.5 ? -1 : 1)\n const top = mouseY - size / 2\n const left = mouseX - size / 2\n const direction = Math.random() <= 0.5 ? -1 : 1\n\n const particle = document.createElement(\"div\")\n\n if (particleType === \"circle\") {\n appendCircleParticle(particle, size)\n } else if (\n particleType.startsWith(\"http\") ||\n particleType.startsWith(\"/\")\n ) {\n appendImageParticle(particle, particleType, size)\n } else {\n appendTextParticle(particle, particleType, size)\n }\n\n particle.style.position = \"absolute\"\n particle.style.transform = `translate3d(${left}px, ${top}px, 0px) rotate(${spinVal}deg)`\n\n container.appendChild(particle)\n\n particles.push({\n direction,\n element: particle,\n left,\n size,\n speedHorz,\n speedUp,\n spinSpeed,\n spinVal,\n top,\n })\n }\n\n function refreshParticles() {\n particles.forEach((p) => {\n p.left = p.left - p.speedHorz * p.direction\n p.top = p.top - p.speedUp\n p.speedUp = Math.min(p.size, p.speedUp - 1)\n p.spinVal = p.spinVal + p.spinSpeed\n\n if (\n p.top >=\n Math.max(window.innerHeight, document.body.clientHeight) + p.size\n ) {\n particles = particles.filter((o) => o !== p)\n p.element.remove()\n }\n\n p.element.setAttribute(\n \"style\",\n [\n \"position:absolute\",\n \"will-change:transform\",\n `top:${p.top}px`,\n `left:${p.left}px`,\n `transform:rotate(${p.spinVal}deg)`,\n ].join(\";\")\n )\n })\n }\n\n let animationFrame: number | undefined\n\n let lastParticleTimestamp = 0\n const particleGenerationDelay = 30\n\n function loop() {\n const currentTime = performance.now()\n if (\n autoAddParticle &&\n particles.length < limit &&\n currentTime - lastParticleTimestamp > particleGenerationDelay\n ) {\n generateParticle()\n lastParticleTimestamp = currentTime\n }\n\n refreshParticles()\n animationFrame = requestAnimationFrame(loop)\n }\n\n loop()\n\n const isTouchInteraction = \"ontouchstart\" in window\n\n const tap = isTouchInteraction ? \"touchstart\" : \"mousedown\"\n const tapEnd = isTouchInteraction ? \"touchend\" : \"mouseup\"\n const move = isTouchInteraction ? \"touchmove\" : \"mousemove\"\n\n const updateMousePosition = (e: MouseEvent | TouchEvent) => {\n if (\"touches\" in e) {\n mouseX = e.touches?.[0].clientX\n mouseY = e.touches?.[0].clientY\n } else {\n mouseX = e.clientX\n mouseY = e.clientY\n }\n }\n\n const tapHandler = (e: MouseEvent | TouchEvent) => {\n updateMousePosition(e)\n autoAddParticle = true\n }\n\n const disableAutoAddParticle = () => {\n autoAddParticle = false\n }\n\n element.addEventListener(move, updateMousePosition, { passive: true })\n element.addEventListener(tap, tapHandler, { passive: true })\n element.addEventListener(tapEnd, disableAutoAddParticle, { passive: true })\n element.addEventListener(\"mouseleave\", disableAutoAddParticle, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener(move, updateMousePosition)\n element.removeEventListener(tap, tapHandler)\n element.removeEventListener(tapEnd, disableAutoAddParticle)\n element.removeEventListener(\"mouseleave\", disableAutoAddParticle)\n\n const interval = setInterval(() => {\n if (animationFrame && particles.length === 0) {\n cancelAnimationFrame(animationFrame)\n clearInterval(interval)\n\n if (--instanceCounter === 0) {\n container.remove()\n }\n }\n }, 500)\n }\n}\n\ninterface CoolModeProps {\n children: ReactNode\n options?: CoolParticleOptions\n}\n\nexport const CoolMode: React.FC = ({ children, options }) => {\n const ref = useRef(null)\n\n useEffect(() => {\n const element = ref.current\n let cleanup: (() => void) | null = null\n\n if (element) {\n cleanup = applyParticleEffect(element, options)\n }\n\n return () => {\n if (cleanup) {\n cleanup()\n }\n }\n }, [options])\n\n return {children}\n}\n",
"type": "registry:ui"
}
]
diff --git a/apps/www/registry/example/cool-mode-custom.tsx b/apps/www/registry/example/cool-mode-custom.tsx
index dcda6105c..86c421c71 100644
--- a/apps/www/registry/example/cool-mode-custom.tsx
+++ b/apps/www/registry/example/cool-mode-custom.tsx
@@ -6,8 +6,7 @@ export default function CoolModeCustom() {
diff --git a/apps/www/registry/magicui/cool-mode.tsx b/apps/www/registry/magicui/cool-mode.tsx
index 3508fd22c..6115a0272 100644
--- a/apps/www/registry/magicui/cool-mode.tsx
+++ b/apps/www/registry/magicui/cool-mode.tsx
@@ -28,6 +28,8 @@ export interface CoolParticleOptions extends BaseParticleOptions {
speedUp?: number
}
+const SVG_NS = "http://www.w3.org/2000/svg"
+
const getContainer = () => {
const id = "_coolMode_effect"
const existingContainer = document.getElementById(id)
@@ -68,6 +70,61 @@ const applyParticleEffect = (
const container = getContainer()
+ const appendCircleParticle = (particle: HTMLDivElement, size: number) => {
+ const circleSVG = document.createElementNS(SVG_NS, "svg")
+ const circle = document.createElementNS(SVG_NS, "circle")
+
+ circle.setAttributeNS(null, "cx", (size / 2).toString())
+ circle.setAttributeNS(null, "cy", (size / 2).toString())
+ circle.setAttributeNS(null, "r", (size / 2).toString())
+ circle.setAttributeNS(null, "fill", `hsl(${Math.random() * 360}, 70%, 50%)`)
+
+ circleSVG.appendChild(circle)
+ circleSVG.setAttribute("width", size.toString())
+ circleSVG.setAttribute("height", size.toString())
+
+ particle.appendChild(circleSVG)
+ }
+
+ const appendImageParticle = (
+ particle: HTMLDivElement,
+ imageSrc: string,
+ size: number
+ ) => {
+ const image = document.createElement("img")
+ image.src = imageSrc
+ image.width = size
+ image.height = size
+ image.alt = ""
+ image.style.borderRadius = "50%"
+
+ particle.appendChild(image)
+ }
+
+ const appendTextParticle = (
+ particle: HTMLDivElement,
+ particleContent: string,
+ size: number
+ ) => {
+ const fontSizeMultiplier = 3
+ const emojiSize = size * fontSizeMultiplier
+ const content = document.createElement("div")
+
+ content.textContent = particleContent
+ content.style.fontSize = `${emojiSize}px`
+ content.style.lineHeight = "1"
+ content.style.textAlign = "center"
+ content.style.width = `${size}px`
+ content.style.height = `${size}px`
+ content.style.display = "flex"
+ content.style.alignItems = "center"
+ content.style.justifyContent = "center"
+ content.style.transform = `scale(${fontSizeMultiplier})`
+ content.style.transformOrigin = "center"
+
+ particle.appendChild(content)
+ }
+
function generateParticle() {
const size =
options?.size || sizes[Math.floor(Math.random() * sizes.length)]
@@ -82,34 +139,14 @@ const applyParticleEffect = (
const particle = document.createElement("div")
if (particleType === "circle") {
- const svgNS = "http://www.w3.org/2000/svg"
- const circleSVG = document.createElementNS(svgNS, "svg")
- const circle = document.createElementNS(svgNS, "circle")
- circle.setAttributeNS(null, "cx", (size / 2).toString())
- circle.setAttributeNS(null, "cy", (size / 2).toString())
- circle.setAttributeNS(null, "r", (size / 2).toString())
- circle.setAttributeNS(
- null,
- "fill",
- `hsl(${Math.random() * 360}, 70%, 50%)`
- )
-
- circleSVG.appendChild(circle)
- circleSVG.setAttribute("width", size.toString())
- circleSVG.setAttribute("height", size.toString())
-
- particle.appendChild(circleSVG)
+ appendCircleParticle(particle, size)
} else if (
particleType.startsWith("http") ||
particleType.startsWith("/")
) {
- // Handle URL-based images
- particle.innerHTML = `
`
+ appendImageParticle(particle, particleType, size)
} else {
- // Handle emoji or text characters
- const fontSizeMultiplier = 3 // Make emojis 3x bigger
- const emojiSize = size * fontSizeMultiplier
- particle.innerHTML = `${particleType}
`
+ appendTextParticle(particle, particleType, size)
}
particle.style.position = "absolute"