release fix and blur improvements

This commit is contained in:
Michael Freno
2025-11-25 16:20:47 -05:00
parent f1f883f5ea
commit 06d87b80f3
8 changed files with 425 additions and 13 deletions

View File

@@ -116,7 +116,7 @@ jobs:
run: | run: |
# Create all 4 profile packages # Create all 4 profile packages
./scripts/create-profile-packages.sh ./scripts/create-profile-packages.sh
# Verify all packages were created # Verify all packages were created
VERSION="${{ steps.version.outputs.version }}" VERSION="${{ steps.version.outputs.version }}"
for profile in minimal slim default full; do for profile in minimal slim default full; do
@@ -155,7 +155,7 @@ jobs:
SLIM_CHECKSUM=$(cat "releases/flexlove-slim-v${VERSION}.zip.sha256" | cut -d ' ' -f 1) SLIM_CHECKSUM=$(cat "releases/flexlove-slim-v${VERSION}.zip.sha256" | cut -d ' ' -f 1)
DEFAULT_CHECKSUM=$(cat "releases/flexlove-default-v${VERSION}.zip.sha256" | cut -d ' ' -f 1) DEFAULT_CHECKSUM=$(cat "releases/flexlove-default-v${VERSION}.zip.sha256" | cut -d ' ' -f 1)
FULL_CHECKSUM=$(cat "releases/flexlove-full-v${VERSION}.zip.sha256" | cut -d ' ' -f 1) FULL_CHECKSUM=$(cat "releases/flexlove-full-v${VERSION}.zip.sha256" | cut -d ' ' -f 1)
echo "minimal=$MINIMAL_CHECKSUM" >> $GITHUB_OUTPUT echo "minimal=$MINIMAL_CHECKSUM" >> $GITHUB_OUTPUT
echo "slim=$SLIM_CHECKSUM" >> $GITHUB_OUTPUT echo "slim=$SLIM_CHECKSUM" >> $GITHUB_OUTPUT
echo "default=$DEFAULT_CHECKSUM" >> $GITHUB_OUTPUT echo "default=$DEFAULT_CHECKSUM" >> $GITHUB_OUTPUT
@@ -184,7 +184,7 @@ jobs:
| Profile | Size | Description | Package | | Profile | Size | Description | Package |
|---------|------|-------------|---------| |---------|------|-------------|---------|
| **Minimal** | ~60% | Core functionality only | `flexlove-minimal-v${{ steps.version.outputs.version }}.zip` | | **Minimal** | ~70% | Core functionality only | `flexlove-minimal-v${{ steps.version.outputs.version }}.zip` |
| **Slim** | ~80% | + Animation and Image support | `flexlove-slim-v${{ steps.version.outputs.version }}.zip` | | **Slim** | ~80% | + Animation and Image support | `flexlove-slim-v${{ steps.version.outputs.version }}.zip` |
| **Default** | ~95% | + Theme and Blur effects | `flexlove-default-v${{ steps.version.outputs.version }}.zip` | | **Default** | ~95% | + Theme and Blur effects | `flexlove-default-v${{ steps.version.outputs.version }}.zip` |
| **Full** | 100% | All modules including debugging tools | `flexlove-full-v${{ steps.version.outputs.version }}.zip` | | **Full** | 100% | All modules including debugging tools | `flexlove-full-v${{ steps.version.outputs.version }}.zip` |

View File

