diff --git a/public/usage-examples/graphics/bitmap_layer_studio-1-example-oop.cs b/public/usage-examples/graphics/bitmap_layer_studio-1-example-oop.cs new file mode 100644 index 000000000..e5ab77959 --- /dev/null +++ b/public/usage-examples/graphics/bitmap_layer_studio-1-example-oop.cs @@ -0,0 +1,56 @@ +using SplashKitSDK; + +namespace BitmapLayerStudio +{ + public class Program + { + public static void Main() + { + Window window = new Window("Bitmap Layer Studio", 960, 540); + + // Scene setup: open window and load four bitmap layers. + Bitmap backgroundLayer = SplashKit.LoadBitmap("background_layer", "layer_background.png"); + Bitmap midLayer = SplashKit.LoadBitmap("mid_layer", "layer_midground.png"); + Bitmap propsLayer = SplashKit.LoadBitmap("props_layer", "layer_props.png"); + Bitmap foregroundLayer = SplashKit.LoadBitmap("foreground_layer", "layer_foreground.png"); + + double alpha = 0.45; + int bgRed = 48; + int bgGreen = 88; + int bgBlue = 128; + int fgRed = 250; + int fgGreen = 216; + int fgBlue = 126; + + // Formula layer: C_out = alpha * C_fg + (1 - alpha) * C_bg. + int outRed = (int)(alpha * fgRed + (1.0 - alpha) * bgRed); + int outGreen = (int)(alpha * fgGreen + (1.0 - alpha) * bgGreen); + int outBlue = (int)(alpha * fgBlue + (1.0 - alpha) * bgBlue); + Color blendGuide = SplashKit.RGBAColor(outRed, outGreen, outBlue, 255); + Color overlayGuide = SplashKit.RGBAColor(fgRed, fgGreen, fgBlue, (int)(alpha * 255)); + + while (!SplashKit.QuitRequested()) + { + SplashKit.ProcessEvents(); + SplashKit.ClearScreen(); + + // Layer pipeline: draw bitmaps back-to-front for stable compositing. + SplashKit.DrawBitmap(backgroundLayer, 0, 0); + SplashKit.DrawBitmap(midLayer, 0, 0); + SplashKit.DrawBitmap(propsLayer, 0, 0); + SplashKit.DrawBitmap(foregroundLayer, 0, 0); + + // Visual pass: draw depth guides and decorative perspective lines. + SplashKit.DrawLine(blendGuide, 0, 370, 960, 370); + SplashKit.DrawLine(overlayGuide, 480, 120, 180, 520); + SplashKit.DrawLine(overlayGuide, 480, 120, 780, 520); + SplashKit.DrawLine(blendGuide, 120, 500, 840, 500); + + SplashKit.RefreshScreen(60); + } + + SplashKit.FreeAllBitmaps(); + window.Close(); + } + } +} diff --git a/public/usage-examples/graphics/bitmap_layer_studio-1-example-top-level.cs b/public/usage-examples/graphics/bitmap_layer_studio-1-example-top-level.cs new file mode 100644 index 000000000..00c586961 --- /dev/null +++ b/public/usage-examples/graphics/bitmap_layer_studio-1-example-top-level.cs @@ -0,0 +1,48 @@ +using SplashKitSDK; +using static SplashKitSDK.SplashKit; + +OpenWindow("Bitmap Layer Studio", 960, 540); + +// Scene setup: open window and load four bitmap layers. +Bitmap backgroundLayer = LoadBitmap("background_layer", "layer_background.png"); +Bitmap midLayer = LoadBitmap("mid_layer", "layer_midground.png"); +Bitmap propsLayer = LoadBitmap("props_layer", "layer_props.png"); +Bitmap foregroundLayer = LoadBitmap("foreground_layer", "layer_foreground.png"); + +double alpha = 0.45; +int bgRed = 48; +int bgGreen = 88; +int bgBlue = 128; +int fgRed = 250; +int fgGreen = 216; +int fgBlue = 126; + +// Formula layer: C_out = alpha * C_fg + (1 - alpha) * C_bg. +int outRed = (int)(alpha * fgRed + (1.0 - alpha) * bgRed); +int outGreen = (int)(alpha * fgGreen + (1.0 - alpha) * bgGreen); +int outBlue = (int)(alpha * fgBlue + (1.0 - alpha) * bgBlue); +Color blendGuide = RGBAColor(outRed, outGreen, outBlue, 255); +Color overlayGuide = RGBAColor(fgRed, fgGreen, fgBlue, (int)(alpha * 255)); + +while (!QuitRequested()) +{ + ProcessEvents(); + ClearScreen(); + + // Layer pipeline: draw bitmaps back-to-front for stable compositing. + DrawBitmap(backgroundLayer, 0, 0); + DrawBitmap(midLayer, 0, 0); + DrawBitmap(propsLayer, 0, 0); + DrawBitmap(foregroundLayer, 0, 0); + + // Visual pass: draw depth guides and decorative perspective lines. + DrawLine(blendGuide, 0, 370, 960, 370); + DrawLine(overlayGuide, 480, 120, 180, 520); + DrawLine(overlayGuide, 480, 120, 780, 520); + DrawLine(blendGuide, 120, 500, 840, 500); + + RefreshScreen(60); +} + +FreeAllBitmaps(); +CloseAllWindows(); diff --git a/public/usage-examples/graphics/bitmap_layer_studio-1-example.cpp b/public/usage-examples/graphics/bitmap_layer_studio-1-example.cpp new file mode 100644 index 000000000..3dde24033 --- /dev/null +++ b/public/usage-examples/graphics/bitmap_layer_studio-1-example.cpp @@ -0,0 +1,52 @@ +#include "splashkit.h" + +int main() +{ + open_window("Bitmap Layer Studio", 960, 540); + + // Scene setup: open window and load four bitmap layers. + bitmap background_layer = load_bitmap("background_layer", "layer_background.png"); + bitmap mid_layer = load_bitmap("mid_layer", "layer_midground.png"); + bitmap props_layer = load_bitmap("props_layer", "layer_props.png"); + bitmap foreground_layer = load_bitmap("foreground_layer", "layer_foreground.png"); + + const double alpha = 0.45; + const int bg_red = 48; + const int bg_green = 88; + const int bg_blue = 128; + const int fg_red = 250; + const int fg_green = 216; + const int fg_blue = 126; + + // Formula layer: C_out = alpha * C_fg + (1 - alpha) * C_bg. + int out_red = static_cast(alpha * fg_red + (1.0 - alpha) * bg_red); + int out_green = static_cast(alpha * fg_green + (1.0 - alpha) * bg_green); + int out_blue = static_cast(alpha * fg_blue + (1.0 - alpha) * bg_blue); + color blend_guide = rgba_color(out_red, out_green, out_blue, 255); + color overlay_guide = rgba_color(fg_red, fg_green, fg_blue, static_cast(alpha * 255)); + + while (!quit_requested()) + { + process_events(); + clear_screen(); + + // Layer pipeline: draw bitmaps back-to-front for stable compositing. + draw_bitmap(background_layer, 0, 0); + draw_bitmap(mid_layer, 0, 0); + draw_bitmap(props_layer, 0, 0); + draw_bitmap(foreground_layer, 0, 0); + + // Visual pass: draw depth guides and decorative perspective lines. + draw_line(blend_guide, 0, 370, 960, 370); + draw_line(overlay_guide, 480, 120, 180, 520); + draw_line(overlay_guide, 480, 120, 780, 520); + draw_line(blend_guide, 120, 500, 840, 500); + + refresh_screen(60); + } + + free_all_bitmaps(); + close_all_windows(); + + return 0; +} diff --git a/public/usage-examples/graphics/bitmap_layer_studio-1-example.png b/public/usage-examples/graphics/bitmap_layer_studio-1-example.png new file mode 100644 index 000000000..6498fcf97 Binary files /dev/null and b/public/usage-examples/graphics/bitmap_layer_studio-1-example.png differ diff --git a/public/usage-examples/graphics/bitmap_layer_studio-1-example.py b/public/usage-examples/graphics/bitmap_layer_studio-1-example.py new file mode 100644 index 000000000..8af88b8e3 --- /dev/null +++ b/public/usage-examples/graphics/bitmap_layer_studio-1-example.py @@ -0,0 +1,45 @@ +from splashkit import * + +open_window("Bitmap Layer Studio", 960, 540) + +# Scene setup: open window and load four bitmap layers. +background_layer = load_bitmap("background_layer", "layer_background.png") +mid_layer = load_bitmap("mid_layer", "layer_midground.png") +props_layer = load_bitmap("props_layer", "layer_props.png") +foreground_layer = load_bitmap("foreground_layer", "layer_foreground.png") + +alpha = 0.45 +bg_red = 48 +bg_green = 88 +bg_blue = 128 +fg_red = 250 +fg_green = 216 +fg_blue = 126 + +# Formula layer: C_out = alpha * C_fg + (1 - alpha) * C_bg. +out_red = int(alpha * fg_red + (1.0 - alpha) * bg_red) +out_green = int(alpha * fg_green + (1.0 - alpha) * bg_green) +out_blue = int(alpha * fg_blue + (1.0 - alpha) * bg_blue) +blend_guide = rgba_color(out_red, out_green, out_blue, 255) +overlay_guide = rgba_color(fg_red, fg_green, fg_blue, int(alpha * 255)) + +while not quit_requested(): + process_events() + clear_screen() + + # Layer pipeline: draw bitmaps back-to-front for stable compositing. + draw_bitmap(background_layer, 0, 0) + draw_bitmap(mid_layer, 0, 0) + draw_bitmap(props_layer, 0, 0) + draw_bitmap(foreground_layer, 0, 0) + + # Visual pass: draw depth guides and decorative perspective lines. + draw_line(blend_guide, 0, 370, 960, 370) + draw_line(overlay_guide, 480, 120, 180, 520) + draw_line(overlay_guide, 480, 120, 780, 520) + draw_line(blend_guide, 120, 500, 840, 500) + + refresh_screen(60) + +free_all_bitmaps() +close_all_windows() diff --git a/public/usage-examples/graphics/bitmap_layer_studio-1-example.txt b/public/usage-examples/graphics/bitmap_layer_studio-1-example.txt new file mode 100644 index 000000000..d1122aefe --- /dev/null +++ b/public/usage-examples/graphics/bitmap_layer_studio-1-example.txt @@ -0,0 +1,2 @@ +Parallax Alley at Dusk +Layer four bitmap planes, blend overlay guides, and tune the scene depth pass. diff --git a/scripts/json-files/guides-groups.json b/scripts/json-files/guides-groups.json index 7fe7bccde..36a7e3fb5 100644 --- a/scripts/json-files/guides-groups.json +++ b/scripts/json-files/guides-groups.json @@ -2,9 +2,9 @@ "animations", "audio", "beyond-splashkit", - "camera", + "Camera", "color", - "graphics", + "Graphics", "input", "interface", "json", diff --git a/scripts/json-files/usage-example-references.json b/scripts/json-files/usage-example-references.json index c41688ec6..cddb098f5 100644 --- a/scripts/json-files/usage-example-references.json +++ b/scripts/json-files/usage-example-references.json @@ -2,7 +2,7 @@ "audio": [ { "funcKey": "play_music_named", - "title": "Music Playback", + "title": "Music Playback\r", "url": "/api/audio/#play-music-named", "functions": [ "audio_ready", @@ -14,7 +14,7 @@ }, { "funcKey": "resume_music", - "title": "Pausing and Resuming Game Music", + "title": "Pausing and Resuming Game Music\r", "url": "/api/audio/#resume-music", "functions": [ "audio_ready", @@ -38,6 +38,31 @@ ] } ], + "color": [ + { + "funcKey": "saturation_of", + "title": "Draws a rectangle in a random colour. The colour's saturation value is displayed on screen", + "url": "/api/color/#saturation-of", + "functions": [ + "open_window", + "random_rgb_color", + "round", + "rectangle_from", + "clear_screen", + "color_white", + "fill_rectangle_record", + "draw_text_no_font_no_size", + "color_black", + "red_of", + "green_of", + "blue_of", + "alpha_of", + "refresh_screen", + "delay", + "close_all_windows" + ] + } + ], "geometry": [ { "funcKey": "center_point", @@ -142,7 +167,7 @@ }, { "funcKey": "closest_point_on_circle", - "title": "Closest Point to Mouse on Circle", + "title": "Closest Point to Mouse on Circle\r", "url": "/api/geometry/#closest-point-on-circle", "functions": [ "open_window", @@ -161,6 +186,25 @@ "close_all_windows" ] }, + { + "funcKey": "lines_intersect", + "title": "Simple Line Intersect Check", + "url": "/api/geometry/#lines-intersect", + "functions": [ + "open_window", + "Point2D", + "line_from_point_to_point", + "draw_line_record", + "color_red", + "draw_text_no_font_no_size", + "color_black", + "color_blue", + "color_green", + "refresh_screen", + "delay", + "close_all_windows" + ] + }, { "funcKey": "line_intersects_rect", "title": "Avoid the Rectangle", @@ -256,25 +300,6 @@ "close_all_windows" ] }, - { - "funcKey": "lines_intersect", - "title": "Simple Line Intersect Check", - "url": "/api/geometry/#lines-intersect", - "functions": [ - "open_window", - "Point2D", - "line_from_point_to_point", - "draw_line_record", - "color_red", - "draw_text_no_font_no_size", - "color_black", - "color_blue", - "color_green", - "refresh_screen", - "delay", - "close_all_windows" - ] - }, { "funcKey": "point_at", "title": "Flower Grid", @@ -508,7 +533,7 @@ }, { "funcKey": "random_window_point", - "title": "Random Portals", + "title": "Random Portals\r", "url": "/api/geometry/#random-window-point", "functions": [ "open_window", @@ -524,6 +549,32 @@ "close_window" ] }, + { + "funcKey": "rectangle_around", + "title": "A perpetually moving circle which increases and decreases in size, surrounded by a rectangle shape", + "url": "/api/geometry/", + "functions": [ + "open_window", + "create_timer", + "start_timer", + "quit_requested", + "point_at", + "cosine", + "sine", + "circle_at", + "timer_ticks", + "reset_timer", + "process_events", + "clear_screen_to_white", + "draw_rectangle_record", + "color_black", + "rectangle_around_circle", + "fill_circle_record", + "color_red", + "refresh_screen", + "close_all_windows" + ] + }, { "funcKey": "same_point", "title": "Point 2D Guessing Game", @@ -561,6 +612,42 @@ "close_all_windows" ] }, + { + "funcKey": "bitmap_center", + "title": "Draw a bitmap with a red dot at its center\r", + "url": "/api/graphics/#bitmap-center", + "functions": [ + "open_window", + "load_bitmap", + "clear_screen", + "color_white", + "draw_bitmap", + "fill_circle_record", + "color_red", + "circle_at", + "refresh_screen", + "delay", + "close_all_windows" + ] + }, + { + "funcKey": "bitmap_layer_studio", + "title": "Parallax Alley at Dusk", + "url": "/api/graphics/", + "functions": [ + "open_window", + "load_bitmap", + "rgba_color", + "quit_requested", + "process_events", + "clear_screen", + "draw_bitmap", + "draw_line", + "refresh_screen", + "free_all_bitmaps", + "close_all_windows" + ] + }, { "funcKey": "clear_screen", "title": "Background Color", @@ -575,7 +662,7 @@ }, { "funcKey": "draw_bitmap_named", - "title": "SplashKit Logo", + "title": "SplashKit Logo\r", "url": "/api/graphics/#draw-bitmap-named", "functions": [ "open_window", @@ -597,6 +684,26 @@ "SplashKit" ] }, + { + "funcKey": "draw_circle", + "title": "Circle Showcase\r", + "url": "/api/graphics/#draw-circle", + "functions": [ + "open_window", + "clear_screen", + "color_white", + "fill_circle", + "color_red", + "color_blue", + "color_green", + "color_orange", + "color_purple", + "random_rgb_color", + "refresh_screen", + "delay", + "close_all_windows" + ] + }, { "funcKey": "draw_circle_on_bitmap", "title": "Creating a Red Planet", @@ -1041,7 +1148,7 @@ }, { "funcKey": "fill_rectangle_on_bitmap", - "title": "Cityscape", + "title": "Cityscape\r", "url": "/api/graphics/#fill-rectangle-on-bitmap", "functions": [ "open_window", @@ -1112,7 +1219,7 @@ }, { "funcKey": "fill_triangle_on_bitmap", - "title": "Hooray! A Red Hat", + "title": "Hooray! A Red Hat\r", "url": "/api/graphics/#fill-triangle-on-bitmap", "functions": [ "open_window", @@ -1172,7 +1279,7 @@ }, { "funcKey": "free_font", - "title": "Freeing Fonts", + "title": "Freeing Fonts\r", "url": "/api/graphics/#free-font", "functions": [ "open_window", @@ -1189,6 +1296,25 @@ "close_all_windows" ] }, + { + "funcKey": "get_font_style", + "title": "The program automatically cycles through font styles for a given font (also displaying example text), with the numerical value of each style being shown on screen\r", + "url": "/api/graphics/#get-font-style", + "functions": [ + "open_window", + "font_named", + "quit_requested", + "process_events", + "set_font_style", + "clear_screen_to_white", + "draw_text_no_font_no_size", + "color_black", + "draw_text", + "refresh_screen", + "delay", + "close_all_windows" + ] + }, { "funcKey": "has_font", "title": "Checking for Font using Variable", @@ -1211,7 +1337,7 @@ }, { "funcKey": "load_font", - "title": "Using Fonts", + "title": "Using Fonts\r", "url": "/api/graphics/#load-font", "functions": [ "open_window", @@ -1242,7 +1368,7 @@ }, { "funcKey": "text_width_font_named", - "title": "Underline Text using Text Width", + "title": "Underline Text using Text Width\r", "url": "/api/graphics/#text-width-font-named", "functions": [ "open_window", @@ -1303,7 +1429,7 @@ "physics": [ { "funcKey": "sprite_bitmap_collision", - "title": "Does SplashKit have bugs?", + "title": "Does SplashKit have bugs?\r", "url": "/api/physics/#sprite-bitmap-collision", "functions": [ "open_window", @@ -1323,7 +1449,7 @@ }, { "funcKey": "sprite_collision", - "title": "Colliding Sprites", + "title": "Colliding Sprites\r", "url": "/api/physics/#sprite-collision", "functions": [ "open_window", @@ -1342,7 +1468,7 @@ }, { "funcKey": "sprite_point_collision", - "title": "Determine Sprite Collisions with Points", + "title": "Determine Sprite Collisions with Points\r", "url": "/api/physics/#sprite-point-collision", "functions": [ "open_window", @@ -1365,7 +1491,7 @@ }, { "funcKey": "sprite_rectangle_collision", - "title": "Detect Sprite Collisions with Rectangles", + "title": "Detect Sprite Collisions with Rectangles\r", "url": "/api/physics/#sprite-rectangle-collision", "functions": [ "open_window", @@ -1390,7 +1516,7 @@ "raspberry": [ { "funcKey": "raspi_i2c_write_data", - "title": "LED Text Scrolling", + "title": "LED Text Scrolling\r", "url": "/api/raspberry/#raspi-i2c-write-data", "functions": [ "write_line", @@ -1407,7 +1533,7 @@ "sprites": [ { "funcKey": "create_sprite", - "title": "Creating a Player Sprite", + "title": "Creating a Player Sprite\r", "url": "/api/sprites/#create-sprite", "functions": [ "open_window", @@ -1425,7 +1551,7 @@ }, { "funcKey": "draw_sprite", - "title": "Drawing a Player Sprite", + "title": "Drawing a Player Sprite\r", "url": "/api/sprites/#draw-sprite", "functions": [ "open_window", @@ -1443,7 +1569,7 @@ }, { "funcKey": "free_sprite", - "title": "Freeing a Sprite", + "title": "Freeing a Sprite\r", "url": "/api/sprites/#free-sprite", "functions": [ "open_window", @@ -1465,7 +1591,7 @@ }, { "funcKey": "sprite_set_position", - "title": "Setting Sprite Position", + "title": "Setting Sprite Position\r", "url": "/api/sprites/#sprite-set-position", "functions": [ "open_window", @@ -1485,7 +1611,7 @@ }, { "funcKey": "sprite_set_velocity", - "title": "Setting Velocity of Sprite", + "title": "Setting Velocity of Sprite\r", "url": "/api/sprites/#sprite-set-velocity", "functions": [ "open_window", @@ -1507,7 +1633,7 @@ }, { "funcKey": "sprite_set_x", - "title": "Setting Sprite X-coordinate", + "title": "Setting Sprite X-coordinate\r", "url": "/api/sprites/#sprite-set-x", "functions": [ "open_window", @@ -1524,7 +1650,7 @@ }, { "funcKey": "sprite_set_y", - "title": "Setting Sprite Y-coordinate", + "title": "Setting Sprite Y-coordinate\r", "url": "/api/sprites/#sprite-set-y", "functions": [ "open_window", @@ -1541,7 +1667,7 @@ }, { "funcKey": "sprite_x", - "title": "Sprite x-coordinate", + "title": "Sprite x-coordinate\r", "url": "/api/sprites/#sprite-x", "functions": [ "open_window", @@ -1561,7 +1687,7 @@ }, { "funcKey": "sprite_y", - "title": "Sprite y-coordinate", + "title": "Sprite y-coordinate\r", "url": "/api/sprites/#sprite-y", "functions": [ "open_window", @@ -1673,7 +1799,7 @@ }, { "funcKey": "current_ticks", - "title": "How many ticks?", + "title": "How many ticks?\r", "url": "/api/utilities/#current-ticks", "functions": [ "write_line", @@ -1790,5 +1916,30 @@ "write_line" ] } + ], + "windows": [ + { + "funcKey": "close_window", + "title": "Starts a countdown to close the window at the push of a button.", + "url": "/api/windows/#close-window", + "functions": [ + "open_window", + "create_timer", + "quit_requested", + "process_events", + "clear_window", + "color_white", + "button_at_position", + "rectangle_from", + "start_timer", + "draw_text_font_as_string", + "color_black", + "timer_ticks", + "reset_timer", + "draw_interface", + "refresh_window", + "close_all_windows" + ] + } ] } \ No newline at end of file diff --git a/scripts/usage-example-scraping.cjs b/scripts/usage-example-scraping.cjs index 0ec5376cf..4291c8f50 100644 --- a/scripts/usage-example-scraping.cjs +++ b/scripts/usage-example-scraping.cjs @@ -9,12 +9,48 @@ const path = require('path'); // Handle and transform file paths const srcDirectory = "./public/usage-examples"; //directory to be scraped const outputDirectory = "./scripts/json-files/usage-example-references.json" //directory where "Usage Example" functions will be savedc +function getApiFunctionLookup() +{ + const apiData = JSON.parse(fs.readFileSync("./scripts/json-files/api.json", "utf8")); + const lookup = {}; + + for (const categoryKey in apiData) + { + if (categoryKey === "types") continue; + + const category = apiData[categoryKey]; + if (!category || !Array.isArray(category.functions)) continue; + + lookup[categoryKey] = new Set( + category.functions.map((func) => func.unique_global_name.toLowerCase()) + ); + } + + return lookup; +} + +function getExampleUrl(folderKey, funcKey, apiFunctionLookup) +{ + const categoryPath = folderKey.replaceAll("_", "-"); + const anchor = funcKey.replaceAll("_", "-"); + const apiFunctions = apiFunctionLookup[folderKey]; + + if (apiFunctions && apiFunctions.has(funcKey)) + { + return `/api/${categoryPath}/#${anchor}`; + } + + // Fallback for integrated/non-API examples: link to the API category page. + return `/api/${categoryPath}/`; +} + // ------------------------------------------------------------------------------ // Scraping all of the folders in usage example and retrieving the functions and title // ------------------------------------------------------------------------------ function getAvailableExamplesFunctionUsage(dir) { const result = {}; const fileNameRegex = /^([a-zA-Z_][a-zA-Z0-9_]*)-/; + const apiFunctionLookup = getApiFunctionLookup(); const ignoreKey = new Set(["if", "else", "elif", "while", "for", "range", "int", "str", "match"]); @@ -55,7 +91,7 @@ function getAvailableExamplesFunctionUsage(dir) { funcEntry = { funcKey: funcKey, title: title, - url: `/api/${folderKey}/#${funcKey.replaceAll("_", "-")}`, + url: getExampleUrl(folderKey, funcKey, apiFunctionLookup), functions: [] }; result[folderKey].push(funcEntry); diff --git a/scripts/usage-examples-testing-script.cjs b/scripts/usage-examples-testing-script.cjs index 978b54d95..8906fbc8a 100644 --- a/scripts/usage-examples-testing-script.cjs +++ b/scripts/usage-examples-testing-script.cjs @@ -95,41 +95,12 @@ function getAllFiles(dir, allFilesList = []) { // Create function link to match with functions in the API Documentation pages function getFunctionLink(jsonData, groupNameToCheck, uniqueNameToCheck) { - let isOverloaded; - let functionIndex = -1; - let functionLink = ""; - for (const categoryKey in jsonData) { - const category = jsonData[categoryKey]; - const categoryFunctions = category.functions; - const functionGroups = {}; // Store functions grouped by name - categoryFunctions.forEach((func) => { - const functionName = func.name; - if (!functionGroups[functionName]) { - functionGroups[functionName] = []; - } - functionGroups[functionName].push(func); - }); - - for (const functionName in functionGroups) { - if (functionName == groupNameToCheck) { - const overloads = functionGroups[functionName]; - isOverloaded = overloads.length > 1; - - if (isOverloaded) { - overloads.forEach((func, index) => { - functionIndex = index + 1; - if (uniqueNameToCheck == func.unique_global_name) { - functionLink = functionName + "-" + (index + 1); - } - }); - } - else { - functionLink = functionName; - } - } - } + // API page anchors are keyed by unique_global_name (kebab-case), including overloads. + // Returning the unique name keeps links stable and avoids invalid numbered hashes. + if (uniqueNameToCheck) { + return uniqueNameToCheck; } - return functionLink; + return groupNameToCheck; } // Clean directory function to remove all files except those in the exclusions list @@ -357,8 +328,14 @@ categories.forEach((categoryKey) => { } // ----------------------------------- + // Support both nested and flat usage-example layouts. + const functionFolderPath = path.join(categoryFilePath, functionKey); + const useNestedLayout = fs.existsSync(functionFolderPath); + // Description - let txtFilePath = categoryFilePath + "/" + functionKey + "/" + exampleTxtKey; + let txtFilePath = useNestedLayout + ? path.join(categoryFilePath, functionKey, exampleTxtKey) + : path.join(categoryFilePath, exampleTxtKey); let exampleTxt = fs.readFileSync(txtFilePath); mdxContent += "\n"; mdxContent += exampleTxt.toString(); @@ -372,13 +349,16 @@ categories.forEach((categoryKey) => { }; // import code - let codePath = categoryFilePath + "/" + functionKey; + let codePath = useNestedLayout ? functionFolderPath : categoryFilePath; const codeFiles = getAllFiles(codePath); let importTitle = exampleKey.replaceAll("-", "_"); let functionTag = ""; + const codeBasePath = useNestedLayout + ? categoryPath + "/" + functionKey + "/" + exampleTxtKey + : categoryPath + "/" + exampleTxtKey; languageOrder.forEach((lang) => { const languageFiles = codeFiles.filter(file => file.startsWith(exampleKey)).filter(file => file.endsWith(languageFileExtensions[lang])); - let codeFilePath = categoryPath + "/" + functionKey + "/" + exampleTxtKey.replaceAll(".txt", languageFileExtensions[lang]); + let codeFilePath = codeBasePath.replaceAll(".txt", languageFileExtensions[lang]); // import code if available if (languageFiles.length > 0) { @@ -494,7 +474,7 @@ categories.forEach((categoryKey) => { mdxContent += "**Output**:\n\n"; const imageFiles = categoryFiles.filter(file => file.endsWith(exampleKey + '.png')); - let outputFilePath = categoryPath + "/" + functionKey + "/" + exampleTxtKey; + let outputFilePath = codeBasePath; // Check for .png files if (imageFiles.length > 0) { outputFilePath = outputFilePath.replaceAll(".txt", ".png");