{"spec_id":"burndown-sprint","library":"makie","language":"julia","code":"# anyplot.ai\n# burndown-sprint: Agile Sprint Burndown Chart\n# Library: makie 0.22.10 | Julia 1.11.9\n# Quality: 90/100 | Created: 2026-06-14\n\nusing CairoMakie\nusing Colors\nusing Random\n\nRandom.seed!(42)\n\n# Theme tokens (Imprint palette — see prompts/default-style-guide.md)\nconst THEME       = get(ENV, \"ANYPLOT_THEME\", \"light\")\nconst PAGE_BG     = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nconst ELEVATED_BG = THEME == \"light\" ? colorant\"#FFFDF6\" : colorant\"#242420\"\nconst INK         = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT    = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nconst INK_MUTED   = THEME == \"light\" ? colorant\"#6B6A63\" : colorant\"#A8A79F\"\nconst IMPRINT_PALETTE = [\n    colorant\"#009E73\",  # 1 brand green (Imprint palette — always first series)\n    colorant\"#C475FD\",  # 2 lavender\n    colorant\"#4467A3\",  # 3 blue\n    colorant\"#BD8233\",  # 4 ochre\n    colorant\"#AE3030\",  # 5 matte red (semantic anchor: bad / scope risk)\n    colorant\"#2ABCCD\",  # 6 cyan\n    colorant\"#954477\",  # 7 rose\n    colorant\"#99B314\",  # 8 lime\n]\n\n# Sprint data: 10 working days (Mon-Fri × 2 weeks), 40 initial story points.\n# Calendar days: 0=Mon 1=Tue 2=Wed 3=Thu 4=Fri 5=Sat 6=Sun 7=Mon … 11=Fri\n# Scope change (+8 pts) added on day 4 (Friday, week 1) — visible as upward jump.\ndays_raw      = [0,  1,  2,  3,  4,  4,  7,  8,  9, 10, 11]\nremaining_raw = [40, 36, 32, 28, 36, 32, 26, 19, 13,  7,  0]\n\n# Build step-function from sprint data (pre-step: each value holds until the next x)\nstep_x = Float64[]\nstep_y = Float64[]\nfor i in eachindex(days_raw)\n    push!(step_x, Float64(days_raw[i]))\n    push!(step_y, Float64(remaining_raw[i]))\n    if i < length(days_raw)\n        push!(step_x, Float64(days_raw[i + 1]))\n        push!(step_y, Float64(remaining_raw[i]))\n    end\nend\n\n# Ideal burndown: straight diagonal from (0, 40) to (11, 0)\nideal_x = [0.0, 11.0]\nideal_y  = [40.0, 0.0]\n\n# Title — includes descriptive prefix so \"burndown-sprint\" reads unambiguously\ntitle_str = \"Sprint Burndown · burndown-sprint · julia · makie · anyplot.ai\"\nn_chars   = length(title_str)\nratio     = n_chars > 67 ? 67.0 / n_chars : 1.0\ntitle_fs  = max(14, round(Int, 20 * ratio))\n\n# X-axis tick labels — weekday names for the 12 calendar days (0–11)\nday_labels = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\",\n              \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\"]\n\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title             = title_str,\n    titlesize         = title_fs,\n    titlecolor        = INK,\n    xlabel            = \"Sprint Day\",\n    ylabel            = \"Story Points Remaining\",\n    xlabelsize        = 14,\n    ylabelsize        = 14,\n    xticklabelsize    = 11,\n    yticklabelsize    = 12,\n    xlabelcolor       = INK,\n    ylabelcolor       = INK,\n    xticklabelcolor   = INK_SOFT,\n    yticklabelcolor   = INK_SOFT,\n    xtickcolor        = INK_SOFT,\n    ytickcolor        = INK_SOFT,\n    backgroundcolor   = PAGE_BG,\n    topspinevisible   = false,\n    rightspinevisible = false,\n    leftspinecolor    = INK_SOFT,\n    bottomspinecolor  = INK_SOFT,\n    xgridvisible      = false,\n    ygridcolor        = RGBAf(Float32(INK.r), Float32(INK.g), Float32(INK.b), 0.15f0),\n    yminorgridvisible = false,\n    xminorgridvisible = false,\n    xticks            = (0:11, day_labels),\n)\n\n# Weekend band — calendar days 5 (Sat) and 6 (Sun)\nvspan!(ax, 4.5, 6.5; color = (INK_MUTED, 0.12))\n\n# Ideal burndown reference (dashed, muted — below ideal means ahead of schedule)\nlines!(ax, ideal_x, ideal_y;\n    color     = INK_SOFT,\n    linewidth = 2.0,\n    linestyle = :dash,\n    label     = \"Ideal\")\n\n# Actual burndown step chart (Imprint brand green — first categorical series)\nlines!(ax, step_x, step_y;\n    color     = IMPRINT_PALETTE[1],\n    linewidth = 3.0,\n    label     = \"Actual\")\n\n# Scope change marker — dotted vertical at day 4 (matte red semantic anchor)\nvlines!(ax, [4.0];\n    color     = (IMPRINT_PALETTE[5], 0.75),\n    linewidth = 1.8,\n    linestyle = :dot)\n\n# Scope change annotation\ntext!(ax, 4.15, 38.5;\n    text     = \"+8 pts\",\n    color    = IMPRINT_PALETTE[5],\n    fontsize = 12,\n    align    = (:left, :center))\n\n# Weekend label\ntext!(ax, 5.5, 43.5;\n    text     = \"Weekend\",\n    color    = INK_MUTED,\n    fontsize = 11,\n    align    = (:center, :center))\n\nxlims!(ax, -0.5, 11.8)\nylims!(ax, -2.0, 47.0)\n\n# Legend — top-right, below/ahead of schedule reading clear from colors\naxislegend(ax;\n    position        = :rt,\n    framecolor      = INK_SOFT,\n    backgroundcolor = ELEVATED_BG,\n    labelcolor      = INK,\n    labelsize       = 12,\n    patchsize       = (25, 3),\n    padding         = (8, 8, 6, 6))\n\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}