@@ -149,6 +149,18 @@ function flexlove.init(config)
NinePatch.init({ ErrorHandler = flexlove._ErrorHandler }) NinePatch.init({ ErrorHandler = flexlove._ErrorHandler })
end end
-- Initialize Blur module with immediate mode optimization config
if ModuleLoader.isModuleLoaded(modulePath .. "modules.Blur") then
local blurOptimizations = config.immediateModeBlurOptimizations
if blurOptimizations == nil then
blurOptimizations = true -- Default to enabled
end
Blur.init({
ErrorHandler = flexlove._ErrorHandler,
immediateModeOptimizations = blurOptimizations and config.immediateMode or false
})
end
-- Initialize required modules -- Initialize required modules
Units.init({ Context = Context, ErrorHandler = flexlove._ErrorHandler }) Units.init({ Context = Context, ErrorHandler = flexlove._ErrorHandler })
Color.init({ ErrorHandler = flexlove._ErrorHandler }) Color.init({ ErrorHandler = flexlove._ErrorHandler })
@@ -439,9 +451,31 @@ function flexlove.endFrame()
stateUpdate._cursorVisible = element._cursorVisible stateUpdate._cursorVisible = element._cursorVisible
stateUpdate._cursorBlinkPaused = element._cursorBlinkPaused stateUpdate._cursorBlinkPaused = element._cursorBlinkPaused
stateUpdate._cursorBlinkPauseTimer = element._cursorBlinkPauseTimer stateUpdate._cursorBlinkPauseTimer = element._cursorBlinkPauseTimer
-- Track blur-related properties for cache invalidation
if element.backdropBlur or element.contentBlur then
stateUpdate._blurX = element.x
stateUpdate._blurY = element.y
stateUpdate._blurWidth = element._borderBoxWidth or (element.width + element.padding.left + element.padding.right)
stateUpdate._blurHeight = element._borderBoxHeight or (element.height + element.padding.top + element.padding.bottom)
if element.backdropBlur then
stateUpdate._backdropBlurIntensity = element.backdropBlur.intensity
stateUpdate._backdropBlurQuality = element.backdropBlur.quality
end
if element.contentBlur then
stateUpdate._contentBlurIntensity = element.contentBlur.intensity
stateUpdate._contentBlurQuality = element.contentBlur.quality
end
end
-- Use optimized update that only changes modified values -- Use optimized update that only changes modified values
StateManager.updateStateIfChanged(element.id, stateUpdate) -- Returns true if state was changed (meaning blur cache needs invalidation)
local stateChanged = StateManager.updateStateIfChanged(element.id, stateUpdate)
-- Invalidate blur cache if blur-related properties changed
if stateChanged and (element.backdropBlur or element.contentBlur) and Blur then
Blur.clearElementCache(element.id)
end
end end
end end

View File

