I have had this issue after upgrading the Xcode to 16.3 version.
Xcode 16.3 and undefined template 'std::char_traits<unsigned char>' prevent building the app
I am not able to build the app in react native.
Blancer.com Tutorials and projects
Freelance Projects, Design and Programming Tutorials
Category Added in a WPeMatico Campaign
I have had this issue after upgrading the Xcode to 16.3 version.
Xcode 16.3 and undefined template 'std::char_traits<unsigned char>' prevent building the app
I am not able to build the app in react native.
Error in Post Comment Route—Need Help:
I’m facing the error in my post comment route, and while I understand it’s coming from the catch block, I can’t find the exact issue. All other functionalities in my code work perfectly—only this part fails. I’ve tried multiple approaches but still can’t resolve it.
Frontend (React) – onSubmit Handler
When a user submits the form, this function executes:
const onSubmit = async (data) => {
try {
console.log("Comment is ", data.Comment);
const response = await postComment(id, { Comment: data.Comment });
console.log("Response data", response.data);
setComments(prevComments => [...prevComments, response.data]);
toastSuccess("New comment added successfully");
reset();
} catch (error) {
toastError(error.message);
if (error.response?.status === 401) {
navigate("/login");
toastError(error?.response?.message);
}
}
};
axios.post directly, but later moved it to a separate api.jsx file and imported postComment from there.id comes from .401), they’re redirected to the login page.Backend (Express) – postComment Controller
module.exports.postComment = async (req, res) => {
try {
let postId = req.params.id;
if (!req.user || !req.user._id) {
console.log("You must be logged in first");
return res.status(401).json({ message: "Unauthorized: Please log in first." });
}
const userId = req.user?._id || null;
let newComment = new CommentListing({
Comment: req.body.Comment,
userName: userId,
date: new Date(),
postId: postId
});
let savedComment = await newComment.save();
res.status(200).json(savedComment);
} catch (error) {
console.error("Error in catch block:", error);
res.status(500).json({
message: "Error posting comment",
error: error.message
});
}
};
This is my route. JS backend:
router.post( wrapAsync(postComment))
This is api.jsx for reference:
export const postComment = (id, commentData) => API.post(`/tools/${id}/comment`, commentData);
I am trying to record audio from speaker only using TypeScript or javascript.
Expected: it is recording audio from speaker only not microphone.
Actual: it is recording audio from microphone
Please help me what is the problem in my code?
let audioChunks: any = [];
navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => {
audioChunks = [];
let rec = new MediaRecorder(stream);
rec.ondataavailable = e => {
audioChunks.push(e.data);
if (rec.state == "inactive") {
let blob = new Blob(audioChunks, { type: 'audio/x-mpeg-3' });
downloadFile(blob, "filename.wav");
}
}
rec.start();
setTimeout(() => {
rec.stop();
}, 10000);
})
.catch(e => console.log(e));
I’m trying to trigger a custom Windows application from my PHP code using a custom protocol handler (videoplugin). I’ve registered the protocol in the Windows Registry and confirmed that it works when I run it manually from the Windows Run dialog.
What works:
Running this from Win + R works and launches the application successfully:
"C:Program Files (x86)IPRPLocalServiceComponentsIPRP Video PluginVideoPlugin.exe" "IP:100.100.210.16;Port:90;UserName:admin;Password:P@ssword1;AccountID:8518;ZoneNo.:501;AlarmTime:2025-04-08T15:01:46;AlarmInfo:Motion Detection Alarm;PCAlarmTimeTag:0;"
And here is my registry config (.reg file):
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOTvideoplugin]
@="URL:VideoPlugin Protocol"
"URL Protocol"=""
[HKEY_CLASSES_ROOTvideopluginshell]
[HKEY_CLASSES_ROOTvideopluginshellopen]
[HKEY_CLASSES_ROOTvideopluginshellopencommand]
@="C:\Program Files (x86)\IPRPLocalServiceComponents\IPRP Video Plugin\VideoPlugin.exe %1"
What fails:
From my PHP code, I’m trying to trigger the URL like this:
if (isset($_POST['triggerVideo'])) {
$firstFourDigits = substr($accountno, 0, 4);
$formattedStartDate = ($DateTimeStart instanceof DateTime) ? $DateTimeStart->format('Y-m-dTH:i:s') : date('Y-m-dTH:i:s');
$videoUrl = "videoplugin:IP:100.100.210.16;Port:90;UserName:admin;Password:P@ssword1;AccountID:$firstFourDigits;ZoneNo.:501;AlarmTime:$formattedStartDate;AlarmInfo:Motion Detection Alarm;PCAlarmTimeTag:0;";
echo "<script>console.log('$videoUrl');</script>";
echo "<script>window.location.href = '$videoUrl';</script>";
exit;
}
When I run this in the browser, nothing happens. The browser either ignores it or throws a permission error. No exceptions are caught in the try…catch block either.
What I’ve tried:
Confirmed that JavaScript is executing by adding console.log.
Question:
How can I reliably open my custom videoplugin: protocol handler from PHP via browser (ideally Chrome or Edge)? Is this behavior blocked by the browser, or is there a better way to launch a native app from PHP?
When I say component syntax, what I’m referring to is this: https://flow.org/en/docs/react/component-syntax/
which looks like this:
export default component MyComponent(someProp: string) {
prettier doesn’t recognize component as a valid keyword (understandably so) and so it breaks and doesn’t check anything in the file
It doesn’t have to be prettier, I’d use another formatter if it works better with Flow’s component syntax, and I’m also open to in depth solutions like cloning the prettier repo and making the changes to support component syntax myself.
I’m trying to create Custom Point Tooltip for Nivo Area Bump Chart some like this for Bump Chart
https://nivo.rocks/storybook/iframe.html?globals=backgrounds.grid:!false&args=&id=bump–custom-point-tooltip&viewMode=story.
{
render: () => {
const data = generateDataWithHoles();
return <Bump<{
x: number;
y: number | null;
}> {...commonProps} useMesh={true} debugMesh={true} pointTooltip={PointTooltip} data={data} />;
}
}
I don’t know if it’s even possible with Area Bump. Any other suggestions?
I have previously intercepted, paused, inserted a body, then continued a fetch() request made from any tab or window using Fetch.enable, listening for Fetch.requestPaused and other Fetch domain definitions, something like this
chrome.debugger.onEvent.addListener(async ({
tabId
}, message, params) => {
console.log(tabId, message, params);
if (
message === 'Fetch.requestPaused' &&
/^chrome-extension|ext_stream/.test(params.request.url)
) {
await chrome.debugger.sendCommand({
tabId
}, 'Fetch.fulfillRequest', {
responseCode: 200,
requestId: params.requestId,
requestHeaders: params.request.headers,
body: bytesArrToBase64(
encoder.encode(
JSON.stringify([...Uint8Array.from({
length: 1764
}, () => 255)])
)
),
});
await chrome.debugger.sendCommand({
tabId
}, 'Fetch.continueRequest', {
requestId: params.requestId,
});
} else {
await chrome.debugger.sendCommand({
tabId
}, 'Fetch.continueRequest', {
requestId: params.requestId,
});
}
});
const tabId = tab.id;
await chrome.debugger.attach({
tabId
}, '1.3');
await chrome.debugger.sendCommand({
tabId
}, 'Fetch.enable', {
patterns: [{
requestStage: "Request",
resourceType: "XHR",
urlPattern: '*ext_stream'
}]
});
Now I’m working on intercepting a WebTransport request, then start a local WebTransport server using Native Messaging, then continue the request.
First iteration of code. I ordinarily wouldn’t ask questions about my first draft. Generally I hack away at for a while before asking about any part of the process. Here goes, anyway, using Network.webTransportCreated
globalThis.port;
chrome.debugger.onEvent.addListener(async ({
tabId
}, message, params) => {
if (message === "Network.webTransportCreated" &&
params.url ===
"https://localhost:4433/path") {
if (globalThis.port === undefined) {
globalThis.port = chrome.runtime.connectNative(chrome.runtime.getManifest().short_name);
port.onMessage.addListener(async (e) => {
console.log(e);
});
port.onDisconnect.addListener(async (e) => {
if (chrome.runtime.lastError) {
console.log(chrome.runtime.lastError);
}
console.log(e);
});
} else {
// ...
}
}
});
At least this is my initial concept for what I want to do. If the Dev Tools Protocol, or other extension API’s don’t have an explicit or implicit way to do this, then I’ll just do this another way. I’ve done this different ways in the past.
I looked. Didn’t find anything that was obvious to me in the Network domain that will facilitate the process I’m able to do with Fetch domain and fetch().
The Network.webTransportCreated event is dispatched when the request is made from the arbitrary Web page console or Snippets. The code looks something like this
(async () => {
try {
const serverCertificateHashes = [
{
"algorithm": "sha-256",
// Hardcoding the certificate here
// after serilizing to JSON for import with {type: "json"}...
"value": Uint8Array.of(
0, 1, 2, ...
),
},
];
const client = new WebTransport(
`https://localhost:4433/path`,
{
serverCertificateHashes,
},
);
// ...
The request doesn’t pause though. It usually takes between 200 to 300 milliseconds to start a node or deno or bun, etc. server using Native Messaging to launch the application; startup time of the executable. So the server is not started in time to handle the request.
I also tried making two (2) WebTransport requests. The first just to start the local WebTransport server. Then the error has to be handled, which involves including async code in error handling code. I think the double request to do one thing pattern has some technical debt. If all else fails, I’ll retry that, though.
Just curious if I’m missing something in the Network domain or extension API’s that could be used for this case – pausing a created WebTransport request, then continuing that request, programmatically?
I’m trying to set-up a custom UMD build for CKEditor5 and the relevant files are available here:
The issue can be seen live at https://saurabhnanda.in/ckeditor-bug/ While I am able to do editor.setData('string without HTML'), a string containing even the most basic HTML, such as, editor.setData('<strong>foobar</strong>'); throws the following error:
Uncaught CKEditorError: pattern is undefined
Read more: https://ckeditor.com/docs/ckeditor5/latest/support/error-codes.html#error-pattern is undefined
_isElementMatching matcher.js:165
match matcher.js:95
node_modules custom-ckeditor.js:14875
fire emittermixin.js:145
_convertItem upcastdispatcher.js:221
_convertChildren upcastdispatcher.js:250
convertChildren upcastdispatcher.js:154
node_modules custom-ckeditor.js:14597
fire emittermixin.js:145
_convertItem upcastdispatcher.js:227
convert upcastdispatcher.js:189
node_modules custom-ckeditor.js:8481
change model.js:192
toModel datacontroller.js:396
node_modules custom-ckeditor.js:98901
fire emittermixin.js:145
node_modules custom-ckeditor.js:98904
parse datacontroller.js:379
node_modules custom-ckeditor.js:8445
_runPendingChanges model.js:822
enqueueChange model.js:215
set datacontroller.js:354
node_modules custom-ckeditor.js:98901
fire emittermixin.js:145
node_modules custom-ckeditor.js:98904
setData editor.js:600
<anonymous> (index):15
setInterval handler* (index):14
promise callback* (index):9
3 ckeditorerror.js:65
I’ve tried with multiple permutations of plugins and including/excluding the GeneralHtmlSupport plugin, but nothing seems to work.
I think I am missing something very basis due to a blind spot. Any help would be appreciated.
I have an animation that I am declaring and playing using JS, but when the animation plays, my event listener doesn’t fire.
Here’s the HTML file:
<!DOCTYPE html>
<html>
<head>
</head>
<body id="body">
<div id="anim"></div>
<style>
#anim {
top: 500px;
left: 500px;
width: 100px;
height: 100px;
background-color: black;
position: absolute;
}
</style>
<script>
let anim = document.getElementById("anim");
const animkeyFrames = new KeyframeEffect(
anim,
[
{ transform: `translate3d(0px, 0px, 0px)` }, // keyframe
{ transform: `translate3d(0px, ${200}px, 0px)` },
],
{
// keyframe options
duration: 1000,
iterations: "1",
},
);
let animation = new Animation(animkeyFrames, document.timeline);
animation.play();
anim.addEventListener('animationstart', () => {
console.log("STARTED");
})
</script>
</body>
</html>
I want “STARTED” to be logged when the animation plays but nothing happens.
I’m using doughnut chart from chartJS for my project. For some reason, it become smaller when I hover into center area of the chart. Below i have a link to the video how its looks like. I want to find what is the cause and how to fix it.
options: {
interaction: {
mode: 'nearest',
intersect: false
},
responsive: true,
maintainAspectRatio: false,
plugins: {
tooltip: {
enabled: true
}
},
elements: {
arc: {
hoverOffset: 0
}
}
Any ideas would be appreciated! Thank you.
Why does using the lazy attribute of el-image inside el-carousel cause several blank pages when flipping to the right?
Online Demo
Example Code
<script setup lang="ts">
</script>
<template>
<div>
<div style="width: 100%; height: 2000px; display: block">lazy load header</div>
<el-carousel height="2000px">
<el-carousel-item>
<el-row>
<el-col :span="24">
<el-image
src="https://dummyimage.com/2000x2000/aaa/fff&text=2000x2000"
lazy
/>
</el-col>
</el-row>
</el-carousel-item>
<el-carousel-item>
<el-row>
<el-col :span="24">
<el-image
src="https://dummyimage.com/2000x2000/bbb/fff&text=2000x2000"
lazy
/>
</el-col>
</el-row>
</el-carousel-item>
<el-carousel-item>
<el-row>
<el-col :span="24">
<el-image
src="https://dummyimage.com/2000x2000/ccc/fff&text=2000x2000"
lazy
/>
</el-col>
</el-row>
</el-carousel-item>
<el-carousel-item>
<el-row>
<el-col :span="24">
<el-image
src="https://dummyimage.com/2000x2000/ddd/fff&text=2000x2000"
lazy
/>
</el-col>
</el-row>
</el-carousel-item>
<el-carousel-item>
<el-row>
<el-col :span="24">
<el-image
src="https://dummyimage.com/2000x2000/eee/fff&text=2000x2000"
lazy
/>
</el-col>
</el-row>
</el-carousel-item>
</el-carousel>
</div>
</template>
<style>
Currently, I’m not sure how to make an attempt. The expected result is that when using the lazy attribute of el-image inside el-carousel, there won’t be any blank pages when flipping to the right.
I’ve been trying to create this design using HTML, CSS and JS (particularly chart.io). I am wondering if there is a better way to do this without relying much on JS. The reason for this is that, this particular screenshot below is for a report. So I need to make sure that the design renders graciously with all browsers. And if a user decides to save it as PDF, the report should not have any problem rendering on different PDF viewers. I’m worried about having too much JS as I’ve had issues before where the designs break in iOS and Acrobat.
For starters, I’ll use 12 o’clock as the top most part of the progress.
This is what I currently have at the moment.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Age Progress and Graph</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2"></script>
<style>
body {
font-family: sans-serif;
display: flex;
align-items: center;
justify-content: space-between;
background: #fff;
margin: 0;
padding: 2rem;
width: 700px;
}
.progress-container {
position: relative;
width: 160px;
height: 160px;
margin-bottom: 2rem;
}
.progress-container svg {
transform: rotate(-90deg);
}
.progress-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
.progress-text h2 {
margin: 0;
font-size: 2rem;
}
.chart-container {
width: 440px;
height: 150px;
}
</style>
</head>
<body>
<div class="progress-container">
<svg width="160" height="160">
<circle
cx="80"
cy="80"
r="70"
stroke="#eee"
stroke-width="8"
fill="none"
></circle>
<circle
cx="80"
cy="80"
r="70"
stroke="url(#gradient)"
stroke-width="8"
fill="none"
stroke-dasharray="440"
stroke-dashoffset="{{DASH_OFFSET}}"
stroke-linecap="round"
></circle>
<defs>
<linearGradient id="gradient" x1="1" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#a646d7" />
<stop offset="100%" stop-color="#e84fd1" />
</linearGradient>
</defs>
</svg>
<div class="progress-text">
<h2 style="font-weight:300;">44.37</h2>
<small>Older ⤴</small>
</div>
</div>
<div class="chart-container">
<canvas id="ageChart"></canvas>
</div>
<script>
Chart.register(ChartDataLabels);
const currentAge = 42;
const biologicalAge = 44.37;
const fullCircle = 440;
const percent = Math.min(biologicalAge / currentAge, 1);
const offset = fullCircle * (1 - percent);
document.querySelector("circle[stroke-dashoffset='{{DASH_OFFSET}}']")
.setAttribute("stroke-dashoffset", offset);
const ctx = document.getElementById('ageChart').getContext('2d');
const dataPoints = [40.44, 45.54, 44.37];
const ageChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['Jan 2024', 'Apr 2024', 'Jul 2024'],
datasets: [{
label: 'Biological Age',
data: dataPoints,
fill: false,
tension: 0.4,
borderColor: function(context) {
const chart = context.chart;
const {ctx, chartArea} = chart;
if (!chartArea) return;
const gradient = ctx.createLinearGradient(chartArea.left, 0, chartArea.right, 0);
gradient.addColorStop(0, '#36d1dc');
gradient.addColorStop(1, '#a646d7');
return gradient;
},
borderWidth: 3,
pointRadius: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
layout: {
padding: {
left: 20,
right: 20
}
},
scales: {
y: {
suggestedMin: 35,
suggestedMax: 50,
ticks: {
stepSize: 5
},
grid: {
drawTicks: true,
drawOnChartArea: true
}
},
x: {
grid: {
drawTicks: false,
drawOnChartArea: false,
drawBorder: false,
color: 'transparent',
lineWidth: 0
},
border: {
display: false
},
ticks: {
padding: 8
},
offset: true
}
},
plugins: {
legend: {
display: false
},
tooltip: {
callbacks: {
label: ctx => `Age: ${ctx.raw}`
}
},
datalabels: {
align: 'center',
anchor: 'center',
formatter: (value) => value.toFixed(2),
backgroundColor: (context) => context.dataIndex === context.dataset.data.length - 1 ? '#000' : '#fff',
borderRadius: 999,
color: (context) => context.dataIndex === context.dataset.data.length - 1 ? '#fff' : '#000',
font: {
weight: 'bold'
},
padding: 6,
borderWidth: 1,
borderColor: '#000'
}
}
},
plugins: [ChartDataLabels]
});
</script>
</body>
</html>
I would greatly appreciate if you could provide some recommendations or if you could help me with this. Thank you in advance.
I have a list of items where one of the attributes can be double clicked and then edited.
I have to use [contenteditable="true"] instead of using a standard input.
The format of the data which is editable may also include a unit of measure, e.g. “150mm”.
I’m currently using .select() which selects everything, including the unit of measure.
See example here https://codepen.io/c01gat3/pen/GgRbwoj
I want to select just the numeric values, or the length of the string less the characters at the end.
Happy for plain javascript or jQuery answers for this project.
$('body').on('dblclick', '.value', function(){
$(this).attr('contenteditable', true);
//*** this is where I need some help
$(this).focus().select();
//How to only select the numbers, not include the "mm"?
//or how to select (length - 2) characters?
});
$(document).mouseup(function(e){
var element = $('body').find('.value[contenteditable="true"]');
if (!element.is(e.target) && element.has(e.target).length === 0){
$('.value').attr('contenteditable', false);
}
});
$(document).keypress(function(e) {
if($('.value[contenteditable="true"]')){
if(e.which == 13){ //enter
$('.value').attr('contenteditable', false);
}
}
});
.list{
display: flex;
flex-direction: column;
gap: 10px;
.item{
display: flex;
.id{
width: 20px;
font-weight: 600;
}
&:has(.value[contenteditable="true"]){
.id{
color: red;
}
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div class="list">
<div class="item">
<span class="id">1</span>
<span class="value">100mm</span>
</div>
<div class="item">
<span class="id">2</span>
<span class="value">2,500mm</span>
</div>
<div class="item">
<span class="id">3</span>
<span class="value">340mm</span>
</div>
</div>
I am trying to find a robust way to get a YouTube video duration/length without using the YouTube API. The main problem is when the video starts with an ad because then document.querySelector(".ytp-time-duration") or document.querySelector("video").duration returns the ad’s duration, not the actual video duration.
Obviously, there are many APIs out there that provide much more information than just video duration, but I don’t think all of these APIs actually rely on the YouTube Data API. So, how can I get the actual video length even if the video starts with ads?
Any solution that works on browser console (JavaScript) is good enough for me.
For context, I’m incredibly new (talking one week) to javascript. I’m involved in a school project to make a choose your own adventure game and am taking it way too seriously. Anyway, I’ve started a game based on mexican folklore and am trying to get a “book” button to work. So you can read in game about the people you meet :). However, one of the “ghost” sprites (la planchada, or planchadafullsprite) will not hide, and the book background will not show up over that sprite’s designated background (planchadabg). This is kind of a trivial question lol but I’m super open to learning about javascript! Here is my code. For reference, I’m doing this on replit. the issues are happening after “showbookscreen” is executed. Sorry for any mistakes I’m super new to coding! 🙂
Also, the button seems to work fine on another screen, with lloronafullsprite and the corresponding background etc. So it means half of the code piece that’s hiding the sprites is working and half of it isn’t? I’m not sure.
//Press a button to choose your path
//See the README file for more information
/* VARIABLES */
let enterButton;
let a1Button;
let a2Button;
let b1Button;
let b2Button;
let screen = 0;
let music;
let softwind;
let lloronaSound;
let musicStopped = false;
let introBg;
let textScreen;
let startButton;
let nextButton;
let charroHead;
let charroFull;
let lloronaHead;
let lloronaFull;
let planchadaHead;
let planchadaFull;
let planchadaBg;
let charroBg;
let lloronaBg;
let forwardButton;
let backButton;
let bookButton;
let bookBg;
let blackBg;
let screenBeforeBook;
let exitButton;
function preload() {
//music
soundFormats("mp3");
music = loadSound("sweetwater.mp3");
lloronaSound = loadSound("Assets/llorona.mp3");
//images
introBg = loadImage("/Assets/introbg.png");
textScreen = loadImage("/Assets/textscreen.png");
startButton = loadImage("/Assets/startbutton.png");
nextButton = loadImage("/Assets/nextbutton.png");
charroHead = loadImage("/Assets/charrohead.png");
charroFull = loadImage("/Assets/charrofull.png");
lloronaHead = loadImage("/Assets/lloronahead.png");
lloronaFull = loadImage("/Assets/lloronafull.png");
lloronaBg = loadImage("/Assets/lloronabg.png");
planchadaBg = loadImage("/Assets/planchadabg.png");
charroBg = loadImage("/Assets/charrobg.png");
forwardButton = loadImage("/Assets/forwardbutton.png");
backButton = loadImage("/Assets/backbutton.png");
planchadaFull = loadImage("/Assets/planchadafull.png");
bookButton = loadImage("/Assets/bookbutton.png");
bookBg = loadImage("/Assets/bookbg.png");
blackBg = loadImage("/Assets/blackbg.png");
exitButton = loadImage("/Assets/exitbutton.png");
}
/* SETUP RUNS ONCE */
function setup() {
createCanvas(780, 520);
textAlign(CENTER);
textSize(20);
noStroke();
// Set up the home screen
background(46, 26, 10);
//Draw background Image
image(introBg, 0, 0);
// Create buttons for all screens
startButton = new Sprite(width/2, height/2 + 200);
nextButton = new Sprite(width + 400, height + 400);
//Resize Images
forwardButton.resize(0,45);
backButton.resize(0,45);
bookButton.resize(0,45);
exitButton.resize(0,45);
// Create sprites
charroFullSprite = new Sprite(charroFull, -2000,-2000)
lloronaFullSprite = new Sprite(lloronaFull, -2000,-2000)
planchadaFullSprite = new Sprite(planchadaFull, -2000,-2000)
charroHeadSprite = new Sprite(charroHead, -2000,-2000)
lloronaHeadSprite = new Sprite(lloronaHead, -2000,-2000)
planchadaHeadSprite = new Sprite(planchadaHead, -2000,-2000)
forwardButtonSprite = new Sprite(forwardButton, -2000,-2000)
backButtonSprite = new Sprite (backButton, -2000,-2000)
bookButtonSprite = new Sprite (bookButton, -2000,-2000)
}
/* DRAW LOOP REPEATS */
function draw() {
// Display start button
startButton.w = 80;
startButton.h = 50;
startButton.collider = "k";
startButton.color = "white";
startButton.text = "start";
//Check start button
if (startButton.mouse.presses()) {
print("pressed");
showIntroScreen0();
screen = 0;
}
// Display Llorona screen
if (screen == 0) {
if (nextButton.mouse.presses()) {
print("pressed");
showLloronaScreen();
screen = 1;
}
}
//Go to charro screen from llorona
if (screen == 1) {
if (forwardButtonSprite.mouse.presses()) {
showCharroScreen();
screen = 2;
}
if (backButtonSprite.mouse.presses()) {
showPlanchadaScreen();
screen = 3;
}
}
//go to llorona screen from planchada
if (screen == 3) {
if (forwardButtonSprite.mouse.presses()) {
print("pressed");
showLloronaScreen();
screen = 1;
}
}
//go to llorona screen from charro
if (screen == 2) {
if (backButtonSprite.mouse.presses()) {
print("pressed");
showLloronaScreen();
screen = 1;
}
}
//go to book screen
if (screen == 1) {
if (bookButtonSprite.mouse.presses()) {
print("pressed");
showBookScreen();
screen = 4;
screenBeforeBook = 1;
}
}
if (screen == 2) {
if (bookButtonSprite.mouse.presses()) {
print("pressed");
showBookScreen();
screen = 4;
screenBeforeBook = 2;
}
}
if (screen == 3) {
if (bookButtonSprite.mouse.presses()) {
print("pressed");
showBookScreen();
screen = 4;
screenBeforeBook = 3;
}
}
//hide buttons in book bg
if (screen == 4) {
forwardButtonSprite.pos = { x: -2000, y: -2000 };
backButtonSprite.pos = { x: -2000, y: -2000 };
bookButtonSprite.pos = { x: -2000, y: -2000 };
lloronaFullSprite.pos = { x: -2000, y: -2000 };
charroFullSprite.pos = { x: -2000, y: -2000 };
planchadaFullSprite.pos = { x: -2000, y: -2000 };
}
//exit book screen
if (screen == 4) {
if (exitButtonSprite.mouse.presses())
if (screenBeforeBook == 1) {
showLloronaScreen();
screen = 1;
}
if (screenBeforeBook == 2) {
showCharroScreen();
screen = 2;
}
if (screenBeforeBook == 3) {
showPlanchadaScreen();
screen = 3;
}
}
}
function mousePressed() {
// Start audio context and play music only on first click and if not stopped
if (!music.isPlaying() && !musicStopped) {
userStartAudio();
music.play();
music.loop();
music.setVolume(0.3);
}
}
/* FUNCTIONS TO DISPLAY SCREENS */
function showIntroScreen0() {
background(46, 26, 10)
image(textScreen, 3, 0);
fill("white");
text(
"Your aunt was murdered ten years ago",
width / 2,
height / 2 - 100
);
//Get rid of begin button
startButton.pos = { x: -100, y: -100};
//Add accept button
nextButton.pos = { x: width/2, y: height/2 + 120};
nextButton.w = 280;
nextButton.h = 90;
nextButton.collider = "k";
nextButton.color = "white";
nextButton.text = "Go searching for answers";
}
async function showLloronaScreen() {
if (music.isPlaying()) {
// Fade out over 1 second
for (let vol = 0.3; vol >= 0; vol -= 0.01) {
music.setVolume(vol);
await delay(33); // approx 30fps
}
music.stop();
musicStopped = true;
}
if (!lloronaSound.isPlaying()) {
lloronaSound.play();
lloronaSound.setVolume(0.05);
}
background(46, 26, 10);
image(lloronaBg, 3, 0);
lloronaFullSprite.pos = { x: width/2, y: height/2 + 50 };
lloronaFullSprite.scale = 0.1;
lloronaFullSprite.rotation = 0;
planchadaFullSprite.pos = { x: -2000, y: -2000 }; // Move planchada off screen
charroFullSprite.pos = { x: -2000, y: -2000 }; // Move charro off screen
fill("antiquewhite");
textAlign(LEFT);
textSize(20);
text(
"tutorial text here",
width/2 - 250,
height/2 - 100
);
//Get rid of accept button
nextButton.pos = { x: -2000, y: -2000 };
//Add forward button at bottom right
forwardButtonSprite.pos = { x: width - 50, y: height - 50 };
forwardButtonSprite.w = 45;
forwardButtonSprite.h = 45;
forwardButtonSprite.collider = "k";
forwardButtonSprite.color = color(255, 255, 255, 0);
forwardButtonSprite.rotation = 0;
//Add back button at bottom left
backButtonSprite.pos = { x: 50, y: height - 50 };
backButtonSprite.w = 45;
backButtonSprite.h = 45;
backButtonSprite.collider = "k";
backButtonSprite.color = color(255, 255, 255, 0);
backButtonSprite.rotation = 0; //Corrected line
//change music
//Add book button at top left
bookButtonSprite.pos = { x: 50, y: 50 };
bookButtonSprite.w = 45;
bookButtonSprite.h = 45;
bookButtonSprite.collider = "k";
bookButtonSprite.color = color(255, 255, 255, 0);
// move exit button off screen
exitButtonSprite.pos = { x: -2000, y: -2000 };
}
function showCharroScreen() {
if (lloronaSound.isPlaying()) {
lloronaSound.pause();
}
background(46, 26, 10);
image(charroBg, 3, 0);
if (charroFullSprite) {
charroFullSprite.remove();
}
charroFullSprite = new Sprite(charroFull, width/2, height/2);
charroFullSprite.scale = 0.1;
lloronaFullSprite.pos = { x: -2000, y: -2000 }; // Move Llorona off screen
forwardButtonSprite.pos = { x: -2000, y: -2000 };
fill("antiquewhite");
textAlign(LEFT);
textSize(20);
text(
"elcharro",
width/2 - 250,
height/2 - 100
);
}
function showPlanchadaScreen() {
if (lloronaSound.isPlaying()) {
lloronaSound.pause();
}
background(46, 26, 10);
image(planchadaBg, 3, 0);
planchadaFullSprite.pos = { x: width/2, y: height/2 + 50 };
planchadaFullSprite.scale = 0.1;
planchadaFullSprite.rotation = 0;
if (screen == 3) {
lloronaFullSprite.pos = { x: width/2, y: height/2 };
} else {
lloronaFullSprite.pos = { x: -2000, y: -2000 };
}
// Move Llorona off screen
backButtonSprite.pos = { x: -2000, y: -2000 };
fill("antiquewhite");
textAlign(LEFT);
textSize(20);
text(
"laplanchada",
width/2 - 250,
height/2 - 100
);
}
function showBookScreen() {
background(46, 26, 10);
image(bookBg, 3, 0);
console.log("Planchada position:", planchadaFullSprite.pos);
console.log("Charro position:", charroFullSprite.pos);
// Add exit button at top right
exitButtonSprite = new Sprite(exitButton, width - 50, 50);
exitButtonSprite.w = 45;
exitButtonSprite.h = 45;
exitButtonSprite.collider = "k";
exitButtonSprite.color = color(255, 255, 255, 0);
}```