@@ -5,8 +5,10 @@ local Cache = {
canvases = {}, canvases = {},
quads = {}, quads = {},
blurInstances = {}, -- Cache blur instances by quality blurInstances = {}, -- Cache blur instances by quality
blurredCanvases = {}, -- Cache pre-blurred canvases for immediate mode
MAX_CANVAS_SIZE = 20, MAX_CANVAS_SIZE = 20,
MAX_QUAD_SIZE = 20, MAX_QUAD_SIZE = 20,
MAX_BLURRED_CANVAS_CACHE = 50, -- Maximum cached blurred canvases
INTENSITY_THRESHOLD = 5, -- Skip blur below this intensity INTENSITY_THRESHOLD = 5, -- Skip blur below this intensity
} }
@@ -121,11 +123,93 @@ function Cache.releaseQuad(quad)
end end
end end
--- Generate cache key for blurred canvas
---@param elementId string Element ID
---@param x number X position
---@param y number Y position
---@param width number Width
---@param height number Height
---@param intensity number Blur intensity
---@param quality number Blur quality
---@param isBackdrop boolean Whether this is backdrop blur
---@return string key Cache key
function Cache.generateBlurCacheKey(elementId, x, y, width, height, intensity, quality, isBackdrop)
return string.format("%s:%d:%d:%d:%d:%d:%d:%s", elementId, x, y, width, height, intensity, quality, tostring(isBackdrop))
end
--- Get cached blurred canvas
---@param key string Cache key
---@return love.Canvas|nil canvas Cached canvas or nil
function Cache.getBlurredCanvas(key)
local entry = Cache.blurredCanvases[key]
if entry then
entry.lastUsed = os.time()
return entry.canvas
end
return nil
end
--- Store blurred canvas in cache
---@param key string Cache key
---@param canvas love.Canvas Canvas to cache
function Cache.setBlurredCanvas(key, canvas)
-- Limit cache size
local count = 0
for _ in pairs(Cache.blurredCanvases) do
count = count + 1
end
if count >= Cache.MAX_BLURRED_CANVAS_CACHE then
-- Remove oldest entry
local oldestKey = nil
local oldestTime = math.huge
for k, v in pairs(Cache.blurredCanvases) do
if v.lastUsed < oldestTime then
oldestTime = v.lastUsed
oldestKey = k
end
end
if oldestKey then
if Cache.blurredCanvases[oldestKey].canvas then
Cache.blurredCanvases[oldestKey].canvas:release()
end
Cache.blurredCanvases[oldestKey] = nil
end
end
Cache.blurredCanvases[key] = {
canvas = canvas,
lastUsed = os.time(),
}
end
--- Clear blurred canvas cache for specific element
---@param elementId string Element ID to clear cache for
function Cache.clearBlurredCanvasesForElement(elementId)
for key, entry in pairs(Cache.blurredCanvases) do
if key:match("^" .. elementId .. ":") then
if entry.canvas then
entry.canvas:release()
end
Cache.blurredCanvases[key] = nil
end
end
end
--- Clear all caches --- Clear all caches
function Cache.clear() function Cache.clear()
-- Release all blurred canvases
for _, entry in pairs(Cache.blurredCanvases) do
if entry.canvas then
entry.canvas:release()
end
end
Cache.canvases = {} Cache.canvases = {}
Cache.quads = {} Cache.quads = {}
Cache.blurInstances = {} Cache.blurInstances = {}
Cache.blurredCanvases = {}
end end
-- ============================================================================ -- ============================================================================
@@ -411,11 +495,129 @@ function Blur.clearCache()
Cache.clear() Cache.clear()
end end
--- Apply backdrop blur with caching support
---@param intensity number Blur intensity (0-100)
---@param x number X position
---@param y number Y position
---@param width number Width of region
---@param height number Height of region
---@param backdropCanvas love.Canvas Canvas containing the backdrop content
---@param elementId string|nil Element ID for caching (nil disables caching)
function Blur:applyBackdropCached(intensity, x, y, width, height, backdropCanvas, elementId)
-- If caching is disabled or no element ID, fall back to regular apply
if not Blur._immediateModeOptimizations or not elementId then
return self:applyBackdrop(intensity, x, y, width, height, backdropCanvas)
end
-- Generate cache key
local cacheKey = Cache.generateBlurCacheKey(elementId, x, y, width, height, intensity, self.quality, true)
-- Check cache
local cachedCanvas = Cache.getBlurredCanvas(cacheKey)
if cachedCanvas then
-- Draw cached blur
local prevCanvas = love.graphics.getCanvas()
local prevShader = love.graphics.getShader()
local prevColor = { love.graphics.getColor() }
local prevBlendMode = love.graphics.getBlendMode()
love.graphics.setCanvas(prevCanvas)
love.graphics.setShader()
love.graphics.setBlendMode(prevBlendMode)
love.graphics.draw(cachedCanvas, x, y)
love.graphics.setShader(prevShader)
love.graphics.setColor(unpack(prevColor))
return
end
-- Not cached, render and cache
if not backdropCanvas then
if Blur._ErrorHandler then
Blur._ErrorHandler:warn("Blur", "applyBackdrop requires a backdrop canvas.")
end
return
end
if intensity <= 0 or width <= 0 or height <= 0 then
return
end
-- Early exit for very low intensity (optimization)
if intensity < Cache.INTENSITY_THRESHOLD then
return
end
intensity = math.max(0, math.min(100, intensity))
local passes = math.ceil(intensity / 20)
passes = math.max(1, math.min(5, passes))
local canvas1 = Cache.getCanvas(width, height)
local canvas2 = Cache.getCanvas(width, height)
local prevCanvas = love.graphics.getCanvas()
local prevShader = love.graphics.getShader()
local prevColor = { love.graphics.getColor() }
local prevBlendMode = love.graphics.getBlendMode()
love.graphics.setCanvas(canvas1)
love.graphics.clear()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setBlendMode("alpha", "premultiplied")
local backdropWidth, backdropHeight = backdropCanvas:getDimensions()
local quad = Cache.getQuad(x, y, width, height, backdropWidth, backdropHeight)
love.graphics.draw(backdropCanvas, quad, 0, 0)
love.graphics.setShader(self.shader)
for i = 1, passes do
love.graphics.setCanvas(canvas2)
love.graphics.clear()
self.shader:send("direction", { 1 / width, 0 })
love.graphics.draw(canvas1, 0, 0)
love.graphics.setCanvas(canvas1)
love.graphics.clear()
self.shader:send("direction", { 0, 1 / height })
love.graphics.draw(canvas2, 0, 0)
end
-- Cache the result
local cachedResult = love.graphics.newCanvas(width, height)
love.graphics.setCanvas(cachedResult)
love.graphics.clear()
love.graphics.setShader()
love.graphics.setBlendMode("alpha", "premultiplied")
love.graphics.draw(canvas1, 0, 0)
Cache.setBlurredCanvas(cacheKey, cachedResult)
love.graphics.setCanvas(prevCanvas)
love.graphics.setShader()
love.graphics.setBlendMode(prevBlendMode)
love.graphics.draw(canvas1, x, y)
love.graphics.setShader(prevShader)
love.graphics.setColor(unpack(prevColor))
Cache.releaseCanvas(canvas1)
Cache.releaseCanvas(canvas2)
Cache.releaseQuad(quad)
end
--- Clear blur cache for specific element
---@param elementId string Element ID
function Blur.clearElementCache(elementId)
Cache.clearBlurredCanvasesForElement(elementId)
end
--- Initialize Blur module with dependencies --- Initialize Blur module with dependencies
---@param deps table Dependencies: { ErrorHandler = ErrorHandler? } ---@param deps table Dependencies: { ErrorHandler = ErrorHandler?, immediateModeOptimizations = boolean? }
function Blur.init(deps) function Blur.init(deps)
if type(deps) == "table" then if type(deps) == "table" then
Blur._ErrorHandler = deps.ErrorHandler Blur._ErrorHandler = deps.ErrorHandler
Blur._immediateModeOptimizations = deps.immediateModeOptimizations or false
end end
end end

View File

@@ -425,7 +425,9 @@ function Renderer:draw(element, backdropCanvas)
if self.backdropBlur and self.backdropBlur.intensity > 0 and backdropCanvas then if self.backdropBlur and self.backdropBlur.intensity > 0 and backdropCanvas then
local blurInstance = self:getBlurInstance() local blurInstance = self:getBlurInstance()
if blurInstance then if blurInstance then
self._Blur.applyBackdrop(blurInstance, self.backdropBlur.intensity, element.x, element.y, borderBoxWidth, borderBoxHeight, backdropCanvas) -- Use cached blur in immediate mode if element has an ID
local elementId = element.id and element.id ~= "" and element.id or nil
blurInstance:applyBackdropCached(self.backdropBlur.intensity, element.x, element.y, borderBoxWidth, borderBoxHeight, backdropCanvas, elementId)
end end
end end

View File

@@ -185,4 +185,5 @@ local TransformProps
---@field gcMemoryThreshold number? -- Memory threshold in MB before forcing GC (default: 100) ---@field gcMemoryThreshold number? -- Memory threshold in MB before forcing GC (default: 100)
---@field gcInterval number? -- Frames between GC steps in periodic mode (default: 60) ---@field gcInterval number? -- Frames between GC steps in periodic mode (default: 60)
---@field gcStepSize number? -- Work units per GC step, higher = more aggressive (default: 200) ---@field gcStepSize number? -- Work units per GC step, higher = more aggressive (default: 200)
---@field immediateModeBlurOptimizations boolean? -- Cache blur canvases in immediate mode to avoid re-rendering each frame (default: true)
local FlexLoveConfig = {} local FlexLoveConfig = {}

View File

@@ -40,16 +40,16 @@ get_description() {
get_modules() { get_modules() {
case "$1" in case "$1" in
minimal) minimal)
echo "utils.lua Units.lua Context.lua StateManager.lua ErrorHandler.lua Color.lua InputEvent.lua TextEditor.lua LayoutEngine.lua Renderer.lua EventHandler.lua ScrollManager.lua Element.lua RoundedRect.lua Grid.lua GestureRecognizer.lua ModuleLoader.lua" echo "utils.lua Units.lua Context.lua StateManager.lua ErrorHandler.lua Color.lua InputEvent.lua TextEditor.lua LayoutEngine.lua Renderer.lua EventHandler.lua ScrollManager.lua Element.lua RoundedRect.lua Grid.lua ModuleLoader.lua types.lua"
;; ;;
slim) slim)
echo "utils.lua Units.lua Context.lua StateManager.lua ErrorHandler.lua Color.lua InputEvent.lua TextEditor.lua LayoutEngine.lua Renderer.lua EventHandler.lua ScrollManager.lua Element.lua RoundedRect.lua Grid.lua GestureRecognizer.lua Animation.lua ImageRenderer.lua ImageScaler.lua ImageCache.lua ModuleLoader.lua" echo "utils.lua Units.lua Context.lua StateManager.lua ErrorHandler.lua Color.lua InputEvent.lua TextEditor.lua LayoutEngine.lua Renderer.lua EventHandler.lua ScrollManager.lua Element.lua RoundedRect.lua Grid.lua ModuleLoader.lua types.lua Animation.lua NinePatch.lua ImageRenderer.lua ImageScaler.lua ImageCache.lua"
;; ;;
default) default)
echo "utils.lua Units.lua Context.lua StateManager.lua ErrorHandler.lua Color.lua InputEvent.lua TextEditor.lua LayoutEngine.lua Renderer.lua EventHandler.lua ScrollManager.lua Element.lua RoundedRect.lua Grid.lua GestureRecognizer.lua Animation.lua NinePatch.lua ImageRenderer.lua ImageScaler.lua ImageCache.lua Theme.lua Blur.lua ModuleLoader.lua" echo "utils.lua Units.lua Context.lua StateManager.lua ErrorHandler.lua Color.lua InputEvent.lua TextEditor.lua LayoutEngine.lua Renderer.lua EventHandler.lua ScrollManager.lua Element.lua RoundedRect.lua Grid.lua ModuleLoader.lua types.lua Animation.lua NinePatch.lua ImageRenderer.lua ImageScaler.lua ImageCache.lua Theme.lua Blur.lua GestureRecognizer.lua"
;; ;;
full) full)
echo "utils.lua Units.lua Context.lua StateManager.lua ErrorHandler.lua Color.lua InputEvent.lua TextEditor.lua LayoutEngine.lua Renderer.lua EventHandler.lua ScrollManager.lua Element.lua RoundedRect.lua Grid.lua GestureRecognizer.lua Animation.lua NinePatch.lua ImageRenderer.lua ImageScaler.lua ImageCache.lua Theme.lua Blur.lua Performance.lua ModuleLoader.lua" echo "utils.lua Units.lua Context.lua StateManager.lua ErrorHandler.lua Color.lua InputEvent.lua TextEditor.lua LayoutEngine.lua Renderer.lua EventHandler.lua ScrollManager.lua Element.lua RoundedRect.lua Grid.lua ModuleLoader.lua types.lua Animation.lua NinePatch.lua ImageRenderer.lua ImageScaler.lua ImageCache.lua Theme.lua Blur.lua GestureRecognizer.lua Performance.lua MemoryScanner.lua"
;; ;;
esac esac
} }

169
scripts/test-release-locally.sh Executable file
View File

@@ -0,0 +1,169 @@
#!/bin/bash
# Local test script for release workflow
# This simulates the key steps of .github/workflows/release.yml
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}==================================${NC}"
echo -e "${BLUE}Local Release Workflow Test${NC}"
echo -e "${BLUE}==================================${NC}"
echo ""
# Step 1: Extract version
echo -e "${YELLOW}Step 1: Extract version from FlexLove.lua${NC}"
VERSION=$(grep -m 1 "_VERSION" FlexLove.lua | sed -E 's/.*"([^"]+)".*/\1/')
if [ -z "$VERSION" ]; then
echo -e "${RED}Error: Could not extract version${NC}"
exit 1
fi
echo -e "${GREEN}✓ Version: ${VERSION}${NC}"
echo ""
# Step 2: Make scripts executable
echo -e "${YELLOW}Step 2: Make scripts executable${NC}"
chmod +x scripts/generate_docs.sh
chmod +x scripts/create-release.sh
chmod +x scripts/create-profile-packages.sh
chmod +x scripts/archive-docs.sh
echo -e "${GREEN}✓ Scripts are executable${NC}"
echo ""
# Step 3: Create release packages
echo -e "${YELLOW}Step 3: Create release packages${NC}"
./scripts/create-profile-packages.sh
echo ""
# Step 4: Verify all packages were created
echo -e "${YELLOW}Step 4: Verify all packages${NC}"
for profile in minimal slim default full; do
if [ ! -f "releases/flexlove-${profile}-v${VERSION}.zip" ]; then
echo -e "${RED}✗ Error: ${profile} profile package was not created${NC}"
exit 1
fi
if [ ! -f "releases/flexlove-${profile}-v${VERSION}.zip.sha256" ]; then
echo -e "${RED}✗ Error: ${profile} checksum file was not created${NC}"
exit 1
fi
SIZE=$(du -h "releases/flexlove-${profile}-v${VERSION}.zip" | cut -f1)
echo -e "${GREEN}${profile} package verified (${SIZE})${NC}"
done
echo ""
# Step 5: Verify checksums
echo -e "${YELLOW}Step 5: Verify checksums${NC}"
cd releases
if shasum -a 256 -c flexlove-*-v${VERSION}.zip.sha256 2>&1 | grep -q "OK"; then
shasum -a 256 -c flexlove-*-v${VERSION}.zip.sha256
echo -e "${GREEN}✓ All checksums verified${NC}"
else
echo -e "${RED}✗ Checksum verification failed${NC}"
exit 1
fi
cd ..
echo ""
# Step 6: Extract checksums for display
echo -e "${YELLOW}Step 6: Extract checksums for release notes${NC}"
MINIMAL_CHECKSUM=$(cat "releases/flexlove-minimal-v${VERSION}.zip.sha256" | cut -d ' ' -f 1)
SLIM_CHECKSUM=$(cat "releases/flexlove-slim-v${VERSION}.zip.sha256" | cut -d ' ' -f 1)
DEFAULT_CHECKSUM=$(cat "releases/flexlove-default-v${VERSION}.zip.sha256" | cut -d ' ' -f 1)
FULL_CHECKSUM=$(cat "releases/flexlove-full-v${VERSION}.zip.sha256" | cut -d ' ' -f 1)
echo -e "${BLUE}Minimal: ${MINIMAL_CHECKSUM}${NC}"
echo -e "${BLUE}Slim: ${SLIM_CHECKSUM}${NC}"
echo -e "${BLUE}Default: ${DEFAULT_CHECKSUM}${NC}"
echo -e "${BLUE}Full: ${FULL_CHECKSUM}${NC}"
echo ""
# Step 7: Check if pre-release
echo -e "${YELLOW}Step 7: Check if pre-release${NC}"
if [[ "$VERSION" =~ (alpha|beta|rc|dev) ]]; then
echo -e "${BLUE}This is a pre-release version${NC}"
else
echo -e "${GREEN}This is a stable release${NC}"
fi
echo ""
# Step 8: Verify package contents
echo -e "${YELLOW}Step 8: Verify package contents${NC}"
TEMP_DIR=$(mktemp -d)
for profile in minimal slim default full; do
unzip -q "releases/flexlove-${profile}-v${VERSION}.zip" -d "${TEMP_DIR}/${profile}"
# Check FlexLove.lua exists
if [ ! -f "${TEMP_DIR}/${profile}/flexlove/FlexLove.lua" ]; then
echo -e "${RED}${profile}: Missing FlexLove.lua${NC}"
exit 1
fi
# Check LICENSE exists
if [ ! -f "${TEMP_DIR}/${profile}/flexlove/LICENSE" ]; then
echo -e "${RED}${profile}: Missing LICENSE${NC}"
exit 1
fi
# Check README exists
if [ ! -f "${TEMP_DIR}/${profile}/flexlove/README.md" ]; then
echo -e "${RED}${profile}: Missing README.md${NC}"
exit 1
fi
# Count modules
MODULE_COUNT=$(find "${TEMP_DIR}/${profile}/flexlove/modules" -name "*.lua" | wc -l | tr -d ' ')
# Check themes for default and full
if [ "$profile" == "default" ] || [ "$profile" == "full" ]; then
if [ ! -d "${TEMP_DIR}/${profile}/flexlove/themes" ]; then
echo -e "${RED}${profile}: Missing themes directory${NC}"
exit 1
fi
# Verify theme files
if [ ! -f "${TEMP_DIR}/${profile}/flexlove/themes/metal.example.lua" ]; then
echo -e "${RED}${profile}: Missing metal.example.lua${NC}"
exit 1
fi
if [ ! -f "${TEMP_DIR}/${profile}/flexlove/themes/space.example.lua" ]; then
echo -e "${RED}${profile}: Missing space.example.lua${NC}"
exit 1
fi
if [ ! -f "${TEMP_DIR}/${profile}/flexlove/themes/README.md" ]; then
echo -e "${RED}${profile}: Missing themes/README.md${NC}"
exit 1
fi
# Verify no other files in themes
THEME_FILE_COUNT=$(find "${TEMP_DIR}/${profile}/flexlove/themes" -type f | wc -l | tr -d ' ')
if [ "$THEME_FILE_COUNT" != "3" ]; then
echo -e "${RED}${profile}: Expected 3 files in themes, found ${THEME_FILE_COUNT}${NC}"
find "${TEMP_DIR}/${profile}/flexlove/themes" -type f
exit 1
fi
echo -e "${GREEN}${profile}: ${MODULE_COUNT} modules + themes verified${NC}"
else
# Verify no themes for minimal and slim
if [ -d "${TEMP_DIR}/${profile}/flexlove/themes" ]; then
echo -e "${RED}${profile}: Should not have themes directory${NC}"
exit 1
fi
echo -e "${GREEN}${profile}: ${MODULE_COUNT} modules verified${NC}"
fi
done
rm -rf "$TEMP_DIR"
echo ""
echo -e "${GREEN}==================================${NC}"
echo -e "${GREEN}✓ All tests passed!${NC}"
echo -e "${GREEN}==================================${NC}"
echo ""
echo -e "${BLUE}Release packages are ready in: releases/${NC}"
echo -e "${BLUE}Version: v${VERSION}${NC}"
echo ""

View File

@@ -86,14 +86,18 @@ function TestBlur:testNewWithNilProps()
end end
function TestBlur:testNewCreatesUniqueShaders() function TestBlur:testNewCreatesUniqueShaders()
-- Each instance should have its own shader -- Blur instances with same quality should share cached shaders (optimization)
local blur1 = Blur.new({quality = 5}) local blur1 = Blur.new({quality = 5})
local blur2 = Blur.new({quality = 5}) local blur2 = Blur.new({quality = 5})
luaunit.assertNotNil(blur1.shader) luaunit.assertNotNil(blur1.shader)
luaunit.assertNotNil(blur2.shader) luaunit.assertNotNil(blur2.shader)
-- Shaders should be different objects even if same quality -- Shaders should be the same object when quality matches (cached)
luaunit.assertNotEquals(blur1.shader, blur2.shader) luaunit.assertEquals(blur1.shader, blur2.shader)
-- Different quality should result in different shaders
local blur3 = Blur.new({quality = 7})
luaunit.assertNotEquals(blur1.shader, blur3.shader)
end end
-- ============================================================================ -- ============================================================================